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')