]>
Commit | Line | Data |
---|---|---|
15591940 | 1 | import re |
2 | ||
3 | from .common import InfoExtractor | |
4 | from ..utils import ( | |
5 | filter_dict, | |
6 | int_or_none, | |
7 | parse_age_limit, | |
8 | smuggle_url, | |
9 | traverse_obj, | |
10 | unsmuggle_url, | |
11 | url_or_none, | |
12 | ) | |
13 | ||
14 | ||
15 | class CineverseBaseIE(InfoExtractor): | |
16 | _VALID_URL_BASE = r'https://www\.(?P<host>%s)' % '|'.join(map(re.escape, ( | |
17 | 'cineverse.com', | |
18 | 'asiancrush.com', | |
19 | 'dovechannel.com', | |
20 | 'screambox.com', | |
21 | 'midnightpulp.com', | |
22 | 'fandor.com', | |
23 | 'retrocrush.tv', | |
24 | ))) | |
25 | ||
26 | ||
27 | class CineverseIE(CineverseBaseIE): | |
28 | _VALID_URL = rf'{CineverseBaseIE._VALID_URL_BASE}/watch/(?P<id>[A-Z0-9]+)' | |
29 | _TESTS = [{ | |
30 | 'url': 'https://www.asiancrush.com/watch/DMR00018919/Women-Who-Flirt', | |
31 | 'skip': 'geo-blocked', | |
32 | 'info_dict': { | |
33 | 'title': 'Women Who Flirt', | |
34 | 'ext': 'mp4', | |
35 | 'id': 'DMR00018919', | |
36 | 'modified_timestamp': 1678744575289, | |
37 | 'cast': ['Xun Zhou', 'Xiaoming Huang', 'Yi-Lin Sie', 'Sonia Sui', 'Quniciren'], | |
38 | 'duration': 5811.597, | |
39 | 'description': 'md5:892fd62a05611d394141e8394ace0bc6', | |
40 | 'age_limit': 13, | |
41 | } | |
42 | }, { | |
43 | 'url': 'https://www.retrocrush.tv/watch/1000000023016/Archenemy! Crystal Bowie', | |
44 | 'skip': 'geo-blocked', | |
45 | 'info_dict': { | |
46 | 'title': 'Archenemy! Crystal Bowie', | |
47 | 'ext': 'mp4', | |
48 | 'id': '1000000023016', | |
49 | 'episode_number': 3, | |
50 | 'season_number': 1, | |
51 | 'cast': ['Nachi Nozawa', 'Yoshiko Sakakibara', 'Toshiko Fujita'], | |
52 | 'age_limit': 0, | |
53 | 'episode': 'Episode 3', | |
54 | 'season': 'Season 1', | |
55 | 'duration': 1485.067, | |
56 | 'description': 'Cobra meets a beautiful bounty hunter by the name of Jane Royal.', | |
57 | 'series': 'Space Adventure COBRA (Original Japanese)', | |
58 | } | |
59 | }] | |
60 | ||
61 | def _real_extract(self, url): | |
62 | url, smuggled_data = unsmuggle_url(url, default={}) | |
63 | self._initialize_geo_bypass({ | |
64 | 'countries': smuggled_data.get('geo_countries'), | |
65 | }) | |
66 | video_id = self._match_id(url) | |
67 | html = self._download_webpage(url, video_id) | |
68 | idetails = self._search_nextjs_data(html, video_id)['props']['pageProps']['idetails'] | |
69 | ||
70 | if idetails.get('err_code') == 1200: | |
71 | self.raise_geo_restricted( | |
72 | 'This video is not available from your location due to geo restriction. ' | |
73 | 'You may be able to bypass it by using the /details/ page instead of the /watch/ page', | |
74 | countries=smuggled_data.get('geo_countries')) | |
75 | ||
76 | return { | |
77 | 'subtitles': filter_dict({ | |
78 | 'en': traverse_obj(idetails, (('cc_url_vtt', 'subtitle_url'), {'url': {url_or_none}})) or None, | |
79 | }), | |
80 | 'formats': self._extract_m3u8_formats(idetails['url'], video_id), | |
81 | **traverse_obj(idetails, { | |
82 | 'title': 'title', | |
83 | 'id': ('details', 'item_id'), | |
84 | 'description': ('details', 'description'), | |
85 | 'duration': ('duration', {lambda x: x / 1000}), | |
86 | 'cast': ('details', 'cast', {lambda x: x.split(', ')}), | |
87 | 'modified_timestamp': ('details', 'updated_by', 0, 'update_time', 'time', {int_or_none}), | |
88 | 'season_number': ('details', 'season', {int_or_none}), | |
89 | 'episode_number': ('details', 'episode', {int_or_none}), | |
90 | 'age_limit': ('details', 'rating_code', {parse_age_limit}), | |
91 | 'series': ('details', 'series_details', 'title'), | |
92 | }), | |
93 | } | |
94 | ||
95 | ||
96 | class CineverseDetailsIE(CineverseBaseIE): | |
97 | _VALID_URL = rf'{CineverseBaseIE._VALID_URL_BASE}/details/(?P<id>[A-Z0-9]+)' | |
98 | _TESTS = [{ | |
99 | 'url': 'https://www.retrocrush.tv/details/1000000023012/Space-Adventure-COBRA-(Original-Japanese)', | |
100 | 'playlist_mincount': 30, | |
101 | 'info_dict': { | |
102 | 'title': 'Space Adventure COBRA (Original Japanese)', | |
103 | 'id': '1000000023012', | |
104 | } | |
105 | }, { | |
106 | 'url': 'https://www.asiancrush.com/details/NNVG4938/Hansel-and-Gretel', | |
107 | 'info_dict': { | |
108 | 'id': 'NNVG4938', | |
109 | 'ext': 'mp4', | |
110 | 'title': 'Hansel and Gretel', | |
111 | 'description': 'md5:e3e4c35309c2e82aee044f972c2fb05d', | |
112 | 'cast': ['Jeong-myeong Cheon', 'Eun Won-jae', 'Shim Eun-gyeong', 'Ji-hee Jin', 'Hee-soon Park', 'Lydia Park', 'Kyeong-ik Kim'], | |
113 | 'duration': 7030.732, | |
114 | }, | |
115 | }] | |
116 | ||
117 | def _real_extract(self, url): | |
118 | host, series_id = self._match_valid_url(url).group('host', 'id') | |
119 | html = self._download_webpage(url, series_id) | |
120 | pageprops = self._search_nextjs_data(html, series_id)['props']['pageProps'] | |
121 | ||
122 | geo_countries = traverse_obj(pageprops, ('itemDetailsData', 'geo_country', {lambda x: x.split(', ')})) | |
123 | geoblocked = traverse_obj(pageprops, ( | |
124 | 'itemDetailsData', 'playback_err_msg')) == 'This title is not available in your location.' | |
125 | ||
126 | def item_result(item): | |
127 | item_url = f'https://www.{host}/watch/{item["item_id"]}/{item["title"]}' | |
128 | if geoblocked: | |
129 | item_url = smuggle_url(item_url, {'geo_countries': geo_countries}) | |
130 | return self.url_result(item_url, CineverseIE) | |
131 | ||
132 | season = traverse_obj(pageprops, ('seasonEpisodes', ..., 'episodes', lambda _, v: v['item_id'] and v['title'])) | |
133 | if season: | |
134 | return self.playlist_result([item_result(ep) for ep in season], playlist_id=series_id, | |
135 | playlist_title=traverse_obj(pageprops, ('itemDetailsData', 'title'))) | |
136 | return item_result(pageprops['itemDetailsData']) |