warp-beacon 2.7.11__tar.gz → 2.7.13__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 (71) hide show
  1. {warp_beacon-2.7.11/warp_beacon.egg-info → warp_beacon-2.7.13}/PKG-INFO +1 -1
  2. warp_beacon-2.7.13/warp_beacon/__version__.py +2 -0
  3. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/instagram/instagram.py +1 -1
  4. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/youtube/abstract.py +30 -2
  5. warp_beacon-2.7.13/warp_beacon/scraper/youtube/shorts.py +124 -0
  6. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/youtube/youtube.py +0 -28
  7. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/progress_bar.py +1 -1
  8. {warp_beacon-2.7.11 → warp_beacon-2.7.13/warp_beacon.egg-info}/PKG-INFO +1 -1
  9. warp_beacon-2.7.11/warp_beacon/__version__.py +0 -2
  10. warp_beacon-2.7.11/warp_beacon/scraper/youtube/shorts.py +0 -61
  11. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/LICENSE +0 -0
  12. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/MANIFEST.in +0 -0
  13. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/README.md +0 -0
  14. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/assets/cc-group-black.png +0 -0
  15. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/assets/placeholder.gif +0 -0
  16. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/etc/.gitignore +0 -0
  17. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/etc/accounts.json +0 -0
  18. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/etc/proxies.json +0 -0
  19. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/etc/warp_beacon.conf +0 -0
  20. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/etc/warp_beacon.service +0 -0
  21. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/pyproject.toml +0 -0
  22. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/setup.cfg +0 -0
  23. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/setup.py +0 -0
  24. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/__init__.py +0 -0
  25. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/compress/__init__.py +0 -0
  26. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/compress/video.py +0 -0
  27. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/jobs/__init__.py +0 -0
  28. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/jobs/abstract.py +0 -0
  29. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/jobs/download_job.py +0 -0
  30. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/jobs/types.py +0 -0
  31. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/jobs/upload_job.py +0 -0
  32. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/mediainfo/__init__.py +0 -0
  33. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/mediainfo/abstract.py +0 -0
  34. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/mediainfo/audio.py +0 -0
  35. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/mediainfo/silencer.py +0 -0
  36. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/mediainfo/video.py +0 -0
  37. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scheduler/__init__.py +0 -0
  38. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scheduler/instagram_human.py +0 -0
  39. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scheduler/scheduler.py +0 -0
  40. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/__init__.py +0 -0
  41. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/abstract.py +0 -0
  42. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/account_selector.py +0 -0
  43. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/exceptions.py +0 -0
  44. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/fail_handler.py +0 -0
  45. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/instagram/__init__.py +0 -0
  46. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/instagram/captcha.py +0 -0
  47. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/instagram/wb_instagrapi.py +0 -0
  48. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/link_resolver.py +0 -0
  49. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/utils.py +0 -0
  50. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/youtube/__init__.py +0 -0
  51. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/scraper/youtube/music.py +0 -0
  52. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/storage/__init__.py +0 -0
  53. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/storage/mongo.py +0 -0
  54. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/__init__.py +0 -0
  55. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/bot.py +0 -0
  56. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/caption_shortener.py +0 -0
  57. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/download_status.py +0 -0
  58. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/edit_message.py +0 -0
  59. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/handlers.py +0 -0
  60. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/placeholder_message.py +0 -0
  61. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/progress_file_reader.py +0 -0
  62. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/types.py +0 -0
  63. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/telegram/utils.py +0 -0
  64. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/uploader/__init__.py +0 -0
  65. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/warp_beacon.py +0 -0
  66. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon/yt_auth.py +0 -0
  67. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon.egg-info/SOURCES.txt +0 -0
  68. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon.egg-info/dependency_links.txt +0 -0
  69. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon.egg-info/entry_points.txt +0 -0
  70. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/warp_beacon.egg-info/requires.txt +0 -0
  71. {warp_beacon-2.7.11 → warp_beacon-2.7.13}/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.7.11
3
+ Version: 2.7.13
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.7.13"
2
+
@@ -475,7 +475,7 @@ class InstagramScraper(ScraperAbstract):
475
475
  "report_type": ReportType.PROGRESS
476
476
  }
477
477
  self.status_pipe.send(msg)
