[ciscolive] Add extractor

This commit is contained in:
Austin de Coup-Crank 2018-10-26 19:15:44 -07:00 committed by Sergey M․
parent 15ed5a2784
commit 05bd5e9c77
No known key found for this signature in database
GPG key ID: 2C393E0F18A9236D
2 changed files with 137 additions and 0 deletions

View file

@ -0,0 +1,136 @@
# coding: utf-8
from __future__ import unicode_literals
import re
from .common import InfoExtractor
from ..compat import (
compat_urllib_parse_urlparse,
compat_parse_qs
)
from ..utils import (
clean_html,
int_or_none,
try_get,
urlencode_postdata,
)
class CiscoLiveIE(InfoExtractor):
IE_NAME = 'ciscolive'
_VALID_URL = r'(?:https?://)?ciscolive\.cisco\.com/on-demand-library/\??(?P<query>[^#]+)#/(?:session/(?P<id>.+))?$'
_TESTS = [
{
'url': 'https://ciscolive.cisco.com/on-demand-library/?#/session/1423353499155001FoSs',
'md5': 'c98acf395ed9c9f766941c70f5352e22',
'info_dict': {
'id': '5803694304001',
'ext': 'mp4',
'title': '13 Smart Automations to Monitor Your Cisco IOS Network',
'description': 'md5:ec4a436019e09a918dec17714803f7cc',
'timestamp': 1530305395,
'uploader_id': '5647924234001',
'upload_date': '20180629',
'location': '16B Mezz.',
},
},
{
'url': 'https://ciscolive.cisco.com/on-demand-library/?search.event=ciscoliveus2018&search.technicallevel=scpsSkillLevel_aintroductory&search.focus=scpsSessionFocus_designAndDeployment#/',
'md5': '993d4cf051f6174059328b1dce8e94bd',
'info_dict': {
'upload_date': '20180629',
'title': 'DevNet Panel-Applying Design Thinking to Building Products in Cisco',
'timestamp': 1530316421,
'uploader_id': '5647924234001',
'id': '5803751616001',
'description': 'md5:5f144575cd6848117fe2f756855b038b',
'location': 'WoS, DevNet Theater',
'ext': 'mp4',
},
},
{
'url': 'https://ciscolive.cisco.com/on-demand-library/?search.technology=scpsTechnology_applicationDevelopment&search.technology=scpsTechnology_ipv6&search.focus=scpsSessionFocus_troubleshootingTroubleshooting#/',
'md5': '80e0c3b87e373fe3a3316b934b8915bf',
'info_dict': {
'upload_date': '20180629',
'title': 'Beating the CCIE Routing & Switching',
'timestamp': 1530311842,
'uploader_id': '5647924234001',
'id': '5803735679001',
'description': 'md5:e71970799e92d7f5ff57ae23f64b0929',
'location': 'Tulúm 02',
'ext': 'mp4',
},
}
]
# These appear to be constant across all Cisco Live presentations
# and are not tied to any user session or event
RAINFOCUS_API_URL = 'https://events.rainfocus.com/api/%s'
RAINFOCUS_APIPROFILEID = 'Na3vqYdAlJFSxhYTYQGuMbpafMqftalz'
RAINFOCUS_WIDGETID = 'n6l4Lo05R8fiy3RpUBm447dZN8uNWoye'
BRIGHTCOVE_URL_TEMPLATE = 'http://players.brightcove.net/5647924234001/SyK2FdqjM_default/index.html?videoId=%s'
def _parse_rf_item(self, rf_item):
''' Parses metadata and passes to Brightcove extractor '''
event_name = rf_item.get('eventName')
title = rf_item['title']
description = clean_html(rf_item.get('abstract'))
presenter_name = try_get(rf_item, lambda x: x['participants'][0]['fullName'])
bc_id = rf_item['videos'][0]['url']
bc_url = self.BRIGHTCOVE_URL_TEMPLATE % bc_id
duration = int_or_none(try_get(rf_item, lambda x: x['times'][0]['length']))
location = try_get(rf_item, lambda x: x['times'][0]['room'])
if duration:
duration = duration * 60
return {
'_type': 'url_transparent',
'creator': presenter_name,
'description': description,
'duration': duration,
'ie_key': 'BrightcoveNew',
'location': location,
'series': event_name,
'title': title,
'url': bc_url,
}
def _check_bc_id_exists(self, rf_item):
''' Checks for the existence of a Brightcove URL in an API result '''
bc_id = try_get(rf_item, lambda x: x['videos'][0]['url'])
if bc_id:
if bc_id.strip().isdigit():
return rf_item
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
HEADERS = {
'Origin': 'https://ciscolive.cisco.com',
'rfApiProfileId': self.RAINFOCUS_APIPROFILEID,
'rfWidgetId': self.RAINFOCUS_WIDGETID,
'Referer': url,
}
# Single session URL (single video)
if mobj.group('id'):
rf_id = mobj.group('id')
request = self.RAINFOCUS_API_URL % 'session'
data = urlencode_postdata({'id': rf_id})
rf_result = self._download_json(request, rf_id, data=data, headers=HEADERS)
rf_item = self._check_bc_id_exists(rf_result['items'][0])
return self._parse_rf_item(rf_item)
else:
# Filter query URL (multiple videos)
rf_query = compat_parse_qs((compat_urllib_parse_urlparse(url).query))
rf_query['type'] = 'session'
rf_query['size'] = 1000
data = urlencode_postdata(rf_query)
request = self.RAINFOCUS_API_URL % 'search'
rf_results = self._download_json(request, 'Filter query', data=data, headers=HEADERS)
entries = [
self._parse_rf_item(rf_item)
for rf_item
in rf_results['sectionList'][0]['items']
if self._check_bc_id_exists(rf_item)
]
return self.playlist_result(entries, 'Filter query')

View file

@ -194,6 +194,7 @@ from .chirbit import (
ChirbitProfileIE, ChirbitProfileIE,
) )
from .cinchcast import CinchcastIE from .cinchcast import CinchcastIE
from .ciscolive import CiscoLiveIE
from .cjsw import CJSWIE from .cjsw import CJSWIE
from .cliphunter import CliphunterIE from .cliphunter import CliphunterIE
from .clippit import ClippitIE from .clippit import ClippitIE