YouTube-Internal-Clients/analysis.py

189 lines
6.3 KiB
Python
Raw Normal View History

2022-03-31 00:14:56 +00:00
import os
2022-03-28 16:05:36 +00:00
import json
2022-04-04 23:11:48 +00:00
def get_min_max_quality_label(formats):
formats = [f for f in formats if f.get("qualityLabel") is not None]
formats.sort(key=lambda x: x.get("width"))
min_format = formats[0]
max_format = formats[-1]
return min_format.get("qualityLabel") + " - " + max_format.get("qualityLabel")
def get_unique_mime_str(formats):
mimes = []
for f in formats:
if f.get("mimeType") is not None:
mime_short = f.get("mimeType").split(";")[0]
if mime_short not in mimes:
mimes.append(mime_short)
mimes_str = ""
for m in mimes:
mimes_str += "`" + m + "` "
return mimes_str
def get_structure_tree(data, depth = 0):
result = ""
for attribute in data:
if isinstance(data[attribute], dict):
result += ("│&nbsp;&nbsp;&nbsp;&nbsp;" * depth) + "├─`" + attribute + "`<br>"
result += get_structure_tree(data[attribute], depth + 1)
if isinstance(data[attribute], list):
result += ("│&nbsp;&nbsp;&nbsp;&nbsp;" * depth) + "├─`[" + attribute + "]` (" + str(len(data[attribute])) + ")<br>"
return result
2022-03-28 16:05:36 +00:00
markdown = ""
2022-04-05 23:57:22 +00:00
markdown += "| ID/ClientName/Version | Quality Formats | Features/Limitations/Attributes |\n"
markdown += "|---------------------------|-----------------|----------|\n"
working_clients_output = ""
2022-04-07 00:33:16 +00:00
working_versions = []
2022-03-28 16:05:36 +00:00
2022-03-31 00:14:56 +00:00
if not os.path.exists('results'):
os.makedirs('results')
files = os.listdir('responses')
2022-03-28 16:05:36 +00:00
client_ids = []
for file in files:
client_id = int(file.split('_')[0])
if client_id not in client_ids:
client_ids.append(client_id)
client_ids.sort()
for client_id in client_ids:
client_files = [file for file in files if file.startswith(str(client_id) + '_')]
client_files.sort(reverse=True) # highest version first
versions = []
for file_name in client_files:
version = file_name.split("_")[1]
if version not in versions:
versions.append(version)
2022-03-28 16:05:36 +00:00
for client_file in client_files:
2022-03-31 00:14:56 +00:00
response_data_raw = open('responses/' + client_file, 'r', encoding='utf-8').read()
2022-03-28 16:05:36 +00:00
response_data = json.loads(response_data_raw)
client_name = None
client_version = client_file.split('_')[1].replace('.json', '')
has_hls_format = ".m3u8" in response_data_raw
has_mpeg_dash = "dashManifest" in response_data_raw
try:
2022-04-05 23:57:22 +00:00
client_name = response_data_raw.split('%26c%3D')[1].split('%26')[0]
except Exception:
try:
client_name = response_data_raw.split('&c=')[1].split('&')[0]
except Exception:
continue
2022-03-28 16:05:36 +00:00
2022-04-07 00:33:16 +00:00
working_clients_output += str(client_id) + ";" + client_name + ";" + client_version + "\n"
2022-04-05 23:57:22 +00:00
2022-04-07 00:33:16 +00:00
if client_version not in working_versions:
working_versions.append(client_version)
2022-03-28 16:05:36 +00:00
2022-04-04 23:11:48 +00:00
formats_combined = []
formatsStr = ""
2022-03-28 16:05:36 +00:00
if response_data.get('streamingData'):
formats = response_data.get('streamingData').get('formats')
2022-04-04 23:11:48 +00:00
if formats is not None:
formatsStr = "<details><summary>Formats (" + str(len(formats)) + ")</summary>"
formats_combined += formats
2022-03-28 16:05:36 +00:00
for format in formats:
2022-04-04 23:11:48 +00:00
formatsStr += str(format.get("itag")) + " - " + str(format.get("qualityLabel")) + " - " + str(format.get("mimeType")).split(';')[0] + "<br>"
2022-03-28 16:05:36 +00:00
2022-04-04 23:11:48 +00:00
formatsStr += "</details>"
2022-03-28 16:05:36 +00:00
2022-04-04 23:11:48 +00:00
adaptiveFormatsStr = ""
2022-03-28 16:05:36 +00:00
if response_data.get('streamingData'):
formats = response_data.get('streamingData').get('adaptiveFormats')
2022-04-04 23:11:48 +00:00
if formats is not None:
adaptiveFormatsStr = "<details><summary>Adaptive Formats (" + str(len(formats)) + ")</summary>"
formats_combined += formats
2022-03-28 16:05:36 +00:00
for format in formats:
2022-04-04 23:11:48 +00:00
adaptiveFormatsStr += str(format.get("itag")) + " - " + str(format.get("qualityLabel")) + " - " + str(format.get("mimeType")).split(';')[0] + "<br>"
adaptiveFormatsStr += "</details>"
2022-03-28 16:05:36 +00:00
2022-04-04 23:11:48 +00:00
formats_summary = "<b>" + get_min_max_quality_label(formats_combined) + "</b><br>"
formats_summary += get_unique_mime_str(formats_combined) + "<br><br>"
2022-03-28 16:05:36 +00:00
extraInfo = ""
2022-04-05 23:57:22 +00:00
if "music.youtube.com" in client_file:
extraInfo += "&bull; Music videos only<br>"
if "www.youtubekids.com" in client_file:
extraInfo += "&bull; \"For Kids\" content only<br>"
2022-03-28 16:05:36 +00:00
if has_hls_format:
2022-04-05 23:57:22 +00:00
extraInfo += "&bull; HLS Support<br>"
2022-03-28 16:05:36 +00:00
if has_mpeg_dash:
2022-04-05 23:57:22 +00:00
extraInfo += "&bull; MPEG-DASH Support<br>"
if client_name == "TVHTML5_SIMPLY_EMBEDDED_PLAYER":
extraInfo += "&bull; No Age-restrictions<br>"
if "android" in client_name.lower():
2022-09-18 18:30:29 +00:00
extraInfo += "&bull; Might require [`androidSdkVersion`](#params)<br>"
2022-03-28 16:05:36 +00:00
2022-04-04 23:32:49 +00:00
ignore_attributes = ["videoDetails", "playerConfig", "responseContext", "playabilityStatus", "streamingData", "playbackTracking", "trackingParams", "adPlacements", "playerAds", "adParams", "adBreakParams", "onResponseReceivedEndpoints", "playerSettingsMenuData"]
2022-04-04 23:11:48 +00:00
if extraInfo != "":
2022-04-05 23:57:22 +00:00
extraInfo += "<br>"
2022-04-04 23:11:48 +00:00
for attribute in response_data:
if attribute not in ignore_attributes:
extraInfo += "&bull; `" + attribute + "`<br>"
if extraInfo != "":
extraInfo += "<br>"
2022-04-05 23:57:22 +00:00
extraInfo += "<details><summary>Show Response</summary>" + get_structure_tree(response_data) +"</details>"
2022-04-04 23:11:48 +00:00
other_versions = ""
if len(versions) > 1:
other_versions = "<br><br><details><summary>All Versions</summary>" + "<br>".join(versions) +"</details>"
2022-03-28 16:05:36 +00:00
markdown += "|ID: *" + str(client_id) + "*<br><b>" + client_name + "</b><br>" + client_version + other_versions + "|" + formats_summary + formatsStr + adaptiveFormatsStr + "|" + extraInfo + "|\n"
2022-03-28 16:05:36 +00:00
break
readme_template = open("templates/readme_template.md", "r").read()
readme_template = readme_template.replace("%table%", markdown)
2022-04-05 23:57:22 +00:00
2022-04-04 23:11:48 +00:00
f = open("results/working_clients.md", "w", encoding="utf-8")
2022-03-28 16:05:36 +00:00
f.write(markdown)
f.close()
2022-03-31 00:14:56 +00:00
f = open("results/working_clients.txt", "w")
2022-04-05 23:57:22 +00:00
f.write(working_clients_output)
f.close()
f = open("results/working_unique_versions.txt", "w")
2022-04-07 00:33:16 +00:00
for v in working_versions:
f.write(v + "\n")
2022-04-05 23:57:22 +00:00
f.close()
f = open("readme.md", "w", encoding="utf-8")
f.write(readme_template)
2022-04-05 23:57:22 +00:00
f.close()