warp-beacon 2.3.38__tar.gz → 2.3.40__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.3.38/warp_beacon.egg-info → warp_beacon-2.3.40}/PKG-INFO +23 -4
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/README.md +19 -2
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/pyproject.toml +2 -1
- warp_beacon-2.3.40/warp_beacon/__version__.py +2 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scheduler/instagram_human.py +6 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scheduler/scheduler.py +3 -1
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/exceptions.py +2 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/youtube/abstract.py +74 -16
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/youtube/youtube.py +27 -7
- {warp_beacon-2.3.38 → warp_beacon-2.3.40/warp_beacon.egg-info}/PKG-INFO +23 -4
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon.egg-info/requires.txt +1 -0
- warp_beacon-2.3.38/warp_beacon/__version__.py +0 -2
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/LICENSE +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/MANIFEST.in +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/assets/placeholder.gif +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/etc/.gitignore +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/etc/accounts.json +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/etc/proxies.json +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/etc/warp_beacon.conf +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/etc/warp_beacon.service +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/setup.cfg +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/setup.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/compress/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/compress/video.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/jobs/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/jobs/abstract.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/jobs/download_job.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/jobs/types.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/jobs/upload_job.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/mediainfo/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/mediainfo/abstract.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/mediainfo/audio.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/mediainfo/silencer.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/mediainfo/video.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scheduler/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/abstract.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/account_selector.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/fail_handler.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/instagram/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/instagram/instagram.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/link_resolver.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/youtube/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/youtube/music.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/scraper/youtube/shorts.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/storage/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/storage/mongo.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/telegram/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/telegram/bot.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/telegram/caption_shortener.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/telegram/handlers.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/telegram/placeholder_message.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/telegram/utils.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/uploader/__init__.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon/warp_beacon.py +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon.egg-info/SOURCES.txt +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon.egg-info/dependency_links.txt +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon.egg-info/entry_points.txt +0 -0
- {warp_beacon-2.3.38 → warp_beacon-2.3.40}/warp_beacon.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: warp_beacon
|
3
|
-
Version: 2.3.
|
3
|
+
Version: 2.3.40
|
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
|
@@ -237,10 +237,13 @@ Requires-Dist: pillow
|
|
237
237
|
Requires-Dist: pymongo
|
238
238
|
Requires-Dist: instagrapi==2.0.0
|
239
239
|
Requires-Dist: bs4
|
240
|
+
Requires-Dist: yt_dlp
|
240
241
|
Dynamic: author
|
241
242
|
Dynamic: home-page
|
243
|
+
Dynamic: license-file
|
242
244
|
|
243
245
|
# 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)
|
246
|
+
> because content should travel freely
|
244
247
|
|
245
248
|
Telegram bot for external social networks media links expanding.
|
246
249
|
Works with a links in personal messages and also with group chats.
|
@@ -253,6 +256,24 @@ Just send a media link to the chat with bot and get a video or audio reply.
|
|
253
256
|
|<img width="700" alt="Instagram Photo post usage example" src="https://github.com/user-attachments/assets/29324b94-7314-4a38-8790-3483011d355d"> Instagram Photo post usage example|<img width="700" alt="Instagram Photo Carousel usage" src="https://github.com/user-attachments/assets/2598e329-e16e-455e-91e9-a027e8994283"> Instagram Photo Carousel usage example|<img width="757" alt="Instagram Photo bulk Strories download usage example" src="https://github.com/user-attachments/assets/2c8c91ac-6ade-4d1d-a677-2b36bb40ff39"> Instagram Photo bulk Strories download usage example|
|
254
257
|
|<img width="700" alt="Instagram specific Story download usage example" src="https://github.com/user-attachments/assets/03dc70c5-6933-4122-9c7c-5f7d734d117b"> Instagram specific Story download usage example|<img width="700" alt="Group chat usage example" src="https://github.com/user-attachments/assets/649fcb1e-785b-4efd-9153-69644c6d898b"> Group chat usage example|
|
255
258
|
|
259
|
+
### **Warp Beacon manifesto**
|
260
|
+
|
261
|
+
> Once, the Internet was built as a borderless network — a space where knowledge, culture, and ideas could flow freely across the globe.
|
262
|
+
> But over time, freedom gave way to artificial walls, anti-bot shields, and region locks.
|
263
|
+
>
|
264
|
+
> **warp_beacon** is our answer to that shift.
|
265
|
+
>
|
266
|
+
> This is a tool for those who refuse to accept "access denied by geolocation" or "content unavailable in your region."
|
267
|
+
> It is a bridge over ML filters, CAPTCHAs, and man-made barriers.
|
268
|
+
>
|
269
|
+
> We don’t break the rules — we restore the original spirit of the Internet:
|
270
|
+
> 📡 **free exchange of information**,
|
271
|
+
> 🌍 **unrestricted access to global content**,
|
272
|
+
> 🤖 **tools that serve the user**, not the platform.
|
273
|
+
>
|
274
|
+
> **warp_beacon** — the freedom to deliver content where it’s needed most.
|
275
|
+
|
276
|
+
## Configuration example ##
|
256
277
|
|
257
278
|
In order to setup your own instance, you will need:
|
258
279
|
|
@@ -261,8 +282,6 @@ In order to setup your own instance, you will need:
|
|
261
282
|
|
262
283
|
All bot configuration stored in [warp_beacon.conf](https://github.com/sb0y/warp_beacon/blob/main/etc/warp_beacon.conf) file.
|
263
284
|
|
264
|
-
## Configuration example ##
|
265
|
-
|
266
285
|
```env
|
267
286
|
TG_TOKEN="you telegram token received from @BotFather"
|
268
287
|
# these 3 settings should be obtained at https://my.telegram.org/apps
|
@@ -1,4 +1,5 @@
|
|
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
|
+
> because content should travel freely
|
2
3
|
|
3
4
|
Telegram bot for external social networks media links expanding.
|
4
5
|
Works with a links in personal messages and also with group chats.
|
@@ -11,6 +12,24 @@ Just send a media link to the chat with bot and get a video or audio reply.
|
|
11
12
|
|<img width="700" alt="Instagram Photo post usage example" src="https://github.com/user-attachments/assets/29324b94-7314-4a38-8790-3483011d355d"> Instagram Photo post usage example|<img width="700" alt="Instagram Photo Carousel usage" src="https://github.com/user-attachments/assets/2598e329-e16e-455e-91e9-a027e8994283"> Instagram Photo Carousel usage example|<img width="757" alt="Instagram Photo bulk Strories download usage example" src="https://github.com/user-attachments/assets/2c8c91ac-6ade-4d1d-a677-2b36bb40ff39"> Instagram Photo bulk Strories download usage example|
|
12
13
|
|<img width="700" alt="Instagram specific Story download usage example" src="https://github.com/user-attachments/assets/03dc70c5-6933-4122-9c7c-5f7d734d117b"> Instagram specific Story download usage example|<img width="700" alt="Group chat usage example" src="https://github.com/user-attachments/assets/649fcb1e-785b-4efd-9153-69644c6d898b"> Group chat usage example|
|
13
14
|
|
15
|
+
### **Warp Beacon manifesto**
|
16
|
+
|
17
|
+
> Once, the Internet was built as a borderless network — a space where knowledge, culture, and ideas could flow freely across the globe.
|
18
|
+
> But over time, freedom gave way to artificial walls, anti-bot shields, and region locks.
|
19
|
+
>
|
20
|
+
> **warp_beacon** is our answer to that shift.
|
21
|
+
>
|
22
|
+
> This is a tool for those who refuse to accept "access denied by geolocation" or "content unavailable in your region."
|
23
|
+
> It is a bridge over ML filters, CAPTCHAs, and man-made barriers.
|
24
|
+
>
|
25
|
+
> We don’t break the rules — we restore the original spirit of the Internet:
|
26
|
+
> 📡 **free exchange of information**,
|
27
|
+
> 🌍 **unrestricted access to global content**,
|
28
|
+
> 🤖 **tools that serve the user**, not the platform.
|
29
|
+
>
|
30
|
+
> **warp_beacon** — the freedom to deliver content where it’s needed most.
|
31
|
+
|
32
|
+
## Configuration example ##
|
14
33
|
|
15
34
|
In order to setup your own instance, you will need:
|
16
35
|
|
@@ -19,8 +38,6 @@ In order to setup your own instance, you will need:
|
|
19
38
|
|
20
39
|
All bot configuration stored in [warp_beacon.conf](https://github.com/sb0y/warp_beacon/blob/main/etc/warp_beacon.conf) file.
|
21
40
|
|
22
|
-
## Configuration example ##
|
23
|
-
|
24
41
|
```env
|
25
42
|
TG_TOKEN="you telegram token received from @BotFather"
|
26
43
|
# these 3 settings should be obtained at https://my.telegram.org/apps
|
@@ -80,6 +80,7 @@ class InstagramHuman(object):
|
|
80
80
|
if random.random() > 0.6:
|
81
81
|
logging.info("Simulation profile view ...")
|
82
82
|
self.profile_view()
|
83
|
+
self.random_pause()
|
83
84
|
except Exception as e:
|
84
85
|
logging.warning("Error in evening_routine")
|
85
86
|
logging.exception(e)
|
@@ -101,7 +102,9 @@ class InstagramHuman(object):
|
|
101
102
|
|
102
103
|
def profile_view(self) -> None:
|
103
104
|
try:
|
105
|
+
logging.info("profile_view ...")
|
104
106
|
my_user_id = self.scrapler.cl.user_id
|
107
|
+
logging.info("user_following ...")
|
105
108
|
friends = list(self.scrapler.download_hndlr(self.scrapler.cl.user_following, my_user_id, amount=random.randint(5, 50)).values())
|
106
109
|
time.sleep(random.uniform(2, 5))
|
107
110
|
if not friends:
|
@@ -111,15 +114,18 @@ class InstagramHuman(object):
|
|
111
114
|
target_user_id = ""
|
112
115
|
if isinstance(random_friend, UserShort):
|
113
116
|
target_user_id = random_friend.pk
|
117
|
+
logging.info("user_info with target_user_id = '%s' ...", target_user_id)
|
114
118
|
self.scrapler.download_hndlr(self.scrapler.cl.user_info, target_user_id)
|
115
119
|
time.sleep(random.uniform(2, 5))
|
116
120
|
elif isinstance(random_friend, str):
|
117
121
|
target_user_id = self.scrapler.download_hndlr(self.scrapler.cl.user_id_from_username, random_friend)
|
122
|
+
logging.info("user_info with target_user_id = '%s' ...", target_user_id)
|
118
123
|
self.scrapler.download_hndlr(self.scrapler.cl.user_info, target_user_id)
|
119
124
|
|
120
125
|
time.sleep(random.uniform(2, 5))
|
121
126
|
|
122
127
|
if random.random() > 0.7:
|
128
|
+
logging.info("user_medias with target_user_id = '%s' ...", target_user_id)
|
123
129
|
self.scrapler.download_hndlr(self.scrapler.cl.user_medias, target_user_id, amount=random.randint(1, 5))
|
124
130
|
|
125
131
|
self.random_pause()
|
@@ -38,6 +38,8 @@ class IGScheduler(object):
|
|
38
38
|
if os.path.exists(self.state_file):
|
39
39
|
with open(self.state_file, 'r', encoding="utf-8") as f:
|
40
40
|
self.state = json.loads(f.read())
|
41
|
+
if "remaining" in self.state:
|
42
|
+
logging.info("Next scheduler activity in '%s' seconds", self.state["remaining"])
|
41
43
|
except Exception as e:
|
42
44
|
logging.error("Failed to load Scheduler state!")
|
43
45
|
logging.exception(e)
|
@@ -89,7 +91,7 @@ class IGScheduler(object):
|
|
89
91
|
self.save_state()
|
90
92
|
|
91
93
|
if self.state["remaining"] <= 0:
|
92
|
-
self.state["remaining"] = randrange(
|
94
|
+
self.state["remaining"] = randrange(4292, 8623)
|
93
95
|
logging.info("Next scheduler activity in '%s' seconds", self.state["remaining"])
|
94
96
|
|
95
97
|
start_time = time.time()
|
@@ -7,26 +7,29 @@ import socket
|
|
7
7
|
import ssl
|
8
8
|
#from abc import abstractmethod
|
9
9
|
from typing import Callable, Union, Optional
|
10
|
+
import logging
|
10
11
|
import json
|
11
12
|
import urllib
|
12
13
|
import http.client
|
14
|
+
import pytubefix.exceptions
|
13
15
|
import requests
|
14
16
|
from PIL import Image
|
15
17
|
import numpy as np
|
18
|
+
from urllib.parse import urlparse, parse_qs
|
16
19
|
|
17
|
-
|
18
|
-
from warp_beacon.scraper.abstract import ScraperAbstract
|
19
|
-
#from warp_beacon.mediainfo.abstract import MediaInfoAbstract
|
20
|
-
from warp_beacon.scraper.exceptions import TimeOut, Unavailable, extract_exception_message
|
21
|
-
|
20
|
+
import pytubefix
|
22
21
|
from pytubefix import YouTube
|
23
22
|
from pytubefix.innertube import _default_clients
|
24
23
|
from pytubefix.streams import Stream
|
25
24
|
from pytubefix.innertube import InnerTube, _client_id, _client_secret
|
26
|
-
from pytubefix.exceptions import VideoUnavailable, VideoPrivate, MaxRetriesExceeded
|
25
|
+
#from pytubefix.exceptions import VideoUnavailable, VideoPrivate, MaxRetriesExceeded
|
27
26
|
from pytubefix import request
|
27
|
+
import yt_dlp
|
28
28
|
|
29
|
-
import
|
29
|
+
from warp_beacon.jobs.download_job import DownloadJob
|
30
|
+
from warp_beacon.scraper.abstract import ScraperAbstract
|
31
|
+
#from warp_beacon.mediainfo.abstract import MediaInfoAbstract
|
32
|
+
from warp_beacon.scraper.exceptions import TimeOut, Unavailable, extract_exception_message
|
30
33
|
|
31
34
|
def patched_fetch_bearer_token(self) -> None:
|
32
35
|
"""Fetch an OAuth token."""
|
@@ -101,13 +104,24 @@ class YoutubeAbstract(ScraperAbstract):
|
|
101
104
|
os.rename(filename, new_filepath)
|
102
105
|
|
103
106
|
return new_filepath
|
107
|
+
|
108
|
+
def get_video_id(self, url: str) -> Optional[str]:
|
109
|
+
parsed_url = urlparse(url)
|
110
|
+
query = parse_qs(parsed_url.query)
|
111
|
+
return query.get('v', [None])[0]
|
104
112
|
|
105
113
|
def remove_tmp_files(self) -> None:
|
106
114
|
for i in os.listdir(self.DOWNLOAD_DIR):
|
107
115
|
if "yt_download_" in i:
|
108
116
|
os.unlink("%s/%s" % (self.DOWNLOAD_DIR, i))
|
109
117
|
|
110
|
-
def calculate_size_with_padding(self,
|
118
|
+
def calculate_size_with_padding(self,
|
119
|
+
image: Image,
|
120
|
+
aspect_ratio_width: int,
|
121
|
+
aspect_ratio_height: int,
|
122
|
+
target_size: tuple=(320, 320),
|
123
|
+
background_color: tuple=(0, 0, 0)
|
124
|
+
) -> Image:
|
111
125
|
aspect_ratio = aspect_ratio_width / aspect_ratio_height
|
112
126
|
target_width, target_height = target_size
|
113
127
|
|
@@ -194,7 +208,7 @@ class YoutubeAbstract(ScraperAbstract):
|
|
194
208
|
kwargs["timeout"] = timeout
|
195
209
|
ret_val = func(*args, **kwargs)
|
196
210
|
break
|
197
|
-
except MaxRetriesExceeded:
|
211
|
+
except pytubefix.exceptions.MaxRetriesExceeded:
|
198
212
|
# do noting, not interested
|
199
213
|
pass
|
200
214
|
#except http.client.IncompleteRead as e:
|
@@ -216,7 +230,21 @@ class YoutubeAbstract(ScraperAbstract):
|
|
216
230
|
retries += 1
|
217
231
|
timeout += timeout_increment
|
218
232
|
time.sleep(pause_secs)
|
219
|
-
except (VideoUnavailable, VideoPrivate) as e:
|
233
|
+
except (pytubefix.exceptions.VideoUnavailable, pytubefix.exceptions.VideoPrivate) as e:
|
234
|
+
raise Unavailable(extract_exception_message(e))
|
235
|
+
except yt_dlp.utils.DownloadError as e:
|
236
|
+
raise Unavailable(extract_exception_message(e))
|
237
|
+
except yt_dlp.utils.GeoRestrictedError:
|
238
|
+
raise Unavailable(extract_exception_message(e))
|
239
|
+
except yt_dlp.utils.PostProcessingError as e:
|
240
|
+
raise Unavailable(extract_exception_message(e))
|
241
|
+
except yt_dlp.utils.ExtractorError as e:
|
242
|
+
raise Unavailable(extract_exception_message(e))
|
243
|
+
except yt_dlp.utils.MaxDownloadsReached as e:
|
244
|
+
raise Unavailable(extract_exception_message(e))
|
245
|
+
except yt_dlp.utils.UnavailableVideoError as e:
|
246
|
+
raise Unavailable(extract_exception_message(e))
|
247
|
+
except yt_dlp.utils.ThrottledDownload as e:
|
220
248
|
raise Unavailable(extract_exception_message(e))
|
221
249
|
|
222
250
|
return ret_val
|
@@ -241,8 +269,8 @@ class YoutubeAbstract(ScraperAbstract):
|
|
241
269
|
yt_opts["token_file"] = self.YT_SESSION_FILE % self.account_index
|
242
270
|
if self.proxy:
|
243
271
|
proxy_dsn = self.proxy.get("dsn", "")
|
272
|
+
logging.info("Using proxy DSN '%s'", proxy_dsn)
|
244
273
|
if proxy_dsn:
|
245
|
-
logging.info("Using proxy DSN '%s'", proxy_dsn)
|
246
274
|
if "https://" in proxy_dsn:
|
247
275
|
yt_opts["proxies"] = {"https": proxy_dsn}
|
248
276
|
elif "http://" in proxy_dsn:
|
@@ -251,14 +279,44 @@ class YoutubeAbstract(ScraperAbstract):
|
|
251
279
|
logging.warning("Proxy DSN malformed!")
|
252
280
|
return YouTube(**yt_opts)
|
253
281
|
|
282
|
+
def build_yt_dlp(self) -> yt_dlp.YoutubeDL:
|
283
|
+
auth_data = {}
|
284
|
+
with open(self.YT_SESSION_FILE % self.account_index, 'r', encoding="utf-8") as f:
|
285
|
+
auth_data = json.loads(f.read())
|
286
|
+
time_name = str(time.time()).replace('.', '_')
|
287
|
+
ydl_opts = {
|
288
|
+
'outtmpl': f'{self.DOWNLOAD_DIR}/{time_name}.%(ext)s',
|
289
|
+
'format': 'bestvideo+bestaudio/best',
|
290
|
+
'merge_output_format': 'mp4',
|
291
|
+
'noplaylist': True,
|
292
|
+
'tv_auth': auth_data
|
293
|
+
}
|
294
|
+
|
295
|
+
if self.proxy:
|
296
|
+
proxy_dsn = self.proxy.get("dsn", "")
|
297
|
+
logging.info("Using proxy DSN '%s'", proxy_dsn)
|
298
|
+
if proxy_dsn:
|
299
|
+
ydl_opts["proxy"] = proxy_dsn
|
300
|
+
|
301
|
+
return yt_dlp.YoutubeDL(ydl_opts)
|
302
|
+
|
254
303
|
def _download(self, _: str) -> list:
|
255
304
|
raise NotImplementedError("You should to implement _download method")
|
305
|
+
|
306
|
+
def _download_yt_dlp(self, _: str) -> list:
|
307
|
+
raise NotImplementedError("You should to implement _download_yt_dlp method")
|
256
308
|
|
257
309
|
def download(self, job: DownloadJob) -> list:
|
310
|
+
ret = []
|
258
311
|
try:
|
259
|
-
|
260
|
-
except Unavailable:
|
261
|
-
logging.warning("
|
262
|
-
time.sleep(2)
|
312
|
+
ret = self.download_hndlr(self._download, job.url, session=True)
|
313
|
+
except (Unavailable, TimeOut):
|
314
|
+
logging.warning("Download failed, trying to download with yt_dlp")
|
263
315
|
|
264
|
-
|
316
|
+
try:
|
317
|
+
ret = self.download_hndlr(self._download_yt_dlp, job.url)
|
318
|
+
except NotImplementedError:
|
319
|
+
logging.info("yt_dlp is not supported for this submodule yet")
|
320
|
+
raise Unavailable("Video unvailable")
|
321
|
+
|
322
|
+
return ret
|
@@ -1,10 +1,10 @@
|
|
1
|
-
|
2
|
-
from warp_beacon.scraper.youtube.abstract import YoutubeAbstract
|
3
|
-
from warp_beacon.scraper.exceptions import YoutubeLiveError, NotFound, YotubeAgeRestrictedError
|
1
|
+
import logging
|
4
2
|
|
5
3
|
from pytubefix.exceptions import AgeRestrictedError
|
6
4
|
|
7
|
-
import
|
5
|
+
from warp_beacon.jobs.types import JobType
|
6
|
+
from warp_beacon.scraper.youtube.abstract import YoutubeAbstract
|
7
|
+
from warp_beacon.scraper.exceptions import YoutubeLiveError, NotFound, YotubeAgeRestrictedError
|
8
8
|
|
9
9
|
class YoutubeScraper(YoutubeAbstract):
|
10
10
|
YT_MAX_RETRIES_DEFAULT = 8
|
@@ -32,14 +32,14 @@ class YoutubeScraper(YoutubeAbstract):
|
|
32
32
|
res = []
|
33
33
|
try:
|
34
34
|
thumbnail = None
|
35
|
+
video_id = self.get_video_id(url)
|
36
|
+
if video_id:
|
37
|
+
thumbnail = self.download_hndlr(self.download_thumbnail, video_id)
|
35
38
|
yt = self.build_yt(url, session=session)
|
36
39
|
|
37
40
|
if self.is_live(yt.initial_data):
|
38
41
|
raise YoutubeLiveError("Youtube Live is not supported")
|
39
42
|
|
40
|
-
if yt:
|
41
|
-
thumbnail = self.download_hndlr(self.download_thumbnail, yt.video_id)
|
42
|
-
|
43
43
|
stream = yt.streams.get_highest_resolution()
|
44
44
|
|
45
45
|
if not stream:
|
@@ -65,4 +65,24 @@ class YoutubeScraper(YoutubeAbstract):
|
|
65
65
|
except AgeRestrictedError as e:
|
66
66
|
raise YotubeAgeRestrictedError("Youtube Age Restricted error")
|
67
67
|
|
68
|
+
return res
|
69
|
+
|
70
|
+
def _download_yt_dlp(self, url: str) -> list:
|
71
|
+
res = []
|
72
|
+
thumbnail = None
|
73
|
+
video_id = self.get_video_id(url)
|
74
|
+
if video_id:
|
75
|
+
thumbnail = self.download_hndlr(self.download_thumbnail, video_id)
|
76
|
+
with self.build_yt_dlp() as ydl:
|
77
|
+
info = ydl.extract_info(url, download=True)
|
78
|
+
local_file = ydl.prepare_filename(info)
|
79
|
+
logging.debug("Temp filename: '%s'", local_file)
|
80
|
+
res.append({
|
81
|
+
"local_media_path": local_file,
|
82
|
+
"performer": info.get("uploader", "Unknown"),
|
83
|
+
"thumb": thumbnail,
|
84
|
+
"canonical_name": info.get("title", ''),
|
85
|
+
"media_type": JobType.VIDEO
|
86
|
+
})
|
87
|
+
|
68
88
|
return res
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: warp_beacon
|
3
|
-
Version: 2.3.
|
3
|
+
Version: 2.3.40
|
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
|
@@ -237,10 +237,13 @@ Requires-Dist: pillow
|
|
237
237
|
Requires-Dist: pymongo
|
238
238
|
Requires-Dist: instagrapi==2.0.0
|
239
239
|
Requires-Dist: bs4
|
240
|
+
Requires-Dist: yt_dlp
|
240
241
|
Dynamic: author
|
241
242
|
Dynamic: home-page
|
243
|
+
Dynamic: license-file
|
242
244
|
|
243
245
|
# 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)
|
246
|
+
> because content should travel freely
|
244
247
|
|
245
248
|
Telegram bot for external social networks media links expanding.
|
246
249
|
Works with a links in personal messages and also with group chats.
|
@@ -253,6 +256,24 @@ Just send a media link to the chat with bot and get a video or audio reply.
|
|
253
256
|
|<img width="700" alt="Instagram Photo post usage example" src="https://github.com/user-attachments/assets/29324b94-7314-4a38-8790-3483011d355d"> Instagram Photo post usage example|<img width="700" alt="Instagram Photo Carousel usage" src="https://github.com/user-attachments/assets/2598e329-e16e-455e-91e9-a027e8994283"> Instagram Photo Carousel usage example|<img width="757" alt="Instagram Photo bulk Strories download usage example" src="https://github.com/user-attachments/assets/2c8c91ac-6ade-4d1d-a677-2b36bb40ff39"> Instagram Photo bulk Strories download usage example|
|
254
257
|
|<img width="700" alt="Instagram specific Story download usage example" src="https://github.com/user-attachments/assets/03dc70c5-6933-4122-9c7c-5f7d734d117b"> Instagram specific Story download usage example|<img width="700" alt="Group chat usage example" src="https://github.com/user-attachments/assets/649fcb1e-785b-4efd-9153-69644c6d898b"> Group chat usage example|
|
255
258
|
|
259
|
+
### **Warp Beacon manifesto**
|
260
|
+
|
261
|
+
> Once, the Internet was built as a borderless network — a space where knowledge, culture, and ideas could flow freely across the globe.
|
262
|
+
> But over time, freedom gave way to artificial walls, anti-bot shields, and region locks.
|
263
|
+
>
|
264
|
+
> **warp_beacon** is our answer to that shift.
|
265
|
+
>
|
266
|
+
> This is a tool for those who refuse to accept "access denied by geolocation" or "content unavailable in your region."
|
267
|
+
> It is a bridge over ML filters, CAPTCHAs, and man-made barriers.
|
268
|
+
>
|
269
|
+
> We don’t break the rules — we restore the original spirit of the Internet:
|
270
|
+
> 📡 **free exchange of information**,
|
271
|
+
> 🌍 **unrestricted access to global content**,
|
272
|
+
> 🤖 **tools that serve the user**, not the platform.
|
273
|
+
>
|
274
|
+
> **warp_beacon** — the freedom to deliver content where it’s needed most.
|
275
|
+
|
276
|
+
## Configuration example ##
|
256
277
|
|
257
278
|
In order to setup your own instance, you will need:
|
258
279
|
|
@@ -261,8 +282,6 @@ In order to setup your own instance, you will need:
|
|
261
282
|
|
262
283
|
All bot configuration stored in [warp_beacon.conf](https://github.com/sb0y/warp_beacon/blob/main/etc/warp_beacon.conf) file.
|
263
284
|
|
264
|
-
## Configuration example ##
|
265
|
-
|
266
285
|
```env
|
267
286
|
TG_TOKEN="you telegram token received from @BotFather"
|
268
287
|
# these 3 settings should be obtained at https://my.telegram.org/apps
|
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
|