478
- self._download_progress_threshold += 10
478
+ self._download_progress_threshold += 20
479
479
 
480
480
  def report_seen(self, items: dict) -> None:
481
481
  try:
@@ -13,6 +13,7 @@ from typing import Callable, Optional, Union
13
13
  from urllib.parse import parse_qs, urlparse
14
14
 
15
15
  import numpy as np
16
+ import av
16
17
  import pytubefix
17
18
  import pytubefix.exceptions
18
19
  import requests
@@ -245,7 +246,7 @@ class YoutubeAbstract(ScraperAbstract):
245
246
  self.status_pipe.send(msg)
246
247
  logging.debug("[Download worker] Downloaded %d%%", percentage_of_completion)
247
248
  if total_size > 0:
248
- self._download_progress_threshold += 10
249
+ self._download_progress_threshold += 20
249
250
 
250
251
  def build_proxies(self, proxy_dsn: str) -> dict:
251
252
  if not proxy_dsn:
@@ -310,7 +311,7 @@ class YoutubeAbstract(ScraperAbstract):
310
311
  self.status_pipe.send(msg)
311
312
  logging.debug("[Download worker][yt_dlp] Downloaded %d%%", percentage_of_completion)
312
313
  if total_size > 0:
313
- self._download_progress_threshold += 10
314
+ self._download_progress_threshold += 20
314
315
 
315
316
  def build_yt_dlp(self, timeout: int = 60) -> yt_dlp.YoutubeDL:
316
317
  auth_data = {}
@@ -387,3 +388,30 @@ class YoutubeAbstract(ScraperAbstract):
387
388
  raise Unavailable("Сontent unvailable")
388
389
 
389
390
  return ret
