diff --git a/deemix/decryption.py b/deemix/decryption.py index 685a920..018c194 100644 --- a/deemix/decryption.py +++ b/deemix/decryption.py @@ -43,6 +43,7 @@ def streamTrack(outputStream, track, start=0, downloadObject=None, listener=None if downloadObject.isCanceled: raise DownloadCanceled headers= {'User-Agent': USER_AGENT_HEADER} chunkLength = start + isCryptedStream = "/mobile/" in track.downloadUrl itemData = { 'id': track.id, @@ -53,6 +54,8 @@ def streamTrack(outputStream, track, start=0, downloadObject=None, listener=None try: with get(track.downloadUrl, headers=headers, stream=True, timeout=10) as request: request.raise_for_status() + if isCryptedStream: + blowfish_key = generateBlowfishKey(str(track.id)) complete = int(request.headers["Content-Length"]) if complete == 0: raise DownloadEmpty @@ -77,6 +80,10 @@ def streamTrack(outputStream, track, start=0, downloadObject=None, listener=None }) for chunk in request.iter_content(2048 * 3): + if isCryptedStream: + if len(chunk) >= 2048: + chunk = decryptChunk(blowfish_key, chunk[0:2048]) + chunk[2048:] + outputStream.write(chunk) chunkLength += len(chunk) @@ -95,66 +102,6 @@ def streamTrack(outputStream, track, start=0, downloadObject=None, listener=None sleep(2) streamTrack(outputStream, track, start, downloadObject, listener) -def streamCryptedTrack(outputStream, track, start=0, downloadObject=None, listener=None): - if downloadObject.isCanceled: raise DownloadCanceled - headers= {'User-Agent': USER_AGENT_HEADER} - chunkLength = start - - itemData = { - 'id': track.id, - 'title': track.title, - 'artist': track.mainArtist.name - } - - try: - with get(track.downloadUrl, headers=headers, stream=True, timeout=10) as request: - request.raise_for_status() - blowfish_key = str.encode(generateBlowfishKey(str(track.id))) - - complete = int(request.headers["Content-Length"]) - if complete == 0: raise DownloadEmpty - if start != 0: - responseRange = request.headers["Content-Range"] - if listener: - listener.send('downloadInfo', { - 'uuid': downloadObject.uuid, - 'data': itemData, - 'state': "downloading", - 'alreadyStarted': True, - 'value': responseRange - }) - else: - if listener: - listener.send('downloadInfo', { - 'uuid': downloadObject.uuid, - 'data': itemData, - 'state': "downloading", - 'alreadyStarted': False, - 'value': complete - }) - - for chunk in request.iter_content(2048 * 3): - if len(chunk) >= 2048: - chunk = decryptChunk(blowfish_key, chunk[0:2048]) + chunk[2048:] - - outputStream.write(chunk) - chunkLength += len(chunk) - - if downloadObject: - if isinstance(downloadObject, Single): - chunkProgres = (chunkLength / (complete + start)) * 100 - downloadObject.progressNext = chunkProgres - else: - chunkProgres = (len(chunk) / (complete + start)) / downloadObject.size * 100 - downloadObject.progressNext += chunkProgres - downloadObject.updateProgress(listener) - - except (SSLError, u3SSLError): - streamCryptedTrack(outputStream, track, chunkLength, downloadObject, listener) - except (RequestsConnectionError, ReadTimeout, ChunkedEncodingError): - sleep(2) - streamCryptedTrack(outputStream, track, start, downloadObject, listener) - class DownloadCanceled(Exception): pass diff --git a/deemix/downloader.py b/deemix/downloader.py index 28f286b..197ab17 100644 --- a/deemix/downloader.py +++ b/deemix/downloader.py @@ -24,7 +24,7 @@ from deemix.types.Picture import StaticPicture from deemix.utils import USER_AGENT_HEADER from deemix.utils.pathtemplates import generatePath, generateAlbumName, generateArtistName, generateDownloadObjectName from deemix.tagger import tagID3, tagFLAC -from deemix.decryption import generateStreamURL, streamTrack, DownloadCanceled +from deemix.decryption import generateCryptedStreamURL, streamTrack, DownloadCanceled from deemix.settings import OverwriteOption logger = logging.getLogger('deemix') @@ -99,7 +99,7 @@ def getPreferredBitrate(track, bitrate, shouldFallback, uuid=None, listener=None def testBitrate(track, formatNumber, formatName): request = requests.head( - generateStreamURL(track.id, track.MD5, track.mediaVersion, formatNumber), + generateCryptedStreamURL(track.id, track.MD5, track.mediaVersion, formatNumber), headers={'User-Agent': USER_AGENT_HEADER}, timeout=30 ) @@ -342,7 +342,7 @@ class Downloader: writepath = Path(currentFilename) if not trackAlreadyDownloaded or self.settings['overwriteFile'] == OverwriteOption.OVERWRITE: - track.downloadUrl = generateStreamURL(track.id, track.MD5, track.mediaVersion, track.bitrate) + track.downloadUrl = generateCryptedStreamURL(track.id, track.MD5, track.mediaVersion, track.bitrate) try: with open(writepath, 'wb') as stream: diff --git a/deemix/utils/crypto.py b/deemix/utils/crypto.py index 6edb49b..c756667 100644 --- a/deemix/utils/crypto.py +++ b/deemix/utils/crypto.py @@ -20,7 +20,7 @@ def generateBlowfishKey(trackId): bfKey = "" for i in range(16): bfKey += chr(ord(idMd5[i]) ^ ord(idMd5[i + 16]) ^ ord(SECRET[i])) - return bfKey + return str.encode(bfKey) def decryptChunk(key, data): return Blowfish.new(key, Blowfish.MODE_CBC, b"\x00\x01\x02\x03\x04\x05\x06\x07").decrypt(data)