|
@ -13,6 +13,7 @@ from ..compat import ( |
|
|
compat_b64decode, |
|
|
compat_b64decode, |
|
|
compat_etree_Element, |
|
|
compat_etree_Element, |
|
|
compat_etree_fromstring, |
|
|
compat_etree_fromstring, |
|
|
|
|
|
compat_str, |
|
|
compat_urllib_parse_urlencode, |
|
|
compat_urllib_parse_urlencode, |
|
|
compat_urllib_request, |
|
|
compat_urllib_request, |
|
|
compat_urlparse, |
|
|
compat_urlparse, |
|
@ -25,9 +26,9 @@ from ..utils import ( |
|
|
intlist_to_bytes, |
|
|
intlist_to_bytes, |
|
|
int_or_none, |
|
|
int_or_none, |
|
|
lowercase_escape, |
|
|
lowercase_escape, |
|
|
|
|
|
merge_dicts, |
|
|
remove_end, |
|
|
remove_end, |
|
|
sanitized_Request, |
|
|
sanitized_Request, |
|
|
unified_strdate, |
|
|
|
|
|
urlencode_postdata, |
|
|
urlencode_postdata, |
|
|
xpath_text, |
|
|
xpath_text, |
|
|
) |
|
|
) |
|
@ -136,6 +137,7 @@ class CrunchyrollIE(CrunchyrollBaseIE, VRVIE): |
|
|
# rtmp |
|
|
# rtmp |
|
|
'skip_download': True, |
|
|
'skip_download': True, |
|
|
}, |
|
|
}, |
|
|
|
|
|
'skip': 'Video gone', |
|
|
}, { |
|
|
}, { |
|
|
'url': 'http://www.crunchyroll.com/media-589804/culture-japan-1', |
|
|
'url': 'http://www.crunchyroll.com/media-589804/culture-japan-1', |
|
|
'info_dict': { |
|
|
'info_dict': { |
|
@ -157,11 +159,12 @@ class CrunchyrollIE(CrunchyrollBaseIE, VRVIE): |
|
|
'info_dict': { |
|
|
'info_dict': { |
|
|
'id': '702409', |
|
|
'id': '702409', |
|
|
'ext': 'mp4', |
|
|
'ext': 'mp4', |
|
|
'title': 'Re:ZERO -Starting Life in Another World- Episode 5 – The Morning of Our Promise Is Still Distant', |
|
|
|
|
|
'description': 'md5:97664de1ab24bbf77a9c01918cb7dca9', |
|
|
|
|
|
|
|
|
'title': compat_str, |
|
|
|
|
|
'description': compat_str, |
|
|
'thumbnail': r're:^https?://.*\.jpg$', |
|
|
'thumbnail': r're:^https?://.*\.jpg$', |
|
|
'uploader': 'TV TOKYO', |
|
|
|
|
|
'upload_date': '20160508', |
|
|
|
|
|
|
|
|
'uploader': 'Re:Zero Partners', |
|
|
|
|
|
'timestamp': 1462098900, |
|
|
|
|
|
'upload_date': '20160501', |
|
|
}, |
|
|
}, |
|
|
'params': { |
|
|
'params': { |
|
|
# m3u8 download |
|
|
# m3u8 download |
|
@ -172,12 +175,13 @@ class CrunchyrollIE(CrunchyrollBaseIE, VRVIE): |
|
|
'info_dict': { |
|
|
'info_dict': { |
|
|
'id': '727589', |
|
|
'id': '727589', |
|
|
'ext': 'mp4', |
|
|
'ext': 'mp4', |
|
|
'title': "KONOSUBA -God's blessing on this wonderful world! 2 Episode 1 – Give Me Deliverance From This Judicial Injustice!", |
|
|
|
|
|
'description': 'md5:cbcf05e528124b0f3a0a419fc805ea7d', |
|
|
|
|
|
|
|
|
'title': compat_str, |
|
|
|
|
|
'description': compat_str, |
|
|
'thumbnail': r're:^https?://.*\.jpg$', |
|
|
'thumbnail': r're:^https?://.*\.jpg$', |
|
|
'uploader': 'Kadokawa Pictures Inc.', |
|
|
'uploader': 'Kadokawa Pictures Inc.', |
|
|
'upload_date': '20170118', |
|
|
|
|
|
'series': "KONOSUBA -God's blessing on this wonderful world!", |
|
|
|
|
|
|
|
|
'timestamp': 1484130900, |
|
|
|
|
|
'upload_date': '20170111', |
|
|
|
|
|
'series': compat_str, |
|
|
'season': "KONOSUBA -God's blessing on this wonderful world! 2", |
|
|
'season': "KONOSUBA -God's blessing on this wonderful world! 2", |
|
|
'season_number': 2, |
|
|
'season_number': 2, |
|
|
'episode': 'Give Me Deliverance From This Judicial Injustice!', |
|
|
'episode': 'Give Me Deliverance From This Judicial Injustice!', |
|
@ -200,10 +204,11 @@ class CrunchyrollIE(CrunchyrollBaseIE, VRVIE): |
|
|
'info_dict': { |
|
|
'info_dict': { |
|
|
'id': '535080', |
|
|
'id': '535080', |
|
|
'ext': 'mp4', |
|
|
'ext': 'mp4', |
|
|
'title': '11eyes Episode 1 – Red Night ~ Piros éjszaka', |
|
|
|
|
|
'description': 'Kakeru and Yuka are thrown into an alternate nightmarish world they call "Red Night".', |
|
|
|
|
|
|
|
|
'title': compat_str, |
|
|
|
|
|
'description': compat_str, |
|
|
'uploader': 'Marvelous AQL Inc.', |
|
|
'uploader': 'Marvelous AQL Inc.', |
|
|
'upload_date': '20091021', |
|
|
|
|
|
|
|
|
'timestamp': 1255512600, |
|
|
|
|
|
'upload_date': '20091014', |
|
|
}, |
|
|
}, |
|
|
'params': { |
|
|
'params': { |
|
|
# Just test metadata extraction |
|
|
# Just test metadata extraction |
|
@ -224,15 +229,17 @@ class CrunchyrollIE(CrunchyrollBaseIE, VRVIE): |
|
|
# just test metadata extraction |
|
|
# just test metadata extraction |
|
|
'skip_download': True, |
|
|
'skip_download': True, |
|
|
}, |
|
|
}, |
|
|
|
|
|
'skip': 'Video gone', |
|
|
}, { |
|
|
}, { |
|
|
# A video with a vastly different season name compared to the series name |
|
|
# A video with a vastly different season name compared to the series name |
|
|
'url': 'http://www.crunchyroll.com/nyarko-san-another-crawling-chaos/episode-1-test-590532', |
|
|
'url': 'http://www.crunchyroll.com/nyarko-san-another-crawling-chaos/episode-1-test-590532', |
|
|
'info_dict': { |
|
|
'info_dict': { |
|
|
'id': '590532', |
|
|
'id': '590532', |
|
|
'ext': 'mp4', |
|
|
'ext': 'mp4', |
|
|
'title': 'Haiyoru! Nyaruani (ONA) Episode 1 – Test', |
|
|
|
|
|
'description': 'Mahiro and Nyaruko talk about official certification.', |
|
|
|
|
|
|
|
|
'title': compat_str, |
|
|
|
|
|
'description': compat_str, |
|
|
'uploader': 'TV TOKYO', |
|
|
'uploader': 'TV TOKYO', |
|
|
|
|
|
'timestamp': 1330956000, |
|
|
'upload_date': '20120305', |
|
|
'upload_date': '20120305', |
|
|
'series': 'Nyarko-san: Another Crawling Chaos', |
|
|
'series': 'Nyarko-san: Another Crawling Chaos', |
|
|
'season': 'Haiyoru! Nyaruani (ONA)', |
|
|
'season': 'Haiyoru! Nyaruani (ONA)', |
|
@ -442,23 +449,21 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text |
|
|
webpage, 'language', default=None, group='lang') |
|
|
webpage, 'language', default=None, group='lang') |
|
|
|
|
|
|
|
|
video_title = self._html_search_regex( |
|
|
video_title = self._html_search_regex( |
|
|
r'(?s)<h1[^>]*>((?:(?!<h1).)*?<span[^>]+itemprop=["\']title["\'][^>]*>(?:(?!<h1).)+?)</h1>', |
|
|
|
|
|
webpage, 'video_title') |
|
|
|
|
|
|
|
|
(r'(?s)<h1[^>]*>((?:(?!<h1).)*?<(?:span[^>]+itemprop=["\']title["\']|meta[^>]+itemprop=["\']position["\'])[^>]*>(?:(?!<h1).)+?)</h1>', |
|
|
|
|
|
r'<title>(.+?),\s+-\s+.+? Crunchyroll'), |
|
|
|
|
|
webpage, 'video_title', default=None) |
|
|
|
|
|
if not video_title: |
|
|
|
|
|
video_title = re.sub(r'^Watch\s+', '', self._og_search_description(webpage)) |
|
|
video_title = re.sub(r' {2,}', ' ', video_title) |
|
|
video_title = re.sub(r' {2,}', ' ', video_title) |
|
|
video_description = (self._parse_json(self._html_search_regex( |
|
|
video_description = (self._parse_json(self._html_search_regex( |
|
|
r'<script[^>]*>\s*.+?\[media_id=%s\].+?({.+?"description"\s*:.+?})\);' % video_id, |
|
|
r'<script[^>]*>\s*.+?\[media_id=%s\].+?({.+?"description"\s*:.+?})\);' % video_id, |
|
|
webpage, 'description', default='{}'), video_id) or media_metadata).get('description') |
|
|
webpage, 'description', default='{}'), video_id) or media_metadata).get('description') |
|
|
if video_description: |
|
|
if video_description: |
|
|
video_description = lowercase_escape(video_description.replace(r'\r\n', '\n')) |
|
|
video_description = lowercase_escape(video_description.replace(r'\r\n', '\n')) |
|
|
video_upload_date = self._html_search_regex( |
|
|
|
|
|
[r'<div>Availability for free users:(.+?)</div>', r'<div>[^<>]+<span>\s*(.+?\d{4})\s*</span></div>'], |
|
|
|
|
|
webpage, 'video_upload_date', fatal=False, flags=re.DOTALL) |
|
|
|
|
|
if video_upload_date: |
|
|
|
|
|
video_upload_date = unified_strdate(video_upload_date) |
|
|
|
|
|
video_uploader = self._html_search_regex( |
|
|
video_uploader = self._html_search_regex( |
|
|
# try looking for both an uploader that's a link and one that's not |
|
|
# try looking for both an uploader that's a link and one that's not |
|
|
[r'<a[^>]+href="/publisher/[^"]+"[^>]*>([^<]+)</a>', r'<div>\s*Publisher:\s*<span>\s*(.+?)\s*</span>\s*</div>'], |
|
|
[r'<a[^>]+href="/publisher/[^"]+"[^>]*>([^<]+)</a>', r'<div>\s*Publisher:\s*<span>\s*(.+?)\s*</span>\s*</div>'], |
|
|
webpage, 'video_uploader', fatal=False) |
|
|
|
|
|
|
|
|
webpage, 'video_uploader', default=False) |
|
|
|
|
|
|
|
|
formats = [] |
|
|
formats = [] |
|
|
for stream in media.get('streams', []): |
|
|
for stream in media.get('streams', []): |
|
@ -611,14 +616,15 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text |
|
|
r'(?s)<h\d[^>]+id=["\']showmedia_about_episode_num[^>]+>.+?</h\d>\s*<h4>\s*Season (\d+)', |
|
|
r'(?s)<h\d[^>]+id=["\']showmedia_about_episode_num[^>]+>.+?</h\d>\s*<h4>\s*Season (\d+)', |
|
|
webpage, 'season number', default=None)) |
|
|
webpage, 'season number', default=None)) |
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
|
|
|
info = self._search_json_ld(webpage, video_id, default={}) |
|
|
|
|
|
|
|
|
|
|
|
return merge_dicts({ |
|
|
'id': video_id, |
|
|
'id': video_id, |
|
|
'title': video_title, |
|
|
'title': video_title, |
|
|
'description': video_description, |
|
|
'description': video_description, |
|
|
'duration': duration, |
|
|
'duration': duration, |
|
|
'thumbnail': thumbnail, |
|
|
'thumbnail': thumbnail, |
|
|
'uploader': video_uploader, |
|
|
'uploader': video_uploader, |
|
|
'upload_date': video_upload_date, |
|
|
|
|
|
'series': series, |
|
|
'series': series, |
|
|
'season': season, |
|
|
'season': season, |
|
|
'season_number': season_number, |
|
|
'season_number': season_number, |
|
@ -626,7 +632,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text |
|
|
'episode_number': episode_number, |
|
|
'episode_number': episode_number, |
|
|
'subtitles': subtitles, |
|
|
'subtitles': subtitles, |
|
|
'formats': formats, |
|
|
'formats': formats, |
|
|
} |
|
|
|
|
|
|
|
|
}, info) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CrunchyrollShowPlaylistIE(CrunchyrollBaseIE): |
|
|
class CrunchyrollShowPlaylistIE(CrunchyrollBaseIE): |
|
|