391
+
392
+ def mux_raw_copy(self, video_path: str, audio_path: str, output_path: str) -> str:
393
+ try:
394
+ with av.open(video_path) as input_video, av.open(audio_path) as input_audio, av.open(output_path, mode='w') as output:
395
+ in_video_stream = input_video.streams.video[0]
396
+ in_audio_stream = input_audio.streams.audio[0]
397
+
398
+ video_stream_map = output.add_stream(template=in_video_stream)
399
+ audio_stream_map = output.add_stream(template=in_audio_stream)
400
+
401
+ for packet in input_video.demux(in_video_stream):
402
+ if packet.dts is None:
403
+ continue
404
+ packet.stream = video_stream_map
405
+ output.mux(packet)
406
+
407
+ for packet in input_audio.demux(in_audio_stream):
408
+ if packet.dts is None:
409
+ continue
410
+ packet.stream = audio_stream_map
411
+ output.mux(packet)
412
+ except Exception as e:
413
+ logging.error("Failed to mux audio and video!")
414
+ logging.exception(e)
415
+ return ''
416
+
417
+ return output_path
@@ -0,0 +1,124 @@
1
+ import os
2
+ import io
3
+ from typing import Optional
4
+ import time
5
+
6
+ import logging
7
+
8
+ from pytubefix.exceptions import AgeRestrictedError
9
+
10
+ from warp_beacon.jobs.types import JobType
11
+ from warp_beacon.scraper.youtube.abstract import YoutubeAbstract
12
+
13
+ from warp_beacon.scraper.exceptions import NotFound, YotubeAgeRestrictedError
14
+
15
+ class YoutubeShortsScraper(YoutubeAbstract):
16
+ YT_MAX_RETRIES_DEFAULT = 8
17
+ YT_PAUSE_BEFORE_RETRY_DEFAULT = 3
18
+ YT_TIMEOUT_DEFAULT = 2
19
+ YT_TIMEOUT_INCREMENT_DEFAULT = 60
20
+
21
+ def _download(self, url: str, session: bool = True, thumbnail: Optional[io.BytesIO] = None, timeout: int = 60) -> list:
22
+ res = self._download_pytubefix_max_res(url=url, session=session, thumbnail=thumbnail, timeout=timeout)
23
+ if not res:
24
+ res = self._download_pytube_dash(url=url, session=session, thumbnail=thumbnail, timeout=timeout)
25
+
26
+ return res
27
+
28
+ def _download_pytube_dash(self, url: str, session: bool = True, thumbnail: Optional[io.BytesIO] = None, timeout: int = 0) -> list:
29
+ res = []
30
+ yt = self.build_yt(url, session=session)
31
+ stream = yt.streams.get_highest_resolution()
32
+
33
+ if not stream:
34
+ raise NotFound("No suitable video stream found")
35
+
36
+ local_file = stream.download(
37
+ output_path=self.DOWNLOAD_DIR,
38
+ max_retries=0,
39
+ timeout=timeout,
40
+ skip_existing=False,
41
+ filename_prefix="yt_download_"
42
+ )
43
+
44
+ local_file = self.rename_local_file(local_file)
45
+
46
+ logging.debug("Temp filename: '%s'", local_file)
47
+ res.append({
48
+ "local_media_path": local_file,
49
+ "performer": yt.author,
50
+ "thumb": thumbnail,
51
+ "canonical_name": stream.title,
52
+ "media_type": JobType.VIDEO
53
+ })
54
+
55
+ return res
56
+
57
+ def _download_yt_dlp(self, url: str, thumbnail: Optional[io.BytesIO] = None, timeout: int = 60) -> list:
58
+ res = []
59
+ with self.build_yt_dlp(timeout) as ydl:
60
+ info = ydl.extract_info(url, download=True)
61
+ local_file = ydl.prepare_filename(info)
62
+ logging.debug("Temp filename: '%s'", local_file)
63
+ res.append({
64
+ "local_media_path": local_file,
65
+ "performer": info.get("uploader", "Unknown"),
66
+ "thumb": thumbnail,
67
+ "canonical_name": info.get("title", ''),
68
+ "media_type": JobType.VIDEO
69
+ })
70
+
71
+ return res
72
+
73
+ def _download_pytubefix_max_res(self, url: str, session: bool = True, thumbnail: Optional[io.BytesIO] = None, timeout: int = 60) -> list:
74
+ res = []
75
+ local_video_file, local_audio_file = '', ''
76
+ try:
77
+ yt = self.build_yt(url, session=session)
78
+
79
+ video_stream = yt.streams.filter(adaptive=True, file_extension='mp4', only_video=True).order_by('resolution').desc().first()
80
+ audio_stream = yt.streams.filter(adaptive=True, file_extension='mp4', only_audio=True).order_by('abr').desc().first()
81
+
82
+ local_video_file = video_stream.download(
83
+ output_path=self.DOWNLOAD_DIR,
84
+ max_retries=3,
85
+ timeout=timeout,
86
+ skip_existing=False,
87
+ filename_prefix="yt_download_video_"
88
+ )
89
+ local_video_file = self.rename_local_file(local_video_file)
90
+ logging.debug("Temp video filename: '%s'", local_video_file)
91
+ local_audio_file = audio_stream.download(
92
+ output_path=self.DOWNLOAD_DIR,
93
+ max_retries=3,
94
+ timeout=timeout,
95
+ skip_existing=False,
96
+ filename_prefix="yt_download_audio_"
97
+ )
98
+ local_audio_file = self.rename_local_file(local_audio_file)
99
+ logging.debug("Temp audio filename: '%s'", local_audio_file)
100
+
101
+ muxed_video = self.mux_raw_copy(
102
+ video_path=local_video_file,
103
+ audio_path=local_audio_file,
104
+ output_path=f"{self.DOWNLOAD_DIR}/yt_muxed_video_{int(time.time())}.mp4")
105
+ if muxed_video:
106
+ muxed_video = self.rename_local_file(muxed_video)
107
+ logging.debug("Temp muxed filename: '%s'", muxed_video)
108
+
109
+ res.append({
110
+ "local_media_path": muxed_video,
111
+ "performer": yt.author,
112
+ "thumb": thumbnail,
113
+ "canonical_name": yt.title,
114
+ "media_type": JobType.VIDEO
115
+ })
116
+ except AgeRestrictedError as e:
117
+ raise YotubeAgeRestrictedError("Youtube Age Restricted error")
118
+ finally:
119
+ if os.path.exists(local_video_file):
120
+ os.unlink(local_video_file)
121
+ if os.path.exists(local_audio_file):
122
+ os.unlink(local_audio_file)
123
+
124
+ return res
@@ -4,7 +4,6 @@ import io
4
4
  from typing import Optional
5
5
  import logging
6
6
 
