]>
Raphaƫl G. Git Repositories - youtubedl/blob - youtube_dl/extractor/funimation.py
2 from __future__
import unicode_literals
7 from .common
import InfoExtractor
8 from ..compat
import compat_HTTPError
18 class FunimationIE(InfoExtractor
):
19 _VALID_URL
= r
'https?://(?:www\.)?funimation(?:\.com|now\.uk)/shows/[^/]+/(?P<id>[^/?#&]+)'
21 _NETRC_MACHINE
= 'funimation'
25 'url': 'https://www.funimation.com/shows/hacksign/role-play/',
28 'display_id': 'role-play',
30 'title': '.hack//SIGN - Role Play',
31 'description': 'md5:b602bdc15eef4c9bbb201bb6e6a4a2dd',
32 'thumbnail': r
're:https?://.*\.jpg',
36 'skip_download': True,
39 'url': 'https://www.funimation.com/shows/attack-on-titan-junior-high/broadcast-dub-preview/',
42 'display_id': 'broadcast-dub-preview',
44 'title': 'Attack on Titan: Junior High - Broadcast Dub Preview',
45 'thumbnail': r
're:https?://.*\.(?:jpg|png)',
49 'skip_download': True,
52 'url': 'https://www.funimationnow.uk/shows/puzzle-dragons-x/drop-impact/simulcast/',
53 'only_matching': True,
57 username
, password
= self
._get
_login
_info
()
61 data
= self
._download
_json
(
62 'https://prod-api-funimationnow.dadcdigital.com/api/auth/login/',
63 None, 'Logging in', data
=urlencode_postdata({
67 self
._TOKEN
= data
['token']
68 except ExtractorError
as e
:
69 if isinstance(e
.cause
, compat_HTTPError
) and e
.cause
.code
== 401:
70 error
= self
._parse
_json
(e
.cause
.read().decode(), None)['error']
71 raise ExtractorError(error
, expected
=True)
74 def _real_initialize(self
):
77 def _real_extract(self
, url
):
78 display_id
= self
._match
_id
(url
)
79 webpage
= self
._download
_webpage
(url
, display_id
)
81 def _search_kane(name
):
82 return self
._search
_regex
(
83 r
"KANE_customdimensions\.%s\s*=\s*'([^']+)';" % name
,
84 webpage
, name
, default
=None)
86 title_data
= self
._parse
_json
(self
._search
_regex
(
87 r
'TITLE_DATA\s*=\s*({[^}]+})',
88 webpage
, 'title data', default
=''),
89 display_id
, js_to_json
, fatal
=False) or {}
91 video_id
= title_data
.get('id') or self
._search
_regex
([
92 r
"KANE_customdimensions.videoID\s*=\s*'(\d+)';",
93 r
'<iframe[^>]+src="/player/(\d+)',
94 ], webpage
, 'video_id', default
=None)
96 player_url
= self
._html
_search
_meta
([
99 'og:video:secure_url',
100 ], webpage
, fatal
=True)
101 video_id
= self
._search
_regex
(r
'/player/(\d+)', player_url
, 'video id')
103 title
= episode
= title_data
.get('title') or _search_kane('videoTitle') or self
._og
_search
_title
(webpage
)
104 series
= _search_kane('showName')
106 title
= '%s - %s' % (series
, title
)
107 description
= self
._html
_search
_meta
(['description', 'og:description'], webpage
, fatal
=True)
112 headers
['Authorization'] = 'Token %s' % self
._TOKEN
113 sources
= self
._download
_json
(
114 'https://www.funimation.com/api/showexperience/%s/' % video_id
,
115 video_id
, headers
=headers
, query
={
116 'pinst_id': ''.join([random
.choice(string
.digits
+ string
.ascii_letters
) for _
in range(8)]),
118 except ExtractorError
as e
:
119 if isinstance(e
.cause
, compat_HTTPError
) and e
.cause
.code
== 403:
120 error
= self
._parse
_json
(e
.cause
.read(), video_id
)['errors'][0]
121 raise ExtractorError('%s said: %s' % (
122 self
.IE_NAME
, error
.get('detail') or error
.get('title')), expected
=True)
126 for source
in sources
:
127 source_url
= source
.get('src')
130 source_type
= source
.get('videoType') or determine_ext(source_url
)
131 if source_type
== 'm3u8':
132 formats
.extend(self
._extract
_m
3u8_formats
(
133 source_url
, video_id
, 'mp4',
134 m3u8_id
='hls', fatal
=False))
137 'format_id': source_type
,
140 self
._sort
_formats
(formats
)
144 'display_id': display_id
,
146 'description': description
,
147 'thumbnail': self
._og
_search
_thumbnail
(webpage
),
149 'season_number': int_or_none(title_data
.get('seasonNum') or _search_kane('season')),
150 'episode_number': int_or_none(title_data
.get('episodeNum')),
152 'season_id': title_data
.get('seriesId'),