766 lines
31 KiB
Python
Executable File
766 lines
31 KiB
Python
Executable File
from ast import keyword
|
|
import sys
|
|
import mutagen
|
|
import eyed3
|
|
from eyed3.id3.frames import ImageFrame
|
|
from mutagen.flac import FLAC
|
|
from mutagen.mp3 import MP3
|
|
from mutagen.id3 import ID3
|
|
from mutagen.wave import WAVE
|
|
from mutagen.oggvorbis import OggVorbis
|
|
from mutagen.id3 import ID3, TIT2, TALB, TPE1, TPE2, COMM, TCOM, TCON, TDRC, TRCK, TPUB, POPM, APIC
|
|
from mutagen.easyid3 import EasyID3
|
|
import os
|
|
from os import listdir
|
|
from os.path import isfile, join
|
|
|
|
from icrawler.builtin import GoogleImageCrawler
|
|
|
|
import spotipy
|
|
from spotipy.oauth2 import SpotifyClientCredentials
|
|
|
|
from datetime import datetime
|
|
|
|
import requests
|
|
import time
|
|
|
|
import logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="{asctime} - {levelname} - [{funcName}:{lineno}] - {message}",
|
|
style="{",
|
|
datefmt="%Y-%m-%d %H:%M",
|
|
)
|
|
|
|
# TODO check if title is correct (not like "artist - name")
|
|
|
|
def switch_ID3_flag_tag(audio, ID3_tag, flac_tag):
|
|
try:
|
|
audio[flac_tag] = str(audio[ID3_tag][0].text[0])
|
|
logging.info("switched ID3 tag " + ID3_tag + " to flac tag " + flac_tag + " with value " + str(audio[flac_tag]) + ", type " + str(type(audio[flac_tag])))
|
|
audio.pop(ID3_tag, None)
|
|
except:
|
|
logging.info("could not switch ID3 tag " + ID3_tag + " to flac tag " + flac_tag)
|
|
|
|
def remove_flac_ID3_tags(audio, x: str):
|
|
if x.endswith(".flac"):
|
|
logging.info("switching ID3 tags to flac tags for file " + x)
|
|
|
|
switch_ID3_flag_tag(audio,"TPE2","BAND")
|
|
switch_ID3_flag_tag(audio, "TPE1", "ARTIST")
|
|
switch_ID3_flag_tag(audio, "TIT2", "TITLE")
|
|
switch_ID3_flag_tag(audio, "TALB", "ALBUM")
|
|
switch_ID3_flag_tag(audio, "COMM", "COMMENT")
|
|
switch_ID3_flag_tag(audio, "TCOM", "COMPOSER")
|
|
switch_ID3_flag_tag(audio, "TCON", "GENRE")
|
|
switch_ID3_flag_tag(audio, "TRCK", "TRACKNUMBER")
|
|
switch_ID3_flag_tag(audio, "TDRC", "DATE")
|
|
switch_ID3_flag_tag(audio, "TPUB", "PUBLISHER")
|
|
|
|
audio.pop("POPM", None)
|
|
audio.pop("APIC", None)
|
|
|
|
|
|
|
|
def make_folder(foldername):
|
|
try:
|
|
logging.info("Creating folder " + foldername)
|
|
if "/" in foldername:
|
|
folders = foldername.split('/')
|
|
pos = "."
|
|
for fold in folders:
|
|
pos = join(pos,fold)
|
|
if not os.path.exists(pos):
|
|
os.mkdir(pos)
|
|
else:
|
|
os.mkdir(foldername)
|
|
except Exception as err:
|
|
logging.error("could not create folder " + foldername)
|
|
logging.error(err)
|
|
|
|
|
|
def search_google_images_and_save(x: str, audio):
|
|
if x.endswith(".flac"):
|
|
remove_flac_ID3_tags(audio,x)
|
|
|
|
audio.save(x)
|
|
|
|
found_image = False
|
|
if (check_tag(audio, x, "TALB","album")):
|
|
# search for artist and album
|
|
if x.endswith(".flac"):
|
|
songpath = join(".",str(audio["artist"]),str(audio["album"]))
|
|
else:
|
|
songpath = join(".",str(audio["TPE2"]),str(audio["TALB"]))
|
|
if "\x00" in songpath:
|
|
# having null bytes in os.replace will throw an error
|
|
songpath = songpath.replace("\x00",", ")
|
|
make_folder(songpath)
|
|
os.replace(join(".",x),join(songpath,x))
|
|
google_keyword = ""
|
|
if x.endswith(".flac"):
|
|
google_keyword = str(audio["artist"]) + " " + str(audio["album"]) + " album"
|
|
else:
|
|
google_keyword = str(audio["TPE2"]) + " " + str(audio["TALB"]) + " album"
|
|
logging.info("Moved file! Now searching for album art... keyword is " + google_keyword)
|
|
google_Crawler = GoogleImageCrawler(storage = {'root_dir': songpath})
|
|
try:
|
|
google_Crawler.crawl(keyword = str(audio["TPE2"]) + " " + str(audio["TALB"]) + " album", max_num = 1)
|
|
found_image = True
|
|
except:
|
|
logging.info("could not find Google result by album, searching by track and artist")
|
|
if (found_image):
|
|
logging.info("changing name of cover art file...")
|
|
logging.info(songpath)
|
|
for f in listdir(songpath):
|
|
logging.info(f)
|
|
if (isfile(join(songpath,f)) and f.split(".")[-1].lower() in ["jpg","png"]):
|
|
os.replace(join(songpath,f),join(songpath,"Cover." + f.split(".")[-1].lower()))
|
|
logging.info("Done!")
|
|
#TODO search for song name and artist if album not found on google images
|
|
# else:
|
|
# songpath = join(".",str(audio["TPE1"]),str(audio["TIT2"]))
|
|
# make_folder(songpath)
|
|
# os.replace(join(".",x),join(songpath,x))
|
|
# logging.info("Moved file! Now searching for album art... keyword is " + str(audio["TPE1"]) + " " + str(audio["TIT2"]))
|
|
# google_Crawler = GoogleImageCrawler(storage = {'root_dir': songpath})
|
|
|
|
|
|
else:
|
|
# search for song name and artist
|
|
# search for artist and album
|
|
# use TPE2 (album artist), because we want to find the album
|
|
songpath = join(".",str(audio["TPE2"]),str(audio["TIT2"]))
|
|
make_folder(songpath)
|
|
os.replace(join(".",x),join(songpath,x))
|
|
logging.info("Moved file! Now searching for album art... keyword is " + str(audio["TPE2"]) + " " + str(audio["TIT2"]))
|
|
google_Crawler = GoogleImageCrawler(storage = {'root_dir': songpath})
|
|
try:
|
|
google_Crawler.crawl(keyword = str(audio["TPE2"]) + " " + str(audio["TIT2"]), max_num = 1)
|
|
found_image = True
|
|
except:
|
|
logging.info("could not find Google result by track and artist")
|
|
if (found_image):
|
|
logging.info("changing name of cover art file...")
|
|
logging.info(songpath)
|
|
for f in listdir(songpath):
|
|
logging.info(f)
|
|
if (isfile(join(songpath,f)) and f.split(".")[-1].lower() in ["jpg","png"]):
|
|
os.replace(join(songpath,f),join(songpath,"Cover." + f.split(".")[-1].lower()))
|
|
logging.info("Done!")
|
|
|
|
# TIT2 = title,
|
|
# TPE1 = artist,
|
|
# TPE2 = band,
|
|
# TALB = album,
|
|
# COMM = comment,
|
|
# TCOM = composer,
|
|
# TCON = genre,
|
|
# TRCK = number,
|
|
# TDRC = year,
|
|
# TPUB = publisher
|
|
|
|
def create_ID3_tag(audio, tagname: str, textvalue: str):
|
|
logging.info("creating ID3 tag " + tagname + " with value " + textvalue)
|
|
if tagname == "TALB":
|
|
audio[tagname] = TALB(encoding=3,text=textvalue)
|
|
elif tagname == "TIT2":
|
|
audio[tagname] = TIT2(encoding=3,text=textvalue)
|
|
elif tagname == "TPE1":
|
|
audio[tagname] = TPE1(encoding=3,text=textvalue)
|
|
elif tagname == "TPE2":
|
|
audio[tagname] = TPE2(encoding=3,text=textvalue)
|
|
elif tagname == "COMM":
|
|
audio[tagname] = COMM(encoding=3,text=textvalue)
|
|
elif tagname == "TCOM":
|
|
audio[tagname] = TCOM(encoding=3,text=textvalue)
|
|
elif tagname == "TCON":
|
|
audio[tagname] = TCON(encoding=3,text=textvalue)
|
|
elif tagname == "TRCK":
|
|
audio[tagname] = TRCK(encoding=3,text=textvalue)
|
|
elif tagname == "TDRC":
|
|
try:
|
|
audio[tagname] = TDRC(encoding=3,text=textvalue)
|
|
except:
|
|
pass
|
|
elif tagname == "TPUB":
|
|
audio[tagname] = TPUB(encoding=3,text=textvalue)
|
|
|
|
def check_tag(audio, filename: str, ID3_tag: str, normal_tag) -> bool:
|
|
res = False
|
|
|
|
# check if the ID3 artist tag exists
|
|
if (ID3_tag in audio.keys() and len(str(audio[ID3_tag])) != 0):
|
|
logging.info(ID3_tag + " ID3 tag found! " + str(audio[ID3_tag]))
|
|
|
|
# apply it to the general album tag
|
|
if audio[ID3_tag] is not str and filename.endswith(".mp3"):
|
|
audio[normal_tag] = audio[ID3_tag]
|
|
else:
|
|
audio[normal_tag] = audio[ID3_tag]
|
|
logging.info("Set " + normal_tag + " to " + str(audio[normal_tag]))
|
|
res = True
|
|
|
|
# check if general album tag exists
|
|
elif (normal_tag in audio.keys() and len(str(audio[normal_tag])) != 0):
|
|
logging.info(normal_tag + " normal tag found! " + str(audio[normal_tag]))
|
|
if audio[normal_tag] is not str:
|
|
audio[normal_tag] = audio[normal_tag][0]
|
|
logging.info("normal tag is not str, set it to " + str(audio[normal_tag][0]))
|
|
if (not filename.endswith(".flac")):
|
|
#apply it to the ID3 tag
|
|
if audio[normal_tag] is not str:
|
|
create_ID3_tag(audio, ID3_tag,audio[normal_tag][0])
|
|
else:
|
|
create_ID3_tag(audio, ID3_tag,audio[normal_tag])
|
|
else:
|
|
logging.debug(filename + " is a flac file, not creating ID3 tag")
|
|
res = True
|
|
|
|
return res
|
|
|
|
def check_title_songname(x: str, audio):
|
|
logging.info("checking title by name " + x)
|
|
extension = x.split(".")[-1].lower()
|
|
if (extension in ["mp3","flac","ogg","wav","m4a","mp4"]):
|
|
x = x.rsplit(".",1)[0] # remove the file extension
|
|
logging.info("file has extension " + extension + ". removing it from title. New title: " + x)
|
|
|
|
items = x.split(" - ")
|
|
if (len(items) > 2):
|
|
logging.info("song title has more than 1 part after the -: " + str(items))
|
|
if (items[1].count(".mp3") >= 1):
|
|
logging.info("setting TIT2 tag to: " + str(items[1].strip().rstrip().rsplit(".")[0])) # get second part of title and remove the file extension
|
|
audio["TIT2"] = TIT2(encoding=3,text=str(items[1].strip().rstrip().rsplit(".")[0]))
|
|
elif (items[1].count(".flac") >= 1):
|
|
logging.info("setting title tag to " + str(items[1].strip().rstrip().rsplit(".")[0])) # get second part of title and remove the file extension
|
|
audio["title"] = str(items[1].strip().rstrip().rsplit(".")[0])
|
|
else:
|
|
logging.info("title: " + str(items[1].strip().rstrip())) # get second part of title and remove the file extension
|
|
audio["TIT2"] = TIT2(encoding=3,text=str(items[1].strip().rstrip()))
|
|
audio["title"] = TIT2(encoding=3,text=str(items[1].strip().rstrip()))
|
|
else:
|
|
logging.info("song title has only 1 part after the -: " + items[0])
|
|
if ("TIT2" not in audio.keys()):
|
|
song_title = items[0].strip().rstrip()
|
|
logging.info("TIT2 tag not found, creating it. Using song title: " + song_title)
|
|
audio["TIT2"] = TIT2(encoding=3,text=song_title)
|
|
audio["title"] = TIT2(encoding=3,text=song_title)
|
|
|
|
def check_for_multiple_artists(audio, filename: str, name: str):
|
|
logging.info("checking for multiple artists for name " + name)
|
|
artists = []
|
|
if (" x " in name):
|
|
artists = name.split(" x ")
|
|
elif (" X " in name):
|
|
artists = name.split(" X ")
|
|
elif ("," in name):
|
|
artists = name.split(",")
|
|
elif ("/" in name):
|
|
artists = name.split("/")
|
|
elif ("\x00" in name):
|
|
artists = name.split("\x00")
|
|
|
|
if (len(artists) > 0):
|
|
logging.info("multiple artists: " + str(artists))
|
|
if filename.endswith(".flac"):
|
|
audio["artist"] = TPE2(encoding=3,text=["\0".join(artists)])
|
|
else:
|
|
audio["TPE1"] = TPE2(encoding=3,text=["\0".join(artists)])
|
|
else:
|
|
logging.info("no multiple artists found in name " + name)
|
|
|
|
|
|
# checks for any artist from the song name. If it exists it sets the properties of the file
|
|
def check_artist_songname(x: str, audio):
|
|
items = x.split(" - ")
|
|
logging.info("Checking artist by name. items: " + str(items))
|
|
if (len(items) > 2):
|
|
check_for_multiple_artists(audio, x, items[0].strip())
|
|
|
|
else: # no multiple artists in name
|
|
logging.info("Setting artist tags TPE1 and TPE2 to " + str(items[0].strip().rstrip()))
|
|
|
|
audio["TPE1"] = TPE1(encoding=3,text=str(items[0].strip().rstrip()))
|
|
audio["TPE2"] = TPE2(encoding=3,text=str(items[0].strip().rstrip()))
|
|
audio["artist"] = audio["TPE1"]
|
|
|
|
def check_artist(audio, filename: str) -> bool:
|
|
res = False
|
|
|
|
# check if the ID3 artist tag exists
|
|
if ("TPE1" in audio.keys()):
|
|
if (len(str(audio["TPE1"])) != 0):
|
|
logging.info("TPE1 tag was found! " + str(audio["TPE1"]))
|
|
|
|
# apply it to general artist tag
|
|
audio["TPE2"] = TPE2(encoding=3,text=str(audio["TPE1"]))
|
|
audio["artist"] = audio["TPE1"]
|
|
logging.info("checking for multiple artists")
|
|
check_for_multiple_artists(audio, filename ,str(audio["TPE1"]))
|
|
res = True
|
|
|
|
|
|
# if no TPE1, check if the ID3 band tag exists
|
|
elif ("TPE2" in audio.keys()):
|
|
if (len(str(audio["TPE2"])) != 0):
|
|
logging.info("TPE2 tag was found! " + str(audio["TPE2"]))
|
|
|
|
# apply it to TPE1 and general artist tags
|
|
audio["TPE1"] = TPE1(encoding=3,text=str(audio["TPE2"]))
|
|
audio["artist"] = audio["TPE1"]
|
|
check_for_multiple_artists(audio,filename,str(audio["TPE2"]))
|
|
res = True
|
|
|
|
# check if artist audio tag exists
|
|
elif ("artist" in audio.keys()):
|
|
if (len(str(audio["artist"])) != 0):
|
|
logging.info("artist tag was found! " + str(audio["artist"]))
|
|
|
|
artist = ""
|
|
if (audio["artist"] is not str):
|
|
artist = audio["artist"][0]
|
|
else:
|
|
artist = audio["artist"]
|
|
|
|
logging.info("artist: " + artist)
|
|
# apply to both ID3 artist tags
|
|
audio["TPE1"] = TPE1(encoding=3,text=artist)
|
|
audio["TPE2"] = TPE2(encoding=3,text=artist)
|
|
|
|
if (audio["TPE2"][0].text is not str):
|
|
audio["TPE2"][0].text = str(audio["TPE2"][0].text[0])
|
|
|
|
if (audio["TPE1"] is not str):
|
|
audio["TPE1"] = audio["TPE1"][0]
|
|
|
|
logging.info("Set TPE1 and TPE2 to " + str(audio["TPE1"][0]) + " and " + str(audio["TPE2"][0]))
|
|
check_for_multiple_artists(audio,filename,artist)
|
|
res = True
|
|
|
|
return res
|
|
|
|
def check_spotify_genre(genres,audio):
|
|
genre = ""
|
|
if (len(genres) > 0):
|
|
if (len(genres) == 1):
|
|
audio["TCON"] = TCON(encoding=3,text=str(genres[0]))
|
|
else:
|
|
for i in range(len(genres)):
|
|
if (i == 0):
|
|
genre = str(genres[i])
|
|
else:
|
|
genre += "," + str(genres[i])
|
|
|
|
logging.info("genre set to " + genre)
|
|
audio["TCON"] = TCON(encoding=3,text=genre)
|
|
|
|
audio["genre"] = audio["TCON"]
|
|
|
|
def embed_music_file(audiostr: str, coverfile: str):
|
|
try:
|
|
new_audio = ID3(audiostr)
|
|
with open(coverfile,'rb') as albumart:
|
|
new_audio.add(APIC(
|
|
encoding=3,
|
|
mime='image/jpeg',
|
|
type=3, desc=u'Cover image',
|
|
data=albumart.read()
|
|
))
|
|
new_audio.save(audiostr)
|
|
logging.info("Finished!")
|
|
except:
|
|
logging.info("could not embed music file")
|
|
|
|
|
|
def check_spotify_album_and_save(spotify, audio,x: str) -> bool:
|
|
found = False
|
|
logging.info("Searching on spotify for album...")
|
|
querystring = ""
|
|
if x.endswith(".flac"):
|
|
querystring = "artist:{0} album:{1}".format(str(audio["artist"]),str(audio["album"]))
|
|
else:
|
|
querystring = "artist:{0} album:{1}".format(str(audio["TPE2"]),str(audio["TALB"]))
|
|
|
|
logging.info("query string: " + querystring)
|
|
try:
|
|
results = spotify.search(q=querystring,type='album')
|
|
except Exception as err:
|
|
logging.error("could not search on spotify")
|
|
logging.error(err)
|
|
logging.info("waiting 30 seconds before trying again")
|
|
time.sleep(30)
|
|
try:
|
|
results = spotify.search(q=querystring,type='album')
|
|
except Exception as err:
|
|
logging.error("could not search on spotify again")
|
|
logging.error(err)
|
|
return found
|
|
|
|
if (len(results["albums"]["items"]) > 0):
|
|
logging.info("album found on spotify!")
|
|
found = True
|
|
album = results["albums"]["items"][0]
|
|
album_artist = album["artists"][0]["name"]
|
|
|
|
if (x.endswith(".flac")):
|
|
try:
|
|
if str(audio["album_artist"]) != album_artist:
|
|
audio["album_artist"] = album_artist
|
|
except:
|
|
audio["album_artist"] = album_artist
|
|
else:
|
|
if (str(audio["TPE2"]) != album_artist):
|
|
audio["TPE2"] = TPE2(encoding=3,text=album_artist)
|
|
|
|
album_image_url = album["images"][0]["url"]
|
|
album_name = album["name"]
|
|
|
|
if x.endswith(".flac"):
|
|
if str(audio["album"] != album_name):
|
|
audio["album"] = album_name
|
|
elif (str(audio["TALB"]) != album_name):
|
|
audio["TALB"] = TALB(encoding=3,text=album_name)
|
|
|
|
if (x.endswith(".flac")):
|
|
audio["year"] = album["release_date"]
|
|
else:
|
|
audio["TDRC"] = TDRC(encoding=3,text=album["release_date"])
|
|
|
|
artist_search = spotify.artist(album['artists'][0]['external_urls']['spotify'])
|
|
logging.info("genres: " + str(artist_search['genres']))
|
|
check_spotify_genre(artist_search['genres'],audio)
|
|
|
|
comment ="Spotify ID: {0}. Release date precision: {1}, total tracks in album: {2}. This album has {3} version(s)".format(album["id"],album["release_date_precision"], album["total_tracks"],len(results["albums"]["items"]))
|
|
logging.info("Comment: " + comment)
|
|
if x.endswith(".flac"):
|
|
audio["comment"] = comment
|
|
else:
|
|
audio["COMM"] = COMM(encoding=3,text=comment)
|
|
|
|
if x.endswith(".flac"):
|
|
remove_flac_ID3_tags(audio,x)
|
|
|
|
audio.save(x)
|
|
|
|
songpath = ""
|
|
|
|
if x.endswith(".flac"):
|
|
songpath = join(".",str(audio["artist"][0]),str(audio["album"][0]))
|
|
make_folder(join(".",str(audio["artist"][0])))
|
|
else:
|
|
if "/" in audio["TPE2"]:
|
|
audio["TPE2"] = audio["TPE2"].replace("/","")
|
|
songpath = join(".",str(audio["TPE2"]),str(audio["TALB"]))
|
|
make_folder(join(".",str(audio["TPE2"])))
|
|
|
|
|
|
|
|
if (not x.endswith(".flac")):
|
|
if ("/" in str(audio["TALB"])):
|
|
logging.info("album contains /")
|
|
folders = str(audio["TALB"]).split('/')
|
|
logging.info(folders)
|
|
pos = join(".",str(audio["TPE2"]))
|
|
for fold in folders:
|
|
make_folder(join(pos,fold))
|
|
pos = join(pos,fold)
|
|
logging.info(pos)
|
|
|
|
make_folder(songpath)
|
|
os.replace(join(".",x),join(songpath,x))
|
|
logging.info("moved song file, now downloading cover art")
|
|
|
|
img_data = requests.get(str(album_image_url)).content
|
|
with open(join(songpath,"Cover.jpg"),'wb') as handler:
|
|
handler.write(img_data)
|
|
logging.info("done getting cover art!")
|
|
|
|
logging.info("now setting cover art..")
|
|
embed_music_file(join(songpath,x),join(songpath,"Cover.jpg"))
|
|
else:
|
|
logging.info("No album found on spotify")
|
|
return found
|
|
|
|
def check_spotify_and_save(spotify, audio,x: str) -> bool:
|
|
found = False
|
|
logging.info("Searching spotify for file " + x)
|
|
artist = ""
|
|
track = ""
|
|
if x.endswith(".flac"):
|
|
if audio["artist"] is not str:
|
|
artist = str(audio["artist"][0])
|
|
else:
|
|
artist = str(audio["artist"])
|
|
if audio["title"] is not str:
|
|
track = str(audio["title"][0])
|
|
else:
|
|
track = str(audio["title"])
|
|
else:
|
|
if audio["TPE2"] is not str:
|
|
logging.info("TPE2 is not str")
|
|
artist = str(audio["TPE2"][0])
|
|
else:
|
|
artist = str(audio["TPE2"])
|
|
|
|
if audio["TIT2"] is not str:
|
|
track = str(audio["TIT2"][0])
|
|
else:
|
|
track = str(audio["TIT2"])
|
|
|
|
querystring = "artist:{0} track:{1}".format(artist.split("\00")[0],track)
|
|
logging.info("query string: " + querystring)
|
|
results = spotify.search(q=querystring,type='track')
|
|
if (len(results['tracks']['items']) > 0):
|
|
logging.info("track found on spotify!")
|
|
found = True
|
|
album = results['tracks']['items'][0]["album"]
|
|
found_artist = album["artists"][0]["name"]
|
|
if (found_artist != artist):
|
|
logging.info("Changing album artist from " + artist + " to " + found_artist)
|
|
if x.endswith(".flac"):
|
|
audio["album_artist"] = found_artist
|
|
else:
|
|
audio["TPE2"] = TPE2(encoding=3,text=found_artist)
|
|
found_album = album["name"]
|
|
if (len(found_album) > 0):
|
|
if x.endswith(".flac"):
|
|
audio["album"] = found_album
|
|
else:
|
|
audio["TALB"] = TALB(encoding=3,text=found_album)
|
|
else:
|
|
if (x.endswith(".flac")):
|
|
audio["album"] = audio["title"][0]
|
|
else:
|
|
audio["TALB"] = TALB(encoding=3,text=str(audio["TIT2"]))
|
|
|
|
comment ="Spotify ID: {0}. Release date precision: {1}, total tracks in album: {2}. This album has {3} version(s)".format(album["id"],album["release_date_precision"], album["total_tracks"],len(results["albums"]["items"]))
|
|
logging.info("Comment: " + comment)
|
|
if x.endswith(".flac"):
|
|
audio["comment"] = comment
|
|
else:
|
|
audio["COMM"] = COMM(encoding=3,text=comment)
|
|
|
|
try:
|
|
year = str(datetime.strptime(album["release_date"], '%Y-%m-%d').year)
|
|
|
|
if x.endswith(".flac"):
|
|
audio["year"] = year
|
|
else:
|
|
audio["TDRC"] = TDRC(encoding=3,text=year)
|
|
|
|
except Exception as err:
|
|
logging.info(err)
|
|
year = str(album["release_date"])
|
|
audio["year"] = year
|
|
|
|
|
|
if x.endswith(".flac"):
|
|
audio["TRACKNUMBER"] = str(results['tracks']['items'][0]["track_number"]) +"/" + str(album["total_tracks"])
|
|
else:
|
|
audio["TRCK"] = TRCK(encoding=3,text=str(results['tracks']['items'][0]["track_number"]) +"/" + str(album["total_tracks"]))
|
|
|
|
if x.endswith(".flac"):
|
|
audio["popularity"] = str(results['tracks']['items'][0]["popularity"])
|
|
else:
|
|
audio["POPM"] = POPM(encoding=3,text=str(results['tracks']['items'][0]["popularity"]))
|
|
|
|
|
|
found_image_url = album["images"][0]["url"]
|
|
logging.info("found cover art image at " + str(found_image_url))
|
|
|
|
artist_search = spotify.artist(results['tracks']['items'][0]['artists'][0]['external_urls']['spotify'])
|
|
logging.info("genres: " + str(artist_search['genres']))
|
|
check_spotify_genre(artist_search['genres'],audio)
|
|
|
|
# remove ID3 tags if it's a flac file, otherwise it will throw an error
|
|
remove_flac_ID3_tags(audio,x)
|
|
|
|
audio.save(x)
|
|
|
|
artist_path = ""
|
|
songpath = ""
|
|
if x.endswith(".flac"):
|
|
artist_path = str(audio["artist"][0])
|
|
else:
|
|
if audio["TPE2"] is not str:
|
|
artist_path = str(audio["TPE2"][0])
|
|
else:
|
|
artist_path = str(audio["TPE2"])
|
|
|
|
logging.info("artist path: " + artist_path)
|
|
if x.endswith(".flac"):
|
|
songpath = join(".",artist_path,str(audio["ALBUM"][0]))
|
|
else:
|
|
songpath = join(".",artist_path,str(audio["TALB"]))
|
|
logging.info("song path: " + songpath)
|
|
|
|
make_folder(join(".",artist_path))
|
|
|
|
if (not x.endswith(".flac") and "/" in str(audio["TALB"])):
|
|
logging.info("album contains /")
|
|
folders = str(audio["TALB"]).split('/')
|
|
logging.info(folders)
|
|
pos = join(".",str(audio["TPE2"]))
|
|
for fold in folders:
|
|
make_folder(join(pos,fold))
|
|
pos = join(pos,fold)
|
|
logging.info(pos)
|
|
|
|
make_folder(songpath)
|
|
os.replace(join(".",x),join(songpath,x))
|
|
logging.info("moved song file, now downloading cover art")
|
|
|
|
img_data = requests.get(str(found_image_url)).content
|
|
with open(join(songpath,"Cover.jpg"),'wb') as handler:
|
|
handler.write(img_data)
|
|
logging.info("done getting cover art!")
|
|
|
|
logging.info("now setting cover art..")
|
|
embed_music_file(join(songpath,x),join(songpath,"Cover.jpg"))
|
|
|
|
|
|
return found
|
|
|
|
def main():
|
|
|
|
# for spotipy to be able to log in, the environment variables SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET have to be set
|
|
# these can be obtained from the spotify developer dashboard
|
|
# they are defined in /etc/profile.d/spotipy.sh
|
|
spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials())
|
|
|
|
onlyfiles = [f for f in listdir(".") if (isfile(join(".",f)) and f.split(".")[-1] in ['mp3','mp4','ogg','wav','flac','m4a','MP3','FLAC','OGG','MP4','WAV','M4A'])]
|
|
# TIT2 = title,
|
|
# TPE1 = artist,
|
|
# TPE2 = band,
|
|
# TALB = album,
|
|
# COMM = comment,
|
|
# TCOM = composer,
|
|
# TCON = genre,
|
|
# TRCK = number,
|
|
# TDRC = year,
|
|
# TPUB = publisher
|
|
|
|
# use: audio["TRCK"] = TRCK(encoding=3, text=u'track_number') and replace the tags with appropriate values
|
|
for x in onlyfiles:
|
|
logging.info("------------------------------------------------")
|
|
logging.info(x)
|
|
|
|
# try to open tags, if the file has none, create a new ID3 object
|
|
try:
|
|
audio = mutagen.File(x)
|
|
except mutagen.mp3.HeaderNotFoundError as err:
|
|
logging.info(err)
|
|
logging.info("header not found")
|
|
audio = mutagen.File(x,easy=True)
|
|
audio.add_tags()
|
|
except mutagen.id3.ID3NoHeaderError:
|
|
logging.info("no header")
|
|
audio = mutagen.File(x,easy=True)
|
|
audio.add_tags()
|
|
except:
|
|
logging.info("opening as ID3")
|
|
audio = ID3(x)
|
|
audio.add_tags()
|
|
|
|
logging.info(type(audio))
|
|
try:
|
|
if (audio.tags == None):
|
|
logging.info("audio has no tags")
|
|
audio.add_tags()
|
|
except:
|
|
pass
|
|
|
|
has_valid_artist = check_artist(audio,x)
|
|
has_valid_album = check_tag(audio,x,"TALB","album")
|
|
has_valid_title = check_tag(audio,x,"TIT2","title")
|
|
if (has_valid_title):
|
|
if x.endswith(".flac"):
|
|
logging.info("Found valid title in title tag: " + str(audio["TITLE"]))
|
|
if audio["TITLE"] is not str:
|
|
check_title_songname(audio["TITLE"][0],audio)
|
|
else:
|
|
check_title_songname(audio["TITLE"],audio)
|
|
else:
|
|
logging.info("Found valid title in TTI2 tag: " + str(audio["TIT2"]) + ". type: " + str(type(audio["TIT2"])))
|
|
if not isinstance(audio["TIT2"], str):
|
|
if (isinstance(audio["TIT2"][0], str)):
|
|
check_title_songname(audio["TIT2"][0],audio)
|
|
else:
|
|
logging.info(type(audio["TIT2"][0]))
|
|
check_title_songname(audio["TIT2"][0].text[0],audio)
|
|
else:
|
|
check_title_songname(audio["TIT2"].text[0],audio)
|
|
else:
|
|
logging.info("No valid title found in TTI2 tag, using name " + x)
|
|
check_title_songname(x,audio)
|
|
has_valid_title = True
|
|
|
|
if (has_valid_artist == False):
|
|
logging.info("No valid artist found, checking for artist by songname of the file (" + x + ")")
|
|
if (" - " in x):
|
|
check_artist_songname(x, audio)
|
|
has_valid_artist = True
|
|
|
|
if (has_valid_artist == False and has_valid_title):
|
|
logging.info("No valid artist found but valid title found, checking for multiple artists")
|
|
check_for_multiple_artists(audio,x,str(audio["TIT2"]))
|
|
has_valid_artist = check_artist(audio, x) # check again
|
|
|
|
check_tag(audio,x,"COMM","comment")
|
|
check_tag(audio,x,"TCOM","composer")
|
|
|
|
has_genre = check_tag(audio,x,"TCON","genre")
|
|
if (has_genre):
|
|
if x.endswith(".flac"):
|
|
audio["genre"] = str(audio["genre"]).replace(" & ",",")
|
|
else:
|
|
audio["TCON"] = TCON(encoding=3, text=str(audio["TCON"]).replace(" & ",",")) # convert genres like Hip-Hop & Rap to Hip-Hop,Rap
|
|
|
|
check_tag(audio,x,"TRCK","track")
|
|
check_tag(audio,x,"TDRC","year")
|
|
check_tag(audio,x,"TPUB","publisher")
|
|
|
|
if (has_valid_artist and has_valid_title):
|
|
found = False
|
|
try:
|
|
found = check_spotify_and_save(spotify, audio,x)
|
|
except Exception as err:
|
|
logging.error("could not find track on spotify: " + str(err))
|
|
found = False
|
|
|
|
if (found == False):
|
|
if (x.endswith(".flac")):
|
|
logging.info("valid artist found. making folder for artist " + str(audio["artist"][0]))
|
|
make_folder(join(".",str(audio["artist"][0])))
|
|
else:
|
|
logging.info("valid artist found. making folder for artist " + str(audio["TPE1"]))
|
|
if "/" in audio["TPE2"]:
|
|
audio["TPE2"] = audio["TPE2"].replace("/","")
|
|
make_folder(join(".",str(audio["TPE2"])))
|
|
|
|
if (has_valid_album):
|
|
if (x.endswith(".flac")):
|
|
make_folder(join(".",str(audio["artist"][0]),str(audio["album"][0])))
|
|
else:
|
|
make_folder(join(".",str(audio["TPE2"]),str(audio["TALB"])))
|
|
|
|
logging.info("spotify did not find artist and track, searching for album...")
|
|
if (has_valid_album):
|
|
album_found = check_spotify_album_and_save(spotify,audio,x)
|
|
if (album_found == False):
|
|
logging.info("Nothing found on spotify, searching Google Images...")
|
|
search_google_images_and_save(x, audio)
|
|
else:
|
|
if x.endswith(".flac"):
|
|
audio["album"] = audio["title"][0]
|
|
else:
|
|
audio["TALB"] = TALB(encoding=3,text=str(audio["TIT2"]))
|
|
search_google_images_and_save(x, audio)
|
|
|
|
logging.info("------------------------------------------------")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|