warp-beacon 2.7.12__py3-none-any.whl → 2.7.13__py3-none-any.whl
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/__version__.py +1 -1
- warp_beacon/scraper/youtube/abstract.py +28 -0
- warp_beacon/scraper/youtube/shorts.py +66 -3
- warp_beacon/scraper/youtube/youtube.py +0 -28
- {warp_beacon-2.7.12.dist-info → warp_beacon-2.7.13.dist-info}/METADATA +1 -1
- {warp_beacon-2.7.12.dist-info → warp_beacon-2.7.13.dist-info}/RECORD +10 -10
- {warp_beacon-2.7.12.dist-info → warp_beacon-2.7.13.dist-info}/WHEEL +0 -0
- {warp_beacon-2.7.12.dist-info → warp_beacon-2.7.13.dist-info}/entry_points.txt +0 -0
- {warp_beacon-2.7.12.dist-info → warp_beacon-2.7.13.dist-info}/licenses/LICENSE +0 -0
- {warp_beacon-2.7.12.dist-info → warp_beacon-2.7.13.dist-info}/top_level.txt +0 -0
warp_beacon/__version__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
__version__ = "2.7.
|
1
|
+
__version__ = "2.7.13"
|
2
2
|
|
@@ -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
|
@@ -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
|
@@ -1,13 +1,16 @@
|
|
1
|
+
import os
|
1
2
|
import io
|
2
3
|
from typing import Optional
|
4
|
+
import time
|
3
5
|
|
4
6
|
import logging
|
5
7
|
|
8
|
+
from pytubefix.exceptions import AgeRestrictedError
|
9
|
+
|
6
10
|
from warp_beacon.jobs.types import JobType
|
7
11
|
from warp_beacon.scraper.youtube.abstract import YoutubeAbstract
|
8
|
-
from warp_beacon.scraper.exceptions import NotFound
|
9
12
|
|
10
|
-
from warp_beacon.
|
13
|
+
from warp_beacon.scraper.exceptions import NotFound, YotubeAgeRestrictedError
|
11
14
|
|
12
15
|
class YoutubeShortsScraper(YoutubeAbstract):
|
13
16
|
YT_MAX_RETRIES_DEFAULT = 8
|
@@ -15,7 +18,14 @@ class YoutubeShortsScraper(YoutubeAbstract):
|
|
15
18
|
YT_TIMEOUT_DEFAULT = 2
|
16
19
|
YT_TIMEOUT_INCREMENT_DEFAULT = 60
|
17
20
|
|
18
|
-
def _download(self, url: str, session: bool = True, thumbnail: Optional[io.BytesIO] = None, timeout: int =
|
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:
|
19
29
|
res = []
|
20
30
|
yt = self.build_yt(url, session=session)
|
21
31
|
stream = yt.streams.get_highest_resolution()
|
@@ -58,4 +68,57 @@ class YoutubeShortsScraper(YoutubeAbstract):
|
|
58
68
|
"media_type": JobType.VIDEO
|
59
69
|
})
|
60
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
|
+
|
61
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 = []
|
@@ -4,7 +4,7 @@ var/warp_beacon/accounts.json,sha256=OsXdncs6h88xrF_AP6_WDCK1waGBn9SR-uYdIeK37GM
|
|
4
4
|
var/warp_beacon/placeholder.gif,sha256=cE5CGJVaop4Sx21zx6j4AyoHU0ncmvQuS2o6hJfEH88,6064
|
5
5
|
var/warp_beacon/proxies.json,sha256=VnjlQDXumOEq72ZFjbh6IqHS1TEHqn8HPYAZqWCeSIA,95
|
6
6
|
warp_beacon/__init__.py,sha256=_rThNODmz0nDp_n4mWo_HKaNFE5jk1_7cRhHyYaencI,163
|
7
|
-
warp_beacon/__version__.py,sha256=
|
7
|
+
warp_beacon/__version__.py,sha256=x219y8Xqh6qOh4lcwrZPGXW00waIfTBdHsot4GpeNiI,24
|
8
8
|
warp_beacon/warp_beacon.py,sha256=ADCR30uGXIsDrt9WoiI9Ghu2QtWs0qZIK6x3pQKM_B4,1109
|
9
9
|
warp_beacon/yt_auth.py,sha256=GUTKqYr_tzDC-07Lx_ahWXSag8EyLxXBUnQbDBIkEmk,6022
|
10
10
|
warp_beacon/compress/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -34,10 +34,10 @@ warp_beacon/scraper/instagram/captcha.py,sha256=9UYziuqB3Tsat_ET6ex-cnZDbi6yCnsX
|
|
34
34
|
warp_beacon/scraper/instagram/instagram.py,sha256=oVXP6VweJCeffhyDU-GZLa66ESW06GvfuGcW2V6YdQ4,18629
|
35
35
|
warp_beacon/scraper/instagram/wb_instagrapi.py,sha256=M5NCtLwdUvByjmDBZMWljgB275R0LSBFblsGpapluD0,5968
|
36
36
|
warp_beacon/scraper/youtube/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
|
-
warp_beacon/scraper/youtube/abstract.py,sha256=
|
37
|
+
warp_beacon/scraper/youtube/abstract.py,sha256=H53RjCGB5W-uvKEgFrPn0kSBxc8EQgpme-9DJF9I7rU,16193
|
38
38
|
warp_beacon/scraper/youtube/music.py,sha256=5AeSBQyUgVCJT2hoBCV2WvlyuV9US09SYJhmBG_P9F8,2755
|
39
|
-
warp_beacon/scraper/youtube/shorts.py,sha256=
|
40
|
-
warp_beacon/scraper/youtube/youtube.py,sha256=
|
39
|
+
warp_beacon/scraper/youtube/shorts.py,sha256=y0591kpWU35rt5OoWamkcHIstNZ98SXUlUKvYmUsyEY,4030
|
40
|
+
warp_beacon/scraper/youtube/youtube.py,sha256=i-3Z5l3S-EltIFbxkbvDjXMgH8fGOrB5-ua1p6iH_Bc,6316
|
41
41
|
warp_beacon/storage/__init__.py,sha256=0Vajd0oITKJfu2vmNx5uQSt3-L6vwIvUYWJo8HZCjco,3398
|
42
42
|
warp_beacon/storage/mongo.py,sha256=qC4ZiO8XXvPnP0rJwz4CJx42pqFsyAjCiW10W5QdT6E,527
|
43
43
|
warp_beacon/telegram/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -52,9 +52,9 @@ warp_beacon/telegram/progress_file_reader.py,sha256=e3equyNKlKs764AD-iE9QRsh3YDH
|
|
52
52
|
warp_beacon/telegram/types.py,sha256=Kvdng6uCF1HRoqQgGW1ZYYPJoVuYkFb-LDvMBbW5Hjk,89
|
53
53
|
warp_beacon/telegram/utils.py,sha256=S1N_JbHM_ExiM5tS0CeYKWIlvaJMlyq85TQNbK_GVds,5029
|
54
54
|
warp_beacon/uploader/__init__.py,sha256=ewvR60k9osJxw_kb5U-TlZkCGR_574biq3w_aR1tjIU,5689
|
55
|
-
warp_beacon-2.7.
|
56
|
-
warp_beacon-2.7.
|
57
|
-
warp_beacon-2.7.
|
58
|
-
warp_beacon-2.7.
|
59
|
-
warp_beacon-2.7.
|
60
|
-
warp_beacon-2.7.
|
55
|
+
warp_beacon-2.7.13.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
56
|
+
warp_beacon-2.7.13.dist-info/METADATA,sha256=wRZPk7SRIYDZ9xSsAVfRdW_TK206mInTQIiZYLRD_sY,23215
|
57
|
+
warp_beacon-2.7.13.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
58
|
+
warp_beacon-2.7.13.dist-info/entry_points.txt,sha256=eSB61Rb89d56WY0O-vEIQwkn18J-4CMrJcLA_R_8h3g,119
|
59
|
+
warp_beacon-2.7.13.dist-info/top_level.txt,sha256=5YQRN46STNg81V_3jdzZ6bftkMxhe1hTPSFvJugDu84,1405
|
60
|
+
warp_beacon-2.7.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|