7
- import av
8
7
  from pytubefix.exceptions import AgeRestrictedError
9
8
 
10
9
  from warp_beacon.jobs.types import JobType
@@ -39,33 +38,6 @@ class YoutubeScraper(YoutubeAbstract):
39
38
  res = self._download_pytube_dash(url=url, session=session, thumbnail=thumbnail, timeout=timeout)
40
39
 
41
40
  return res
42
-
43
- def mux_raw_copy(self, video_path: str, audio_path: str, output_path: str) -> str:
44
- try:
45
- with av.open(video_path) as input_video, av.open(audio_path) as input_audio, av.open(output_path, mode='w') as output:
46
- in_video_stream = input_video.streams.video[0]
47
- in_audio_stream = input_audio.streams.audio[0]
48
-
49
- video_stream_map = output.add_stream(template=in_video_stream)
50
- audio_stream_map = output.add_stream(template=in_audio_stream)
51
-
52
- for packet in input_video.demux(in_video_stream):
53
- if packet.dts is None:
54
- continue
55
- packet.stream = video_stream_map
56
- output.mux(packet)
57
-
58
- for packet in input_audio.demux(in_audio_stream):
59
- if packet.dts is None:
60
- continue
61
- packet.stream = audio_stream_map
62
- output.mux(packet)
63
- except Exception as e:
64
- logging.error("Failed to mux audio and video!")
65
- logging.exception(e)
66
- return ''
67
-
68
- return output_path
69
41
 
70
42
  def _download_pytubefix_max_res(self, url: str, session: bool = True, thumbnail: Optional[io.BytesIO] = None, timeout: int = 60) -> list:
71
43
  res = []
@@ -125,7 +125,7 @@ class ProgressBar(object):
125
125
  logging.warning("An error occurred while setup task to update progress bar")
126
126
  logging.exception(e)
127
127
  if total > 0 and percent != 0:
128
- self._next_threshold += 15
128
+ self._next_threshold += 20
129
129
 
130
130
  @staticmethod
131
131
  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.7.11
3
+ Version: 2.7.13
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.7.11"
2
-
@@ -1,61 +0,0 @@
1
- import io
2
- from typing import Optional
3
-
4
- import logging
5
-
6
- from warp_beacon.jobs.types import JobType
7
- from warp_beacon.scraper.youtube.abstract import YoutubeAbstract
8
- from warp_beacon.scraper.exceptions import NotFound
9
-
10
- from warp_beacon.mediainfo.video import VideoInfo
11
-
12
- class YoutubeShortsScraper(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 _download(self, url: str, session: bool = True, thumbnail: Optional[io.BytesIO] = None, timeout: int = 0) -> list:
19
- res = []
20
- yt = self.build_yt(url, session=session)
21
- stream = yt.streams.get_highest_resolution()
22
-
23
- if not stream:
24
- raise NotFound("No suitable video stream found")
25
-
26
- local_file = stream.download(
27
- output_path=self.DOWNLOAD_DIR,
28
- max_retries=0,
29
- timeout=timeout,
30
- skip_existing=False,
31
- filename_prefix="yt_download_"
32
- )
33
-
34
- local_file = self.rename_local_file(local_file)
35
-
36
- logging.debug("Temp filename: '%s'", local_file)
37
- res.append({
38
- "local_media_path": local_file,
39
- "performer": yt.author,
40
- "thumb": thumbnail,
41
- "canonical_name": stream.title,
42
- "media_type": JobType.VIDEO
43
- })
44
-
45
- return res
46
-
47
- def _download_yt_dlp(self, url: str, thumbnail: Optional[io.BytesIO] = None, timeout: int = 60) -> list:
48
- res = []
49
- with self.build_yt_dlp(timeout) as ydl:
50
- info = ydl.extract_info(url, download=True)
51
- local_file = ydl.prepare_filename(info)
52
- logging.debug("Temp filename: '%s'", local_file)
53
- res.append({
54
- "local_media_path": local_file,
55
- "performer": info.get("uploader", "Unknown"),
56
- "thumb": thumbnail,
57
- "canonical_name": info.get("title", ''),
58
- "media_type": JobType.VIDEO
59
- })
60
-
61
- return res
File without changes
File without changes
File without changes
File without changes
File without changes