Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add playback ticket management for video download fixes #33407 fixes #33456 #7

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150,110 changes: 150,109 additions & 1 deletion data.json.example

Large diffs are not rendered by default.

49 changes: 40 additions & 9 deletions mediasite_migration_scripts/data_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
import xml.dom.minidom as xml
from pymediainfo import MediaInfo
import requests

from mediasite_migration_scripts.lib.utils import MediasiteSetup

Expand All @@ -13,6 +14,7 @@ def __init__(self, config_file=None, debug=False):
self.debug = debug
self.setup = MediasiteSetup(config_file)
self.mediasite = self.setup.mediasite
self.download_protection_enabled = None

print('Getting presentations... (take a few minutes)')
self.presentations = self.mediasite.presentation.get_all_presentations()
Expand All @@ -38,11 +40,14 @@ def extract_mediasite_data(self, parent_id=None):
i = 0
presentations_folders = list()
for folder in self.folders:
if i == 0:
print(f'Requesting metadata... ({len(self.folders)} folders)')
if i > 1:
print('Requesting: ', f'[{i}]/[{len(self.folders)}] --', round(i / len(self.folders) * 100, 1), '%', end='\r', flush=True)

path = self._find_folder_path(folder['id'], self.folders)
if self._is_folder_to_add(path):
logging.debug('-' * 50)
logging.debug('Found folder : ' + path)
presentations_folders.append({**folder,
'catalogs': self.get_folder_catalogs_infos(folder['id']),
Expand Down Expand Up @@ -75,6 +80,8 @@ def get_presentations_infos(self, folder_id):

for presentation in self.presentations:
if presentation.get('ParentFolderId') == folder_id:
logging.debug('-' * 50)
logging.debug(f'Getting infos for presentation: {presentation.get("Id")}')
has_slides_details = False
for stream_type in presentation.get('Streams'):
if stream_type.get('StreamType') == 'Slide':
Expand Down Expand Up @@ -162,15 +169,15 @@ def get_presenters_infos(self, presentation_id):
return presenters_infos

def get_videos_infos(self, presentation_id):
logging.debug(f"Gathering video info for presentation : {presentation_id}")
logging.debug(f"Gathering videos infos for presentation : {presentation_id}")

videos_infos = []
video = self.mediasite.presentation.get_content(presentation_id, 'OnDemandContent')
videos_infos = self._get_video_details(video)
videos_infos = self._get_video_details(video, presentation_id)

return videos_infos

def _get_video_details(self, video):
def _get_video_details(self, video, presentation_id):
video_list = []

for file in video:
Expand All @@ -183,6 +190,19 @@ def _get_video_details(self, video):
file_name = file['FileNameWithExtension']
video_url = os.path.join(storage_url, file_name) if file_name and storage_url else None

if self.download_protection_enabled is None:
self.download_protection_enabled = self.is_download_protected(video_url)
logging.info('Download protection seems enabled, will request playbackTickets from now on')

if self.download_protection_enabled:
ticket = self.mediasite.content.get_authorization_ticket(presentation_id)
if ticket:
playbackTicket = ticket.get('TicketId')
if not playbackTicket:
logging.error(f'No valid playbackTicket in {ticket}')
else:
video_url += f'?playbackTicket={playbackTicket}&site={self.get_hostname()}'

file_infos = {
'url': video_url,
'format': file['ContentMimeType'],
Expand All @@ -197,7 +217,7 @@ def _get_video_details(self, video):
file_infos['encoding_infos'] = self._get_encoding_infos_from_api(file['ContentEncodingSettingsId'], file_infos['url'])

if not file_infos.get('encoding_infos'):
logging.debug(f"Failed to get video encoding infos from API for presentation: {file['ParentResourceId']}")
logging.debug(f"No video encoding info found in the API for presentation: {file['ParentResourceId']}, will analyze file")
if file_infos.get('url'):
file_infos['encoding_infos'] = self._parse_encoding_infos(file_infos['url'])
elif 'LocalUrl' in content_server:
Expand All @@ -216,6 +236,13 @@ def _get_video_details(self, video):
'files': [file_infos]})
return video_list

def is_download_protected(self, url):
with requests.Session() as session:
protected = True
with session.get(url, stream=True) as r:
protected = 400 < r.status_code < 404
return protected

def _get_encoding_infos_from_api(self, settings_id, video_url):
logging.debug(f'Getting encoding infos from api with settings id: {settings_id}')
encoding_infos = {}
Expand Down Expand Up @@ -271,8 +298,14 @@ def _parse_encoding_infos(self, video_url):
if not encoding_infos.get('video_codec'):
logging.warning(f'File is not a video: {video_url}')
except Exception as e:
logging.debug(f'Video encoding infos could not be parsed for: {video_url}')
logging.debug(e)
r = requests.head(video_url)
if r.status_code == 404:
logging.warning(f'File not found: {video_url} {r.status_code}')
elif 400 < r.status_code < 500:
logging.warning(f'File request reject: {video_url} {r.status_code}')
else:
logging.warning(f'Video encoding infos could not be parsed: {video_url} {r.status_code}')
logging.debug(e)

return encoding_infos

Expand Down Expand Up @@ -312,6 +345,4 @@ def get_slides_infos(self, presentation, details=False):

def get_hostname(self):
api_url = self.setup.config.get("mediasite_base_url")
hostname = api_url.split('/').pop()
hostname = '/'.join(hostname)
return hostname
return requests.compat.urlparse(api_url).netloc
Empty file.