<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Заметки — Игорь К.: заметки с тегом автоматизация</title>
<link>https://blog.fossko.ru/tags/avtomatizaciya/</link>
<description>Блог Игоря К. о маркетинге, аналитике, фотографии и жизни...</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.4 (v4171)</generator>

<itunes:subtitle>Блог Игоря К. о маркетинге, аналитике, фотографии и жизни...</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit></itunes:explicit>

<item>
<title>Как я помог организовать мониторинг и сохранение публичных видеостримов</title>
<guid isPermaLink="false">576</guid>
<link>https://blog.fossko.ru/all/kak-ya-pomog-organizovat-monitoring-i-sohranenie-publichnyh-v/</link>
<pubDate>Sat, 07 Feb 2026 10:21:20 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/kak-ya-pomog-organizovat-monitoring-i-sohranenie-publichnyh-v/</comments>
<description>
&lt;p&gt;На стриминговых платформах трансляции часто запускаются без расписания. Страницы могут оставаться неактивными часами, а затем в любой момент переходить в режим прямого эфира. Если такие трансляции нужно фиксировать и сохранять, ручной контроль быстро перестаёт работать.&lt;/p&gt;
&lt;p&gt;С такой задачей ко мне обратился заказчик. На тот момент он мониторил &lt;b&gt;три модели&lt;/b&gt; и делал это вручную: открывал страницы, проверял статус, ждал начала эфира и запускал сохранение сам. Даже при таком объёме на это уходило много времени и внимания, а часть трансляций всё равно пропускалась.&lt;/p&gt;
&lt;p&gt;Моя задача была в том, чтобы &lt;b&gt;снять с человека постоянное дежурство&lt;/b&gt; и заменить его системой автоматического мониторинга, которую можно сопровождать, а не обслуживать вручную.&lt;/p&gt;
&lt;h2&gt;Контекст: стримы ведут модели&lt;/h2&gt;
&lt;p&gt;На платформе работают модели — живые авторы трансляций. Каждая из них выходит в эфир по собственному графику:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;заранее неизвестно, когда начнётся трансляция;&lt;/li&gt;
&lt;li&gt;страница большую часть времени неактивна;&lt;/li&gt;
&lt;li&gt;прямой ссылки на видео нет до момента старта;&lt;/li&gt;
&lt;li&gt;эфир может закончиться в любой момент.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Даже при работе с одной моделью это означает необходимость постоянно возвращаться к странице и проверять её состояние. В случае заказчика таких страниц было три — и уже на этом объёме ручной процесс стал трудоёмким и неудобным.&lt;/p&gt;
&lt;h2&gt;В чём была основная сложность&lt;/h2&gt;
&lt;p&gt;Проблема была не в сохранении видео как таковом, а в самом процессе наблюдения:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;нужно регулярно проверять несколько страниц, чтобы не пропустить начало эфира;&lt;/li&gt;
&lt;li&gt;невозможно надолго отвлечься без риска что-то упустить;&lt;/li&gt;
&lt;li&gt;видео становится доступно только в момент начала трансляции;&lt;/li&gt;
&lt;li&gt;внимание постоянно тратится на ожидание.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Даже три модели требуют постоянного внимания. При дальнейшем расширении списка моделей к этому добавляется ещё один слой сложности — &lt;b&gt;ресурсный&lt;/b&gt;.&lt;/p&gt;
&lt;h2&gt;Как выстроена система мониторинга&lt;/h2&gt;
&lt;p&gt;Вместо ручных действий была выстроена система из нескольких специализированных скриптов. Каждый из них решает свою задачу и работает автоматически. В обычном режиме система не требует участия человека, но за ней нужно присматривать и периодически адаптировать под изменения — этим я и занимаюсь.&lt;/p&gt;
&lt;p&gt;В упрощённом виде логика работы выглядит так:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Отслеживание состояния страниц&lt;/b&gt;.   Скрипты регулярно проверяют состояние страниц и понимают, активна ли модель в данный момент. Если трансляции нет, система не выполняет лишних действий.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Режим ожидания&lt;/b&gt;.  Пока эфиры не идут, мониторинг работает с минимальной нагрузкой и просто ждёт изменений.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Фиксация начала трансляции&lt;/b&gt; . Когда модель выходит в эфир, система автоматически фиксирует переход страницы в активное состояние.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Обнаружение видео&lt;/b&gt;. В момент начала трансляции система определяет, что на странице появилось активное видео и его можно сохранять.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Сохранение и продолжение мониторинга&lt;/b&gt;. После завершения эфира система возвращается в режим ожидания и продолжает работу без участия человека.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Почему такой формат оказался удобным&lt;/h2&gt;
&lt;p&gt;Такой подход оправдан уже &lt;b&gt;даже при работе с одной моделью&lt;/b&gt;.&lt;br /&gt;
Трансляции запускаются нерегулярно, и чтобы не пропустить эфир, нужно постоянно проверять страницу или держать её открытой.&lt;/p&gt;
&lt;p&gt;В случае с тремя моделями эта нагрузка просто утраивается: внимание распыляется, возрастает риск пропустить начало трансляции, а сам процесс превращается в постоянное ожидание.&lt;/p&gt;
&lt;p&gt;Автоматический мониторинг снимает эту нагрузку: система сама следит за состоянием страниц и реагирует только тогда, когда действительно начинается трансляция.&lt;/p&gt;
&lt;p&gt;При увеличении количества моделей появляется вторая задача — &lt;b&gt;управление ресурсами&lt;/b&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;возрастает нагрузка на сервер;&lt;/li&gt;
&lt;li&gt;увеличивается потребление сетевой пропускной способности;&lt;/li&gt;
&lt;li&gt;появляются ограничения по количеству параллельных операций.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В этом случае уже недостаточно просто «проверять чаще». Нужен подход, в котором мониторинг, нагрузка и объём данных находятся в балансе.&lt;/p&gt;
&lt;p&gt;Автоматизация здесь — не отдельный инструмент, а часть процесса, который я настраиваю, сопровождаю и адаптирую под конкретные объёмы и условия работы.&lt;/p&gt;
&lt;h2&gt;Надёжность и длительная работа&lt;/h2&gt;
&lt;p&gt;Отдельное внимание уделено стабильности:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;система рассчитана на длительную работу без остановок;&lt;/li&gt;
&lt;li&gt;при отсутствии активности не расходует ресурсы;&lt;/li&gt;
&lt;li&gt;корректно восстанавливается после временных сбоев;&lt;/li&gt;
&lt;li&gt;по логам понятно, что происходит и в каком состоянии мониторинг.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Это позволяет использовать решение в повседневной работе без возврата к ручному контролю.&lt;/p&gt;
&lt;h2&gt;Результат&lt;/h2&gt;
&lt;p&gt;В итоге заказчик перестал тратить время на постоянное наблюдение даже за этими тремя страницами.&lt;br /&gt;
Мониторинг и сохранение трансляций выполняются автоматически, иногда нужно сопровождать систему, следить за состоянием и адаптировать под изменения.&lt;/p&gt;
&lt;p&gt;Такие задачи редко удаётся закрыть одним готовым инструментом.&lt;br /&gt;
Обычно приходится учитывать особенности конкретной платформы, подстраивать логику мониторинга и со временем её поддерживать.&lt;/p&gt;
</description>
</item>

