]>
Raphaƫl G. Git Repositories - youtubedl/blob - youtube_dl/extractor/funimation.py
107f658baf2c393036dd4d2c770c01258e29e1a9
2 from __future__
import unicode_literals
4 from .common
import InfoExtractor
5 from ..compat
import compat_HTTPError
15 class FunimationIE(InfoExtractor
):
16 _VALID_URL
= r
'https?://(?:www\.)?funimation(?:\.com|now\.uk)/shows/[^/]+/(?P<id>[^/?#&]+)'
18 _NETRC_MACHINE
= 'funimation'
22 'url': 'https://www.funimation.com/shows/hacksign/role-play/',
25 'display_id': 'role-play',
27 'title': '.hack//SIGN - Role Play',
28 'description': 'md5:b602bdc15eef4c9bbb201bb6e6a4a2dd',
29 'thumbnail': r
're:https?://.*\.jpg',
33 'skip_download': True,
36 'url': 'https://www.funimation.com/shows/attack-on-titan-junior-high/broadcast-dub-preview/',
39 'display_id': 'broadcast-dub-preview',
41 'title': 'Attack on Titan: Junior High - Broadcast Dub Preview',
42 'thumbnail': r
're:https?://.*\.(?:jpg|png)',
46 'skip_download': True,
49 'url': 'https://www.funimationnow.uk/shows/puzzle-dragons-x/drop-impact/simulcast/',
50 'only_matching': True,
54 (username
, password
) = self
._get
_login
_info
()
58 data
= self
._download
_json
(
59 'https://prod-api-funimationnow.dadcdigital.com/api/auth/login/',
60 None, 'Logging in', data
=urlencode_postdata({
64 self
._TOKEN
= data
['token']
65 except ExtractorError
as e
:
66 if isinstance(e
.cause
, compat_HTTPError
) and e
.cause
.code
== 401:
67 error
= self
._parse
_json
(e
.cause
.read().decode(), None)['error']
68 raise ExtractorError(error
, expected
=True)
71 def _real_initialize(self
):
74 def _real_extract(self
, url
):
75 display_id
= self
._match
_id
(url
)
76 webpage
= self
._download
_webpage
(url
, display_id
)
78 def _search_kane(name
):
79 return self
._search
_regex
(
80 r
"KANE_customdimensions\.%s\s*=\s*'([^']+)';" % name
,
81 webpage
, name
, default
=None)
83 title_data
= self
._parse
_json
(self
._search
_regex
(
84 r
'TITLE_DATA\s*=\s*({[^}]+})',
85 webpage
, 'title data', default
=''),
86 display_id
, js_to_json
, fatal
=False) or {}
88 video_id
= title_data
.get('id') or self
._search
_regex
([
89 r
"KANE_customdimensions.videoID\s*=\s*'(\d+)';",
90 r
'<iframe[^>]+src="/player/(\d+)"',
91 ], webpage
, 'video_id', default
=None)
93 player_url
= self
._html
_search
_meta
([
96 'og:video:secure_url',
97 ], webpage
, fatal
=True)
98 video_id
= self
._search
_regex
(r
'/player/(\d+)', player_url
, 'video id')
100 title
= episode
= title_data
.get('title') or _search_kane('videoTitle') or self
._og
_search
_title
(webpage
)
101 series
= _search_kane('showName')
103 title
= '%s - %s' % (series
, title
)
104 description
= self
._html
_search
_meta
(['description', 'og:description'], webpage
, fatal
=True)
109 headers
['Authorization'] = 'Token %s' % self
._TOKEN
110 sources
= self
._download
_json
(
111 'https://prod-api-funimationnow.dadcdigital.com/api/source/catalog/video/%s/signed/' % video_id
,
112 video_id
, headers
=headers
)['items']
113 except ExtractorError
as e
:
114 if isinstance(e
.cause
, compat_HTTPError
) and e
.cause
.code
== 403:
115 error
= self
._parse
_json
(e
.cause
.read(), video_id
)['errors'][0]
116 raise ExtractorError('%s said: %s' % (
117 self
.IE_NAME
, error
.get('detail') or error
.get('title')), expected
=True)
121 for source
in sources
:
122 source_url
= source
.get('src')
125 source_type
= source
.get('videoType') or determine_ext(source_url
)
126 if source_type
== 'm3u8':
127 formats
.extend(self
._extract
_m
3u8_formats
(
128 source_url
, video_id
, 'mp4',
129 m3u8_id
='hls', fatal
=False))
132 'format_id': source_type
,
135 self
._sort
_formats
(formats
)
139 'display_id': display_id
,
141 'description': description
,
142 'thumbnail': self
._og
_search
_thumbnail
(webpage
),
144 'season_number': int_or_none(title_data
.get('seasonNum') or _search_kane('season')),
145 'episode_number': int_or_none(title_data
.get('episodeNum')),
147 'season_id': title_data
.get('seriesId'),