|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | | -import multiprocessing |
4 | | -import multiprocessing.dummy |
5 | | -from typing import Any, Callable, Optional |
6 | | - |
7 | | -import youtube_dl |
8 | | -from playwright.sync_api import sync_playwright |
9 | | -from youtube_dl.utils import DownloadError, YoutubeDLError |
| 3 | +from typing import Optional |
10 | 4 |
|
| 5 | +from .execute_parallel import execute_parallel |
11 | 6 | from .monsnode_parser import MonsnodeParser |
12 | | -from .twitter_crawler import TwitterCrawler |
| 7 | +from .platform_video_downloader import PlatformVideoDownloader |
13 | 8 |
|
14 | 9 |
|
15 | 10 | class VideoDownloader: |
16 | | - video_output_path: str = 'videos' |
| 11 | + """YoutubeDL wrapper with extra features""" |
17 | 12 | username: Optional[str] = None |
18 | 13 | password: Optional[str] = None |
19 | | - monsnode_parser: MonsnodeParser |
| 14 | + platform_video_downloader: PlatformVideoDownloader |
20 | 15 |
|
21 | 16 | def __init__( |
22 | 17 | self, |
23 | | - video_output_path: Optional[str] = None, |
24 | 18 | username: Optional[str] = None, |
25 | 19 | password: Optional[str] = None, |
26 | | - monsnode_parser: MonsnodeParser = MonsnodeParser(), |
| 20 | + platform_video_downloader: PlatformVideoDownloader = PlatformVideoDownloader('videos', MonsnodeParser()), |
27 | 21 | ): |
28 | | - self.video_output_path = video_output_path or self.video_output_path |
29 | 22 | self.username = username |
30 | 23 | self.password = password |
31 | | - self.monsnode_parser = monsnode_parser |
| 24 | + self.platform_video_downloader = platform_video_downloader |
32 | 25 |
|
33 | 26 | def download_videos(self, links: list[str]) -> None: |
34 | 27 | arguments = [(link, ) for link in links] |
35 | | - self._execute_parallel( |
36 | | - self.download_video, |
37 | | - arguments, |
38 | | - ) |
| 28 | + execute_parallel(self.download_video, arguments) |
39 | 29 |
|
40 | 30 | def download_video(self, link: str) -> None: |
41 | | - try: |
42 | | - self._download_public_video(link) |
43 | | - except DownloadError as error: |
44 | | - if not self.username or not self.password: |
45 | | - raise ValueError('Username and password are required for private videos') from error |
46 | | - print('Failed to download video, trying to download with authentication ...') |
47 | | - self._download_twitter_private_video(link, self.username, self.password) |
48 | | - except YoutubeDLError: |
49 | | - link = link.replace('\n', '') |
50 | | - print(f'{link} failed') |
51 | | - |
52 | | - def _download_public_video(self, link: str, video_filename: Optional[str] = None) -> None: |
53 | 31 | if 'monsnode.com' in link: |
54 | | - self.monsnode_parser.get_video(link) |
55 | | - video_filename, link = self.monsnode_parser.get_video(link) |
56 | | - |
57 | | - youtube_dl_output_template = \ |
58 | | - f'{self.video_output_path}/{video_filename}' \ |
59 | | - if video_filename else \ |
60 | | - f'{self.video_output_path}/%(title)s.%(ext)s' |
61 | | - youtube_dl_option = {'format': 'bestvideo/best', 'outtmpl': youtube_dl_output_template} |
62 | | - |
63 | | - with youtube_dl.YoutubeDL(youtube_dl_option) as youtube_dl_downloader: |
64 | | - youtube_dl_downloader.download([link]) |
65 | | - |
66 | | - def _download_twitter_private_video(self, target_link: str, username: str, password: str) -> None: |
67 | | - with sync_playwright() as playwright_sync: |
68 | | - browser = playwright_sync.webkit.launch(headless=True) |
69 | | - page = browser.new_page() |
70 | | - crawler = TwitterCrawler(page) |
71 | | - crawler.login(username, password) |
72 | | - video_info = crawler.get_video_of_tweet(target_link) |
73 | | - if video_info: # only if video exists |
74 | | - print('twitter video found, downloading ...') |
75 | | - video_filename, links = video_info |
76 | | - for link in links: |
77 | | - self._download_public_video(link, video_filename) |
78 | | - page.close() |
79 | | - browser.close() |
80 | | - |
81 | | - def _execute_parallel(self, func: Callable[[str], None], *args: Any, **kwargs: Any) -> None: |
82 | | - pool = multiprocessing.dummy.Pool(multiprocessing.cpu_count()) |
83 | | - pool.starmap(func, *args, **kwargs) |
| 32 | + self.platform_video_downloader.download_monsnode_video(link) |
| 33 | + return |
| 34 | + self.platform_video_downloader.download_twitter_video(link, self.username, self.password) |
0 commit comments