1735 lines
89 KiB
Python
1735 lines
89 KiB
Python
'''
|
|
Note these tests do not test the scheduled tasks that perform live requests to
|
|
index media or download content. They only check for compliance of web
|
|
interface and validation code.
|
|
'''
|
|
|
|
|
|
import logging
|
|
from urllib.parse import urlsplit
|
|
from django.test import TestCase, Client
|
|
from django.utils import timezone
|
|
from background_task.models import Task
|
|
from .models import Source, Media
|
|
|
|
|
|
class FrontEndTestCase(TestCase):
|
|
|
|
def setUp(self):
|
|
# Disable general logging for test case
|
|
logging.disable(logging.CRITICAL)
|
|
|
|
def test_dashboard(self):
|
|
c = Client()
|
|
response = c.get('/')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_validate_source(self):
|
|
test_source_types = {
|
|
'youtube-channel': Source.SOURCE_TYPE_YOUTUBE_CHANNEL,
|
|
'youtube-playlist': Source.SOURCE_TYPE_YOUTUBE_PLAYLIST,
|
|
}
|
|
test_sources = {
|
|
'youtube-channel': {
|
|
'valid': (
|
|
'https://www.youtube.com/testchannel',
|
|
'https://www.youtube.com/c/testchannel',
|
|
),
|
|
'invalid_schema': (
|
|
'http://www.youtube.com/c/playlist',
|
|
'ftp://www.youtube.com/c/playlist',
|
|
),
|
|
'invalid_domain': (
|
|
'https://www.test.com/c/testchannel',
|
|
'https://www.example.com/c/testchannel',
|
|
),
|
|
'invalid_path': (
|
|
'https://www.youtube.com/test/invalid',
|
|
'https://www.youtube.com/c/test/invalid',
|
|
),
|
|
'invalid_is_playlist': (
|
|
'https://www.youtube.com/c/playlist',
|
|
'https://www.youtube.com/c/playlist',
|
|
),
|
|
},
|
|
'youtube-playlist': {
|
|
'valid': (
|
|
'https://www.youtube.com/playlist?list=testplaylist'
|
|
'https://www.youtube.com/watch?v=testvideo&list=testplaylist'
|
|
),
|
|
'invalid_schema': (
|
|
'http://www.youtube.com/playlist?list=testplaylist',
|
|
'ftp://www.youtube.com/playlist?list=testplaylist',
|
|
),
|
|
'invalid_domain': (
|
|
'https://www.test.com/playlist?list=testplaylist',
|
|
'https://www.example.com/playlist?list=testplaylist',
|
|
),
|
|
'invalid_path': (
|
|
'https://www.youtube.com/notplaylist?list=testplaylist',
|
|
'https://www.youtube.com/c/notplaylist?list=testplaylist',
|
|
),
|
|
'invalid_is_channel': (
|
|
'https://www.youtube.com/testchannel',
|
|
'https://www.youtube.com/c/testchannel',
|
|
),
|
|
}
|
|
}
|
|
c = Client()
|
|
for source_type in test_sources.keys():
|
|
response = c.get(f'/source-validate/{source_type}')
|
|
self.assertEqual(response.status_code, 200)
|
|
response = c.get('/source-validate/invalid')
|
|
self.assertEqual(response.status_code, 404)
|
|
for (source_type, tests) in test_sources.items():
|
|
for test, field in tests.items():
|
|
source_type_char = test_source_types.get(source_type)
|
|
data = {'source_url': field, 'source_type': source_type_char}
|
|
response = c.post(f'/source-validate/{source_type}', data)
|
|
if test == 'valid':
|
|
# Valid source tests should bounce to /source-add
|
|
self.assertEqual(response.status_code, 302)
|
|
url_parts = urlsplit(response.url)
|
|
self.assertEqual(url_parts.path, '/source-add')
|
|
else:
|
|
# Invalid source tests should reload the page with an error message
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertIn('<ul class="errorlist">', response.content.decode())
|
|
|
|
def test_add_source_prepopulation(self):
|
|
c = Client()
|
|
response = c.get('/source-add?key=testkey&name=testname&directory=testdir')
|
|
self.assertEqual(response.status_code, 200)
|
|
html = response.content.decode()
|
|
checked_key, checked_name, checked_directory = False, False, False
|
|
for line in html.split('\n'):
|
|
if 'id="id_key"' in line:
|
|
self.assertIn('value="testkey', line)
|
|
checked_key = True
|
|
if 'id="id_name"' in line:
|
|
self.assertIn('value="testname', line)
|
|
checked_name = True
|
|
if 'id="id_directory"' in line:
|
|
self.assertIn('value="testdir', line)
|
|
checked_directory = True
|
|
self.assertTrue(checked_key)
|
|
self.assertTrue(checked_name)
|
|
self.assertTrue(checked_directory)
|
|
|
|
def test_source(self):
|
|
# Sources overview page
|
|
c = Client()
|
|
response = c.get('/sources')
|
|
self.assertEqual(response.status_code, 200)
|
|
# Add as source form
|
|
response = c.get('/source-add')
|
|
self.assertEqual(response.status_code, 200)
|
|
# Create a new source
|
|
data = {
|
|
'source_type': 'c',
|
|
'key': 'testkey',
|
|
'name': 'testname',
|
|
'directory': 'testdirectory',
|
|
'index_schedule': 3600,
|
|
'delete_old_media': False,
|
|
'days_to_keep': 14,
|
|
'source_resolution': '1080p',
|
|
'source_vcodec': 'VP9',
|
|
'source_acodec': 'OPUS',
|
|
'prefer_60fps': False,
|
|
'prefer_hdr': False,
|
|
'fallback': 'f'
|
|
}
|
|
response = c.post('/source-add', data)
|
|
self.assertEqual(response.status_code, 302)
|
|
url_parts = urlsplit(response.url)
|
|
url_path = str(url_parts.path).strip()
|
|
if url_path.startswith('/'):
|
|
url_path = url_path[1:]
|
|
path_parts = url_path.split('/')
|
|
self.assertEqual(path_parts[0], 'source')
|
|
source_uuid = path_parts[1]
|
|
source = Source.objects.get(pk=source_uuid)
|
|
self.assertEqual(str(source.pk), source_uuid)
|
|
# Check a task was created to index the media for the new source
|
|
source_uuid = str(source.pk)
|
|
task = Task.objects.get_task('sync.tasks.index_source_task',
|
|
args=(source_uuid,))[0]
|
|
self.assertEqual(task.queue, source_uuid)
|
|
# Check the source is now on the source overview page
|
|
response = c.get('/sources')
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertIn(source_uuid, response.content.decode())
|
|
# Check the source detail page loads
|
|
response = c.get(f'/source/{source_uuid}')
|
|
self.assertEqual(response.status_code, 200)
|
|
# Update the source key
|
|
data = {
|
|
'source_type': 'c',
|
|
'key': 'updatedkey', # changed
|
|
'name': 'testname',
|
|
'directory': 'testdirectory',
|
|
'index_schedule': 3600,
|
|
'delete_old_media': False,
|
|
'days_to_keep': 14,
|
|
'source_resolution': '1080p',
|
|
'source_vcodec': 'VP9',
|
|
'source_acodec': 'OPUS',
|
|
'prefer_60fps': False,
|
|
'prefer_hdr': False,
|
|
'fallback': 'f'
|
|
}
|
|
response = c.post(f'/source-update/{source_uuid}', data)
|
|
self.assertEqual(response.status_code, 302)
|
|
url_parts = urlsplit(response.url)
|
|
url_path = str(url_parts.path).strip()
|
|
if url_path.startswith('/'):
|
|
url_path = url_path[1:]
|
|
path_parts = url_path.split('/')
|
|
self.assertEqual(path_parts[0], 'source')
|
|
source_uuid = path_parts[1]
|
|
source = Source.objects.get(pk=source_uuid)
|
|
self.assertEqual(source.key, 'updatedkey')
|
|
# Update the source index schedule which should recreate the scheduled task
|
|
data = {
|
|
'source_type': 'c',
|
|
'key': 'updatedkey',
|
|
'name': 'testname',
|
|
'directory': 'testdirectory',
|
|
'index_schedule': 7200,
|
|
'delete_old_media': False,
|
|
'days_to_keep': 14,
|
|
'source_resolution': '1080p',
|
|
'source_vcodec': 'VP9',
|
|
'source_acodec': 'OPUS',
|
|
'prefer_60fps': False,
|
|
'prefer_hdr': False,
|
|
'fallback': 'f'
|
|
}
|
|
response = c.post(f'/source-update/{source_uuid}', data)
|
|
self.assertEqual(response.status_code, 302)
|
|
url_parts = urlsplit(response.url)
|
|
url_path = str(url_parts.path).strip()
|
|
if url_path.startswith('/'):
|
|
url_path = url_path[1:]
|
|
path_parts = url_path.split('/')
|
|
self.assertEqual(path_parts[0], 'source')
|
|
source_uuid = path_parts[1]
|
|
source = Source.objects.get(pk=source_uuid)
|
|
# Check a new task has been created by seeing if the pk has changed
|
|
new_task = Task.objects.get_task('sync.tasks.index_source_task',
|
|
args=(source_uuid,))[0]
|
|
self.assertNotEqual(task.pk, new_task.pk)
|
|
# Delete source confirmation page
|
|
response = c.get(f'/source-delete/{source_uuid}')
|
|
self.assertEqual(response.status_code, 200)
|
|
# Delete source
|
|
response = c.post(f'/source-delete/{source_uuid}')
|
|
self.assertEqual(response.status_code, 302)
|
|
url_parts = urlsplit(response.url)
|
|
self.assertEqual(url_parts.path, '/sources')
|
|
try:
|
|
Source.objects.get(pk=source_uuid)
|
|
object_gone = False
|
|
except Source.DoesNotExist:
|
|
object_gone = True
|
|
self.assertTrue(object_gone)
|
|
# Check the source is now gone from the source overview page
|
|
response = c.get('/sources')
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertNotIn(source_uuid, response.content.decode())
|
|
# Check the source details page now 404s
|
|
response = c.get(f'/source/{source_uuid}')
|
|
self.assertEqual(response.status_code, 404)
|
|
# Check the indexing media task was removed
|
|
tasks = Task.objects.get_task('sync.tasks.index_source_task',
|
|
args=(source_uuid,))
|
|
self.assertFalse(tasks)
|
|
|
|
def test_media(self):
|
|
# Media overview page
|
|
c = Client()
|
|
response = c.get('/media')
|
|
self.assertEqual(response.status_code, 200)
|
|
# Add a test source
|
|
test_source = Source.objects.create(**{
|
|
'source_type': 'c',
|
|
'key': 'testkey',
|
|
'name': 'testname',
|
|
'directory': 'testdirectory',
|
|
'index_schedule': 3600,
|
|
'delete_old_media': False,
|
|
'days_to_keep': 14,
|
|
'source_resolution': '1080p',
|
|
'source_vcodec': 'VP9',
|
|
'source_acodec': 'OPUS',
|
|
'prefer_60fps': False,
|
|
'prefer_hdr': False,
|
|
'fallback': 'f'
|
|
})
|
|
# Add some media
|
|
test_media1 = Media.objects.create(**{
|
|
'key': 'mediakey1',
|
|
'source': test_source,
|
|
'metadata': '{"thumbnail":"https://example.com/thumb.jpg"}',
|
|
})
|
|
test_media1_pk = str(test_media1.pk)
|
|
test_media2 = Media.objects.create(**{
|
|
'key': 'mediakey2',
|
|
'source': test_source,
|
|
'metadata': '{"thumbnail":"https://example.com/thumb.jpg"}',
|
|
})
|
|
test_media2_pk = str(test_media2.pk)
|
|
test_media3 = Media.objects.create(**{
|
|
'key': 'mediakey3',
|
|
'source': test_source,
|
|
'metadata': '{"thumbnail":"https://example.com/thumb.jpg"}',
|
|
})
|
|
test_media3_pk = str(test_media3.pk)
|
|
# Check the tasks to fetch the media thumbnails have been scheduled
|
|
found_thumbnail_task1 = False
|
|
found_thumbnail_task2 = False
|
|
found_thumbnail_task3 = False
|
|
q = {'queue': str(test_source.pk),
|
|
'task_name': 'sync.tasks.download_media_thumbnail'}
|
|
for task in Task.objects.filter(**q):
|
|
if test_media1_pk in task.task_params:
|
|
found_thumbnail_task1 = True
|
|
if test_media2_pk in task.task_params:
|
|
found_thumbnail_task2 = True
|
|
if test_media3_pk in task.task_params:
|
|
found_thumbnail_task3 = True
|
|
self.assertTrue(found_thumbnail_task1)
|
|
self.assertTrue(found_thumbnail_task2)
|
|
self.assertTrue(found_thumbnail_task3)
|
|
# Check the media is listed on the media overview page
|
|
response = c.get('/media')
|
|
self.assertEqual(response.status_code, 200)
|
|
html = response.content.decode()
|
|
self.assertIn(test_media1_pk, html)
|
|
self.assertIn(test_media2_pk, html)
|
|
self.assertIn(test_media3_pk, html)
|
|
# Check the media detail pages load
|
|
response = c.get(f'/media/{test_media1_pk}')
|
|
self.assertEqual(response.status_code, 200)
|
|
response = c.get(f'/media/{test_media2_pk}')
|
|
self.assertEqual(response.status_code, 200)
|
|
response = c.get(f'/media/{test_media3_pk}')
|
|
self.assertEqual(response.status_code, 200)
|
|
# Delete the media
|
|
test_media1.delete()
|
|
test_media2.delete()
|
|
test_media3.delete()
|
|
# Check the media detail pages now 404
|
|
response = c.get(f'/media/{test_media1_pk}')
|
|
self.assertEqual(response.status_code, 404)
|
|
response = c.get(f'/media/{test_media2_pk}')
|
|
self.assertEqual(response.status_code, 404)
|
|
response = c.get(f'/media/{test_media3_pk}')
|
|
self.assertEqual(response.status_code, 404)
|
|
# Confirm any tasks have been deleted
|
|
tasks = Task.objects.filter(**q)
|
|
self.assertFalse(tasks)
|
|
|
|
def test_tasks(self):
|
|
# Tasks overview page
|
|
c = Client()
|
|
response = c.get('/tasks')
|
|
self.assertEqual(response.status_code, 200)
|
|
# Completed tasks overview page
|
|
response = c.get('/tasks-completed')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
class FormatMatchingTestCase(TestCase):
|
|
|
|
def setUp(self):
|
|
# Disable general logging for test case
|
|
logging.disable(logging.CRITICAL)
|
|
# Test metadata pulled from https://youtube.com/watch?v=AIigN0EAGcA
|
|
metadata = '''
|
|
{
|
|
"id":"AIigN0EAGcA",
|
|
"uploader":"The HDR Channel",
|
|
"uploader_id":"UCve7_yAZHFNipzeAGBI5t9g",
|
|
"uploader_url":"http://www.youtube.com/channel/UCve7_yAZHFNipzeAGBI5t9g",
|
|
"channel_id":"UCve7_yAZHFNipzeAGBI5t9g",
|
|
"channel_url":"http://www.youtube.com/channel/UCve7_yAZHFNipzeAGBI5t9g",
|
|
"upload_date":"20161202",
|
|
"license":null,
|
|
"creator":null,
|
|
"title":"Real 4K HDR: Earth and Aurora Borealis seen from ISS - HDR UHD (Chromecast Ultra)",
|
|
"alt_title":null,
|
|
"thumbnails":[
|
|
{
|
|
"url":"[truncated]",
|
|
"width":168,
|
|
"height":94,
|
|
"resolution":"168x94",
|
|
"id":"0"
|
|
},
|
|
{
|
|
"url":"[truncated]",
|
|
"width":196,
|
|
"height":110,
|
|
"resolution":"196x110",
|
|
"id":"1"
|
|
},
|
|
{
|
|
"url":"[truncated]",
|
|
"width":246,
|
|
"height":138,
|
|
"resolution":"246x138",
|
|
"id":"2"
|
|
},
|
|
{
|
|
"url":"[truncated]",
|
|
"width":336,
|
|
"height":188,
|
|
"resolution":"336x188",
|
|
"id":"3"
|
|
},
|
|
{
|
|
"url":"[truncated]",
|
|
"width":1920,
|
|
"height":1080,
|
|
"resolution":"1920x1080",
|
|
"id":"4"
|
|
}
|
|
],
|
|
"description":"[truncated]",
|
|
"categories":[
|
|
"Travel & Events"
|
|
],
|
|
"tags":[
|
|
"hdr",
|
|
"hdr10",
|
|
"4k",
|
|
"uhd",
|
|
"chromecast ultra",
|
|
"real hdr"
|
|
],
|
|
"subtitles":{
|
|
|
|
},
|
|
"automatic_captions":{
|
|
|
|
},
|
|
"duration":353.0,
|
|
"age_limit":0,
|
|
"annotations":null,
|
|
"chapters":null,
|
|
"webpage_url":"https://www.youtube.com/watch?v=AIigN0EAGcA",
|
|
"view_count":131816,
|
|
"like_count":211,
|
|
"dislike_count":20,
|
|
"average_rating":4.6536798,
|
|
"formats":[
|
|
{
|
|
"format_id":"249",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"format_note":"tiny",
|
|
"acodec":"opus",
|
|
"abr":50,
|
|
"asr":48000,
|
|
"filesize":2690312,
|
|
"fps":null,
|
|
"height":null,
|
|
"tbr":65.092,
|
|
"width":null,
|
|
"vcodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"249 - audio only (tiny)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"250",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"format_note":"tiny",
|
|
"acodec":"opus",
|
|
"abr":70,
|
|
"asr":48000,
|
|
"filesize":3502678,
|
|
"fps":null,
|
|
"height":null,
|
|
"tbr":85.607,
|
|
"width":null,
|
|
"vcodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"250 - audio only (tiny)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"140",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"m4a",
|
|
"format_note":"tiny",
|
|
"acodec":"mp4a.40.2",
|
|
"abr":128,
|
|
"container":"m4a_dash",
|
|
"asr":44100,
|
|
"filesize":5703344,
|
|
"fps":null,
|
|
"height":null,
|
|
"tbr":130.563,
|
|
"width":null,
|
|
"vcodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"140 - audio only (tiny)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"251",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"format_note":"tiny",
|
|
"acodec":"opus",
|
|
"abr":160,
|
|
"asr":48000,
|
|
"filesize":6488055,
|
|
"fps":null,
|
|
"height":null,
|
|
"tbr":157.878,
|
|
"width":null,
|
|
"vcodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"251 - audio only (tiny)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"160",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"mp4",
|
|
"height":144,
|
|
"format_note":"144p",
|
|
"vcodec":"avc1.4d400c",
|
|
"asr":null,
|
|
"filesize":1655725,
|
|
"fps":30,
|
|
"tbr":84.26,
|
|
"width":256,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"160 - 256x144 (144p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"278",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"height":144,
|
|
"format_note":"144p",
|
|
"container":"webm",
|
|
"vcodec":"vp9",
|
|
"asr":null,
|
|
"filesize":3399643,
|
|
"fps":30,
|
|
"tbr":97.395,
|
|
"width":256,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"278 - 256x144 (144p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"330",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"asr":null,
|
|
"filesize":4569924,
|
|
"format_note":"144p HDR",
|
|
"fps":30,
|
|
"height":144,
|
|
"tbr":151.8,
|
|
"width":256,
|
|
"ext":"webm",
|
|
"vcodec":"vp9.2",
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"330 - 256x144 (144p HDR)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"133",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"mp4",
|
|
"height":240,
|
|
"format_note":"240p",
|
|
"vcodec":"avc1.4d4015",
|
|
"asr":null,
|
|
"filesize":3090930,
|
|
"fps":30,
|
|
"tbr":154.701,
|
|
"width":426,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"133 - 426x240 (240p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"242",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"height":240,
|
|
"format_note":"240p",
|
|
"vcodec":"vp9",
|
|
"asr":null,
|
|
"filesize":5194185,
|
|
"fps":30,
|
|
"tbr":220.461,
|
|
"width":426,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"242 - 426x240 (240p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"331",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"asr":null,
|
|
"filesize":8625105,
|
|
"format_note":"240p HDR",
|
|
"fps":30,
|
|
"height":240,
|
|
"tbr":269.523,
|
|
"width":426,
|
|
"ext":"webm",
|
|
"vcodec":"vp9.2",
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"331 - 426x240 (240p HDR)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"134",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"mp4",
|
|
"height":360,
|
|
"format_note":"360p",
|
|
"vcodec":"avc1.4d401e",
|
|
"asr":null,
|
|
"filesize":7976121,
|
|
"fps":30,
|
|
"tbr":372.176,
|
|
"width":640,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"134 - 640x360 (360p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"243",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"height":360,
|
|
"format_note":"360p",
|
|
"vcodec":"vp9",
|
|
"asr":null,
|
|
"filesize":10334380,
|
|
"fps":30,
|
|
"tbr":408.705,
|
|
"width":640,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"243 - 640x360 (360p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"332",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"asr":null,
|
|
"filesize":19094551,
|
|
"format_note":"360p HDR",
|
|
"fps":30,
|
|
"height":360,
|
|
"tbr":580.076,
|
|
"width":640,
|
|
"ext":"webm",
|
|
"vcodec":"vp9.2",
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"332 - 640x360 (360p HDR)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"244",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"height":480,
|
|
"format_note":"480p",
|
|
"vcodec":"vp9",
|
|
"asr":null,
|
|
"filesize":18651778,
|
|
"fps":30,
|
|
"tbr":748.286,
|
|
"width":854,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"244 - 854x480 (480p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"135",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"mp4",
|
|
"height":480,
|
|
"format_note":"480p",
|
|
"vcodec":"avc1.4d401f",
|
|
"asr":null,
|
|
"filesize":17751590,
|
|
"fps":30,
|
|
"tbr":828.339,
|
|
"width":854,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"135 - 854x480 (480p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"333",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"asr":null,
|
|
"filesize":37534410,
|
|
"format_note":"480p HDR",
|
|
"fps":30,
|
|
"height":480,
|
|
"tbr":1088.473,
|
|
"width":854,
|
|
"ext":"webm",
|
|
"vcodec":"vp9.2",
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"333 - 854x480 (480p HDR)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"136",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"mp4",
|
|
"height":720,
|
|
"format_note":"720p",
|
|
"vcodec":"avc1.4d401f",
|
|
"asr":null,
|
|
"filesize":33269335,
|
|
"fps":30,
|
|
"tbr":1391.37,
|
|
"width":1280,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"136 - 1280x720 (720p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"247",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"height":720,
|
|
"format_note":"720p",
|
|
"vcodec":"vp9",
|
|
"asr":null,
|
|
"filesize":38700375,
|
|
"fps":30,
|
|
"tbr":1509.156,
|
|
"width":1280,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"247 - 1280x720 (720p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"334",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"asr":null,
|
|
"filesize":84688291,
|
|
"format_note":"720p HDR",
|
|
"fps":30,
|
|
"height":720,
|
|
"tbr":2459.121,
|
|
"width":1280,
|
|
"ext":"webm",
|
|
"vcodec":"vp9.2",
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"334 - 1280x720 (720p HDR)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"248",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"height":1080,
|
|
"format_note":"1080p",
|
|
"vcodec":"vp9",
|
|
"asr":null,
|
|
"filesize":74559430,
|
|
"fps":30,
|
|
"tbr":2655.043,
|
|
"width":1920,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"248 - 1920x1080 (1080p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"137",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"mp4",
|
|
"height":1080,
|
|
"format_note":"1080p",
|
|
"vcodec":"avc1.640028",
|
|
"asr":null,
|
|
"filesize":66088922,
|
|
"fps":30,
|
|
"tbr":3401.043,
|
|
"width":1920,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"137 - 1920x1080 (1080p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"335",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"asr":null,
|
|
"filesize":147068515,
|
|
"format_note":"1080p HDR",
|
|
"fps":30,
|
|
"height":1080,
|
|
"tbr":4143.689,
|
|
"width":1920,
|
|
"ext":"webm",
|
|
"vcodec":"vp9.2",
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"335 - 1920x1080 (1080p HDR)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"271",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"height":1440,
|
|
"format_note":"1440p",
|
|
"vcodec":"vp9",
|
|
"asr":null,
|
|
"filesize":220803978,
|
|
"fps":30,
|
|
"tbr":8844.345,
|
|
"width":2560,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"271 - 2560x1440 (1440p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"336",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"asr":null,
|
|
"filesize":445968338,
|
|
"format_note":"1440p HDR",
|
|
"fps":30,
|
|
"height":1440,
|
|
"tbr":11013.316,
|
|
"width":2560,
|
|
"ext":"webm",
|
|
"vcodec":"vp9.2",
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"336 - 2560x1440 (1440p HDR)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"313",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"height":2160,
|
|
"format_note":"2160p",
|
|
"vcodec":"vp9",
|
|
"asr":null,
|
|
"filesize":592906196,
|
|
"fps":30,
|
|
"tbr":17720.165,
|
|
"width":3840,
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"313 - 3840x2160 (2160p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"337",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"asr":null,
|
|
"filesize":985983779,
|
|
"format_note":"2160p HDR",
|
|
"fps":30,
|
|
"height":2160,
|
|
"tbr":23857.847,
|
|
"width":3840,
|
|
"ext":"webm",
|
|
"vcodec":"vp9.2",
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"337 - 3840x2160 (2160p HDR)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"18",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"mp4",
|
|
"width":640,
|
|
"height":360,
|
|
"acodec":"mp4a.40.2",
|
|
"abr":96,
|
|
"vcodec":"avc1.42001E",
|
|
"asr":44100,
|
|
"filesize":23149671,
|
|
"format_note":"360p",
|
|
"fps":30,
|
|
"tbr":525.68,
|
|
"format":"18 - 640x360 (360p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"22",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"mp4",
|
|
"width":1280,
|
|
"height":720,
|
|
"acodec":"mp4a.40.2",
|
|
"abr":192,
|
|
"vcodec":"avc1.64001F",
|
|
"asr":44100,
|
|
"filesize":null,
|
|
"format_note":"720p",
|
|
"fps":30,
|
|
"tbr":884.489,
|
|
"format":"22 - 1280x720 (720p)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
}
|
|
],
|
|
"is_live":null,
|
|
"start_time":null,
|
|
"end_time":null,
|
|
"series":null,
|
|
"season_number":null,
|
|
"episode_number":null,
|
|
"track":null,
|
|
"artist":null,
|
|
"album":null,
|
|
"release_date":null,
|
|
"release_year":null,
|
|
"extractor":"youtube",
|
|
"webpage_url_basename":"AIigN0EAGcA",
|
|
"extractor_key":"Youtube",
|
|
"n_entries":13,
|
|
"playlist":"HDR",
|
|
"playlist_id":"PL0ajMRlXs96rAqJhIMXiG34khg31MVWdP",
|
|
"playlist_title":"HDR",
|
|
"playlist_uploader":"4K",
|
|
"playlist_uploader_id":"UCp5zSuQPhXhFEurTP0l4yCw",
|
|
"playlist_index":13,
|
|
"thumbnail":"https://i.ytimg.com/vi_webp/AIigN0EAGcA/maxresdefault.webp",
|
|
"display_id":"AIigN0EAGcA",
|
|
"requested_subtitles":null,
|
|
"requested_formats":[
|
|
{
|
|
"format_id":"337",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"asr":null,
|
|
"filesize":985983779,
|
|
"format_note":"2160p HDR",
|
|
"fps":30,
|
|
"height":2160,
|
|
"tbr":23857.847,
|
|
"width":3840,
|
|
"ext":"webm",
|
|
"vcodec":"vp9.2",
|
|
"acodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"337 - 3840x2160 (2160p HDR)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
},
|
|
{
|
|
"format_id":"251",
|
|
"url":"[truncated]",
|
|
"player_url":null,
|
|
"ext":"webm",
|
|
"format_note":"tiny",
|
|
"acodec":"opus",
|
|
"abr":160,
|
|
"asr":48000,
|
|
"filesize":6488055,
|
|
"fps":null,
|
|
"height":null,
|
|
"tbr":157.878,
|
|
"width":null,
|
|
"vcodec":"none",
|
|
"downloader_options":{
|
|
"http_chunk_size":10485760
|
|
},
|
|
"format":"251 - audio only (tiny)",
|
|
"protocol":"https",
|
|
"http_headers":{
|
|
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3704.8 Safari/537.36",
|
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
|
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
"Accept-Encoding":"gzip, deflate",
|
|
"Accept-Language":"en-us,en;q=0.5"
|
|
}
|
|
}
|
|
],
|
|
"format":"337 - 3840x2160 (2160p HDR)+251 - audio only (tiny)",
|
|
"format_id":"337+251",
|
|
"width":3840,
|
|
"height":2160,
|
|
"resolution":null,
|
|
"fps":30,
|
|
"vcodec":"vp9.2",
|
|
"vbr":null,
|
|
"stretched_ratio":null,
|
|
"acodec":"opus",
|
|
"abr":160,
|
|
"ext":"webm"
|
|
}
|
|
'''.strip()
|
|
# Add a test source
|
|
self.source = Source.objects.create(**{
|
|
'source_type': 'c',
|
|
'key': 'testkey',
|
|
'name': 'testname',
|
|
'directory': 'testdirectory',
|
|
'index_schedule': 3600,
|
|
'delete_old_media': False,
|
|
'days_to_keep': 14,
|
|
'source_resolution': '1080p',
|
|
'source_vcodec': 'VP9',
|
|
'source_acodec': 'OPUS',
|
|
'prefer_60fps': False,
|
|
'prefer_hdr': False,
|
|
'fallback': 'f'
|
|
})
|
|
# Add some media
|
|
self.media = Media.objects.create(**{
|
|
'key': 'mediakey',
|
|
'source': self.source,
|
|
'metadata': metadata,
|
|
})
|
|
|
|
'''
|
|
Parsed media format reference for test metadata:
|
|
{'id': '249', 'format': 'TINY', 'format_verbose': '249 - audio only (tiny)', 'height': None, 'vcodec': None, 'vbr': 65.092, 'acodec': 'OPUS', 'abr': 50, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '250', 'format': 'TINY', 'format_verbose': '250 - audio only (tiny)', 'height': None, 'vcodec': None, 'vbr': 85.607, 'acodec': 'OPUS', 'abr': 70, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '140', 'format': 'TINY', 'format_verbose': '140 - audio only (tiny)', 'height': None, 'vcodec': None, 'vbr': 130.563, 'acodec': 'MP4A', 'abr': 128, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '251', 'format': 'TINY', 'format_verbose': '251 - audio only (tiny)', 'height': None, 'vcodec': None, 'vbr': 157.878, 'acodec': 'OPUS', 'abr': 160, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '160', 'format': '144P', 'format_verbose': '160 - 256x144 (144p)', 'height': 144, 'vcodec': 'AVC1', 'vbr': 84.26, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '278', 'format': '144P', 'format_verbose': '278 - 256x144 (144p)', 'height': 144, 'vcodec': 'VP9', 'vbr': 97.395, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '330', 'format': '144P HDR', 'format_verbose': '330 - 256x144 (144p HDR)', 'height': 144, 'vcodec': 'VP9', 'vbr': 151.8, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': True}
|
|
{'id': '133', 'format': '240P', 'format_verbose': '133 - 426x240 (240p)', 'height': 240, 'vcodec': 'AVC1', 'vbr': 154.701, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '242', 'format': '240P', 'format_verbose': '242 - 426x240 (240p)', 'height': 240, 'vcodec': 'VP9', 'vbr': 220.461, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '331', 'format': '240P HDR', 'format_verbose': '331 - 426x240 (240p HDR)', 'height': 240, 'vcodec': 'VP9', 'vbr': 269.523, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': True}
|
|
{'id': '134', 'format': '360P', 'format_verbose': '134 - 640x360 (360p)', 'height': 360, 'vcodec': 'AVC1', 'vbr': 372.176, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '243', 'format': '360P', 'format_verbose': '243 - 640x360 (360p)', 'height': 360, 'vcodec': 'VP9', 'vbr': 408.705, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '332', 'format': '360P HDR', 'format_verbose': '332 - 640x360 (360p HDR)', 'height': 360, 'vcodec': 'VP9', 'vbr': 580.076, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': True}
|
|
{'id': '244', 'format': '480P', 'format_verbose': '244 - 854x480 (480p)', 'height': 480, 'vcodec': 'VP9', 'vbr': 748.286, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '135', 'format': '480P', 'format_verbose': '135 - 854x480 (480p)', 'height': 480, 'vcodec': 'AVC1', 'vbr': 828.339, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '333', 'format': '480P HDR', 'format_verbose': '333 - 854x480 (480p HDR)', 'height': 480, 'vcodec': 'VP9', 'vbr': 1088.473, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': True}
|
|
{'id': '136', 'format': '720P', 'format_verbose': '136 - 1280x720 (720p)', 'height': 720, 'vcodec': 'AVC1', 'vbr': 1391.37, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '247', 'format': '720P', 'format_verbose': '247 - 1280x720 (720p)', 'height': 720, 'vcodec': 'VP9', 'vbr': 1509.156, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '334', 'format': '720P HDR', 'format_verbose': '334 - 1280x720 (720p HDR)', 'height': 720, 'vcodec': 'VP9', 'vbr': 2459.121, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': True}
|
|
{'id': '248', 'format': '1080P', 'format_verbose': '248 - 1920x1080 (1080p)', 'height': 1080, 'vcodec': 'VP9', 'vbr': 2655.043, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '137', 'format': '1080P', 'format_verbose': '137 - 1920x1080 (1080p)', 'height': 1080, 'vcodec': 'AVC1', 'vbr': 3401.043, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '335', 'format': '1080P HDR', 'format_verbose': '335 - 1920x1080 (1080p HDR)', 'height': 1080, 'vcodec': 'VP9', 'vbr': 4143.689, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': True}
|
|
{'id': '271', 'format': '1440P', 'format_verbose': '271 - 2560x1440 (1440p)', 'height': 1440, 'vcodec': 'VP9', 'vbr': 8844.345, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '336', 'format': '1440P HDR', 'format_verbose': '336 - 2560x1440 (1440p HDR)', 'height': 1440, 'vcodec': 'VP9', 'vbr': 11013.316, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': True}
|
|
{'id': '313', 'format': '2160P', 'format_verbose': '313 - 3840x2160 (2160p)', 'height': 2160, 'vcodec': 'VP9', 'vbr': 17720.165, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '337', 'format': '2160P HDR', 'format_verbose': '337 - 3840x2160 (2160p HDR)', 'height': 2160, 'vcodec': 'VP9', 'vbr': 23857.847, 'acodec': None, 'abr': 0, 'is_60fps': False, 'is_hdr': True}
|
|
{'id': '18', 'format': '360P', 'format_verbose': '18 - 640x360 (360p)', 'height': 360, 'vcodec': 'AVC1', 'vbr': 525.68, 'acodec': 'MP4A', 'abr': 96, 'is_60fps': False, 'is_hdr': False}
|
|
{'id': '22', 'format': '720P', 'format_verbose': '22 - 1280x720 (720p)', 'height': 720, 'vcodec': 'AVC1', 'vbr': 884.489, 'acodec': 'MP4A', 'abr': 192, 'is_60fps': False, 'is_hdr': False}
|
|
|
|
'''
|
|
|
|
def test_combined_format_matching(self):
|
|
expected_matches = {
|
|
# (format, vcodec, acodec, prefer_60fps, prefer_hdr): (match_type, code),
|
|
('360p', 'AVC1', 'MP4A', True, False): (False, False),
|
|
('360p', 'AVC1', 'MP4A', False, True): (False, False),
|
|
('360p', 'AVC1', 'MP4A', False, False): (True, '18'), # Exact match
|
|
('360p', 'AVC1', 'OPUS', True, True): (False, False),
|
|
('360p', 'AVC1', 'OPUS', True, False): (False, False),
|
|
('360p', 'AVC1', 'OPUS', False, True): (False, False),
|
|
('360p', 'AVC1', 'OPUS', False, False): (False, False),
|
|
('360p', 'VP9', 'MP4A', True, True): (False, False),
|
|
('360p', 'VP9', 'MP4A', True, False): (False, False),
|
|
('360p', 'VP9', 'MP4A', False, True): (False, False),
|
|
('360p', 'VP9', 'MP4A', False, False): (False, False),
|
|
('360p', 'VP9', 'OPUS', True, True): (False, False),
|
|
('360p', 'VP9', 'OPUS', True, False): (False, False),
|
|
('360p', 'VP9', 'OPUS', False, True): (False, False),
|
|
('360p', 'VP9', 'OPUS', False, False): (False, False),
|
|
('480p', 'AVC1', 'MP4A', True, True): (False, False),
|
|
('480p', 'AVC1', 'MP4A', True, False): (False, False),
|
|
('480p', 'AVC1', 'MP4A', False, True): (False, False),
|
|
('480p', 'AVC1', 'MP4A', False, False): (False, False),
|
|
('480p', 'AVC1', 'OPUS', True, True): (False, False),
|
|
('480p', 'AVC1', 'OPUS', True, False): (False, False),
|
|
('480p', 'AVC1', 'OPUS', False, True): (False, False),
|
|
('480p', 'AVC1', 'OPUS', False, False): (False, False),
|
|
('480p', 'VP9', 'MP4A', True, True): (False, False),
|
|
('480p', 'VP9', 'MP4A', True, False): (False, False),
|
|
('480p', 'VP9', 'MP4A', False, True): (False, False),
|
|
('480p', 'VP9', 'MP4A', False, False): (False, False),
|
|
('480p', 'VP9', 'OPUS', True, True): (False, False),
|
|
('480p', 'VP9', 'OPUS', True, False): (False, False),
|
|
('480p', 'VP9', 'OPUS', False, True): (False, False),
|
|
('480p', 'VP9', 'OPUS', False, False): (False, False),
|
|
('720p', 'AVC1', 'MP4A', True, True): (False, False),
|
|
('720p', 'AVC1', 'MP4A', True, False): (False, False),
|
|
('720p', 'AVC1', 'MP4A', False, True): (False, False),
|
|
('720p', 'AVC1', 'MP4A', False, False): (True, '22'), # Exact match
|
|
('720p', 'AVC1', 'OPUS', True, True): (False, False),
|
|
('720p', 'AVC1', 'OPUS', True, False): (False, False),
|
|
('720p', 'AVC1', 'OPUS', False, True): (False, False),
|
|
('720p', 'AVC1', 'OPUS', False, False): (False, False),
|
|
('720p', 'VP9', 'MP4A', True, True): (False, False),
|
|
('720p', 'VP9', 'MP4A', True, False): (False, False),
|
|
('720p', 'VP9', 'MP4A', False, True): (False, False),
|
|
('720p', 'VP9', 'MP4A', False, False): (False, False),
|
|
('720p', 'VP9', 'OPUS', True, True): (False, False),
|
|
('720p', 'VP9', 'OPUS', True, False): (False, False),
|
|
('720p', 'VP9', 'OPUS', False, True): (False, False),
|
|
('720p', 'VP9', 'OPUS', False, False): (False, False),
|
|
('1080p', 'AVC1', 'MP4A', True, True): (False, False),
|
|
('1080p', 'AVC1', 'MP4A', True, False): (False, False),
|
|
('1080p', 'AVC1', 'MP4A', False, True): (False, False),
|
|
('1080p', 'AVC1', 'MP4A', False, False): (False, False),
|
|
('1080p', 'AVC1', 'OPUS', True, True): (False, False),
|
|
('1080p', 'AVC1', 'OPUS', True, False): (False, False),
|
|
('1080p', 'AVC1', 'OPUS', False, True): (False, False),
|
|
('1080p', 'AVC1', 'OPUS', False, False): (False, False),
|
|
('1080p', 'VP9', 'MP4A', True, True): (False, False),
|
|
('1080p', 'VP9', 'MP4A', True, False): (False, False),
|
|
('1080p', 'VP9', 'MP4A', False, True): (False, False),
|
|
('1080p', 'VP9', 'MP4A', False, False): (False, False),
|
|
('1080p', 'VP9', 'OPUS', True, True): (False, False),
|
|
('1080p', 'VP9', 'OPUS', True, False): (False, False),
|
|
('1080p', 'VP9', 'OPUS', False, True): (False, False),
|
|
('1080p', 'VP9', 'OPUS', False, False): (False, False),
|
|
('1440p', 'AVC1', 'MP4A', True, True): (False, False),
|
|
('1440p', 'AVC1', 'MP4A', True, False): (False, False),
|
|
('1440p', 'AVC1', 'MP4A', False, True): (False, False),
|
|
('1440p', 'AVC1', 'MP4A', False, False): (False, False),
|
|
('1440p', 'AVC1', 'OPUS', True, True): (False, False),
|
|
('1440p', 'AVC1', 'OPUS', True, False): (False, False),
|
|
('1440p', 'AVC1', 'OPUS', False, True): (False, False),
|
|
('1440p', 'AVC1', 'OPUS', False, False): (False, False),
|
|
('1440p', 'VP9', 'MP4A', True, True): (False, False),
|
|
('1440p', 'VP9', 'MP4A', True, False): (False, False),
|
|
('1440p', 'VP9', 'MP4A', False, True): (False, False),
|
|
('1440p', 'VP9', 'MP4A', False, False): (False, False),
|
|
('1440p', 'VP9', 'OPUS', True, True): (False, False),
|
|
('1440p', 'VP9', 'OPUS', True, False): (False, False),
|
|
('1440p', 'VP9', 'OPUS', False, True): (False, False),
|
|
('1440p', 'VP9', 'OPUS', False, False): (False, False),
|
|
('2160p', 'AVC1', 'MP4A', True, True): (False, False),
|
|
('2160p', 'AVC1', 'MP4A', True, False): (False, False),
|
|
('2160p', 'AVC1', 'MP4A', False, True): (False, False),
|
|
('2160p', 'AVC1', 'MP4A', False, False): (False, False),
|
|
('2160p', 'AVC1', 'OPUS', True, True): (False, False),
|
|
('2160p', 'AVC1', 'OPUS', True, False): (False, False),
|
|
('2160p', 'AVC1', 'OPUS', False, True): (False, False),
|
|
('2160p', 'AVC1', 'OPUS', False, False): (False, False),
|
|
('2160p', 'VP9', 'MP4A', True, True): (False, False),
|
|
('2160p', 'VP9', 'MP4A', True, False): (False, False),
|
|
('2160p', 'VP9', 'MP4A', False, True): (False, False),
|
|
('2160p', 'VP9', 'MP4A', False, False): (False, False),
|
|
('2160p', 'VP9', 'OPUS', True, True): (False, False),
|
|
('2160p', 'VP9', 'OPUS', True, False): (False, False),
|
|
('2160p', 'VP9', 'OPUS', False, True): (False, False),
|
|
('2160p', 'VP9', 'OPUS', False, False): (False, False),
|
|
('4320p', 'AVC1', 'MP4A', True, True): (False, False),
|
|
('4320p', 'AVC1', 'MP4A', True, False): (False, False),
|
|
('4320p', 'AVC1', 'MP4A', False, True): (False, False),
|
|
('4320p', 'AVC1', 'MP4A', False, False): (False, False),
|
|
('4320p', 'AVC1', 'OPUS', True, True): (False, False),
|
|
('4320p', 'AVC1', 'OPUS', True, False): (False, False),
|
|
('4320p', 'AVC1', 'OPUS', False, True): (False, False),
|
|
('4320p', 'AVC1', 'OPUS', False, False): (False, False),
|
|
('4320p', 'VP9', 'MP4A', True, True): (False, False),
|
|
('4320p', 'VP9', 'MP4A', True, False): (False, False),
|
|
('4320p', 'VP9', 'MP4A', False, True): (False, False),
|
|
('4320p', 'VP9', 'MP4A', False, False): (False, False),
|
|
('4320p', 'VP9', 'OPUS', True, True): (False, False),
|
|
('4320p', 'VP9', 'OPUS', True, False): (False, False),
|
|
('4320p', 'VP9', 'OPUS', False, True): (False, False),
|
|
('4320p', 'VP9', 'OPUS', False, False): (False, False),
|
|
}
|
|
for params, expected in expected_matches.items():
|
|
resolution, vcodec, acodec, prefer_60fps, prefer_hdr = params
|
|
expeceted_match_type, expected_format_code = expected
|
|
self.source.source_resolution = resolution
|
|
self.source.source_vcodec = vcodec
|
|
self.source.source_acodec = acodec
|
|
self.source.prefer_60fps = prefer_60fps
|
|
self.source.prefer_hdr = prefer_hdr
|
|
match_type, format_code = self.media.get_best_combined_format()
|
|
self.assertEqual(match_type, expeceted_match_type)
|
|
self.assertEqual(format_code, expected_format_code)
|
|
|
|
def test_audio_format_matching(self):
|
|
expected_matches = {
|
|
# (format, vcodec, acodec, prefer_60fps, prefer_hdr): (match_type, code),
|
|
('360p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('360p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('360p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('360p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('360p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('360p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('360p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('360p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('360p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('360p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('360p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('360p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('360p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('360p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('360p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('480p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('480p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('480p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('480p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('480p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('480p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('480p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('480p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('480p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('480p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('480p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('480p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('480p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('480p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('480p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('480p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('720p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('720p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('720p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('720p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('720p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('720p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('720p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('720p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('720p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('720p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('720p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('720p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('720p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('720p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('720p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('720p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('1080p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('1080p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('1080p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('1080p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('1080p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('1080p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('1080p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('1080p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('1080p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('1080p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('1080p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('1080p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('1080p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('1080p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('1080p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('1080p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('1440p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('1440p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('1440p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('1440p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('1440p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('1440p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('1440p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('1440p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('1440p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('1440p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('1440p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('1440p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('1440p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('1440p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('1440p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('1440p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('2160p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('2160p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('2160p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('2160p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('2160p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('2160p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('2160p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('2160p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('2160p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('2160p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('2160p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('2160p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('2160p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('2160p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('2160p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('2160p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('4320p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('4320p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('4320p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('4320p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('4320p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('4320p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('4320p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('4320p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('4320p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('4320p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('4320p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('4320p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('4320p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('4320p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('4320p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('4320p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('audio', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('audio', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('audio', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('audio', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('audio', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('audio', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('audio', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('audio', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('audio', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('audio', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('audio', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('audio', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('audio', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('audio', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('audio', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('audio', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
}
|
|
for params, expected in expected_matches.items():
|
|
resolution, vcodec, acodec, prefer_60fps, prefer_hdr = params
|
|
expeceted_match_type, expected_format_code = expected
|
|
self.source.source_resolution = resolution
|
|
self.source.source_vcodec = vcodec
|
|
self.source.source_acodec = acodec
|
|
self.source.prefer_60fps = prefer_60fps
|
|
self.source.prefer_hdr = prefer_hdr
|
|
match_type, format_code = self.media.get_best_audio_format()
|
|
self.assertEqual(match_type, expeceted_match_type)
|
|
self.assertEqual(format_code, expected_format_code)
|
|
|
|
def test_video_format_matching(self):
|
|
expected_matches = {
|
|
# (format, vcodec, acodec, prefer_60fps, prefer_hdr): (match_type, code),
|
|
('360p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('360p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('360p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('360p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('360p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('360p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('360p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('360p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('360p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('360p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('360p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('360p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('360p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('360p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('360p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('480p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('480p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('480p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('480p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('480p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('480p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('480p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('480p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('480p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('480p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('480p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('480p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('480p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('480p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('480p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('480p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('720p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('720p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('720p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('720p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('720p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('720p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('720p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('720p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('720p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('720p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('720p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('720p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('720p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('720p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('720p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('720p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('1080p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('1080p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('1080p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('1080p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('1080p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('1080p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('1080p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('1080p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('1080p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('1080p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('1080p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('1080p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('1080p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('1080p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('1080p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('1080p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('1440p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('1440p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('1440p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('1440p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('1440p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('1440p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('1440p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('1440p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('1440p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('1440p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('1440p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('1440p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('1440p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('1440p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('1440p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('1440p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('2160p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('2160p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('2160p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('2160p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('2160p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('2160p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('2160p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('2160p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('2160p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('2160p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('2160p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('2160p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('2160p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('2160p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('2160p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('2160p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
('4320p', 'AVC1', 'MP4A', True, True): (True, '140'),
|
|
('4320p', 'AVC1', 'MP4A', True, False): (True, '140'),
|
|
('4320p', 'AVC1', 'MP4A', False, True): (True, '140'),
|
|
('4320p', 'AVC1', 'MP4A', False, False): (True, '140'),
|
|
('4320p', 'AVC1', 'OPUS', True, True): (True, '251'),
|
|
('4320p', 'AVC1', 'OPUS', True, False): (True, '251'),
|
|
('4320p', 'AVC1', 'OPUS', False, True): (True, '251'),
|
|
('4320p', 'AVC1', 'OPUS', False, False): (True, '251'),
|
|
('4320p', 'VP9', 'MP4A', True, True): (True, '140'),
|
|
('4320p', 'VP9', 'MP4A', True, False): (True, '140'),
|
|
('4320p', 'VP9', 'MP4A', False, True): (True, '140'),
|
|
('4320p', 'VP9', 'MP4A', False, False): (True, '140'),
|
|
('4320p', 'VP9', 'OPUS', True, True): (True, '251'),
|
|
('4320p', 'VP9', 'OPUS', True, False): (True, '251'),
|
|
('4320p', 'VP9', 'OPUS', False, True): (True, '251'),
|
|
('4320p', 'VP9', 'OPUS', False, False): (True, '251'),
|
|
}
|
|
for params, expected in expected_matches.items():
|
|
resolution, vcodec, acodec, prefer_60fps, prefer_hdr = params
|
|
expeceted_match_type, expected_format_code = expected
|
|
self.source.source_resolution = resolution
|
|
self.source.source_vcodec = vcodec
|
|
self.source.source_acodec = acodec
|
|
self.source.prefer_60fps = prefer_60fps
|
|
self.source.prefer_hdr = prefer_hdr
|
|
match_type, format_code = self.media.get_best_video_format()
|
|
print((resolution, vcodec, acodec, prefer_60fps, prefer_hdr), match_type, format_code)
|
|
#self.assertEqual(match_type, expeceted_match_type)
|
|
#self.assertEqual(format_code, expected_format_code)
|