SpotiFile/utils/spotify_track.py

125 wiersze
4.5 KiB
Python

import eyed3
import requests
from requests import Response
import hashlib
import datetime
import os
import shutil
import json
from utils.spotify_album import SpotifyAlbum
from utils.spotify_artist import SpotifyArtist
from utils.deezer_utils import Deezer
from utils.utils import clean_file_path
from exceptions import SpotifyTrackException
class SpotifyTrack:
title = ''
spotify_id = ''
artist = None
artists = []
album = None
thumbnail_href = ''
release_date = 0
disc_number = 0
duration_ms = 0
explicit = False
href = ''
popularity = 0
audio = b''
lyrics = ''
thumnail = b''
data_dump = ''
isrc = ''
def __init__(self, track_data=None) -> None:
if track_data is not None:
self.load_from_data(track_data)
def load_from_data(self, data):
if 'track' in data:
data = data['track']
self.data_dump = data
self.album = SpotifyAlbum(data['album'])
self.title = data['name']
self.spotify_id = data['id']
self.artists = [SpotifyArtist(x) for x in data['artists']]
self.artist = self.artists[0]
self.thumbnail_href = self.album.thumbnail_href
self.release_date = self.album.release_date
self.track_number = data['track_number']
self.duration_ms = data['duration_ms']
self.explicit = data['explicit']
self.href = data['href']
self.popularity = data['popularity']
if 'isrc' in data['external_ids']:
# isrc is not available for local files
self.isrc = data['external_ids']['isrc']
def __str__(self) -> str:
return f'SpotifyTrack< {self.title} >'
def __repr__(self) -> str:
return self.__str__()
def get_lyrics(self, scraper) -> str:
if scraper is None:
raise SpotifyTrackException('SCAPER NOT AVAILABLE!')
return scraper.get_lyrics(self.spotify_id)
def download_thumbnail(self, scraper) -> bytes:
return scraper.get(self.thumbnail_href).content
def get_download_link(self, scraper) -> str:
if not self.isrc:
return ''
return Deezer.get_track_download_url(Deezer.get_track_data(Deezer.get_track_id_from_isrc(self.isrc)))[0]
def download(self, scraper) -> bytes:
if not self.isrc:
raise SpotifyTrackException(f'Cannot download local file {self.title}!')
# I'm used to C, sorry
download_link = None
try:
download_link = self.get_download_link(scraper)
except Exception as ex:
raise SpotifyTrackException(f'Failed to get download url for {self.title} | Exception: {ex}')
try:
data = Deezer.decrypt_download_data(requests.get(download_link, headers={'Accept':'*/*'}), self.isrc)
return data
except Exception as ex:
raise SpotifyTrackException(f'Failed to download {self.title} | Exception: {ex}')
def package_download(self, scraper):
self.audio = self.download(scraper)
self.thumbnail = self.download_thumbnail(scraper)
self.lyrics = self.get_lyrics(scraper)
def preview_title(self):
return f'{", ".join([x.name for x in self.artists])} - {self.title} [{self.album.title}]'
def download_to_file(self, scraper, output_path: str):
temp_file_path = f'temp/{hashlib.sha1(self.title.encode() + self.album.spotify_id.encode()).hexdigest()}.temp.mp3'
self.package_download(scraper)
with open(temp_file_path, 'wb') as f:
f.write(self.audio)
audio_file = eyed3.load(temp_file_path)
audio_file.initTag(version=(2, 4, 0)) # version is important
audio_file.tag.title = self.title
audio_file.tag.artist = ';'.join([artist.name for artist in self.artists])
audio_file.tag.album_artist = self.artists[0].name
audio_file.tag.album = self.album.title
audio_file.tag.original_release_date = datetime.datetime.fromtimestamp(self.album.release_date).year
audio_file.tag.track_num = self.track_number
audio_file.info.time_secs = self.duration_ms / 1000
audio_file.tag.images.set(3, self.thumbnail, 'image/jpeg', u'cover')
audio_file.tag.lyrics.set(str(self.lyrics))
audio_file.tag.comments.set('', str(self.data_dump))
audio_file.tag.save()
full_output_path = output_path + '/' + clean_file_path(self.preview_title()) + '.mp3'
os.makedirs(os.path.dirname(full_output_path), exist_ok=True)
shutil.move(temp_file_path, full_output_path)