<item>
<title>Google скрипт просит права сразу на все документы</title>
<guid isPermaLink="false">543</guid>
<link>https://blog.fossko.ru/all/google-skript-prosit-prava-srazu-na-vse-dokumenty/</link>
<pubDate>Mon, 18 Dec 2023 11:33:08 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/google-skript-prosit-prava-srazu-na-vse-dokumenty/</comments>
<description>
&lt;p&gt;Когда Google Apps Script просит доступ ко всем документам на гугл диске.&lt;br /&gt;
Чтобы избежать проблем с доступом, добавьте в шапку скриптов код:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;/**
 * @OnlyCurrentDoc
 */&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/image-18.png" width="990" height="389" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Код вставляется со всеми слешами и звездочками. &lt;a href="https://developers.google.com/apps-script/guides/services/authorization?hl=ru#manual_authorization_scopes_forand"&gt;Справка гугл документов&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Парсим телеграм каналы агентств интернет-маркетинга</title>
<guid isPermaLink="false">540</guid>
<link>https://blog.fossko.ru/all/parsim-telegram-kanaly-agentstv-internet-marketinga/</link>
<pubDate>Tue, 28 Nov 2023 20:21:53 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/parsim-telegram-kanaly-agentstv-internet-marketinga/</comments>
<description>
&lt;p&gt;В гугл таблицах автоматически получим ссылки на телеграм каналы интернет-агентств.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Предыстория&lt;/b&gt; .У Павела Злобина вышла статья «&lt;a href="https://pavezlo.ru/testirovanie-gipotez/top-telegramm-kanalov-pro-marketing/"&gt;Топ телеграм каналов про маркетинг&lt;/a&gt;»  в которой описывает как можно получить телеграм каналы агентств.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/Reyting-agentstv-Performance-marketinga,-TOP-luchshih-perfomans-kompaniy---Opera-2023-11-28-20.16.58.jpg" width="639" height="503" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;&lt;a href="https://ratingruneta.ru/performance/"&gt;В рейтинге рунета есть список топ-100 агентств&lt;/a&gt;, из списка мы можем получить название и ссылку на страницу о агентстве&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Наименование агенства&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;=IMPORTXML(A1;&amp;quot;//table[@id=&amp;#039;rating_table_id&amp;#039;]/tbody/tr/td/div/a&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ссылка на страницу&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;=IMPORTXML(A1;&amp;quot;//table[@id=&amp;#039;rating_table_id&amp;#039;]/tbody/tr/td/div/a/@href&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/IT-Agency--otzyvy-klientov,-portfolio,-klienty,-stoimost-uslug---Opera-2023-11-28-20.19.32.jpg" width="848" height="214" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;На подробной странице агентства может быть ссылка на телеграм и ВК, получим их&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ссылка на телеграм&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;=IFNA(IMPORTXML(&amp;quot;https://ratingruneta.ru&amp;quot;&amp;amp;B4;&amp;quot;//a[@class=&amp;#039;_1OOlgax2iF telegram&amp;#039;]//@href&amp;quot;);&amp;quot;&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ссылка на ВК&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;=IFNA(IMPORTXML(&amp;quot;https://ratingruneta.ru&amp;quot;&amp;amp;B4;&amp;quot;//a[@class=&amp;#039;_1OOlgax2iF vkontakte&amp;#039;]//@href&amp;quot;);&amp;quot;&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/TG-kanaly-ratingruneta---Google-Tablicy---Opera-2023-11-28-20.13.26.jpg" width="763" height="650" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Протягиваем формулы, и получаем готовую страницу&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Таким же образом можно получить информацию о других рейтингах.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.google.com/spreadsheets/d/1OnaWe5nGN7f7FH4CZm9ec3E6LkSapPqGDDphsvZUGvU/edit#gid=0"&gt;Ссылка на таблицу&lt;/a&gt;&lt;/p&gt;
</description>
</item>

