2 from __future__
import unicode_literals
4 from .common
import InfoExtractor
6 from ..compat
import compat_str
15 class FancodeVodIE(InfoExtractor
):
16 IE_NAME
= 'fancode:vod'
18 _VALID_URL
= r
'https?://(?:www\.)?fancode\.com/video/(?P<id>[0-9]+)\b'
21 'url': 'https://fancode.com/video/15043/match-preview-pbks-vs-mi',
23 'skip_download': True,
26 'id': '6249806281001',
28 'title': 'Match Preview: PBKS vs MI',
29 'thumbnail': r
're:^https?://.*\.jpg$',
30 "timestamp": 1619081590,
33 'upload_date': '20210422',
34 'uploader_id': '6008340455001'
37 'url': 'https://fancode.com/video/15043',
38 'only_matching': True,
42 _NETRC_MACHINE
= 'fancode'
44 _LOGIN_HINT
= 'Use "--username refresh --password <refresh_token>" to login using a refresh token'
47 'content-type': 'application/json',
48 'origin': 'https://fancode.com',
49 'referer': 'https://fancode.com',
53 # Access tokens are shortlived, so get them using the refresh token.
54 username
, password
= self
._get
_login
_info
()
55 if username
== 'refresh' and password
is not None:
58 "query":"mutation RefreshToken($refreshToken: String\\u0021) { refreshToken(refreshToken: $refreshToken) { accessToken }}",
62 "operationName":"RefreshToken"
65 token_json
= self
.download_gql('refresh token', data
, "Getting the Access token")
66 self
._ACCESS
_TOKEN
= try_get(token_json
, lambda x
: x
['data']['refreshToken']['accessToken'])
67 if self
._ACCESS
_TOKEN
is None:
68 self
.report_warning('Failed to get Access token')
70 self
.headers
.update({'Authorization': 'Bearer %s' % self._ACCESS_TOKEN}
)
71 elif username
is not None:
72 self
.report_warning(f
'Login using username and password is not currently supported. {self._LOGIN_HINT}')
74 def _real_initialize(self
):
77 def _check_login_required(self
, is_available
, is_premium
):
79 if is_premium
and self
._ACCESS
_TOKEN
is None:
80 msg
= f
'This video is only available for registered users. {self._LOGIN_HINT}'
81 elif not is_available
and self
._ACCESS
_TOKEN
is not None:
82 msg
= 'This video isn\'t available to the current logged in account'
84 self
.raise_login_required(msg
, metadata_available
=True, method
=None)
86 def download_gql(self
, variable
, data
, note
, fatal
=False, headers
=headers
):
87 return self
._download
_json
(
88 'https://www.fancode.com/graphql', variable
,
89 data
=data
.encode(), note
=note
,
90 headers
=headers
, fatal
=fatal
)
92 def _real_extract(self
, url
):
94 BRIGHTCOVE_URL_TEMPLATE
= 'https://players.brightcove.net/%s/default_default/index.html?videoId=%s'
95 video_id
= self
._match
_id
(url
)
97 brightcove_user_id
= '6008340455001'
99 "query":"query Video($id: Int\\u0021, $filter: SegmentFilter) { media(id: $id, filter: $filter) { id contentId title contentId publishedTime totalViews totalUpvotes provider thumbnail { src } mediaSource {brightcove } duration isPremium isUserEntitled tags duration }}",
103 "contentDataType":"DEFAULT"
106 "operationName":"Video"
109 metadata_json
= self
.download_gql(video_id
, data
, note
='Downloading metadata')
111 media
= try_get(metadata_json
, lambda x
: x
['data']['media'], dict) or {}
112 brightcove_video_id
= try_get(media
, lambda x
: x
['mediaSource']['brightcove'], compat_str
)
114 if brightcove_video_id
is None:
115 raise ExtractorError('Unable to extract brightcove Video ID')
117 is_premium
= media
.get('isPremium')
119 self
._check
_login
_required
(media
.get('isUserEntitled'), is_premium
)
122 '_type': 'url_transparent',
123 'url': BRIGHTCOVE_URL_TEMPLATE
% (brightcove_user_id
, brightcove_video_id
),
124 'ie_key': 'BrightcoveNew',
126 'title': media
['title'],
127 'like_count': media
.get('totalUpvotes'),
128 'view_count': media
.get('totalViews'),
129 'tags': media
.get('tags'),
130 'release_timestamp': parse_iso8601(media
.get('publishedTime')),
131 'availability': self
._availability
(needs_premium
=is_premium
),
135 class FancodeLiveIE(FancodeVodIE
):
136 IE_NAME
= 'fancode:live'
138 _VALID_URL
= r
'https?://(www\.)?fancode\.com/match/(?P<id>[0-9]+).+'
141 'url': 'https://fancode.com/match/35328/cricket-fancode-ecs-hungary-2021-bub-vs-blb?slug=commentary',
145 'title': 'BUB vs BLB',
146 "timestamp": 1624863600,
148 'upload_date': '20210628',
152 'url': 'https://fancode.com/match/35328/',
153 'only_matching': True,
155 'url': 'https://fancode.com/match/35567?slug=scorecard',
156 'only_matching': True,
159 def _real_extract(self
, url
):
161 id = self
._match
_id
(url
)
163 "query":"query MatchResponse($id: Int\\u0021, $isLoggedIn: Boolean\\u0021) { match: matchWithScores(id: $id) { id matchDesc mediaId videoStreamId videoStreamUrl { ...VideoSource } liveStreams { videoStreamId videoStreamUrl { ...VideoSource } contentId } name startTime streamingStatus isPremium isUserEntitled @include(if: $isLoggedIn) status metaTags bgImage { src } sport { name slug } tour { id name } squads { name shortName } liveStreams { contentId } mediaId }}fragment VideoSource on VideoSource { title description posterUrl url deliveryType playerType}",
168 "operationName":"MatchResponse"
171 info_json
= self
.download_gql(id, data
, "Info json")
173 match_info
= try_get(info_json
, lambda x
: x
['data']['match'])
175 if match_info
.get('streamingStatus') != "STARTED":
176 raise ExtractorError('The stream can\'t be accessed', expected
=True)
177 self
._check
_login
_required
(match_info
.get('isUserEntitled'), True) # all live streams are premium only
181 'title': match_info
.get('name'),
182 'formats': self
._extract
_akamai
_formats
(try_get(match_info
, lambda x
: x
['videoStreamUrl']['url']), id),
183 'ext': mimetype2ext(try_get(match_info
, lambda x
: x
['videoStreamUrl']['deliveryType'])),
185 'release_timestamp': parse_iso8601(match_info
.get('startTime'))