warp-beacon 2.6.62__tar.gz → 2.6.64__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {warp_beacon-2.6.62/warp_beacon.egg-info → warp_beacon-2.6.64}/PKG-INFO +4 -4
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/README.md +3 -3
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/setup.py +2 -0
- warp_beacon-2.6.64/warp_beacon/__version__.py +2 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/abstract.py +15 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/account_selector.py +4 -4
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/instagram/instagram.py +51 -12
- warp_beacon-2.6.64/warp_beacon/scraper/instagram/wb_instagrapi.py +62 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/youtube/abstract.py +0 -15
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/download_status.py +4 -2
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/edit_message.py +2 -2
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/progress_bar.py +25 -6
- warp_beacon-2.6.64/warp_beacon/telegram/types.py +6 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64/warp_beacon.egg-info}/PKG-INFO +4 -4
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon.egg-info/SOURCES.txt +2 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon.egg-info/top_level.txt +2 -0
- warp_beacon-2.6.62/warp_beacon/__version__.py +0 -2
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/LICENSE +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/MANIFEST.in +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/assets/placeholder.gif +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/etc/.gitignore +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/etc/accounts.json +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/etc/proxies.json +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/etc/warp_beacon.conf +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/etc/warp_beacon.service +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/pyproject.toml +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/setup.cfg +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/compress/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/compress/video.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/jobs/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/jobs/abstract.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/jobs/download_job.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/jobs/types.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/jobs/upload_job.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/mediainfo/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/mediainfo/abstract.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/mediainfo/audio.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/mediainfo/silencer.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/mediainfo/video.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scheduler/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scheduler/instagram_human.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scheduler/scheduler.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/exceptions.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/fail_handler.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/instagram/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/instagram/captcha.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/link_resolver.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/utils.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/youtube/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/youtube/music.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/youtube/shorts.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/scraper/youtube/youtube.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/storage/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/storage/mongo.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/bot.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/caption_shortener.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/handlers.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/placeholder_message.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/progress_file_reader.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/telegram/utils.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/uploader/__init__.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/warp_beacon.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon/yt_auth.py +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon.egg-info/dependency_links.txt +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon.egg-info/entry_points.txt +0 -0
- {warp_beacon-2.6.62 → warp_beacon-2.6.64}/warp_beacon.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: warp_beacon
|
3
|
-
Version: 2.6.
|
3
|
+
Version: 2.6.64
|
4
4
|
Summary: Telegram bot for expanding external media links
|
5
5
|
Home-page: https://github.com/sb0y/warp_beacon
|
6
6
|
Author: Andrey Bagrintsev
|
@@ -248,10 +248,10 @@ Dynamic: license-file
|
|
248
248
|
# warp_beacon [](https://github.com/sb0y/warp_beacon/actions/workflows/python-publish.yml) [](https://github.com/sb0y/warp_beacon/actions/workflows/docker-image.yml) [](https://github.com/sb0y/warp_beacon/actions/workflows/build-deb.yml)
|
249
249
|
> because content should travel freely
|
250
250
|
|
251
|
-
Telegram bot
|
252
|
-
Works with
|
251
|
+
Telegram bot that expands media links from external social networks.
|
252
|
+
Works with links sent in private messages or group chats.
|
253
253
|
|
254
|
-
Just send a media link to the
|
254
|
+
Just send a media link to the bot, and it will reply with a video or audio file.
|
255
255
|
|
256
256
|
| | | |
|
257
257
|
|:-------------------------:|:-------------------------:|:-------------------------:|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# warp_beacon [](https://github.com/sb0y/warp_beacon/actions/workflows/python-publish.yml) [](https://github.com/sb0y/warp_beacon/actions/workflows/docker-image.yml) [](https://github.com/sb0y/warp_beacon/actions/workflows/build-deb.yml)
|
2
2
|
> because content should travel freely
|
3
3
|
|
4
|
-
Telegram bot
|
5
|
-
Works with
|
4
|
+
Telegram bot that expands media links from external social networks.
|
5
|
+
Works with links sent in private messages or group chats.
|
6
6
|
|
7
|
-
Just send a media link to the
|
7
|
+
Just send a media link to the bot, and it will reply with a video or audio file.
|
8
8
|
|
9
9
|
| | | |
|
10
10
|
|:-------------------------:|:-------------------------:|:-------------------------:|
|
@@ -70,6 +70,7 @@ setup(
|
|
70
70
|
"warp_beacon/telegram/progress_file_reader",
|
71
71
|
"warp_beacon/telegram/edit_message",
|
72
72
|
"warp_beacon/telegram/download_status",
|
73
|
+
"warp_beacon/telegram/types",
|
73
74
|
"warp_beacon/jobs/abstract",
|
74
75
|
"warp_beacon/jobs/download_job",
|
75
76
|
"warp_beacon/jobs/upload_job",
|
@@ -84,6 +85,7 @@ setup(
|
|
84
85
|
"warp_beacon/scraper/exceptions",
|
85
86
|
"warp_beacon/scraper/types",
|
86
87
|
"warp_beacon/scraper/instagram/instagram",
|
88
|
+
"warp_beacon/scraper/instagram/wb_instagrapi",
|
87
89
|
"warp_beacon/scraper/account_selector",
|
88
90
|
"warp_beacon/scraper/youtube/abstract",
|
89
91
|
"warp_beacon/scraper/youtube/youtube",
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import os
|
2
|
+
import time
|
2
3
|
import pathlib
|
3
4
|
from abc import ABC, abstractmethod
|
4
5
|
from typing import Callable, Union
|
@@ -77,6 +78,20 @@ class ScraperAbstract(ABC):
|
|
77
78
|
logging.exception(e)
|
78
79
|
|
79
80
|
return ''
|
81
|
+
|
82
|
+
def rename_local_file(self, filename: str) -> str:
|
83
|
+
if not os.path.exists(filename):
|
84
|
+
raise NameError("No file provided")
|
85
|
+
path_info = pathlib.Path(filename)
|
86
|
+
ext = path_info.suffix
|
87
|
+
#old_filename = path_info.stem
|
88
|
+
time_name = str(time.time()).replace('.', '_')
|
89
|
+
new_filename = f"{time_name}{ext}"
|
90
|
+
new_filepath = f"{os.path.dirname(filename)}/{new_filename}"
|
91
|
+
|
92
|
+
os.rename(filename, new_filepath)
|
93
|
+
|
94
|
+
return new_filepath
|
80
95
|
|
81
96
|
def force_ipv6(self) -> None:
|
82
97
|
def allowed_gai_family():
|
@@ -267,8 +267,8 @@ class AccountSelector(object):
|
|
267
267
|
idx = self.account_index[self.current_module_name].value
|
268
268
|
if idx not in self.ig_accounts_session_id:
|
269
269
|
self.ig_accounts_session_id[idx] = str(uuid.uuid4())
|
270
|
-
else:
|
271
|
-
if random.random() > 0.95:
|
272
|
-
|
273
|
-
|
270
|
+
#else:
|
271
|
+
#if random.random() > 0.95:
|
272
|
+
# self.ig_accounts_session_id[idx] = str(uuid.uuid4())
|
273
|
+
# logging.info("Rotated client_session_id — simulating app restart")
|
274
274
|
return self.ig_accounts_session_id[idx]
|
@@ -3,11 +3,12 @@ import time
|
|
3
3
|
import socket
|
4
4
|
import ssl
|
5
5
|
import re
|
6
|
+
from pathlib import Path
|
7
|
+
import random
|
6
8
|
from typing import Callable, Optional, Union
|
7
9
|
|
8
10
|
import logging
|
9
11
|
|
10
|
-
import random
|
11
12
|
import email
|
12
13
|
import imaplib
|
13
14
|
import json
|
@@ -19,7 +20,6 @@ from instagrapi import exceptions
|
|
19
20
|
from instagrapi.exceptions import UnknownError as IGUnknownError
|
20
21
|
from instagrapi.mixins.story import Story
|
21
22
|
from instagrapi.types import Media
|
22
|
-
from instagrapi import Client
|
23
23
|
from instagrapi.mixins.challenge import ChallengeChoice
|
24
24
|
#from instagrapi.exceptions import LoginRequired, PleaseWaitFewMinutes, MediaNotFound, ClientNotFoundError, UserNotFound, ChallengeRequired, \
|
25
25
|
# ChallengeSelfieCaptcha, ChallengeUnknownStep, UnknownError as IGUnknownError
|
@@ -29,6 +29,8 @@ from warp_beacon.scraper.abstract import ScraperAbstract
|
|
29
29
|
from warp_beacon.jobs.types import JobType
|
30
30
|
from warp_beacon.jobs.download_job import DownloadJob
|
31
31
|
from warp_beacon.telegram.utils import Utils
|
32
|
+
from warp_beacon.scraper.instagram.wb_instagrapi import WBClient
|
33
|
+
from warp_beacon.telegram.types import ReportType
|
32
34
|
|
33
35
|
INST_SESSION_FILE_TPL = "/var/warp_beacon/inst_session_account_%d.json"
|
34
36
|
|
@@ -43,7 +45,7 @@ class InstagramScraper(ScraperAbstract):
|
|
43
45
|
super().__init__(account, proxy)
|
44
46
|
#
|
45
47
|
self.inst_session_file = INST_SESSION_FILE_TPL % self.account_index
|
46
|
-
self.cl =
|
48
|
+
self.cl = WBClient()
|
47
49
|
if self.proxy:
|
48
50
|
proxy_dsn = self.proxy.get("dsn", "")
|
49
51
|
if proxy_dsn:
|
@@ -53,6 +55,17 @@ class InstagramScraper(ScraperAbstract):
|
|
53
55
|
self.setup_device()
|
54
56
|
self.cl.challenge_code_handler = self.challenge_code_handler
|
55
57
|
self.cl.change_password_handler = self.change_password_handler
|
58
|
+
self.cl.public.headers.update({
|
59
|
+
"Connection": "keep-alive",
|
60
|
+
"Accept": "*/*",
|
61
|
+
"Accept-Encoding": "gzip, deflate, br",
|
62
|
+
"Accept-Language": "en-US,en;q=0.9",
|
63
|
+
"User-Agent": (
|
64
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
65
|
+
"(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
|
66
|
+
)
|
67
|
+
})
|
68
|
+
self.cl.set_progress_callback(self.download_progress)
|
56
69
|
|
57
70
|
def setup_device(self) -> None:
|
58
71
|
if not self.client_session_id:
|
@@ -227,9 +240,13 @@ class InstagramScraper(ScraperAbstract):
|
|
227
240
|
def download_video(self, url: str, media_info: Media) -> dict:
|
228
241
|
self.cl.request_timeout = int(os.environ.get("IG_REQUEST_TIMEOUT", default=60))
|
229
242
|
path = self.download_hndlr(self.cl.video_download_by_url, url, folder='/tmp')
|
230
|
-
return {
|
231
|
-
"
|
232
|
-
"
|
243
|
+
return {
|
244
|
+
"local_media_path": self.rename_local_file(str(path)),
|
245
|
+
"canonical_name": self.extract_canonical_name(media_info),
|
246
|
+
"media_type": JobType.VIDEO,
|
247
|
+
"last_pk": media_info.pk,
|
248
|
+
"media_info": {"duration": round(media_info.video_duration)}
|
249
|
+
}
|
233
250
|
|
234
251
|
def download_photo(self, url: str, media_info: Media) -> dict:
|
235
252
|
path = str(self.download_hndlr(self.cl.photo_download_by_url, url, folder='/tmp'))
|
@@ -238,8 +255,13 @@ class InstagramScraper(ScraperAbstract):
|
|
238
255
|
path = InstagramScraper.convert_webp_to_png(path)
|
239
256
|
if ".heic" in path_lowered:
|
240
257
|
path = InstagramScraper.convert_heic_to_png(path)
|
241
|
-
return {
|
242
|
-
|
258
|
+
return {
|
259
|
+
"local_media_path": self.rename_local_file(path),
|
260
|
+
"canonical_name": self.extract_canonical_name(media_info),
|
261
|
+
"media_type": JobType.IMAGE,
|
262
|
+
"last_pk": media_info.pk
|
263
|
+
}
|
264
|
+
|
243
265
|
def download_story(self, story_info: Story) -> dict:
|
244
266
|
path, media_type, media_info = "", JobType.UNKNOWN, {}
|
245
267
|
logging.info("Story id is '%s'", story_info.id)
|
@@ -263,7 +285,7 @@ class InstagramScraper(ScraperAbstract):
|
|
263
285
|
media_type = JobType.VIDEO
|
264
286
|
media_info["duration"] = story_info.video_duration
|
265
287
|
|
266
|
-
return {"local_media_path": path, "media_type": media_type, "media_info": media_info, "effective_url": effective_url}
|
288
|
+
return {"local_media_path": self.rename_local_file(path), "media_type": media_type, "media_info": media_info, "effective_url": effective_url}
|
267
289
|
|
268
290
|
def download_stories(self, stories: list[Story]) -> dict:
|
269
291
|
chunks = []
|
@@ -309,8 +331,11 @@ class InstagramScraper(ScraperAbstract):
|
|
309
331
|
try:
|
310
332
|
scrap_type, media_id = self.scrap(job.url)
|
311
333
|
if scrap_type == "media":
|
312
|
-
|
313
|
-
|
334
|
+
self.status_pipe.send({
|
335
|
+
"action": "report_download_status",
|
336
|
+
"report_type": ReportType.ANNOUNCE,
|
337
|
+
"label": "Collecting meta information ..."
|
338
|
+
})
|
314
339
|
media_info = self.download_hndlr(self.cl.media_info, media_id, use_cache=False)
|
315
340
|
logging.info("media_type is '%d', product_type is '%s'", media_info.media_type, media_info.product_type)
|
316
341
|
if media_info.media_type == 2 and media_info.product_type == "clips": # Reels
|
@@ -400,4 +425,18 @@ class InstagramScraper(ScraperAbstract):
|
|
400
425
|
chars = list("abcdefghijklmnopqrstuvwxyz1234567890!&£@#")
|
401
426
|
password = "".join(random.sample(chars, 10))
|
402
427
|
logging.info("Generated new IG password: '%s'", password)
|
403
|
-
return password
|
428
|
+
return password
|
429
|
+
|
430
|
+
def download_progress(self, total: int | None, bytes_transferred: int, path: Path) -> None:
|
431
|
+
percentage_of_completion = round(bytes_transferred / (total or 1) * 100)
|
432
|
+
logging.debug("[Download] IG file %s, %d", str(path), percentage_of_completion)
|
433
|
+
msg = {
|
434
|
+
"action": "report_download_status",
|
435
|
+
"current": bytes_transferred,
|
436
|
+
"total": total or 0,
|
437
|
+
"message_id": self.job.placeholder_message_id,
|
438
|
+
"chat_id": self.job.chat_id,
|
439
|
+
"completed": bool(total and bytes_transferred >= total),
|
440
|
+
"report_type": ReportType.PROGRESS
|
441
|
+
}
|
442
|
+
self.status_pipe.send(msg)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import logging
|
2
|
+
from typing import Callable
|
3
|
+
from urllib.parse import urlparse
|
4
|
+
from pathlib import Path
|
5
|
+
import requests
|
6
|
+
|
7
|
+
from instagrapi import Client
|
8
|
+
from instagrapi.exceptions import VideoNotDownload
|
9
|
+
|
10
|
+
class WBClient(Client):
|
11
|
+
"""
|
12
|
+
patched instagrapi
|
13
|
+
"""
|
14
|
+
def __init__(self) -> None:
|
15
|
+
super().__init__()
|
16
|
+
self.progress_callback = None
|
17
|
+
|
18
|
+
def set_progress_callback(self, callback: Callable[[int | None, int, Path], None]) -> None:
|
19
|
+
if not callback or not callable(callback):
|
20
|
+
raise TypeError("Progress callback must be callable")
|
21
|
+
self.progress_callback = callback
|
22
|
+
|
23
|
+
def video_download_by_url(self, url: str, filename: str = "", folder: Path = "") -> Path:
|
24
|
+
fname = urlparse(url).path.rsplit("/", 1)[1]
|
25
|
+
filename = f"{filename}.{fname.rsplit('.', 1)[1]}" if filename else fname
|
26
|
+
path = Path(folder or Path.cwd()) / filename
|
27
|
+
|
28
|
+
logging.info("Downloading video from %s to %s", url, path)
|
29
|
+
|
30
|
+
response = requests.get(url, stream=True, timeout=self.request_timeout)
|
31
|
+
response.raise_for_status()
|
32
|
+
|
33
|
+
content_length = 0
|
34
|
+
try:
|
35
|
+
content_length = int(response.headers.get("Content-Length", 0))
|
36
|
+
except (TypeError, ValueError):
|
37
|
+
logging.warning("Content-Length header is missing or invalid.")
|
38
|
+
content_length = 0
|
39
|
+
|
40
|
+
downloaded = 0
|
41
|
+
with open(path, "wb") as f:
|
42
|
+
for chunk in response.iter_content(chunk_size=8192):
|
43
|
+
if chunk:
|
44
|
+
f.write(chunk)
|
45
|
+
downloaded += len(chunk)
|
46
|
+
if self.progress_callback:
|
47
|
+
try:
|
48
|
+
self.progress_callback(
|
49
|
+
total=content_length or None,
|
50
|
+
bytes_transferred=downloaded,
|
51
|
+
path=path
|
52
|
+
)
|
53
|
+
except Exception as e:
|
54
|
+
logging.warning("Progress callback raised an exception!", exc_info=e)
|
55
|
+
|
56
|
+
|
57
|
+
if content_length and downloaded != content_length:
|
58
|
+
raise VideoNotDownload(
|
59
|
+
f'Broken file "{path}" (expected {content_length}, got {downloaded})'
|
60
|
+
)
|
61
|
+
|
62
|
+
return path.resolve()
|
@@ -4,7 +4,6 @@ import json
|
|
4
4
|
import logging
|
5
5
|
import math
|
6
6
|
import os
|
7
|
-
import pathlib
|
8
7
|
import socket
|
9
8
|
import ssl
|
10
9
|
import time
|
@@ -65,20 +64,6 @@ class YoutubeAbstract(ScraperAbstract):
|
|
65
64
|
logging.exception(e)
|
66
65
|
|
67
66
|
return 0
|
68
|
-
|
69
|
-
def rename_local_file(self, filename: str) -> str:
|
70
|
-
if not os.path.exists(filename):
|
71
|
-
raise NameError("No file provided")
|
72
|
-
path_info = pathlib.Path(filename)
|
73
|
-
ext = path_info.suffix
|
74
|
-
#old_filename = path_info.stem
|
75
|
-
time_name = str(time.time()).replace('.', '_')
|
76
|
-
new_filename = f"{time_name}{ext}"
|
77
|
-
new_filepath = f"{os.path.dirname(filename)}/{new_filename}"
|
78
|
-
|
79
|
-
os.rename(filename, new_filepath)
|
80
|
-
|
81
|
-
return new_filepath
|
82
67
|
|
83
68
|
def get_video_id(self, url: str) -> Optional[str]:
|
84
69
|
parsed_url = urlparse(url)
|
@@ -2,6 +2,7 @@ import logging
|
|
2
2
|
from multiprocessing import Pipe
|
3
3
|
from pyrogram import Client
|
4
4
|
from warp_beacon.telegram.progress_bar import ProgressBar
|
5
|
+
from warp_beacon.telegram.types import ReportType
|
5
6
|
|
6
7
|
class DownloadStatus(object):
|
7
8
|
status_pipe = None
|
@@ -15,12 +16,13 @@ class DownloadStatus(object):
|
|
15
16
|
self.status_pipe, self.child_conn = Pipe()
|
16
17
|
|
17
18
|
async def handle_message(self, msg: dict, progress_bar: ProgressBar) -> None:
|
18
|
-
|
19
|
+
progress_bar.progress_callback(
|
19
20
|
current=msg.get("current", 0),
|
20
21
|
total=msg.get("total", 0),
|
21
22
|
message_id=msg.get("message_id", 0),
|
22
23
|
chat_id=msg.get("chat_id", 0),
|
23
|
-
operation="Downloading"
|
24
|
+
operation="Downloading",
|
25
|
+
report_type=msg.get("report_type", ReportType.PROGRESS)
|
24
26
|
)
|
25
27
|
|
26
28
|
def on_status(self) -> None:
|
@@ -93,8 +93,8 @@ class EditMessage(object):
|
|
93
93
|
file_name: str = None
|
94
94
|
) -> None:
|
95
95
|
progress_bar = ProgressBar(self.client)
|
96
|
-
await progress_bar.progress_callback(current=0, total=0, chat_id=chat_id, message_id=message_id, operation="Uploading", label=file_name)
|
97
|
-
raw_file = await self.client.save_file(path=media.media, progress=progress_bar.progress_callback, progress_args=(chat_id, message_id, "Uploading", file_name,))
|
96
|
+
await progress_bar.progress_callback(current=0, total=0, chat_id=chat_id, message_id=message_id, operation="Uploading", label=file_name, report_type="progress")
|
97
|
+
raw_file = await self.client.save_file(path=media.media, progress=progress_bar.progress_callback, progress_args=(chat_id, message_id, "Uploading", file_name, "progress"))
|
98
98
|
|
99
99
|
caption = media.caption
|
100
100
|
parse_mode = media.parse_mode
|
@@ -6,6 +6,7 @@ import hashlib
|
|
6
6
|
from pyrogram.enums import ParseMode
|
7
7
|
from pyrogram.errors.exceptions.bad_request_400 import MessageNotModified
|
8
8
|
from pyrogram import Client
|
9
|
+
from warp_beacon.telegram.types import ReportType
|
9
10
|
|
10
11
|
class ProgressBar(object):
|
11
12
|
def __init__(self, client: Client) -> None:
|
@@ -68,7 +69,27 @@ class ProgressBar(object):
|
|
68
69
|
else:
|
69
70
|
logging.exception("Error in edit_message_caption", exc_info=exc)
|
70
71
|
|
71
|
-
|
72
|
+
def progress_callback(self, current: int, total: int, chat_id: int | str, message_id: int, operation: str, report_type: ReportType, label: str = "") -> None:
|
73
|
+
if report_type == ReportType.PROGRESS:
|
74
|
+
return self.render_progress_bar(current=current, total=total, chat_id=chat_id, message_id=message_id, operation=operation, label=label)
|
75
|
+
elif report_type == ReportType.ANNOUNCE:
|
76
|
+
return self.render_progress_announce(chat_id=chat_id, message_id=message_id, label=label)
|
77
|
+
|
78
|
+
def render_progress_announce(self, chat_id: int | str, message_id: int, label: str) -> None:
|
79
|
+
try:
|
80
|
+
#await self.client.edit_message_caption(chat_id, message_id, f"{pbar} <b>{operation}</b> {label}", ParseMode.HTML)
|
81
|
+
# we don't need to wait completion, waste of time and resources
|
82
|
+
task = self.client.loop.create_task(
|
83
|
+
self.client.edit_message_caption(chat_id, message_id, f"<b>{label}</b>", ParseMode.HTML)
|
84
|
+
)
|
85
|
+
task.add_done_callback(self._on_edit_done)
|
86
|
+
except MessageNotModified:
|
87
|
+
logging.warning("bad_request_400.MessageNotModified")
|
88
|
+
except Exception as e:
|
89
|
+
logging.warning("An error occurred while setup task to update progress bar")
|
90
|
+
logging.exception(e)
|
91
|
+
|
92
|
+
def render_progress_bar(self, current: int, total: int, chat_id: int | str, message_id: int, operation: str, label: str = "") -> None:
|
72
93
|
percent = 0
|
73
94
|
if total:
|
74
95
|
percent = round(current * 100 / (total or 1))
|
@@ -81,11 +102,11 @@ class ProgressBar(object):
|
|
81
102
|
try:
|
82
103
|
#await self.client.edit_message_caption(chat_id, message_id, f"{pbar} <b>{operation}</b> {label}", ParseMode.HTML)
|
83
104
|
# we don't need to wait completion, waste of time and resources
|
84
|
-
text = f"{pbar}\n
|
105
|
+
text = f"{pbar}\n{operation}"
|
85
106
|
if label:
|
86
|
-
text += f"\n{label}"
|
107
|
+
text += f"\n<code>{label}</code>"
|
87
108
|
if total:
|
88
|
-
text += f" {self.format_size_si(total)}"
|
109
|
+
text += f" <b>{self.format_size_si(total)}</b>"
|
89
110
|
task = self.client.loop.create_task(
|
90
111
|
self.client.edit_message_caption(chat_id, message_id, text, ParseMode.HTML)
|
91
112
|
)
|
@@ -97,8 +118,6 @@ class ProgressBar(object):
|
|
97
118
|
logging.exception(e)
|
98
119
|
if total > 0:
|
99
120
|
self._next_threshold += 20
|
100
|
-
if percent >= 100:
|
101
|
-
self.complete = True
|
102
121
|
|
103
122
|
@staticmethod
|
104
123
|
def make_hash(chat_id: str | int, message_id: int, algorithm: str = 'sha256') -> str:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: warp_beacon
|
3
|
-
Version: 2.6.
|
3
|
+
Version: 2.6.64
|
4
4
|
Summary: Telegram bot for expanding external media links
|
5
5
|
Home-page: https://github.com/sb0y/warp_beacon
|
6
6
|
Author: Andrey Bagrintsev
|
@@ -248,10 +248,10 @@ Dynamic: license-file
|
|
248
248
|
# warp_beacon [](https://github.com/sb0y/warp_beacon/actions/workflows/python-publish.yml) [](https://github.com/sb0y/warp_beacon/actions/workflows/docker-image.yml) [](https://github.com/sb0y/warp_beacon/actions/workflows/build-deb.yml)
|
249
249
|
> because content should travel freely
|
250
250
|
|
251
|
-
Telegram bot
|
252
|
-
Works with
|
251
|
+
Telegram bot that expands media links from external social networks.
|
252
|
+
Works with links sent in private messages or group chats.
|
253
253
|
|
254
|
-
Just send a media link to the
|
254
|
+
Just send a media link to the bot, and it will reply with a video or audio file.
|
255
255
|
|
256
256
|
| | | |
|
257
257
|
|:-------------------------:|:-------------------------:|:-------------------------:|
|
@@ -45,6 +45,7 @@ warp_beacon/scraper/utils.py
|
|
45
45
|
warp_beacon/scraper/instagram/__init__.py
|
46
46
|
warp_beacon/scraper/instagram/captcha.py
|
47
47
|
warp_beacon/scraper/instagram/instagram.py
|
48
|
+
warp_beacon/scraper/instagram/wb_instagrapi.py
|
48
49
|
warp_beacon/scraper/youtube/__init__.py
|
49
50
|
warp_beacon/scraper/youtube/abstract.py
|
50
51
|
warp_beacon/scraper/youtube/music.py
|
@@ -61,5 +62,6 @@ warp_beacon/telegram/handlers.py
|
|
61
62
|
warp_beacon/telegram/placeholder_message.py
|
62
63
|
warp_beacon/telegram/progress_bar.py
|
63
64
|
warp_beacon/telegram/progress_file_reader.py
|
65
|
+
warp_beacon/telegram/types.py
|
64
66
|
warp_beacon/telegram/utils.py
|
65
67
|
warp_beacon/uploader/__init__.py
|
@@ -21,6 +21,7 @@ warp_beacon/scraper/exceptions
|
|
21
21
|
warp_beacon/scraper/fail_handler
|
22
22
|
warp_beacon/scraper/instagram
|
23
23
|
warp_beacon/scraper/instagram/instagram
|
24
|
+
warp_beacon/scraper/instagram/wb_instagrapi
|
24
25
|
warp_beacon/scraper/link_resolver
|
25
26
|
warp_beacon/scraper/types
|
26
27
|
warp_beacon/scraper/utils
|
@@ -40,6 +41,7 @@ warp_beacon/telegram/handlers
|
|
40
41
|
warp_beacon/telegram/placeholder_message
|
41
42
|
warp_beacon/telegram/progress_bar
|
42
43
|
warp_beacon/telegram/progress_file_reader
|
44
|
+
warp_beacon/telegram/types
|
43
45
|
warp_beacon/telegram/utils
|
44
46
|
warp_beacon/uploader
|
45
47
|
warp_beacon/warp_beacon
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|