<item>
<title>Транскрибируем видео из телеграма</title>
<guid isPermaLink="false">510</guid>
<link>https://blog.fossko.ru/all/transkribiruem-video-iz-telegrama/</link>
<pubDate>Fri, 12 May 2023 12:51:24 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/transkribiruem-video-iz-telegrama/</comments>
<description>
&lt;p&gt;Когда требуется распознать видео с вебинара в телеграме, делаем следующее:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Скачиваем видео к себе на компьютер&lt;/li&gt;
&lt;li&gt;Вытаскиваем аудиодорожку через ffmpeg&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;ffmpeg -i video1014957119.mp4 video1014957119.mp3&lt;/code&gt;&lt;/pre&gt;&lt;ol start="3"&gt;
&lt;li&gt;Транскрибируем через &lt;a href="/all/rasshifrovka-audio-i-video/"&gt;whisper-ctranslate2 в Гугл колаб&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/whisper-ctranslate2-audio-to-text-bystry.ipynb---Colaboratory---Google-Chrome-2023-05-12-12.44.30.jpg" width="920" height="416" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Фрагмент вебинара SEO c Ильей Карбышевом: &lt;a href="https://t.me/irinausichenko/865" class="nu"&gt;«&lt;u&gt;SEO для редакторов&lt;/u&gt;»&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Расшифровка аудио и видео</title>
<guid isPermaLink="false">508</guid>
<link>https://blog.fossko.ru/all/rasshifrovka-audio-i-video/</link>
<pubDate>Fri, 21 Apr 2023 15:13:37 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/rasshifrovka-audio-i-video/</comments>
<description>
&lt;p&gt;Когда требуется расшифровать аудиофайл, или ролик с ютуба, я пользуюсь whisper или whisper-ctranslate2 в среде &lt;a href="https://colab.research.google.com/"&gt;Гугл колаб&lt;/a&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;div class="fotorama" data-width="761" data-ratio="1.4834307992203"&gt;
&lt;img src="https://blog.fossko.ru/pictures/Untitled0.ipynb---Colaboratory---Google-Chrome-2023-04-21-14.35.15.jpg" width="761" height="513" alt="" /&gt;
&lt;img src="https://blog.fossko.ru/pictures/Untitled0.ipynb---Colaboratory---Google-Chrome-2023-04-21-14.36.18.jpg" width="711" height="309" alt="" /&gt;
&lt;/div&gt;
&lt;div class="e2-text-caption"&gt;При использовании библиотеки whisper-ctranslate2 лучше использовать графическую карту — GPU. Меню → Среда выполнения → Сменить среду выполнения → GPU&lt;/div&gt;
&lt;/div&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# установка оригинального whisper
!pip install git+https://github.com/openai/whisper.git

# установка ffmpeg
!sudo apt update &amp;amp;&amp;amp; sudo apt install ffmpeg

# установка whisper-ctranslate2
!pip install -U whisper-ctranslate2

# установка yt-dlp для сохранения видео с ютуба
!pip install yt-dlp&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Двойной символ &amp;&amp; используется для запуска двух команд одновременно, если первая команда завершена успешно. Это означает, что если первая команда возвращает ошибку, то вторая команда не будет выполнена.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/Softcatala/whisper-ctranslate2"&gt;Гитхаб whisper-ctranslate2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;С декабря 2023 года выдается ошибка: «RuntimeError: Library libcublas.so.11 is not found or cannot be loaded»&lt;br /&gt;
Для исправления ошибки установите Cuda 11 командой:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;!apt install libcublas11&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Скачивать будем ролик Ильи Бирмана из лекции &lt;a href="https://ilyabirman.ru/meanwhile/all/understanding-the-task/"&gt;о понимании задачи&lt;/a&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# качаем ролик id в mp3 в корень
!yt-dlp -x --audio-format mp3 -o ./birman_ponimanie_zadachi.mp3 -- PbnbwkoCQOE&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Распознавать можно whisper-ctranslate2 — по моим наблюдением расшифровывает в 2—3 раза быстрее чем оригинальный whisper.  На данный момент модель large-v2 самая полная.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;#распознаем через whisper-ctranslate2
!whisper-ctranslate2 &amp;quot;birman_ponimanie_zadachi.mp3&amp;quot; --language Russian  -o ./result --model large-v2 --model_dir ./model&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/rasshifrovka-audio-i-video.png" width="749" height="558" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Результат в консоле будет появляться по мере распознавания. Результирующие файлы будут в папке result в форматах .json, .srt, .tsv, .txt и .vtt. Например, в txt — только текст, в tsv — таймкоды, в vtt и srt — субтитры.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Через оригинальный whisper имеет смысл распознавать на компьютерах без видеокарт, это долго, но работает. Whisper требует версию питона 3.8—3.10, на других версиях не заработает.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;#распознаем через оригинальный whisper
!whisper &amp;quot;iliahov2.mp3&amp;quot; -o ./result --model large-v2 --model_dir ./model&lt;/code&gt;&lt;/pre&gt;&lt;p class="loud"&gt;Если вам нужно что-то распознать или транскрибацию провести. Пишите в телеграм, договоримся :—)&lt;/p&gt;
</description>
</item>

