2 from __future__
import unicode_literals
6 from .common
import InfoExtractor
9 compat_urllib_parse_urlparse
,
20 class CiscoLiveBaseIE(InfoExtractor
):
21 # These appear to be constant across all Cisco Live presentations
22 # and are not tied to any user session or event
23 RAINFOCUS_API_URL
= 'https://events.rainfocus.com/api/%s'
24 RAINFOCUS_API_PROFILE_ID
= 'Na3vqYdAlJFSxhYTYQGuMbpafMqftalz'
25 RAINFOCUS_WIDGET_ID
= 'n6l4Lo05R8fiy3RpUBm447dZN8uNWoye'
26 BRIGHTCOVE_URL_TEMPLATE
= 'http://players.brightcove.net/5647924234001/SyK2FdqjM_default/index.html?videoId=%s'
29 'Origin': 'https://ciscolive.cisco.com',
30 'rfApiProfileId': RAINFOCUS_API_PROFILE_ID
,
31 'rfWidgetId': RAINFOCUS_WIDGET_ID
,
34 def _call_api(self
, ep
, rf_id
, query
, referrer
, note
=None):
35 headers
= self
.HEADERS
.copy()
36 headers
['Referer'] = referrer
37 return self
._download
_json
(
38 self
.RAINFOCUS_API_URL
% ep
, rf_id
, note
=note
,
39 data
=urlencode_postdata(query
), headers
=headers
)
41 def _parse_rf_item(self
, rf_item
):
42 event_name
= rf_item
.get('eventName')
43 title
= rf_item
['title']
44 description
= clean_html(rf_item
.get('abstract'))
45 presenter_name
= try_get(rf_item
, lambda x
: x
['participants'][0]['fullName'])
46 bc_id
= rf_item
['videos'][0]['url']
47 bc_url
= self
.BRIGHTCOVE_URL_TEMPLATE
% bc_id
48 duration
= float_or_none(try_get(rf_item
, lambda x
: x
['times'][0]['length']))
49 location
= try_get(rf_item
, lambda x
: x
['times'][0]['room'])
52 duration
= duration
* 60
55 '_type': 'url_transparent',
57 'ie_key': 'BrightcoveNew',
59 'description': description
,
61 'creator': presenter_name
,
67 class CiscoLiveSessionIE(CiscoLiveBaseIE
):
68 _VALID_URL
= r
'https?://(?:www\.)?ciscolive(?:\.cisco)?\.com/[^#]*#/session/(?P<id>[^/?&]+)'
70 'url': 'https://ciscolive.cisco.com/on-demand-library/?#/session/1423353499155001FoSs',
71 'md5': 'c98acf395ed9c9f766941c70f5352e22',
73 'id': '5803694304001',
75 'title': '13 Smart Automations to Monitor Your Cisco IOS Network',
76 'description': 'md5:ec4a436019e09a918dec17714803f7cc',
77 'timestamp': 1530305395,
78 'upload_date': '20180629',
79 'uploader_id': '5647924234001',
80 'location': '16B Mezz.',
83 'url': 'https://www.ciscolive.com/global/on-demand-library.html?search.event=ciscoliveemea2019#/session/15361595531500013WOU',
84 'only_matching': True,
86 'url': 'https://www.ciscolive.com/global/on-demand-library.html?#/session/1490051371645001kNaS',
87 'only_matching': True,
90 def _real_extract(self
, url
):
91 rf_id
= self
._match
_id
(url
)
92 rf_result
= self
._call
_api
('session', rf_id
, {'id': rf_id
}, url
)
93 return self
._parse
_rf
_item
(rf_result
['items'][0])
96 class CiscoLiveSearchIE(CiscoLiveBaseIE
):
97 _VALID_URL
= r
'https?://(?:www\.)?ciscolive(?:\.cisco)?\.com/(?:global/)?on-demand-library(?:\.html|/)'
99 'url': 'https://ciscolive.cisco.com/on-demand-library/?search.event=ciscoliveus2018&search.technicallevel=scpsSkillLevel_aintroductory&search.focus=scpsSessionFocus_designAndDeployment#/',
101 'title': 'Search query',
105 'url': 'https://ciscolive.cisco.com/on-demand-library/?search.technology=scpsTechnology_applicationDevelopment&search.technology=scpsTechnology_ipv6&search.focus=scpsSessionFocus_troubleshootingTroubleshooting#/',
106 'only_matching': True,
108 'url': 'https://www.ciscolive.com/global/on-demand-library.html?search.technicallevel=scpsSkillLevel_aintroductory&search.event=ciscoliveemea2019&search.technology=scpsTechnology_dataCenter&search.focus=scpsSessionFocus_bestPractices#/',
109 'only_matching': True,
113 def suitable(cls
, url
):
114 return False if CiscoLiveSessionIE
.suitable(url
) else super(CiscoLiveSearchIE
, cls
).suitable(url
)
117 def _check_bc_id_exists(rf_item
):
118 return int_or_none(try_get(rf_item
, lambda x
: x
['videos'][0]['url'])) is not None
120 def _entries(self
, query
, url
):
123 for page_num
in itertools
.count(1):
124 results
= self
._call
_api
(
125 'search', None, query
, url
,
126 'Downloading search JSON page %d' % page_num
)
127 sl
= try_get(results
, lambda x
: x
['sectionList'][0], dict)
130 items
= results
.get('items')
131 if not items
or not isinstance(items
, list):
134 if not isinstance(item
, dict):
136 if not self
._check
_bc
_id
_exists
(item
):
138 yield self
._parse
_rf
_item
(item
)
139 size
= int_or_none(results
.get('size'))
142 total
= int_or_none(results
.get('total'))
143 if total
is not None and query
['from'] + query
['size'] > total
:
145 query
['from'] += query
['size']
147 def _real_extract(self
, url
):
148 query
= compat_parse_qs(compat_urllib_parse_urlparse(url
).query
)
149 query
['type'] = 'session'
150 return self
.playlist_result(
151 self
._entries
(query
, url
), playlist_title
='Search query')