warp-beacon 2.5.0__tar.gz → 2.5.1__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.
Files changed (62) hide show
  1. {warp_beacon-2.5.0/warp_beacon.egg-info → warp_beacon-2.5.1}/PKG-INFO +1 -1
  2. warp_beacon-2.5.1/warp_beacon/__version__.py +2 -0
  3. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/youtube/music.py +1 -1
  4. warp_beacon-2.5.1/warp_beacon/scraper/youtube/youtube.py +195 -0
  5. {warp_beacon-2.5.0 → warp_beacon-2.5.1/warp_beacon.egg-info}/PKG-INFO +1 -1
  6. warp_beacon-2.5.0/warp_beacon/__version__.py +0 -2
  7. warp_beacon-2.5.0/warp_beacon/scraper/youtube/youtube.py +0 -88
  8. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/LICENSE +0 -0
  9. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/MANIFEST.in +0 -0
  10. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/README.md +0 -0
  11. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/assets/placeholder.gif +0 -0
  12. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/etc/.gitignore +0 -0
  13. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/etc/accounts.json +0 -0
  14. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/etc/proxies.json +0 -0
  15. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/etc/warp_beacon.conf +0 -0
  16. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/etc/warp_beacon.service +0 -0
  17. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/pyproject.toml +0 -0
  18. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/setup.cfg +0 -0
  19. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/setup.py +0 -0
  20. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/__init__.py +0 -0
  21. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/compress/__init__.py +0 -0
  22. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/compress/video.py +0 -0
  23. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/jobs/__init__.py +0 -0
  24. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/jobs/abstract.py +0 -0
  25. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/jobs/download_job.py +0 -0
  26. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/jobs/types.py +0 -0
  27. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/jobs/upload_job.py +0 -0
  28. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/mediainfo/__init__.py +0 -0
  29. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/mediainfo/abstract.py +0 -0
  30. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/mediainfo/audio.py +0 -0
  31. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/mediainfo/silencer.py +0 -0
  32. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/mediainfo/video.py +0 -0
  33. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scheduler/__init__.py +0 -0
  34. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scheduler/instagram_human.py +0 -0
  35. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scheduler/scheduler.py +0 -0
  36. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/__init__.py +0 -0
  37. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/abstract.py +0 -0
  38. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/account_selector.py +0 -0
  39. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/exceptions.py +0 -0
  40. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/fail_handler.py +0 -0
  41. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/instagram/__init__.py +0 -0
  42. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/instagram/instagram.py +0 -0
  43. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/link_resolver.py +0 -0
  44. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/youtube/__init__.py +0 -0
  45. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/youtube/abstract.py +0 -0
  46. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/scraper/youtube/shorts.py +0 -0
  47. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/storage/__init__.py +0 -0
  48. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/storage/mongo.py +0 -0
  49. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/telegram/__init__.py +0 -0
  50. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/telegram/bot.py +0 -0
  51. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/telegram/caption_shortener.py +0 -0
  52. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/telegram/handlers.py +0 -0
  53. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/telegram/placeholder_message.py +0 -0
  54. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/telegram/utils.py +0 -0
  55. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/uploader/__init__.py +0 -0
  56. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/warp_beacon.py +0 -0
  57. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon/yt_auth.py +0 -0
  58. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon.egg-info/SOURCES.txt +0 -0
  59. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon.egg-info/dependency_links.txt +0 -0
  60. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon.egg-info/entry_points.txt +0 -0
  61. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon.egg-info/requires.txt +0 -0
  62. {warp_beacon-2.5.0 → warp_beacon-2.5.1}/warp_beacon.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: warp_beacon
3
- Version: 2.5.0
3
+ Version: 2.5.1
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
@@ -0,0 +1,2 @@
1
+ __version__ = "2.5.1"
2
+
@@ -49,7 +49,7 @@ class YoutubeMusicScraper(YoutubeAbstract):
49
49
  "local_media_path": self.rename_local_file(local_file),
50
50
  "performer": yt.author,
51
51
  "thumb": thumbnail,
52
- "canonical_name": stream.title,
52
+ "canonical_name": yt.title,
53
53
  "media_type": JobType.AUDIO
54
54
  })
55
55
  except Exception:
@@ -0,0 +1,195 @@
1
+ import time
2
+ import os
3
+ import logging
4
+
5
+ import av
6
+ from pytubefix.exceptions import AgeRestrictedError
7
+
8
+ from warp_beacon.jobs.types import JobType
9
+ from warp_beacon.scraper.youtube.abstract import YoutubeAbstract
10
+ from warp_beacon.scraper.exceptions import YoutubeLiveError, NotFound, YotubeAgeRestrictedError
11
+
12
+ class YoutubeScraper(YoutubeAbstract):
13
+ YT_MAX_RETRIES_DEFAULT = 8
14
+ YT_PAUSE_BEFORE_RETRY_DEFAULT = 3
15
+ YT_TIMEOUT_DEFAULT = 2
16
+ YT_TIMEOUT_INCREMENT_DEFAULT = 60
17
+
18
+ def is_live(self, data: dict) -> bool:
19
+ '''
20
+ x.contents.twoColumnWatchNextResults.results.results.contents[0].videoPrimaryInfoRenderer.viewCount.videoViewCountRenderer.isLive
21
+ '''
22
+ try:
23
+ contents = data.get("contents", {}).get("twoColumnWatchNextResults", {}).get("results", {}).get("results", {}).get("contents", [])
24
+ for i in contents:
25
+ video_view_count_renderer = i.get("videoPrimaryInfoRenderer", {}).get("viewCount", {}).get("videoViewCountRenderer", {})
26
+ if video_view_count_renderer:
27
+ return video_view_count_renderer.get("isLive", False)
28
+ except Exception as e:
29
+ logging.warning("Failed to check if stream is live!")
30
+ logging.exception(e)
31
+
32
+ return False
33
+
34
+ def _download(self, url: str, session: bool = True, timeout: int = 60) -> list:
35
+ res = None
36
+ try:
37
+ res = self._download_pytubefix_max_res(url=url, session=session, timeout=timeout)
38
+ except Exception as e:
39
+ logging.error("Failed to download video with highest resolution via pytubefix!")
40
+ logging.exception(e)
41
+
42
+ if not res:
43
+ try:
44
+ res = self._download_pytube_dash(url=url, session=session, timeout=timeout)
45
+ except Exception as e:
46
+ logging.error("Failed to download DASH stream video via pytubefix!")
47
+ logging.exception(e)
48
+
49
+ return res
50
+
51
+ def mux_raw_copy(self, video_path: str, audio_path: str, output_path: str) -> str:
52
+ try:
53
+ with av.open(video_path) as input_video, av.open(audio_path) as input_audio, av.open(output_path, mode='w') as output:
54
+ in_video_stream = input_video.streams.video[0]
55
+ in_audio_stream = input_audio.streams.audio[0]
56
+
57
+ out_video_stream = output.add_stream(codec_name=in_video_stream.codec.name)
58
+ out_audio_stream = output.add_stream(codec_name=in_audio_stream.codec.name)
59
+
60
+ for packet in input_video.demux(in_video_stream):
61
+ if packet.dts is None:
62
+ continue
63
+ packet.stream = out_video_stream
64
+ output.mux(packet)
65
+
66
+ for packet in input_audio.demux(in_audio_stream):
67
+ if packet.dts is None:
68
+ continue
69
+ packet.stream = out_audio_stream
70
+ output.mux(packet)
71
+ except Exception as e:
72
+ logging.error("Failed to mux audio and video!")
73
+ logging.exception(e)
74
+ return ''
75
+
76
+ return output_path
77
+
78
+ def _download_pytubefix_max_res(self, url: str, session: bool = True, timeout: int = 60) -> list:
79
+ res = []
80
+ local_video_file, local_audio_file = '', ''
81
+ try:
82
+ thumbnail = None
83
+ video_id = self.get_video_id(url)
84
+ if video_id:
85
+ thumbnail = self.download_hndlr(self.download_thumbnail, video_id)
86
+ yt = self.build_yt(url, session=session)
87
+
88
+ if self.is_live(yt.initial_data):
89
+ raise YoutubeLiveError("Youtube Live is not supported")
90
+
91
+ video_stream = yt.streams.filter(adaptive=True, file_extension='mp4', only_video=True).order_by('resolution').desc().first()
92
+ audio_stream = yt.streams.filter(adaptive=True, file_extension='mp4', only_audio=True).order_by('abr').desc().first()
93
+
94
+ local_video_file = video_stream.download(
95
+ output_path=self.DOWNLOAD_DIR,
96
+ max_retries=3,
97
+ timeout=timeout,
98
+ skip_existing=False,
99
+ filename_prefix="yt_download_video_"
100
+ )
101
+ local_video_file = self.rename_local_file(local_video_file)
102
+ logging.debug("Temp video filename: '%s'", local_video_file)
103
+ local_audio_file = audio_stream.download(
104
+ output_path=self.DOWNLOAD_DIR,
105
+ max_retries=3,
106
+ timeout=timeout,
107
+ skip_existing=False,
108
+ filename_prefix="yt_download_audio_"
109
+ )
110
+ local_audio_file = self.rename_local_file(local_audio_file)
111
+ logging.debug("Temp audio filename: '%s'", local_audio_file)
112
+
113
+ muxed_video = self.mux_raw_copy(
114
+ video_path=local_video_file,
115
+ audio_path=local_audio_file,
116
+ output_path=f"{self.DOWNLOAD_DIR}/yt_muxed_video_{int(time.time())}.mp4")
117
+ if muxed_video:
118
+ muxed_video = self.rename_local_file(muxed_video)
119
+ logging.debug("Temp muxed filename: '%s'", muxed_video)
120
+
121
+ res.append({
122
+ "local_media_path": muxed_video,
123
+ "performer": yt.author,
124
+ "thumb": thumbnail,
125
+ "canonical_name": yt.title,
126
+ "media_type": JobType.VIDEO
127
+ })
128
+ except AgeRestrictedError as e:
129
+ raise YotubeAgeRestrictedError("Youtube Age Restricted error")
130
+ finally:
131
+ if os.path.exists(local_video_file):
132
+ os.unlink(local_video_file)
133
+ if os.path.exists(local_audio_file):
134
+ os.unlink(local_audio_file)
135
+
136
+ return res
137
+
138
+ def _download_pytube_dash(self, url: str, session: bool = True, timeout: int = 60) -> list:
139
+ res = []
140
+ try:
141
+ thumbnail = None
142
+ video_id = self.get_video_id(url)
143
+ if video_id:
144
+ thumbnail = self.download_hndlr(self.download_thumbnail, video_id)
145
+ yt = self.build_yt(url, session=session)
146
+
147
+ if self.is_live(yt.initial_data):
148
+ raise YoutubeLiveError("Youtube Live is not supported")
149
+
150
+ stream = yt.streams.get_highest_resolution()
151
+
152
+ if not stream:
153
+ raise NotFound("No suitable video stream found")
154
+
155
+ logging.info("Starting download ...")
156
+
157
+ local_file = stream.download(
158
+ output_path=self.DOWNLOAD_DIR,
159
+ max_retries=0,
160
+ timeout=timeout,
161
+ skip_existing=False,
162
+ filename_prefix="yt_download_"
163
+ )
164
+ logging.debug("Temp filename: '%s'", local_file)
165
+ res.append({
166
+ "local_media_path": self.rename_local_file(local_file),
167
+ "performer": yt.author,
168
+ "thumb": thumbnail,
169
+ "canonical_name": stream.title,
170
+ "media_type": JobType.VIDEO
171
+ })
172
+ except AgeRestrictedError as e:
173
+ raise YotubeAgeRestrictedError("Youtube Age Restricted error")
174
+
175
+ return res
176
+
177
+ def _download_yt_dlp(self, url: str, timeout: int = 60) -> list:
178
+ res = []
179
+ thumbnail = None
180
+ video_id = self.get_video_id(url)
181
+ if video_id:
182
+ thumbnail = self.download_hndlr(self.download_thumbnail, video_id)
183
+ with self.build_yt_dlp(timeout) as ydl:
184
+ info = ydl.extract_info(url, download=True)
185
+ local_file = ydl.prepare_filename(info)
186
+ logging.debug("Temp filename: '%s'", local_file)
187
+ res.append({
188
+ "local_media_path": local_file,
189
+ "performer": info.get("uploader", "Unknown"),
190
+ "thumb": thumbnail,
191
+ "canonical_name": info.get("title", ''),
192
+ "media_type": JobType.VIDEO
193
+ })
194
+
195
+ return res
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: warp_beacon
3
- Version: 2.5.0
3
+ Version: 2.5.1
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
@@ -1,2 +0,0 @@
1
- __version__ = "2.5.0"
2
-
@@ -1,88 +0,0 @@
1
- import logging
2
-
3
- from pytubefix.exceptions import AgeRestrictedError
4
-
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
-
9
- class YoutubeScraper(YoutubeAbstract):
10
- YT_MAX_RETRIES_DEFAULT = 8
11
- YT_PAUSE_BEFORE_RETRY_DEFAULT = 3
12
- YT_TIMEOUT_DEFAULT = 2
13
- YT_TIMEOUT_INCREMENT_DEFAULT = 60
14
-
15
- def is_live(self, data: dict) -> bool:
16
- '''
17
- x.contents.twoColumnWatchNextResults.results.results.contents[0].videoPrimaryInfoRenderer.viewCount.videoViewCountRenderer.isLive
18
- '''
19
- try:
20
- contents = data.get("contents", {}).get("twoColumnWatchNextResults", {}).get("results", {}).get("results", {}).get("contents", [])
21
- for i in contents:
22
- video_view_count_renderer = i.get("videoPrimaryInfoRenderer", {}).get("viewCount", {}).get("videoViewCountRenderer", {})
23
- if video_view_count_renderer:
24
- return video_view_count_renderer.get("isLive", False)
25
- except Exception as e:
26
- logging.warning("Failed to check if stream is live!")
27
- logging.exception(e)
28
-
29
- return False
30
-
31
- def _download(self, url: str, session: bool = True, timeout: int = 60) -> list:
32
- res = []
33
- try:
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)
38
- yt = self.build_yt(url, session=session)
39
-
40
- if self.is_live(yt.initial_data):
41
- raise YoutubeLiveError("Youtube Live is not supported")
42
-
43
- stream = yt.streams.get_highest_resolution()
44
-
45
- if not stream:
46
- raise NotFound("No suitable video stream found")
47
-
48
- logging.info("Starting download ...")
49
-
50
- local_file = stream.download(
51
- output_path=self.DOWNLOAD_DIR,
52
- max_retries=0,
53
- timeout=timeout,
54
- skip_existing=False,
55
- filename_prefix="yt_download_"
56
- )
57
- logging.debug("Temp filename: '%s'", local_file)
58
- res.append({
59
- "local_media_path": self.rename_local_file(local_file),
60
- "performer": yt.author,
61
- "thumb": thumbnail,
62
- "canonical_name": stream.title,
63
- "media_type": JobType.VIDEO
64
- })
65
- except AgeRestrictedError as e:
66
- raise YotubeAgeRestrictedError("Youtube Age Restricted error")
67
-
68
- return res
69
-
70
- def _download_yt_dlp(self, url: str, timeout: int = 60) -> 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(timeout) 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
-
88
- return res
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes