Skip to content

Instantly share code, notes, and snippets.

@D-Brox
Forked from Davr1/classfinder.py
Last active February 13, 2024 17:18
Show Gist options
  • Save D-Brox/69243b1612cccc4cf0d38464a844ea80 to your computer and use it in GitHub Desktop.
Save D-Brox/69243b1612cccc4cf0d38464a844ea80 to your computer and use it in GitHub Desktop.
import json
import re
from operator import itemgetter
import requests
from itertools import combinations
def best_similarity(master, candidates):
counts = [0] * len(candidates)
for candidate_index, candidate in enumerate(candidates):
for item in candidate:
if item in master:
counts[candidate_index] += 1
# makes sure that candidates with a similar amount of items but less matches have some advantage
# over candidates with more items and more matches
# can be visualised as y = -x^2 + 100, where x = 0 is a perfect match
counts[candidate_index] *= (-((len(candidate) - len(master)) ** 2) + 100)
candidate_scores = list(zip(counts, candidates))
# returns a map
return sorted(candidate_scores, key=itemgetter(0), reverse = True)
def main():
old = requests.get("https://discord.com/assets/454210598d8beed381ab.js")._content.decode("utf8")
new = requests.get("https://canary.discord.com/assets/782c119d5f878e08f08e.js")._content.decode("utf8")
# jsonifies the source files
replacements = [[r"\n", ""],
[r"\},\d+.*?s=", ","],
[r"\}{2,}.*", "}]"],
[r"^.*\{,", "["],
[r"(?<=\{|,)\b", "\""],
[":", "\":"],
["\"+", "\""]]
for r in replacements:
old = re.sub(r[0], r[1], old)
new = re.sub(r[0], r[1], new)
old = json.loads(old)
new = json.loads(new)
output = open("classes2.txt", "w")
print("Searching perfect matches")
metadict_old = {}
metadict_new = {}
for n,i in enumerate(old):
metadict_old.setdefault(' '.join(i.keys()),[]).append([i,n])
for n,i in enumerate(new):
metadict_new.setdefault(' '.join(i.keys()),[]).append([i,n])
aux = []
for i in metadict_old:
if i not in metadict_new:
continue
for j in range(len(metadict_old[i]))
aux.append([metadict_old[i][j][0],metadict_new[i][j][0]])
known_pairs = []
for i in aux:
for j in i[0]:
if re.search(r"^\d|\(|\)",i[0][j]) or re.search(r"^\d|\(|\)",i[1][j]):
continue
for n,k in enumerate(i[0][j].split(" ")):
if j+"-" in k or k.split("-")[0] in i[1][j].split(" ")[n]]:
known_pairs.append([k,i[1][j].split(" ")[n]])
print(f"Found {len(known_pairs)} perfect group matches")
print("Removing already matched cases")
unknown_old = [j for i in metadict_old if i not in metadict_new for j in metadict_old[i]]
unknown_new = [j for i in metadict_new if i not in metadict_old for j in metadict_new[i]]
old = [None]*len(old)
new = [None]*len(new)
for c,i in unknown_old:
old[i] = c
for c,i in unknown_new:
new[i] = c
old = [i for i in old if i]
new = [i for i in new if i]
for n,element_map in enumerate(new):
new[n] = {i:element_map[i] for i in element_map if not re.search(r"^\d|\(|\)",element_map[i])}
for n,element_map in enumerate(old):
old[n] = {i:element_map[i] for i in element_map if not re.search(r"^\d|\(|\)",element_map[i])}
print("Finding best group matches")
matches = []
for element_map in old:
matches.append(best_similarity(element_map, new))
done = False
ok = [False]*len(old)
while not done:
done = True
for i in range(len(old)):
if ok[i]:
continue
match_list = [[matches[i][0][0],i]]
for j in range(len(old)):
if i >=j or ok[j]:
continue
else:
if matches[i][1] == matches[j][1]:
match_list.append([matches[j][0][0],j])
match_list = sorted(match_list, reverse = True)
if len(match_list) != 1:
done = False
ok[match_list[0][1]] = True
while len(match_list) > 1:
for k in range(1,len(match_list)):
if matches[match_list[0][1]] == matches[match_list[k][1]][1:]:
matches[match_list[k][1]] = matches[match_list[k][1]][1:]
ok[match_list[k][1]]=False
match_list.pop(0)
best_pairs = []
missing = {}
for n,element_map in enumerate(old):
match = matches[n][0][1]
for element in element_map:
# checks if element contains a number as the first character, or a parenthesis
# -> gets rid of elements such as "calc(...)" or "24px"
if element in match and match[element] and re.search(r"^\d|\(|\)", match[element]):
continue
else:
try:
idx = new.index(match)
# splits elements with multiple classes into multiple lines
for substring in zip(element_map[element].split(' '), match[element].split(' ')):
new[idx].pop(element,None)
if [substring[0],substring[1]] not in best_pairs:
if element+"-" in substring[0] and element+"-" in substring[1]:
best_pairs.append([substring[0],substring[1]])
except:
if not re.search(r"^\d|\(|\)",element_map[element]):
missing[element]=element_map[element].split(" ")[0]
print(f"Found {len(best_pairs)} best matches")
missing = {i:missing[i] for i in missing if missing[i] not in [i[0] for i in known_pairs]}
missing = {i:missing[i] for i in missing if missing[i] not in [i[0] for i in best_pairs]}
new = [i for i in new if i]
print(f"Finding first match for {len(missing)} missing classes")
matched_pairs = []
failed = 0
for element in missing:
found = False
for n,element_map in enumerate(new):
if element in element_map:
matched_pairs.append([missing[element],element_map[element]])
found = True
break
if not found:
print(f"Couldn't find [{element} : {missing[element]}]")
failed+=1
if failed:
print(f"Failed to find equivalent new classes for {failed} old classes")
known_pairs.extend(best_pairs)
known_pairs.extend(matched_pairs)
for i in range(len(known_pairs)):
for j in range(len(known_pairs)):
if i >=j:
continue
else:
if known_pairs[i] == known_pairs[j]:
known_pairs[j] = None
for i in known_pairs:
if i and not i[0].startswith("-") and i[0] != i[1]:
output.write(f"{i[0]} = {i[1]}\n")
print("Finished")
output.close()
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment