''' Match functions take a single Media object instance as its only argument and return two boolean values. The first value is if the match was exact or "best fit", the second argument is the ID of the format that was matched. ''' from django.conf import settings min_height = getattr(settings, 'VIDEO_HEIGHT_CUTOFF', 360) fallback_hd_cutoff = getattr(settings, 'VIDEO_HEIGHT_IS_HD', 500) def get_best_combined_format(media): ''' Attempts to see if there is a single, combined audio and video format that exactly matches the source requirements. This is used over separate audio and video formats if possible. Combined formats are the easiest to check for as they must exactly match the source profile be be valid. ''' for fmt in media.iter_formats(): # Check height matches if media.source.source_resolution.strip().upper() != fmt['format']: continue # Check the video codec matches if media.source.source_vcodec != fmt['vcodec']: continue # Check the audio codec matches if media.source.source_acodec != fmt['acodec']: continue # if the source prefers 60fps, check for it if media.source.prefer_60fps: if not fmt['is_60fps']: continue # If the source prefers HDR, check for it if media.source.prefer_hdr: if not fmt['is_hdr']: continue # If we reach here, we have a combined match! return True, fmt['id'] return False, False def get_best_audio_format(media): ''' Finds the best match for the source required audio format. If the source has a 'fallback' of fail this can return no match. ''' # Order all audio-only formats by bitrate audio_formats = [] for fmt in media.iter_formats(): # If the format has a video stream, skip it if fmt['vcodec'] is not None: continue audio_formats.append(fmt) audio_formats = list(reversed(sorted(audio_formats, key=lambda k: k['abr']))) if not audio_formats: # Media has no audio formats at all return False, False # Find the highest bitrate audio format with a matching codec for fmt in audio_formats: if media.source.source_acodec == fmt['acodec']: # Matched! return True, fmt['id'] # No codecs matched if media.source.can_fallback: # Can fallback, find the next highest bitrate non-matching codec return False, audio_formats[0] else: # Can't fallback return False, False def get_best_video_format(media): ''' Finds the best match for the source required video format. If the source has a 'fallback' of fail this can return no match. Resolution is treated as the most important factor to match. This is pretty verbose due to the 'soft' matching requirements for prefer_hdr and prefer_60fps. ''' # Check if the source wants audio only, fast path to return if media.source.is_audio: return False, False # Filter video-only formats by resolution that matches the source video_formats = [] for fmt in media.iter_formats(): # If the format has an audio stream, skip it if fmt['acodec'] is not None: continue if media.source.source_resolution.strip().upper() == fmt['format']: video_formats.append(fmt) # Check we matched some streams if not video_formats: # No streams match the requested resolution, see if we can fallback if media.source.can_fallback: # Find the next-best format matches by height for fmt in media.iter_formats(): # If the format has an audio stream, skip it if fmt['acodec'] is not None: continue if (fmt['height'] <= media.source.source_resolution_height and fmt['height'] >= min_height): video_formats.append(fmt) else: # Can't fallback return False, False video_formats = list(reversed(sorted(video_formats, key=lambda k: k['height']))) source_resolution = media.source.source_resolution.strip().upper() source_vcodec = media.source.source_vcodec if not video_formats: # Still no matches return False, False exact_match, best_match = None, None # Of our filtered video formats, check for resolution + codec + hdr + fps match if media.source.prefer_60fps and media.source.prefer_hdr: for fmt in video_formats: # Check for an exact match if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and fmt['is_hdr'] and fmt['is_60fps']): # Exact match exact_match, best_match = True, fmt break if media.source.can_fallback: if not best_match: for fmt in video_formats: # Check for a resolution, hdr and fps match but drop the codec if (source_resolution == fmt['format'] and fmt['is_hdr'] and fmt['is_60fps']): # Close match exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for a codec, hdr and fps match but drop the resolution if (source_vcodec == fmt['vcodec'] and fmt['is_hdr'] and fmt['is_60fps']): # Close match exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution, codec and 60fps match if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and fmt['is_60fps']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution and hdr match if (source_resolution == fmt['format'] and fmt['is_hdr']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution and 60fps match if (source_resolution == fmt['format'] and fmt['is_60fps']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution, codec and hdr match if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and fmt['is_hdr']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution and codec if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution if source_resolution == fmt['format']: exact_match, best_match = False, fmt break if not best_match: # Match the highest resolution exact_match, best_match = False, video_formats[0] # Check for resolution + codec + fps match if media.source.prefer_60fps and not media.source.prefer_hdr: for fmt in video_formats: # Check for an exact match if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and fmt['is_60fps'] and not fmt['is_hdr']): # Exact match exact_match, best_match = True, fmt break if media.source.can_fallback: if not best_match: for fmt in video_formats: # Check for a resolution and fps match but drop the codec if (source_resolution == fmt['format'] and fmt['is_60fps'] and not fmt['is_hdr']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for a codec and fps match but drop the resolution if (source_vcodec == fmt['vcodec'] and fmt['is_60fps'] and not fmt['is_hdr']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for a codec and 60fps match if (source_vcodec == fmt['vcodec'] and fmt['is_60fps']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for codec and resolution match bot drop 60fps if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and not fmt['is_hdr']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for codec and resolution match only if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution if source_resolution == fmt['format']: exact_match, best_match = False, fmt break if not best_match: # Match the highest resolution exact_match, best_match = False, video_formats[0] # Check for resolution + codec + hdr elif media.source.prefer_hdr and not media.source.prefer_60fps: for fmt in video_formats: # Check for an exact match if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and fmt['is_hdr']): # Exact match exact_match, best_match = True, fmt break if media.source.can_fallback: if not best_match: for fmt in video_formats: # Check for a resolution and fps match but drop the codec if (source_resolution == fmt['format'] and fmt['is_hdr'] and not fmt['is_60fps']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for a codec and fps match but drop the resolution if (source_vcodec == fmt['vcodec'] and fmt['is_hdr'] and not fmt['is_60fps']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for a codec and 60fps match if (source_vcodec == fmt['vcodec'] and fmt['is_hdr']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for codec and resolution match bot drop hdr if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and not fmt['is_60fps']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for codec and resolution match only if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution if source_resolution == fmt['format']: exact_match, best_match = False, fmt break if not best_match: # Match the highest resolution exact_match, best_match = False, video_formats[0] # check for resolution + codec elif not media.source.prefer_hdr and not media.source.prefer_60fps: for fmt in video_formats: # Check for an exact match if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and not fmt['is_60fps'] and not fmt['is_hdr']): # Exact match exact_match, best_match = True, fmt break if media.source.can_fallback: if not best_match: for fmt in video_formats: # Check for a resolution, hdr and fps match but drop the codec if (source_resolution == fmt['format'] and not fmt['is_hdr'] and not fmt['is_60fps']): # Close match exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for a codec, hdr and fps match but drop the resolution if (source_vcodec == fmt['vcodec'] and not fmt['is_hdr'] and fmt['is_60fps']): # Close match exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution, codec and hdr match if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and not fmt['is_hdr']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution, codec and 60fps match if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec'] and not fmt['is_60fps']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution and codec if (source_resolution == fmt['format'] and source_vcodec == fmt['vcodec']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution and not hdr if (source_resolution == fmt['format'] and not fmt['is_hdr']): exact_match, best_match = False, fmt break if not best_match: for fmt in video_formats: # Check for resolution if source_resolution == fmt['format']: exact_match, best_match = False, fmt break if not best_match: # Match the highest resolution exact_match, best_match = False, video_formats[0] # See if we found a match if best_match: # Final check to see if the match we found was good enough if exact_match: return True, best_match['id'] elif media.source.can_fallback: # Allow the fallback if it meets requirements if (media.source.fallback == media.source.FALLBACK_NEXT_BEST_HD and best_match['height'] >= fallback_hd_cutoff): return False, best_match['id'] elif media.source.fallback == media.source.FALLBACK_NEXT_BEST: return False, best_match['id'] # Nope, failed to find match return False, False