<item>
<title>Выполняем SQL запрос в питоне</title>
<guid isPermaLink="false">507</guid>
<link>https://blog.fossko.ru/all/vypolnyaem-sql-zapros-v-pitone/</link>
<pubDate>Thu, 20 Apr 2023 17:16:02 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/vypolnyaem-sql-zapros-v-pitone/</comments>
<description>
&lt;p&gt;В питоне можно выполнить запрос к базе данных на SQL сервере, а ответ получить как датасет пандос.&lt;/p&gt;
&lt;p&gt;Импортируем библиотеки, в примере мы будем подключаться к MS SQL серверу, но можно подключаться к другим базам данных, используя нужную библиотеку.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;import pyodbc
import pandas as pd&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В переменную con запишем подключение к SQL серверу&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# создание подключения к базе данных
con = pyodbc.connect(&amp;quot;Driver={SQL Server Native Client 11.0};&amp;quot;
                      &amp;quot;Server=NAME_SQL_SERVER;&amp;quot;
                      &amp;quot;Database=NAME_BASE;&amp;quot;
                      &amp;quot;Trusted_Connection=yes;&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Функция select — для быстрой отправки sql запроса, на входе sql запрос, на выходе результат выполнения&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# функция отправки запроса к базе sql
def select(sql):
    return pd.read_sql(sql,con)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Используем тройные кавычки, для переноса построчно, иначе нужно писать в одну строку&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# Переменной sql присваиваем запрос
sql=&amp;#039;&amp;#039;&amp;#039;

DECLARE
@today DATE,
@yesterday DATE

SELECT
@yesterday = DATEADD(day, -1, CAST(GETDATE() AS date))  --вчера в виде даты без времени
,@today = CAST(GETDATE() AS date)  --сегодня в виде даты без времени

SELECT 
  *  
FROM table.data

WHERE
 DataZvonka &amp;lt;= @yesterday 
 and
 DataPrihoda &amp;gt;= @today

&amp;#039;&amp;#039;&amp;#039;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Присваиваем датасету df, результат выполнения запроса sql&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# создание датасета с данными запроса
df=select(sql)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Дальше можно производить вычисления в пандос, и делать что нужно с данными, например, записать в гугл таблицу, отправить в телеграм группу.&lt;/p&gt;
</description>
</item>

<item>
<title>Unpivot в Google Sheets</title>
<guid isPermaLink="false">475</guid>
<link>https://blog.fossko.ru/all/unpivot-v-google-sheets/</link>
<pubDate>Thu, 02 Feb 2023 14:53:47 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/unpivot-v-google-sheets/</comments>
<description>
&lt;p&gt;Что если у нас уже имеется возрастная когорта, без исходных данных.&lt;br /&gt;
Требуется из нее получить сколько денег мы заработали каждый месяц?&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/unpivot-v-google-sheets.png" width="722" height="286" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Есть когорта — в столбцах время прошедшее с момента месяца первой регистрации, строчки — время первой регистрации. Мы хотим ее перевернуть и получить данные по каждому месяцу&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Вопрос&lt;/b&gt;: Как считали возраст? Между месяцами или между датами?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Если между датами, то 1-к-1 в календарную когорту перевести нельзя, так как у каждого юзера там свой собственный m0.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Если между месяцами, то можно просто “сдвинуть” все колонки вправо и заменить возраст на календарный месяц.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Мы считаем по второму варианту:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;каждой оплате присваиваем первый день месяца оплаты,&lt;/li&gt;
&lt;li&gt;каждой регистрации первый первый день месяца оплаты.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Наш вариант второй — между месяцами.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/unpivot-v-google-sheets-2.png" width="722" height="288" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Наша когорта, линиями показано, из чего состоит каждый месяц.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Основная формула, для решения задачи:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;OFFSET(C5,0,$B5))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;возвращаем значение со сдвигом строки, для этого пронумеруем строки в минус.&lt;br /&gt;
Дальше if отрезает не нужное&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/unpivot-v-google-sheets-1.png" width="971" height="797" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Получившаяся помесячная когорта с выручкой.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Итоговая формула:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;=IFERROR(IF(OFFSET(C3;0;$B3)=$B3;&amp;quot;&amp;quot;;OFFSET(C3;0;$B3));&amp;quot;&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="https://docs.google.com/spreadsheets/d/1QT7OAnAv20KVaoeb5uqDRmT0qjz9WcO4FmGZCdiTszM/edit?usp=sharing"&gt;Таблица со всеми формулами&lt;/a&gt;&lt;/p&gt;
</description>
</item>

<item>
<title>Типограф в гугл документах</title>
<guid isPermaLink="false">472</guid>
<link>https://blog.fossko.ru/all/tipograf-v-gugl-dokumentah/</link>
<pubDate>Sun, 29 Jan 2023 15:46:28 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/tipograf-v-gugl-dokumentah/</comments>
<description>
&lt;p&gt;Когда используешь гугл документы для набора текстов для печати, не хватает встроенного типографа. Типограф нужен для правильного проставления неразрывного пробела, знака тире, замены кавычек на правильные.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/glebkema/google-docs-typograf"&gt;Скрипт от Глеба Керамского&lt;/a&gt; написан на google apps script и легко адаптируется&lt;/p&gt;
&lt;h2&gt;Скрипт работает только в текущем документе&lt;/h2&gt;
&lt;p&gt;В оригинале скрипт можно запускать в определенном документе, для этого:&lt;br /&gt;
открываем наш гугл документ и переходим в Apps Script&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah.png" width="744" height="260" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Меню — расширения — Apps Script&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Копируем код из скрипта Глеба и вставляем в наш скрипт&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-1.png" width="1194" height="866" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;У Глеба на гитхабе код лежит в файле &lt;a href="https://github.com/glebkema/google-docs-typograf/blob/master/Code.gs"&gt;Code.gs&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Можно остановиться на этом, но лучше в только что созданный скрипт, добавить следующее&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;/**
 * @OnlyCurrentDoc
 */&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Эта строчка позволит ограничить запуск скрипта текущим документом&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-2.png" width="1078" height="527" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Итоговый скрипт с нашим дополнением&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Дальше мы сохраняем и переходим в гугл документ.&lt;/p&gt;
&lt;p&gt;Для работы скрипта нужно перегрузить страницу, нажимаем CTRL+F5&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-3.png" width="1278" height="545" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;После перезагрузки страницы в этом документе появился пункт меню — typograf, при нажатии на него текст будет отипографирован.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;div class="fotorama" data-width="729" data-ratio="1.744019138756"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-4.png" width="729" height="418" alt="" /&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-5.png" width="767" height="649" alt="" /&gt;
&lt;/div&gt;
&lt;div class="e2-text-caption"&gt;Если вы запускаете скрипт первый раз, будет предложено проверить разрешение скрипта. После разрешение текст будет отипографирован.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-6.png" width="713" height="412" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Пример до: висячие предлоги и дефис вместо тире.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-7.png" width="726" height="396" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;После применения скрипта, висячие пробелы пропали и дефис поменялся на длинное тире. На самом деле тут после всех предлогов стали неразрывные пробелы.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Для применения скрипта нужно в каждом документе проделать следующие шаги:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Зайти в гитхаб и скопировать скрипт.&lt;/li&gt;
&lt;li&gt;Добавить скрипт в google apps script.&lt;/li&gt;
&lt;li&gt;Перезагрузить документ.&lt;/li&gt;
&lt;li&gt;Выполнить скрипт.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Скрипт работает для любого документа к которому есть доступ.&lt;/h2&gt;
&lt;p&gt;Можно сделать один скрипт на все документы к которым есть доступ.&lt;br /&gt;
Для этого нужно сделать google apps script который не подключен к конкретному документу, для этого зайдите на гугл диск в любую папку, например «Скрипты», нажмите правой клавишей пункт Еще — google apps script&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-8.png" width="768" height="501" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;При таком создании, скрипт будет работать отдельно от документа&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Рекомендую дать скрипту нормально название, например «Типограф», так будет проще искать по поиску на гугл диске.&lt;/p&gt;
&lt;p&gt;Копируем в наш скрипт &lt;a href="https://github.com/glebkema/google-docs-typograf/blob/master/Code.gs"&gt;код из гитхаба Глеба.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Теперь нам нужно модифицировать скрипт&lt;/p&gt;
&lt;p&gt;В функции typograf() комментируем строчку с выбором текущего файла, ставит две косые&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;//var body = DocumentApp.getActiveDocument().getBody();&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Создаем новую переменную в которую будем вставлять урл нашего документа&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;var body = DocumentApp.openByUrl(&amp;#039;https://docs.google.com/document/d/XXXXXXX&amp;#039;);&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-9.png" width="1303" height="613" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Наши изменения скрипта&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Сохраняем.&lt;/p&gt;
&lt;p&gt;Теперь нам нужно подправить какой-то документ:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Копируем его полный адрес&lt;/li&gt;
&lt;li&gt;Вставляем в переменную body — не забываем что адрес вставляется в одинарной в кавычках, у меня одинарная кавычка.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;var body = DocumentApp.openByUrl(&amp;#039;URL_DOC&amp;#039;);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Сохраняем.&lt;/p&gt;
&lt;p&gt;Осталось запустить, для этого в скрипте выбираем Типограф и кнопку «выполнить»&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/tipograf-v-gugl-dokumentah-10.png" width="860" height="270" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Если у вас не выбран типограф — нажимаем стрелочку вниз и выбираем.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Скрипт попросит авторизацию на возможное изменения всех документов, даем ему это разрешения.&lt;/p&gt;
&lt;p&gt;После запуска скрипт запустится и оттипографирует ваш документ.&lt;/p&gt;
&lt;p&gt;Если нужно, можно вставить ссылку на другой документ, а затем еще один.&lt;/p&gt;
</description>
</item>

<item>
<title>Отправляем поток из РСС в телеграм через Google Apps Script</title>
<guid isPermaLink="false">471</guid>
<link>https://blog.fossko.ru/all/otpravlyaem-potok-iz-rss-v-telegram-cherez-google-apps-script/</link>
<pubDate>Thu, 22 Dec 2022 11:50:33 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/otpravlyaem-potok-iz-rss-v-telegram-cherez-google-apps-script/</comments>
<description>
&lt;p&gt;Обновляем канал «&lt;a href="https://t.me/pochitaet"&gt;Почитаем…&lt;/a&gt;»&lt;br /&gt;
Теперь новые статьи будут приходить в канал автономно, через гугл таблицы и без участия локального сервера с питоном.&lt;br /&gt;
&lt;a href="/all/otpravlyaem-novye-statyi-iz-rss-v-telegram/"&gt;Раньше работало через питон и базу данных на sqlite3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;В гугл таблице нам нужны три листа: rss, rss_data, error&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rss — будем хранить рсс потоки сайтов,&lt;/li&gt;
&lt;li&gt;rss_data — будем хранить базу данных что отпарсилось и что отправлено,&lt;/li&gt;
&lt;li&gt;error — будем хранить ошибки при отладке, если это потребуется&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/image-12.png" width="1124" height="610" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;На листе rss, в первой колонке перечислены все рсс-потоки, при необходимости добавить или удалить, делаем это здесь.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/image-11.png" width="1124" height="610" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;На листе rss_data, первая строчка с наименованием колонок&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;У меня сейчас 110 источников, когда идет запись в таблицу, скрипт не успевает обработать все данные, и отваливается по тайм-ауту гугла. После нескольких запусков он все ссылки обработает и начинает укладываться в тайминг.&lt;br /&gt;
Возможно, в будущем, нужно скрипт делить на несколько&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/otpravlyaem-potok-iz-rss-v-telegram-cherez-google-apps-script.png" width="510" height="834" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;сообщения приходят в том же виде, что и раньше.&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Парсинг потоков рсс через гугл таблицы&lt;/h2&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;// Считываем базу данных РСС
function data_base_rss() {
  var app = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(&amp;quot;rss_data&amp;quot;)
  data_base= app.getRange(1,1, app.getLastRow(), app.getLastColumn()).getValues(); //только заполненный диапазон
  return(data_base)
}

// поиск по базе данных
function find_rss(url) {
  rezult = rss_data.findIndex(item =&amp;gt; item[3] === url) //ищем в 4 столбце
  //console.log(rezult) //-1 если не найдено, и индекс положительный если нашлось это что нашлось лог
  return(rezult)
}


// Запись нового поста в таблицу
function data_write_rss(data) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(&amp;quot;rss_data&amp;quot;);
  var value = data
  sheet.getRange(sheet.getLastRow() + 1,1,1,4).setValues([value]);
  console.log(data)
}

// Запись error в таблицу
function error_log(data) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(&amp;quot;error&amp;quot;);
  //var sheet = spreadsheet.getActiveSheet();
  //var value = new Date(); // value you want to insert
  //var value = data
  sheet.getRange(sheet.getLastRow() + 1,1,1,3).setValues([data]);
  console.log(data)
}


//функция проверки новых постов текущего потока
function get_rss(rss_url) {
  var url =rss_url
  var date_rss =[]
  var xml = UrlFetchApp.fetch(url).getContentText()
  document = XmlService.parse(xml);
  root = document.getRootElement();
  channel = root.getChild(&amp;#039;channel&amp;#039;);
  items = channel.getChildren(&amp;#039;item&amp;#039;);
  items.forEach(item =&amp;gt; {
    parsing_date=new Date(); // дата текущая
    title = item.getChild(&amp;#039;title&amp;#039;).getText();
    link = item.getChild(&amp;#039;link&amp;#039;).getText()
    try{
    author = item.getChild(&amp;#039;author&amp;#039;).getText();} //автор не у всех бывает
    catch(e){author =&amp;quot;&amp;quot;}
    if (find_rss(link) == -1) {
      data_write_rss([parsing_date,title,author,link])  
    }
   });
  console.log(date_rss)
}

// Основная функция парсинга всех РСС потоков, ее нужно установить в запуск раз в 15 минут
function parse_rss() {
  var rss_data=data_base_rss()
  var app = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(&amp;quot;rss&amp;quot;)
  url_array = app.getRange(1,1, app.getLastRow(), 1).getValues(); //только заполненный первый столбец
  console.log(url_array);
  url_array.forEach(url =&amp;gt; {
    console.log(url)
    try{ 
      get_rss(url)}
    catch(e){console.log(&amp;quot;! недействительный URL&amp;quot;, console.log(url),&amp;#039;Ошибка &amp;#039; + e.name + &amp;quot;:&amp;quot; + e.message + &amp;quot;\n&amp;quot; + e.stack)
    //error_log([new Date(),url,&amp;#039;Ошибка &amp;#039; + e.name + &amp;quot;:&amp;quot; + e.message + &amp;quot;\n&amp;quot; + e.stack]) //При необходимости записи ошибок снять комментарий     
    } //Обработка ошибки 
  })
}&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Код отправки сообщений в телеграм:&lt;/h2&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;const tokendr = &amp;quot;BOT_token&amp;quot;; 
const IDChattelegramdr = &amp;quot;ID_CHAT&amp;quot; 

function timerSENDtgDR() {
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let ws = ss.getSheetByName(&amp;quot;rss_data&amp;quot;); //таблица с которой берем данные
  let data = ws.getRange(2, 1, ws.getLastRow()-1, 5).getValues(); //диапазон с которого берем данные
  Logger.log ( data ); 
  for (i = 0; i &amp;lt; data.length; i++) {
    let dataInfo = data[i]; //строчка таблицы
    //Logger.log ( dataInfo );
    let telegram_send = dataInfo[4]; //пятая ячейка telegram_send
    Logger.log(telegram_send)
    if (telegram_send ===&amp;quot;&amp;quot;){
      title = dataInfo[1];
      author = dataInfo[2];
      if (author !=&amp;#039;&amp;#039;){
      author=author+&amp;quot;\n\n&amp;quot;    //если имя автора есть, добавить переносы строк
      }
      link = dataInfo[3];
      sendTextDR(IDChattelegramdr, &amp;quot;&amp;lt;b&amp;gt;&amp;quot;+title+&amp;quot;&amp;lt;/b&amp;gt;\n\n&amp;quot; + author + link);
      ws.getRange(i+2 , 5, 1, 1).setValues([[new Date()]]);
      Utilities.sleep(500);// pause in the loop for 500 milliseconds
      Logger.log (&amp;quot;сообщение отправлено&amp;quot;);
    }
  }
}
 
function sendTextDR(chatId, text, keyBoard) {
  let data = {
    method: &amp;#039;post&amp;#039;,
    payload: {
      method: &amp;#039;sendMessage&amp;#039;,
      chat_id: String(chatId),
      text: text,
      //parse_mode:&amp;#039;Markdown&amp;#039;,
      parse_mode: &amp;#039;html&amp;#039;,
      reply_markup: JSON.stringify(keyBoard)
    }
  }
  UrlFetchApp.fetch(&amp;#039;https://api.telegram.org/bot&amp;#039; + tokendr + &amp;#039;/&amp;#039;, data);
}&lt;/code&gt;&lt;/pre&gt;</description>
</item>

<item>
<title>Видеонаблюдение через телеграм</title>
<guid isPermaLink="false">466</guid>
<link>https://blog.fossko.ru/all/videonablyudenie-cherez-telegram/</link>
<pubDate>Sat, 15 Oct 2022 15:01:43 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/videonablyudenie-cherez-telegram/</comments>
<description>
&lt;p&gt;На камерах Hikvision можно сделать простое видеонаблюдение через телеграм.&lt;br /&gt;
Когда в камере срабатывает датчик движения, камера отправляет на телеграм фотографию что произошло.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/image-6.png" width="510" height="942" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Отправляются три изображения с интервалом 2 секунды, от момента срабатывания датчика&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;По умолчанию, мы не можем отправлять изображения в телеграм, можем только на почту.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;div class="fotorama" data-width="1091" data-ratio="1.4924760601915"&gt;
&lt;img src="https://blog.fossko.ru/pictures/Nastroyki---Internet-Explorer-2022-10-15-14.23.59.jpg" width="1091" height="731" alt="" /&gt;
&lt;img src="https://blog.fossko.ru/pictures/Nastroyki---Internet-Explorer-2022-10-15-14.24.25.jpg" width="1092" height="731" alt="" /&gt;
&lt;/div&gt;
&lt;div class="e2-text-caption"&gt;Настройки детектора движения: «Настройки» → «По событию» → «События» → «Детектор движения». Настраиваем зону срабатывания и событие отправки на электронную почту.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Отправлять события нужно на гугл почту. В гугле есть App Script, с помощью которого можно пересылать почту в телеграм.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/Nastroyki---Internet-Explorer-2022-10-15-14.29.27.jpg" width="1068" height="728" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Настройки видеокамеры для отправки на электронную почту: «Настройки» → «Сеть» → «Доп. настройки» → «Email»&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/videonablyudenie-cherez-telegram.png" width="820" height="521" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Если все настроено правильно, в почту гугл начнут приходить письма с фотографиями.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;На гитхабе выложен &lt;a href="https://github.com/kooison/Gmail-to-Telegram"&gt;пример скрипта, для отправки вложенных в письма фотографий в телеграм&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Нам, остается немного его доработать, так как скрипт отправляет первое вложение в телеграм.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/videonablyudenie-cherez-telegram-1.png" width="1183" height="794" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Присваиваем всем нашим письмам ярлык — CAMERA, скрипт проверяет или все письма или по определенным параметрам, например, ярлык.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/image-7.png" width="696" height="401" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Если правильно настроено правило, ярлыки появляются у каждого нового письма с камеры&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/videonablyudenie-cherez-telegram-3.png" width="1203" height="969" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Дальше в апп скрипте вставляем наш скрипт, запускаем, тестирует, занимаемся отладкой.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/videonablyudenie-cherez-telegram-4.png" width="1325" height="980" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Ставим запуск скрипта раз в минуту. То есть почта будет проверяться раз в минуту и при соответвии условиям отправляться.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Мой скрипт:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;// The token of your Telegram bot
var TOKEN = &amp;quot;token bot&amp;quot;;

// Name of the Telegram channel which bot is added into
var CHANNEL = &amp;quot;id канала&amp;quot;;

// Name of the Gmail Label which need to search for
var LABEL = &amp;quot;CAMERA&amp;quot;

function processEmails() {
  
  // Search unread emails with specified label
  var search = &amp;quot;label:&amp;quot; + LABEL + &amp;quot; is:unread&amp;quot;;
  Logger.log(&amp;#039;Search: &amp;#039; + search);
  var threads = GmailApp.search(search, 0, 10);
  
  for (var i = 0; i &amp;lt; threads.length; i++) {
    var messages = threads[i].getMessages();
    Logger.log(&amp;#039;Number of emails found: &amp;#039; + messages.length);

    for (var j = 0; j &amp;lt; messages.length; j++) {
      var m = messages[j];
      if (!m.isInTrash() &amp;amp;&amp;amp; m.isUnread()) {
        if (m.getAttachments().length &amp;gt; 0) {
          
          // Get the first attachment (image jpeg file)
          // and send to telegram bot
          sendPhoto(m.getAttachments()[0].copyBlob());
          Logger.log(&amp;#039;фото: &amp;#039; + &amp;#039;1&amp;#039;);
          Utilities.sleep(500);// pause in the loop for 500 milliseconds
          sendPhoto(m.getAttachments()[1].copyBlob());
          Logger.log(&amp;#039;фото: &amp;#039; + &amp;#039;2&amp;#039;);
          Utilities.sleep(500);// pause in the loop for 500 milliseconds
          sendPhoto(m.getAttachments()[2].copyBlob());
          Logger.log(&amp;#039;фото: &amp;#039; + &amp;#039;3&amp;#039;);
          Utilities.sleep(500);// pause in the loop for 500 milliseconds   
        }
        m.markRead(); 
        m.moveToTrash(); // Where I would need a delete forever trigger;
      }
    }
  }
}

function sendPhoto(photo) {
  var payload = {
    &amp;#039;chat_id&amp;#039;: CHANNEL,
    &amp;#039;photo&amp;#039;: photo
  };
  var options = {
    &amp;#039;method&amp;#039;: &amp;#039;post&amp;#039;,
    &amp;#039;payload&amp;#039;: payload
  };
  UrlFetchApp.fetch(&amp;quot;https://api.telegram.org/bot&amp;quot; + TOKEN + &amp;quot;/sendPhoto&amp;quot;, options);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Из правок:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;отправляются 1,2,3 вложения,&lt;/li&gt;
&lt;li&gt;между отправкой пауза 0,5 секунды,&lt;/li&gt;
&lt;li&gt;сообщение после обработки удаляется в корзину.&lt;/li&gt;
&lt;/ul&gt;
</description>
</item>

<item>
<title>Отправляем новые статьи из РСС в телеграм</title>
<guid isPermaLink="false">465</guid>
<link>https://blog.fossko.ru/all/otpravlyaem-novye-statyi-iz-rss-v-telegram/</link>
<pubDate>Mon, 10 Oct 2022 10:10:19 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/otpravlyaem-novye-statyi-iz-rss-v-telegram/</comments>
<description>
&lt;p&gt;Удобно присылать новые ссылки на статьи моих подписок РСС в телеграм, так как вся коммуникация уже в нем, фидли почти не использую.&lt;/p&gt;
&lt;p&gt;Евгений Гончаров, в статье &lt;a href="https://sys-adm.in/programming/805-rss-fider-na-python-s-opravkoj-uvedomlenij-v-telegram.html" class="nu"&gt;«&lt;u&gt;RSS фидер на Python с оправкой уведомлений в Телеграм&lt;/u&gt;»&lt;/a&gt; описал весь принцип отправки и использование базы данных для контроля что отправили. &lt;a href="https://github.com/m0zgen/rss2bot/blob/master/rss.py"&gt;Готовый код на гитхабе Евгения&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Я внес небольшие изменения в код:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Сообщения в телеграм отправляются с задержкой 1 секунда. Если не использовать таймаут, сервер телеграма, может отправить не все сообщения.&lt;/li&gt;
&lt;li&gt;Изменил вид отправки сообщений: добавил переносы строк и автора, если он есть.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/image-5.png" width="518" height="904" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;В канал телеграма приходят новые сообщения. Проверка РСС проходит с 7 утра до 11 вечера, с интервалом 30 минут.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Канал открытый, можно подписаться на &lt;a href="https://t.me/pochitaet" class="nu"&gt;«&lt;u&gt;Почитаем&lt;/u&gt;»&lt;/a&gt;, там 95 источников РСС: например, избранное блогов на Эгее, Илья Бирман, Максим Ильяхов, Николай Товеровский, и другие.&lt;/p&gt;
&lt;p&gt;В примере скрипта: блоги на Эгее и мой блог.&lt;/p&gt;
&lt;p&gt;Скрипт:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;#!/usr/bin/python3
# Created by Yevgeniy Goncharov, https://sys-adm.in
# Script for reading and forwarding to Telegram, rss feeds


# Imports
import sqlite3
import requests
import feedparser
import os
import urllib
import random
import time

# Bot creds
bot_token = &amp;#039;bot_token&amp;#039;
bot_chatID = &amp;#039;bot_chatID&amp;#039;

# Feeds
myfeeds = [
    &amp;#039;https://blogengine.ru/blogs/rss/&amp;#039;,
    &amp;#039;http://blog.fossko.ru/rss/&amp;#039;,

]

# User agents
uags = [
  &amp;#039;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15&amp;#039;,
  &amp;#039;Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0&amp;#039;,
  &amp;#039;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36&amp;#039;,
  &amp;#039;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0&amp;#039;,
  &amp;#039;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36&amp;#039;,
]

# Random User Agent (from uags list)
ua = random.choice(uags)

# Header
headers = {
  &amp;quot;Connection&amp;quot; : &amp;quot;close&amp;quot;,  # another way to cover tracks
  &amp;quot;User-Agent&amp;quot; : ua
}

# Proxies
proxies = {
}

# DB
scriptDir = os.path.dirname(os.path.realpath(__file__))
db_connection = sqlite3.connect(scriptDir + &amp;#039;/rss.sqlite&amp;#039;)
db = db_connection.cursor()
db.execute(&amp;#039;CREATE TABLE IF NOT EXISTS myrss (title TEXT, date TEXT)&amp;#039;)

# Get posts from DB and print
def get_posts():
    with db_connection:
        db.execute(&amp;quot;SELECT * FROM myrss&amp;quot;)
       # print(db.fetchall())

# Check post in DB
def article_is_not_db(article_title, article_date):
    db.execute(&amp;quot;SELECT * from myrss WHERE title=? AND date=?&amp;quot;, (article_title, article_date))
    if not db.fetchall():
        return True
    else:
        return False

# Add post to DB
def add_article_to_db(article_title, article_date):
    db.execute(&amp;quot;INSERT INTO myrss VALUES (?,?)&amp;quot;, (article_title, article_date))
    db_connection.commit()

# Send notify to Telegram bot
def bot_sendtext(bot_message):
    #bot_message = urllib.parse.quote(bot_message)
    bot_message = bot_message
    send_text = &amp;#039;https://api.telegram.org/bot&amp;#039; + bot_token + &amp;#039;/sendMessage?chat_id=&amp;#039; + bot_chatID + &amp;#039;&amp;amp;parse_mode=Markdown&amp;amp;text=&amp;#039; + bot_message
    requests.get(send_text, proxies=proxies, headers=headers)
    print(send_text)

# Check, read articles
def read_article_feed(feed):
    &amp;quot;&amp;quot;&amp;quot; Get articles from RSS feed &amp;quot;&amp;quot;&amp;quot;
    feedparser.USER_AGENT = ua
    feed = feedparser.parse(feed)
    print(feed)
    for article in feed[&amp;#039;entries&amp;#039;]:
        if article_is_not_db(article[&amp;#039;title&amp;#039;], article[&amp;#039;published&amp;#039;]):
            add_article_to_db(article[&amp;#039;title&amp;#039;], article[&amp;#039;published&amp;#039;])
           # bot_sendtext(&amp;#039;New feed found &amp;#039; + article[&amp;#039;title&amp;#039;] +&amp;#039;, &amp;#039; + article[&amp;#039;link&amp;#039;] + &amp;#039;, &amp;#039; + article[&amp;#039;description&amp;#039;])
            try:
                rss_autor = article[&amp;#039;author&amp;#039;] +&amp;#039;%0A%0A&amp;#039;
            except:
                rss_autor = &amp;quot;&amp;quot;
            MSGsend=&amp;#039;*&amp;#039;+ article[&amp;#039;title&amp;#039;] + &amp;#039;*%0A%0A&amp;#039; + rss_autor + article[&amp;#039;link&amp;#039;]
            MSGsend=MSGsend.replace(&amp;quot;_&amp;quot;, &amp;quot;\_&amp;quot;)  # замена подчеркивания для отправки в ТГ
            bot_sendtext(MSGsend)            
            time.sleep(1)
           # print(article)

# Rotate feeds array
def spin_feds():
    for x in myfeeds:
       # print(x)
        read_article_feed(x)

# Runner :)
if __name__ == &amp;#039;__main__&amp;#039;:
    spin_feds()
    # get_posts()
    db_connection.close()&lt;/code&gt;&lt;/pre&gt;</description>
</item>

<item>
<title>Отправка из Яндекс форм в телеграм</title>
<guid isPermaLink="false">464</guid>
<link>https://blog.fossko.ru/all/otpravka-iz-yandeks-form-v-telegram/</link>
<pubDate>Thu, 12 May 2022 10:09:13 +0300</pubDate>
<author></author>
<comments>https://blog.fossko.ru/all/otpravka-iz-yandeks-form-v-telegram/</comments>
<description>
&lt;p&gt;У Яндекса есть удобный сервис — Яндекс формы, он позволяет вставлять любые формы на любые сайты.&lt;br /&gt;
А вот получение данных не всегда удобное: нужно зайти в форму, перейти к ответам, посмотреть результаты.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/Zayavka-dzen-(Nastroyki)---Google-Chrome-2023-04-21-13.19.06.jpg" width="1003" height="236" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Входим в форму — интеграции&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/Zayavka-dzen-(Nastroyka-integraciy)---Google-Chrome-2023-04-21-13.19.41.jpg" width="1127" height="883" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Можно отправлять на е-маил, это реализовано сразу, включаем в настройках, указываем кому отправить форму, что написать и заполняем шаблон.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Для отправки в телеграм, используется интеграция — *&lt;b&gt;API Запрос заданным методом&lt;/b&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/Zayavka-dzen-(Nastroyka-integraciy)---Google-Chrome-2023-04-21-13.21.43.jpg" width="1009" height="712" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Метод запроса POST&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;У меня отправляется только если весь запрос передать в УРЛ, по-хорошему нужно передавать через тело запроса, но у меня не работает.&lt;/p&gt;
&lt;p&gt;В УРЛ подставляем следующее:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;https://api.telegram.org/ИД вашего бота:Секретный ключ бота/sendMessage?chat_id=ИД кому отправлять&amp;amp;text=*Дзен_Яндекс*: Что из формы отправлять   &amp;amp;parse_mode=Markdown

https://api.telegram.org/bot111111:AABBBCCDDDFFFHJGHGHG/sendMessage?chat_id=1111111&amp;amp;text=&amp;amp;text=*Заявка_с_Дзена*%0A
Ответы на все вопросы&amp;amp;parse_mode=Markdown&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Айди канала или пользователя можно &lt;a href="/all/kak-uznat-ay-di-kanala-gruppy-ili-polzovatelya-v-telegram/"&gt;узнать через бота&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;%0A — Это символ пробела&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/Novaya-forma-(Uvedomleniya)---Google-Chrome-2022-05-12-09.56.45.jpg" width="951" height="646" alt="" /&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/image-8.png" width="926" height="489" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;После какого-то обновления на Яндекс Формах не проходят знаки пробела, можно поставить подчеркивание и пользоваться дальше&lt;/div&gt;
&lt;/div&gt;
&lt;p class="loud"&gt;Ответы на вопросы — что передаем в сообщении, выбирается в параметрах, там куча всего можно передавать.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://blog.fossko.ru/pictures/otpravka-iz-yandeks-form-v-telegram.png" width="368" height="404" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Варианты, что можно отправить из формы в телеграм&lt;/div&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;div class="fotorama" data-width="829" data-ratio="1.5612052730697"&gt;
&lt;img src="https://blog.fossko.ru/pictures/Novaya-forma--Yandex.Forms---Google-Chrome-2022-05-12-09.51.51.jpg" width="829" height="531" alt="" /&gt;
&lt;img src="https://blog.fossko.ru/pictures/Telegram-(1801441)-2022-05-12-09.55.21.jpg" width="440" height="122" alt="" /&gt;
&lt;/div&gt;
&lt;div class="e2-text-caption"&gt;Заполняем форму и получаем ответ в телеграм&lt;/div&gt;
&lt;/div&gt;
</description>
</item>


</channel>
</rss>