93 lines
2.4 KiB
Python
93 lines
2.4 KiB
Python
# https://pypi.org/project/music-helper/
|
||
import hashlib
|
||
import re
|
||
import warnings
|
||
|
||
from attrs import define
|
||
from cryptography.hazmat.backends import default_backend
|
||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||
|
||
from .track_formats import TrackFormat
|
||
|
||
|
||
def clean_query(query):
|
||
query = re.sub(r"/ feat[.]? /g", " ", query)
|
||
query = re.sub(r"/ ft[.]? /g", " ", query)
|
||
query = re.sub(r"/\(feat[.]? /g", " ", query)
|
||
query = re.sub(r"/\(ft[.]? /g", " ", query)
|
||
query = re.sub(r"/&/g", "", query)
|
||
query = re.sub(r"/–/g", "-", query)
|
||
query = re.sub(r"/–/g", "-", query)
|
||
|
||
return query
|
||
|
||
|
||
def get_text_md5(text, encoding="UTF-8"):
|
||
return hashlib.md5(str(text).encode(encoding)).hexdigest()
|
||
|
||
|
||
@define
|
||
class UrlDecrypter:
|
||
md5_origin: str
|
||
track_id: str
|
||
media_version: str
|
||
|
||
def get_url_for(self, track_format: TrackFormat):
|
||
step1 = (
|
||
f"{self.md5_origin}¤{track_format.code}¤"
|
||
f"{self.track_id}¤{self.media_version}"
|
||
)
|
||
m = hashlib.md5()
|
||
m.update(bytes([ord(x) for x in step1]))
|
||
|
||
step2 = f"{m.hexdigest()}¤{step1}¤"
|
||
step2 = step2.ljust(80, " ")
|
||
|
||
cipher = Cipher(
|
||
algorithm=algorithms.AES(key=bytes("jo6aey6haid2Teih", "ascii")),
|
||
mode=modes.ECB(),
|
||
backend=default_backend(),
|
||
)
|
||
|
||
encryptor = cipher.encryptor()
|
||
step3 = encryptor.update(bytes([ord(x) for x in step2])).hex()
|
||
|
||
cdn = self.md5_origin[0]
|
||
|
||
return f"https://e-cdns-proxy-{cdn}.dzcdn.net/mobile/1/{step3}"
|
||
|
||
|
||
@define
|
||
class ChunkDecrypter:
|
||
cipher: Cipher
|
||
|
||
@classmethod
|
||
def from_track_id(cls, track_id: str):
|
||
with warnings.catch_warnings():
|
||
warnings.filterwarnings("ignore")
|
||
cipher = Cipher(
|
||
algorithms.Blowfish(get_blowfish_key(track_id)),
|
||
modes.CBC(bytes([i for i in range(8)])),
|
||
default_backend(),
|
||
)
|
||
|
||
return cls(cipher=cipher)
|
||
|
||
def decrypt_chunk(self, chunk: bytes):
|
||
decryptor = self.cipher.decryptor()
|
||
return decryptor.update(chunk) + decryptor.finalize()
|
||
|
||
|
||
def get_blowfish_key(track_id: str):
|
||
secret = "g4el58wc0zvf9na1"
|
||
|
||
m = hashlib.md5()
|
||
m.update(bytes([ord(x) for x in track_id]))
|
||
id_md5 = m.hexdigest()
|
||
|
||
blowfish_key = bytes(
|
||
[(ord(id_md5[i]) ^ ord(id_md5[i + 16]) ^ ord(secret[i])) for i in range(16)]
|
||
)
|
||
|
||
return blowfish_key
|