84 lines
2.8 KiB
Python
84 lines
2.8 KiB
Python
# Copyright 2019 (c) Anna Schumaker.
|
|
from . import data
|
|
from . import notify
|
|
import mutagen
|
|
import os
|
|
import re
|
|
|
|
discno_map = { "one" : "1", "two" : "2", "three" : "3", "four" : "4", "five" : "5" }
|
|
tag_map = dict()
|
|
|
|
class Tag:
|
|
def extract(info, key, default):
|
|
return info.get(key, [ default ])[0]
|
|
|
|
def lookup(tag, cb):
|
|
ret = tag_map.setdefault(hash(tag), tag)
|
|
if ret == tag:
|
|
notify.Notify.notify(cb, ret)
|
|
return ret
|
|
|
|
|
|
class Album(Tag):
|
|
def __init__(self, info):
|
|
self.album = Tag.extract(info, "album", "Unknown Album")
|
|
self.genre = Tag.extract(info, "genre", "Unknown")
|
|
self.date = int(Tag.extract(info, "date", 0))
|
|
self.tracktotal = int(Tag.extract(info, "tracktotal", 0))
|
|
self.albumartist = Tag.extract(info, "albumartist",
|
|
Tag.extract(info, "album artist",
|
|
Tag.extract(info, "artist", "Unknown Artist")))
|
|
|
|
# Try to detect album names that have a discnumber embedded in them
|
|
match = re.search("(cd|dis[c|k])(\s)*(([0-9]+)|one|two|three|four|five)", self.album.lower())
|
|
if match and match.start() > 0:
|
|
self.album = self.album[:match.start()].strip(" ;({[-")
|
|
|
|
def __hash__(self):
|
|
return hash((self.album, self.albumartist, self.date))
|
|
|
|
def lookup(info):
|
|
return Tag.lookup(Album(info), "new-album")
|
|
|
|
|
|
class Track(Tag):
|
|
def __init__(self, path):
|
|
info = mutagen.File(path)
|
|
|
|
self.path = path
|
|
self.title = Tag.extract(info, "title", os.path.basename(path))
|
|
self.artist = Tag.extract(info, "artist", "Unknown Artist")
|
|
self.tracknumber = int(Tag.extract(info, "tracknumber", 0))
|
|
self.discnumber = int(Tag.extract(info, "discnumber", 1))
|
|
self.length = info.info.length
|
|
self.album = Album.lookup(info)
|
|
|
|
# Try to detect discnumbers that are embedded in the album name
|
|
discno = Tag.extract(info, "album", "Unknown Album")[len(self.album.album):]
|
|
match = re.search("([1-9][0-9]*)|one|two|three|four|five", discno.lower())
|
|
if match:
|
|
self.discnumber = int(discno_map.get(match.group(), match.group()))
|
|
|
|
def __getitem__(self, key):
|
|
item = vars(self).get(key)
|
|
if not item or item == self.album:
|
|
item = vars(self.album).get(key)
|
|
return item
|
|
|
|
def __hash__(self):
|
|
return hash((hash(self.album), self.title, self.artist,
|
|
self.tracknumber, self.discnumber))
|
|
|
|
def add(path):
|
|
track = Track(path)
|
|
return track if Tag.lookup(track, "new-track") == track else None
|
|
|
|
|
|
def save():
|
|
with data.DataFile("tags.pickle", data.WRITE) as f:
|
|
f.pickle(tag_map)
|
|
|
|
def load():
|
|
with data.DataFile("tags.pickle", data.READ) as f:
|
|
tag_map.update(f.unpickle())
|