-
Notifications
You must be signed in to change notification settings - Fork 43
/
analysis.py
188 lines (130 loc) · 6.34 KB
/
analysis.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import os
import json
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 += ("│ " * depth) + "├─`" + attribute + "`<br>"
result += get_structure_tree(data[attribute], depth + 1)
if isinstance(data[attribute], list):
result += ("│ " * depth) + "├─`[" + attribute + "]` (" + str(len(data[attribute])) + ")<br>"
return result
markdown = ""
markdown += "| ID/ClientName/Version | Quality Formats | Features/Limitations/Attributes |\n"
markdown += "|---------------------------|-----------------|----------|\n"
working_clients_output = ""
working_versions = []
if not os.path.exists('results'):
os.makedirs('results')
files = os.listdir('responses')
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)
for client_file in client_files:
response_data_raw = open('responses/' + client_file, 'r', encoding='utf-8').read()
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:
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
working_clients_output += str(client_id) + ";" + client_name + ";" + client_version + "\n"
if client_version not in working_versions:
working_versions.append(client_version)
formats_combined = []
formatsStr = ""
if response_data.get('streamingData'):
formats = response_data.get('streamingData').get('formats')
if formats is not None:
formatsStr = "<details><summary>Formats (" + str(len(formats)) + ")</summary>"
formats_combined += formats
for format in formats:
formatsStr += str(format.get("itag")) + " - " + str(format.get("qualityLabel")) + " - " + str(format.get("mimeType")).split(';')[0] + "<br>"
formatsStr += "</details>"
adaptiveFormatsStr = ""
if response_data.get('streamingData'):
formats = response_data.get('streamingData').get('adaptiveFormats')
if formats is not None:
adaptiveFormatsStr = "<details><summary>Adaptive Formats (" + str(len(formats)) + ")</summary>"
formats_combined += formats
for format in formats:
adaptiveFormatsStr += str(format.get("itag")) + " - " + str(format.get("qualityLabel")) + " - " + str(format.get("mimeType")).split(';')[0] + "<br>"
adaptiveFormatsStr += "</details>"
formats_summary = "<b>" + get_min_max_quality_label(formats_combined) + "</b><br>"
formats_summary += get_unique_mime_str(formats_combined) + "<br><br>"
extraInfo = ""
if "music.youtube.com" in client_file:
extraInfo += "• Music videos only<br>"
if "www.youtubekids.com" in client_file:
extraInfo += "• \"For Kids\" content only<br>"
if has_hls_format:
extraInfo += "• HLS Support<br>"
if has_mpeg_dash:
extraInfo += "• MPEG-DASH Support<br>"
if client_name == "TVHTML5_SIMPLY_EMBEDDED_PLAYER":
extraInfo += "• No Age-restrictions<br>"
if "android" in client_name.lower():
extraInfo += "• Might require [`androidSdkVersion`](#params)<br>"
ignore_attributes = ["videoDetails", "playerConfig", "responseContext", "playabilityStatus", "streamingData", "playbackTracking", "trackingParams", "adPlacements", "playerAds", "adParams", "adBreakParams", "onResponseReceivedEndpoints", "playerSettingsMenuData"]
if extraInfo != "":
extraInfo += "<br>"
for attribute in response_data:
if attribute not in ignore_attributes:
extraInfo += "• `" + attribute + "`<br>"
if extraInfo != "":
extraInfo += "<br>"
extraInfo += "<details><summary>Show Response</summary>" + get_structure_tree(response_data) +"</details>"
other_versions = ""
if len(versions) > 1:
other_versions = "<br><br><details><summary>All Versions</summary>" + "<br>".join(versions) +"</details>"
markdown += "|ID: *" + str(client_id) + "*<br><b>" + client_name + "</b><br>" + client_version + other_versions + "|" + formats_summary + formatsStr + adaptiveFormatsStr + "|" + extraInfo + "|\n"
break
readme_template = open("templates/readme_template.md", "r").read()
readme_template = readme_template.replace("%table%", markdown)
f = open("results/working_clients.md", "w", encoding="utf-8")
f.write(markdown)
f.close()
f = open("results/working_clients.txt", "w")
f.write(working_clients_output)
f.close()
f = open("results/working_unique_versions.txt", "w")
for v in working_versions:
f.write(v + "\n")
f.close()
f = open("readme.md", "w", encoding="utf-8")
f.write(readme_template)
f.close()