| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- import html
- import venigma
- import os
- import base64
- import re
- import hashlib
- class AudioListItem:
- def __init__(self, json_item):
- self._jitem = json_item
- def id(self):
- return self._jitem["audio_raw_id"]
- def key(self):
- return self._jitem["access_key"]
- def cid(self):
- return f"{self.id()}_{self.key()}"
- def _code(self):
- return self._jitem["track_code"]
- def audio_list(plain_list):
- return [AudioListItem(item) for item in plain_list["payload"][1][0]]
- class AudioDataItem:
- def __init__(self, json_data):
- self._jdata = json_data
- self._manifest = None
- def cid(self):
- return f"{self._jdata[1]}_{self._jdata[0]}"
- def index(self):
- return base64.b16encode(self.hindex().encode()).decode()
- def cursed_url(self):
- return self._jdata[2]
- def blessed_url(self, config):
- return venigma.decode(config, self.cursed_url())
- def root_url(self, config):
- blessed_url = self.blessed_url(config)
- parts = blessed_url.split("/")
- return "/".join(parts[:-1]) + "/"
- def title(self):
- return html.unescape(self._jdata[3])
- def artist(self):
- return html.unescape(self._jdata[4])
- def img(self):
- return self._jdata[14]
- def hindex(self):
- return f"{self.title()} - {self.artist()}"
- def findex(self, config):
- return f"{config.audio_directory()}{self.cid()}.mp3"
- def _hash(self, manifest_hash, mp3):
- hash = hashlib.sha256(manifest_hash)
- hash.update(mp3)
- return hash.hexdigest()
- def _hashfile(self, config):
- return f"{self.manifest().directory(config)}sha256sum"
- def hash(self, config):
- f = open(self._hashfile(config), "w+")
- fmp3 = open(self.findex(config), "rb")
- manifest_hash = self.manifest().hashed(config)
- h = self._hash(manifest_hash.encode(), fmp3.read())
- fmp3.close()
- f.write(h)
- f.close()
- return h
- def hashed(self, config):
- hashfile = self._hashfile(config)
- findex = self.findex(config)
- manifest_hash = self.manifest().hashed(config)
- if (
- not os.path.isfile(hashfile)
- or not os.path.isfile(findex)
- or not manifest_hash
- ):
- return None
- fmp3 = open(findex, "rb")
- h = self._hash(manifest_hash.encode(), fmp3.read())
- fmp3.close()
- f = open(hashfile, "r")
- fh = f.read()
- f.close()
- return h if h == fh else None
- def manifest(self, manifest=None):
- if manifest is None:
- return self._manifest
- else:
- self._manifest = manifest
- if manifest.data() is None:
- manifest.data(self)
- def audio_data(plain_data):
- return [AudioDataItem(data) for data in plain_data["payload"][1][0]]
- class Manifest:
- def __init__(self, raw_content):
- self._rcontent = raw_content
- self._data = None
- def load(config, data):
- index = Manifest._index_for(config, data)
- if os.path.isfile(index):
- f = open(index, "rb")
- manifest = Manifest(f.read())
- f.close()
- data.manifest(manifest)
- return manifest
- else:
- return None
- def content(self):
- return self._rcontent
- def _directory_for(config, data):
- directory = config.manifests_directory()
- return f"{directory}{data.index()}/"
- def directory(self, config):
- return Manifest._directory_for(config, self.data())
- def _index_for(config, data):
- return f"{Manifest._directory_for(config, data)}index.m3u8"
- def index(self, config):
- return Manifest._index_for(config, self.data())
- def store(self, config):
- directory = self.directory(config)
- if not os.path.exists(directory):
- os.makedirs(directory)
- f = open(self.index(config), "wb+")
- f.write(self.content())
- f.close()
- def chunks(self):
- regex = r"seg\-\d+\-\w+\.ts\?siren=\d"
- return re.findall(regex, self.content().decode("utf-8"))
- def _hash(self, chunks):
- hash = hashlib.sha1(self.content())
- for chunk in chunks:
- if not chunk:
- continue
- hash.update(chunk.data())
- return hash.hexdigest()
- def _hashfile(self, config):
- return f"{self.directory(config)}sha1sum"
- def hash(self, config, chunks):
- f = open(self._hashfile(config), "w+")
- h = self._hash(chunks)
- f.write(h)
- f.close()
- return h
- def hashed(self, config):
- hashfile = self._hashfile(config)
- chunks = [Chunk.load(config, self, chunk) for chunk in self.chunks()]
- if not os.path.isfile(hashfile) or any(chunks) is None:
- return None
- h = self._hash(chunks)
- f = open(hashfile, "r")
- fh = f.read()
- f.close()
- return h if h == fh else None
- def data(self, data=None):
- if data is None:
- return self._data
- else:
- self._data = data
- if data.manifest() is None:
- data.manifest(self)
- class Chunk:
- def __init__(self, manifest, name, raw_data):
- self._name = name
- self._rdata = raw_data
- self._manifest = manifest
- def _index_for(config, manifest, name):
- return f"{manifest.directory(config)}{name}"
- def load(config, manifest, name):
- index = Chunk._index_for(config, manifest, name)
- if os.path.isfile(index):
- f = open(index, "rb")
- chunk = Chunk(manifest, name, f.read())
- f.close()
- return chunk
- else:
- return None
- def name(self):
- return self._name
- def data(self):
- return self._rdata
- def manifest(self):
- return self._manifest
- def store(self, config):
- f = open(f"{Chunk._index_for(config, self.manifest(), self.name())}", "wb+")
- f.write(self.data())
- f.close()
|