v0.3.0
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,2 @@
 | 
				
			|||||||
config.ini
 | 
					config.toml
 | 
				
			||||||
post_id.json
 | 
					post_id.json
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
FROM alpine:latest
 | 
					FROM alpine:3.16.2
 | 
				
			||||||
 | 
					COPY . /opt/vk-toot
 | 
				
			||||||
 | 
					WORKDIR /opt/vk-toot
 | 
				
			||||||
RUN apk update && apk add python3 py3-pip
 | 
					RUN apk update && apk add python3 py3-pip
 | 
				
			||||||
RUN mkdir -p /opt/vk-mastodon-bridge
 | 
					 | 
				
			||||||
ADD . /opt/vk-mastodon-bridge
 | 
					 | 
				
			||||||
WORKDIR /opt/vk-mastodon-bridge
 | 
					 | 
				
			||||||
RUN pip install --upgrade pip && pip install --requirement requirements.txt
 | 
					RUN pip install --upgrade pip && pip install --requirement requirements.txt
 | 
				
			||||||
CMD python3 vk_mastodon_bridge.py
 | 
					CMD python3 vk_toot.py
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										103
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								README.md
									
									
									
									
									
								
							@@ -1,25 +1,42 @@
 | 
				
			|||||||
# vk-mastodon-bridge
 | 
					# VK-Toot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Бридж для кросспостинга из [VK](https://vk.com) в [Mastodon](https://joinmastodon.org/). Это приложение будет дублировать посты из паблика или публичной группы VK в аккаунт Mastodon.
 | 
					Кросспостинг из [VK](https://vk.com) в [Mastodon](https://joinmastodon.org/).
 | 
				
			||||||
 | 
					Это приложение будет дублировать посты из паблика или публичной группы VK в
 | 
				
			||||||
 | 
					аккаунт Mastodon.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Пример аккаунта бота: [@jrokku@mas.to](https://mas.to/@jrokku)
 | 
					Пример аккаунта бота: [@jrokku@mas.to](https://mas.to/@jrokku)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Как это работает
 | 
					## Как это работает
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Скрипт согласно заданному промежутку времени (см. ниже `POLLING_TIME`) ходит в API VK и забирает оттуда самый свежий пост, запоминает его ID в файл. Затем ходит в API Mastodon и создаёт новый пост, который содержит оригинальный текст поста, ссылку на оригинальный пост, ссылки на каждое вложение из оригинального поста.
 | 
					Скрипт согласно заданному промежутку времени (см. ниже `POLLING_TIME`) ходит в
 | 
				
			||||||
 | 
					API VK и забирает оттуда самый свежий пост, запоминает его ID в файл. Затем
 | 
				
			||||||
 | 
					ходит в API Mastodon и создаёт новый пост, который содержит оригинальный текст
 | 
				
			||||||
 | 
					поста, ссылку на оригинальный пост, ссылки на каждое вложение из оригинального
 | 
				
			||||||
 | 
					поста.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Известные проблемы/TODO
 | 
					## Известные проблемы/TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Не учитывается длина поста. Если исходный пост не будет укладываться в лимит символов на инстансе Mastodon'а, то неизвестно что произойдёт. Решение: надо обрезать текст поста в функции `build_post()`.
 | 
					- Не учитывается длина поста. Если исходный пост не будет укладываться в
 | 
				
			||||||
- Никак не обрабатываются вложения типов отличных от фото (`photo`) и фотоальбома (`album`). Надо добавить хотя бы `video`.
 | 
					  лимит символов на инстансе Mastodon'а, то пост не опубликуется. Решение:
 | 
				
			||||||
- Указывать в списке вложений в посте только те вложения, которые не были загружены в Mastodon. Пока формируется полный список вложений.
 | 
					  надо обрезать текст поста в функции `build_post()`. Логика сложнее, чем
 | 
				
			||||||
 | 
					  кажется, поэтому я жду озарения.
 | 
				
			||||||
 | 
					- Никак не обрабатываются вложения типов отличных от фото (`photo`) и
 | 
				
			||||||
 | 
					  фотоальбома (`album`). Надо добавить хотя бы `video`.
 | 
				
			||||||
 | 
					- Указывать в списке вложений в посте только те вложения, которые не были
 | 
				
			||||||
 | 
					  загружены в Mastodon. Пока формируется полный список вложений.
 | 
				
			||||||
- Добавить поддержку `group_id`.
 | 
					- Добавить поддержку `group_id`.
 | 
				
			||||||
 | 
					- Добавить флаг `SHOW_ATTACHMENTS_LIST` для возможности скрытия списка
 | 
				
			||||||
 | 
					  вложений из текста.
 | 
				
			||||||
 | 
					- Добавить `mastodon.POST_CHAR_LIMIT` для обрезки текста относительно лимита
 | 
				
			||||||
 | 
					  инстанса.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Настройки и запуск
 | 
					## Настройки и запуск
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### API Mastodon
 | 
					### API Mastodon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Для получения токена API Mastodon достаточно добавить приложение в своём профиле (Preferences -> Development). Из разрешений достаточно `write` для создания постов, ничего другого бридж делать не умеет.
 | 
					Для получения токена API Mastodon достаточно добавить приложение в своём
 | 
				
			||||||
 | 
					профиле (Preferences -> Development). Из разрешений достаточно `write` для
 | 
				
			||||||
 | 
					создания постов, ничего другого бридж делать не умеет.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### API VK
 | 
					### API VK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,64 +46,85 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    https://oauth.vk.com/authorize?client_id=12345678&display=page&redirect_uri=https://oauth.vk.com/blank.html&scope=offline&response_type=token&v=5.131
 | 
					    https://oauth.vk.com/authorize?client_id=12345678&display=page&redirect_uri=https://oauth.vk.com/blank.html&scope=offline&response_type=token&v=5.131
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Здесь параметр `client_id` равняется `APP_ID` приложения, `scope=offline` задаёт нулевой (бесконечный) срок жизни токена.
 | 
					Здесь параметр `client_id` равняется `APP_ID` приложения, `scope=offline`
 | 
				
			||||||
 | 
					задаёт нулевой (бесконечный) срок жизни токена.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
При переходе по ссылке произойдёт редирект на страницу с подтверждением выдачи доступа приложению и далее редирект на страницу с предупреждением. Нас интересует значение query-параметра `access_token` в адресной строке.
 | 
					При переходе по ссылке произойдёт редирект на страницу с подтверждением
 | 
				
			||||||
 | 
					выдачи доступа приложению и далее редирект на страницу с предупреждением.
 | 
				
			||||||
 | 
					Нас интересует значение query-параметра `access_token` в адресной строке.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Это всё также описано в [документации к API](https://dev.vk.com/api/access-token/implicit-flow-user).
 | 
					Это всё также описано в [документации к API](https://dev.vk.com/api/access-token/implicit-flow-user).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Конфигуарация
 | 
					### Конфигуарация
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Конфигурация задаётся в файле `./data/config.ini` и разделена на три секции: `mastodon`, `vk` и `bridge`. Последний содержит параметры приложения, первые два реквизиты API. См. `./data/config.example.ini`.
 | 
					Конфигурация задаётся в файле `./data/config.toml` и разделена на три секции:
 | 
				
			||||||
 | 
					`mastodon`, `vk` и `bridge`. Последний содержит параметры приложения, первые
 | 
				
			||||||
 | 
					два реквизиты API. См. `./data/config.example.toml`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Секция    | Переменная            | Умолчание | Пример                            | Описание                                       |
 | 
					#### Mastodon (`mastodon`)
 | 
				
			||||||
| --------- | --------------------- | --------- |---------------------------------- | ---------------------------------------------- |
 | 
					
 | 
				
			||||||
| mastodon  | `API_URL`             | нет       | https://mastodon.social/api/v1    | URL адрес API Mastodon.                        |
 | 
					* `API_URL`: URL адрес API Mastodon. Пример: **https://mastodon.social/api/v1**
 | 
				
			||||||
| mastodon  | `API_ACCESS_TOKEN`    | нет       |                                   | Ключ API Mastodon.                             |
 | 
					* `API_ACCESS_TOKEN`: Ключ API Mastodon.
 | 
				
			||||||
| vk        | `API_URL`             | нет       | https://api.vk.com/method         | URL API VK.                                    |
 | 
					
 | 
				
			||||||
| vk        | `API_VERSION`         | нет       | 5.131                             | Версия VK API.                                 |
 | 
					#### VK (`vk`)
 | 
				
			||||||
| vk        | `API_ACCESS_TOKEN`    | нет       |                                   | Ключ API VK.                                   |
 | 
					
 | 
				
			||||||
| vk        | `GROUP_DOMAIN`        | нет       | apiclub                           | slug адрес группы/паблика VK.                  |
 | 
					* `API_URL`: **https://api.vk.com/method** URL API VK.
 | 
				
			||||||
| bridge    | `POLLING_TIME`        | 300       | 300                               | Задержка получением постов из VK в секундах.   |
 | 
					* `API_VERSION`: **5.131** Версия VK API.
 | 
				
			||||||
| bridge    | `REQUEST_DELAY`       | 1         | 1                                 | Задержка загрузки медиа в Mastodon в секундах. |
 | 
					* `API_ACCESS_TOKEN`: Ключ API VK.
 | 
				
			||||||
 | 
					* `GROUP_DOMAIN`: slug адрес группы/паблика VK. Пример: **apiclub**.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Настройки VK-Toot (`bridge`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `POLLING_TIME`: **300** Задержка получения постов из VK в секундах.
 | 
				
			||||||
 | 
					* `REQUEST_DELAY`: **1** Задержка загрузки медиа в Mastodon в секундах. Если
 | 
				
			||||||
 | 
					  Возникают ошибки 429 Too Many Requests, то следует увеличить эту цифру.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Запуск без Docker
 | 
					### Запуск без Docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Переименуйте `config.example.ini` в `config.ini` и отредактируйте значения в нём.
 | 
					Переименуйте `config.example.toml` в `config.toml` и отредактируйте его.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
pip install -r requirements.txt
 | 
					pip install -r requirements.txt
 | 
				
			||||||
python vk-mastodon-bridge.py
 | 
					python vk_toot.py
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Docker
 | 
					### Docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Переименуйте `config.example.toml` в `config.toml` и отредактируйте его.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Сборка образа:
 | 
					Сборка образа:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
sudo docker build -t vk-mastodon-bridge:0.2.1 .
 | 
					sudo docker build -t vk-toot:0.3.0 .
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Запуск контейнера:
 | 
					Запуск контейнера:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
sudo docker run --detach \
 | 
					sudo docker run \
 | 
				
			||||||
    --name vk-mastodon-bridge \
 | 
					    --detach \
 | 
				
			||||||
    --volume /opt/vk-mastodon-bridge/data:/opt/vk-mastodon-bridge/data \
 | 
					    --name vk-toot \
 | 
				
			||||||
    vk-mastodon-bridge:0.2.1
 | 
					    --volume /opt/vk-toot/data:/opt/vk-toot/data \
 | 
				
			||||||
 | 
					    vk-toot:0.3.0
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## История изменений
 | 
					## История изменений
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Next
 | 
					### 0.3.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Переменные окружения заменены на config.ini.
 | 
					- BREAKING! Приложение переименовано в vk-toot.
 | 
				
			||||||
 | 
					- BREAKING! Вместо переменных окружения теперь используется config.toml. Для
 | 
				
			||||||
 | 
					  изменения параметров больше не нужна пересборка контейнера.
 | 
				
			||||||
 | 
					- Улучшено логирование.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 0.2.1
 | 
					### 0.2.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Исправлена публиация постов. Mastodon API мог отвечать кодом 429 из-за слишком частых загрузок медиа. Решено через добавление задержки `REQUEST_DELAY`.
 | 
					- Исправлена публиация постов. Mastodon API мог отвечать кодом 429 из-за
 | 
				
			||||||
 | 
					  слишком частых загрузок медиа. Решено через добавление задержки
 | 
				
			||||||
 | 
					  `REQUEST_DELAY`.
 | 
				
			||||||
- Исправлена ошибка при посте статуса с менее чем 4-я вложениями.
 | 
					- Исправлена ошибка при посте статуса с менее чем 4-я вложениями.
 | 
				
			||||||
- Файл `./data/last_post_id` теперь содержит JSON и называется `./data/post_id.json`. ID хранится в единственном поле `post_id`.
 | 
					- Файл `./data/last_post_id` теперь содержит JSON и называется
 | 
				
			||||||
 | 
					  `./data/post_id.json`. ID хранится в единственном поле `post_id`.
 | 
				
			||||||
- Имя модуля теперь не содержит дефисов.
 | 
					- Имя модуля теперь не содержит дефисов.
 | 
				
			||||||
- Добавлено логирование. Лог пишется в STDOUT.
 | 
					- Добавлено логирование. Лог пишется в STDOUT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,7 +132,8 @@ sudo docker run --detach \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- Реализована загрузка вложений в Mastodon (до 4-х штук). Только изображения.
 | 
					- Реализована загрузка вложений в Mastodon (до 4-х штук). Только изображения.
 | 
				
			||||||
- Обновлён путь до приложения в Dockerfile.
 | 
					- Обновлён путь до приложения в Dockerfile.
 | 
				
			||||||
- Изменено место хранения файла `last_post_id`, теперь он в директории `data/`, откуда его можно удобно монтировать как Docker volume.
 | 
					- Изменено место хранения файла `last_post_id`, теперь он в директории
 | 
				
			||||||
 | 
					  `data/`, откуда его можно удобно монтировать как Docker volume.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 0.1.0
 | 
					### 0.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1,2 @@
 | 
				
			|||||||
requests==2.28.1
 | 
					requests==2.28.1
 | 
				
			||||||
 | 
					toml==0.10.2
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,13 +8,13 @@ import datetime
 | 
				
			|||||||
import logging
 | 
					import logging
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
import urllib.parse
 | 
					import urllib.parse
 | 
				
			||||||
import configparser
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import requests
 | 
					import requests
 | 
				
			||||||
 | 
					import toml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config = configparser.ConfigParser()
 | 
					with open('./data/config.toml', 'r') as file:
 | 
				
			||||||
config.read('./data/config.ini')
 | 
					    config = toml.loads(file.read())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MASTODON_API_URL = config['mastodon']['API_URL']
 | 
					MASTODON_API_URL = config['mastodon']['API_URL']
 | 
				
			||||||
MASTODON_API_ACCESS_TOKEN = config['mastodon']['API_ACCESS_TOKEN']
 | 
					MASTODON_API_ACCESS_TOKEN = config['mastodon']['API_ACCESS_TOKEN']
 | 
				
			||||||
@@ -24,11 +24,11 @@ VK_API_ACCESS_TOKEN = config['vk']['API_ACCESS_TOKEN']
 | 
				
			|||||||
VK_GROUP_DOMAIN = config['vk']['GROUP_DOMAIN']
 | 
					VK_GROUP_DOMAIN = config['vk']['GROUP_DOMAIN']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Set up logger
 | 
					# Set up logger
 | 
				
			||||||
logger = logging.getLogger('vk_mastodon_bridge')
 | 
					log = logging.getLogger('vk_toot')
 | 
				
			||||||
logger.setLevel(logging.INFO)
 | 
					log.setLevel(logging.INFO)
 | 
				
			||||||
handler = logging.StreamHandler(stream=sys.stdout)
 | 
					handler = logging.StreamHandler(stream=sys.stdout)
 | 
				
			||||||
handler.setFormatter(logging.Formatter(fmt = '[%(asctime)s: %(levelname)s] %(message)s'))
 | 
					handler.setFormatter(logging.Formatter(fmt = '[%(asctime)s: %(levelname)s] %(message)s'))
 | 
				
			||||||
logger.addHandler(handler)
 | 
					log.addHandler(handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_vk_group_last_post():
 | 
					def get_vk_group_last_post():
 | 
				
			||||||
    """Return dict with VK group last post data."""
 | 
					    """Return dict with VK group last post data."""
 | 
				
			||||||
@@ -107,7 +107,7 @@ def post_media(file: str) -> str:
 | 
				
			|||||||
    headers = {'Authorization': 'Bearer ' + MASTODON_API_ACCESS_TOKEN}
 | 
					    headers = {'Authorization': 'Bearer ' + MASTODON_API_ACCESS_TOKEN}
 | 
				
			||||||
    files = {'file': open(file,'rb')}
 | 
					    files = {'file': open(file,'rb')}
 | 
				
			||||||
    response = requests.post(MASTODON_API_URL + '/media', files=files, headers=headers)
 | 
					    response = requests.post(MASTODON_API_URL + '/media', files=files, headers=headers)
 | 
				
			||||||
    logger.info('Post media on Mastodon. Response: ' \
 | 
					    log.info('Post media on Mastodon. Response: ' \
 | 
				
			||||||
        + str(response.status_code) + ' ' + str(response.text))
 | 
					        + str(response.status_code) + ' ' + str(response.text))
 | 
				
			||||||
    # Sleep some seconds to prevent HTTP 429 response.
 | 
					    # Sleep some seconds to prevent HTTP 429 response.
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
@@ -124,12 +124,13 @@ def publish_toot(post_text: str, media_ids: list):
 | 
				
			|||||||
    headers = {'Authorization': 'Bearer ' + MASTODON_API_ACCESS_TOKEN}
 | 
					    headers = {'Authorization': 'Bearer ' + MASTODON_API_ACCESS_TOKEN}
 | 
				
			||||||
    params = {'status': post_text, 'media_ids[]': media_ids}
 | 
					    params = {'status': post_text, 'media_ids[]': media_ids}
 | 
				
			||||||
    response = requests.post(MASTODON_API_URL + '/statuses', data=params, headers=headers)
 | 
					    response = requests.post(MASTODON_API_URL + '/statuses', data=params, headers=headers)
 | 
				
			||||||
 | 
					    log.info('Publish toot. Response: %s' % response.text)
 | 
				
			||||||
    post_url = json.loads(response.text)['url']
 | 
					    post_url = json.loads(response.text)['url']
 | 
				
			||||||
    logger.info('Publish status. Response: ' \
 | 
					    log.info('Status: ' \
 | 
				
			||||||
        + str(response.status_code) + ' Status: ' + str(post_url))
 | 
					        + str(response.status_code) + ' URL: ' + str(post_url))
 | 
				
			||||||
    return response
 | 
					    return response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def post_toot(post_data: dict) -> str:
 | 
					def toot(post_data: dict) -> str:
 | 
				
			||||||
    """Upload media files, generate status text for Mastodon post and publish.
 | 
					    """Upload media files, generate status text for Mastodon post and publish.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    post_text = get_vk_post_text(post_data)
 | 
					    post_text = get_vk_post_text(post_data)
 | 
				
			||||||
@@ -140,7 +141,7 @@ def post_toot(post_data: dict) -> str:
 | 
				
			|||||||
    # Upload only first 4 photos and get media_ids
 | 
					    # Upload only first 4 photos and get media_ids
 | 
				
			||||||
    i = 0
 | 
					    i = 0
 | 
				
			||||||
    media_ids = []
 | 
					    media_ids = []
 | 
				
			||||||
    logger.info('Attachments: %s' % str(attachments))
 | 
					    log.info('Attachments: %s' % str(attachments))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    attachments_count = len(attachments)
 | 
					    attachments_count = len(attachments)
 | 
				
			||||||
    if attachments_count > 4:
 | 
					    if attachments_count > 4:
 | 
				
			||||||
@@ -149,12 +150,12 @@ def post_toot(post_data: dict) -> str:
 | 
				
			|||||||
    while i < attachments_count:
 | 
					    while i < attachments_count:
 | 
				
			||||||
        if list(attachments[i].keys())[0] == 'photo':
 | 
					        if list(attachments[i].keys())[0] == 'photo':
 | 
				
			||||||
            photo_url = attachments[i]['photo']
 | 
					            photo_url = attachments[i]['photo']
 | 
				
			||||||
            logger.info('Download image: %s' % photo_url)
 | 
					            log.info('Download image: %s' % photo_url)
 | 
				
			||||||
            tmpfile = download_file(photo_url)  # Download file from VK
 | 
					            tmpfile = download_file(photo_url)  # Download file from VK
 | 
				
			||||||
            logger.info('Image saved locally as: %s' % tmpfile)
 | 
					            log.info('Image saved locally as: %s' % tmpfile)
 | 
				
			||||||
            media_id = json.loads(post_media(tmpfile).text)['id'] # Upload file to Mastodon
 | 
					            media_id = json.loads(post_media(tmpfile).text)['id'] # Upload file to Mastodon
 | 
				
			||||||
            media_ids.append(media_id)  # Save uploaded media IDs
 | 
					            media_ids.append(media_id)  # Save uploaded media IDs
 | 
				
			||||||
            logger.info('Remove local file: %s' % tmpfile)
 | 
					            log.info('Remove local file: %s' % tmpfile)
 | 
				
			||||||
            os.remove(tmpfile)  # Remove local file
 | 
					            os.remove(tmpfile)  # Remove local file
 | 
				
			||||||
        i += 1
 | 
					        i += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -167,7 +168,8 @@ def post_toot(post_data: dict) -> str:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    # Get status text
 | 
					    # Get status text
 | 
				
			||||||
    text = post_text + '\n\n' + 'Source: ' + vk_post_url + '\n\nAttachments:\n' + post_attachments
 | 
					    text = post_text + '\n\n' + 'Source: ' + vk_post_url + '\n\nAttachments:\n' + post_attachments
 | 
				
			||||||
 | 
					    print('Длина текста', len(text))
 | 
				
			||||||
 | 
					    print(text)
 | 
				
			||||||
    # Post toot!
 | 
					    # Post toot!
 | 
				
			||||||
    publish_toot(text, media_ids)
 | 
					    publish_toot(text, media_ids)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -182,15 +184,15 @@ def read_lock_file(file: str):
 | 
				
			|||||||
        return data['post_id']
 | 
					        return data['post_id']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def poll():
 | 
					def poll():
 | 
				
			||||||
    logger.info('Start polling %s' % datetime.datetime.now().isoformat())
 | 
					    log.info('Start polling %s' % datetime.datetime.now().isoformat())
 | 
				
			||||||
    lock_file = './data/post_id.json'
 | 
					    lock_file = './data/post_id.json'
 | 
				
			||||||
    if os.path.exists(lock_file):
 | 
					    if os.path.exists(lock_file):
 | 
				
			||||||
        prev_post_id = read_lock_file(lock_file)
 | 
					        prev_post_id = read_lock_file(lock_file)
 | 
				
			||||||
        logger.info('Read last post ID from file: %s' % lock_file)
 | 
					        log.info('Read last post ID from file: %s' % lock_file)
 | 
				
			||||||
        logger.info('Last post ID: %s' % prev_post_id)
 | 
					        log.info('Last post ID: %s' % prev_post_id)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        prev_post_id = 0
 | 
					        prev_post_id = 0
 | 
				
			||||||
        logger.info('Last post ID: 0')
 | 
					        log.info('Last post ID: 0')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while True:
 | 
					    while True:
 | 
				
			||||||
        post_data = get_vk_group_last_post()  # raw data
 | 
					        post_data = get_vk_group_last_post()  # raw data
 | 
				
			||||||
@@ -198,11 +200,12 @@ def poll():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # Don't post duplicates
 | 
					        # Don't post duplicates
 | 
				
			||||||
        if int(post_id) == int(prev_post_id):
 | 
					        if int(post_id) == int(prev_post_id):
 | 
				
			||||||
            logger.info('Post with VK ID %s already posted, skipping' % post_id)
 | 
					            log.info('Post with VK ID %s already posted, skipping' % post_id)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            # Toot!
 | 
					            # Toot!
 | 
				
			||||||
            logger.info('Toot! VK post ID: %s' % post_id)
 | 
					            log.info('Toot! VK post ID: {}, URL: {}'.format(
 | 
				
			||||||
            post_toot(post_data)
 | 
					                post_id, get_vk_post_url(post_data)))
 | 
				
			||||||
 | 
					            toot(post_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        touch_lock_file(lock_file, post_id)
 | 
					        touch_lock_file(lock_file, post_id)
 | 
				
			||||||
        prev_post_id = read_lock_file(lock_file)
 | 
					        prev_post_id = read_lock_file(lock_file)
 | 
				
			||||||
@@ -215,4 +218,9 @@ def poll():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    log.info('VK-Toot started. [bridge]: {}; [mastodon].API_URL {}'.format(
 | 
				
			||||||
 | 
					        dict(config['bridge']),
 | 
				
			||||||
 | 
					        config['mastodon']['API_URL'],
 | 
				
			||||||
 | 
					    ))
 | 
				
			||||||
 | 
					    # Start polling
 | 
				
			||||||
    poll()
 | 
					    poll()
 | 
				
			||||||
		Reference in New Issue
	
	Block a user