curds: Add a Track Tag class
This is similar to the Album tag and stores its data in the same dictionary. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
04ac4398e2
commit
60f56ba3b7
|
@ -1,7 +1,10 @@
|
|||
# Copyright 2019 (c) Anna Schumaker.
|
||||
import mutagen
|
||||
import os
|
||||
import re
|
||||
|
||||
tag_map = dict()
|
||||
discno_map = { "one" : "1", "two" : "2", "three" : "3", "four" : "4", "five" : "5" }
|
||||
tag_map = dict()
|
||||
|
||||
class Tag:
|
||||
def extract(info, key, default):
|
||||
|
@ -32,3 +35,29 @@ class Album(Tag):
|
|||
def lookup(info):
|
||||
return Tag.lookup(Album(info))
|
||||
|
||||
|
||||
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 __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) == track else None
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
# Copyright 2019 (c) Anna Schumaker.
|
||||
import os
|
||||
import tags
|
||||
import unittest
|
||||
|
||||
test_tracks = os.path.abspath("./trier/Test Album")
|
||||
|
||||
class TestTrackTag(unittest.TestCase):
|
||||
def test_track_init_basic(self):
|
||||
p = [ test_tracks, "01 - Test Track.ogg" ]
|
||||
t = tags.Track(os.path.join(*p))
|
||||
self.assertIsInstance(t, tags.Tag)
|
||||
self.assertEqual(t.path, os.path.join(*p))
|
||||
self.assertEqual(t.title, "Test Track")
|
||||
self.assertEqual(t.artist, "Test Artist")
|
||||
self.assertEqual(t.tracknumber, 1)
|
||||
self.assertEqual(t.discnumber, 1)
|
||||
self.assertEqual(t.length, 10)
|
||||
self.assertEqual(t.album.album, "Test Album")
|
||||
self.assertEqual(t.album.date, 2019)
|
||||
self.assertEqual(t.album.genre, "Test")
|
||||
self.assertEqual(t.album.albumartist, "Test Artist")
|
||||
self.assertEqual(hash(t), hash((hash(t.album), "Test Track", "Test Artist", 1, 1)))
|
||||
|
||||
def test_track_init_empty(self):
|
||||
p = [ test_tracks, "00 - Empty Track.ogg" ]
|
||||
t = tags.Track(os.path.join(*p))
|
||||
self.assertIsInstance(t, tags.Tag)
|
||||
self.assertEqual(t.path, os.path.join(*p))
|
||||
self.assertEqual(t.title, "00 - Empty Track.ogg")
|
||||
self.assertEqual(t.artist, "Unknown Artist")
|
||||
self.assertEqual(t.tracknumber, 0)
|
||||
self.assertEqual(t.length, 0)
|
||||
self.assertEqual(t.discnumber, 1)
|
||||
self.assertEqual(t.album.album, "Unknown Album")
|
||||
self.assertEqual(t.album.date, 0)
|
||||
self.assertEqual(t.album.genre, "Unknown")
|
||||
self.assertEqual(t.album.albumartist, "Unknown Artist")
|
||||
self.assertEqual(hash(t), hash((hash(t.album), "00 - Empty Track.ogg", "Unknown Artist", 0, 1)))
|
||||
|
||||
def test_track_discno_detect(self):
|
||||
join = os.path.join
|
||||
self.assertEqual(tags.Track(join(test_tracks, "02 - Test {Disc 2}.ogg")).discnumber, 2)
|
||||
self.assertEqual(tags.Track(join(test_tracks, "03 - Test [Disk One].ogg")).discnumber, 1)
|
||||
self.assertEqual(tags.Track(join(test_tracks, "04 - Test (Disc Two).ogg")).discnumber, 2)
|
||||
self.assertEqual(tags.Track(join(test_tracks, "05 - Test - Disc Three.ogg")).discnumber, 3)
|
||||
self.assertEqual(tags.Track(join(test_tracks, "06 - Test;CD Four.ogg")).discnumber, 4)
|
||||
self.assertEqual(tags.Track(join(test_tracks, "07 - Test;CdFive.ogg")).discnumber, 5)
|
||||
self.assertEqual(tags.Track(join(test_tracks, "08 - Test CD 6/10.ogg")).discnumber, 6)
|
||||
self.assertEqual(tags.Track(join(test_tracks, "09 - Test {Disc 02}.ogg")).discnumber, 2)
|
||||
self.assertEqual(tags.Track(join(test_tracks, "10 - Test {Disc 20}.ogg")).discnumber, 20)
|
||||
|
||||
def test_track_add(self):
|
||||
tags.tag_map.clear()
|
||||
t = tags.Track.add(os.path.join(test_tracks, "01 - Test Track.ogg"))
|
||||
self.assertIsNotNone(t)
|
||||
self.assertIn(t, tags.tag_map.values())
|
||||
self.assertIn(t.album, tags.tag_map.values())
|
||||
|
||||
for i in range(10):
|
||||
u = tags.Track.add(os.path.join(test_tracks, "01 - Test Track.ogg"))
|
||||
self.assertIsNone(u)
|
||||
self.assertEqual(len(tags.tag_map), 2)
|
|
@ -1,94 +0,0 @@
|
|||
# Copyright 2019 (c) Anna Schumaker.
|
||||
import concurrent.futures
|
||||
import mutagen
|
||||
import os
|
||||
import track
|
||||
import unittest
|
||||
|
||||
test_tracks = os.path.abspath("./trier/Test Album")
|
||||
test_library = os.path.abspath("./trier/Test Library")
|
||||
|
||||
class TestTrackClass(unittest.TestCase):
|
||||
def setUp(self):
|
||||
track.track_list.clear()
|
||||
|
||||
def test_init_basic(self):
|
||||
p = [ test_tracks, "01 - Test Track.ogg" ]
|
||||
t = track.Track(os.path.join(*p))
|
||||
self.assertEqual(t.path, os.path.join(*p))
|
||||
self.assertEqual(t.title, "Test Track")
|
||||
self.assertEqual(t.artist, "Test Artist")
|
||||
self.assertEqual(t.tracknumber, 1)
|
||||
self.assertEqual(t.length, 10)
|
||||
self.assertEqual(t.discnumber, 1)
|
||||
self.assertEqual(t.album.album, "Test Album")
|
||||
self.assertEqual(t.album.date, 2019)
|
||||
self.assertEqual(t.album.genre, "Test")
|
||||
self.assertEqual(t.album.albumartist, "Test Artist")
|
||||
self.assertEqual(len(track.track_list), 0)
|
||||
|
||||
def test_init_empty(self):
|
||||
p = [ test_tracks, "00 - Empty Track.ogg" ]
|
||||
t = track.Track(os.path.join(*p))
|
||||
self.assertEqual(t.path, os.path.join(*p))
|
||||
self.assertEqual(t.title, "00 - Empty Track.ogg")
|
||||
self.assertEqual(t.artist, "Unknown Artist")
|
||||
self.assertEqual(t.tracknumber , 0)
|
||||
self.assertEqual(t.length, 0)
|
||||
self.assertEqual(t.discnumber, 1)
|
||||
self.assertEqual(t.album.album, "Unknown Album")
|
||||
self.assertEqual(t.album.date, 0)
|
||||
self.assertEqual(t.album.genre, "Unknown")
|
||||
self.assertEqual(t.album.albumartist, "Unknown Artist")
|
||||
self.assertEqual(len(track.track_list), 0)
|
||||
|
||||
def test_init_discno_detect(self):
|
||||
join = os.path.join
|
||||
self.assertEqual(track.Track(join(test_tracks, "02 - Test {Disc 2}.ogg")).discnumber, 2)
|
||||
self.assertEqual(track.Track(join(test_tracks, "03 - Test [Disk One].ogg")).discnumber, 1)
|
||||
self.assertEqual(track.Track(join(test_tracks, "04 - Test (Disc Two).ogg")).discnumber, 2)
|
||||
self.assertEqual(track.Track(join(test_tracks, "05 - Test - Disc Three.ogg")).discnumber, 3)
|
||||
self.assertEqual(track.Track(join(test_tracks, "06 - Test;CD Four.ogg")).discnumber, 4)
|
||||
self.assertEqual(track.Track(join(test_tracks, "07 - Test;CdFive.ogg")).discnumber, 5)
|
||||
self.assertEqual(track.Track(join(test_tracks, "08 - Test CD 6/10.ogg")).discnumber, 6)
|
||||
self.assertEqual(track.Track(join(test_tracks, "09 - Test {Disc 02}.ogg")).discnumber, 2)
|
||||
self.assertEqual(track.Track(join(test_tracks, "10 - Test {Disc 20}.ogg")).discnumber, 20)
|
||||
|
||||
def test_track_add(self):
|
||||
fs = track.add(os.path.join(test_tracks, "01 - Test Track.ogg"))
|
||||
self.assertEqual(len(track.track_list), 0)
|
||||
t = fs.result()
|
||||
self.assertIsNotNone(t)
|
||||
self.assertEqual(len(track.track_list), 1)
|
||||
self.assertIn(t, track.track_list)
|
||||
|
||||
self.assertIsNone(track.add(os.path.join(test_tracks, "01 - Test Track.ogg")).result())
|
||||
self.assertEqual(len(track.track_list), 1)
|
||||
self.assertIsNone(track.add("99 - No Such Track.ogg").result())
|
||||
self.assertEqual(len(track.track_list), 1)
|
||||
|
||||
fs = track.add(os.path.join(test_tracks, "02 - Test {Disc 2}.ogg"))
|
||||
u = fs.result()
|
||||
self.assertIsNotNone(u)
|
||||
self.assertEqual(len(track.track_list), 2)
|
||||
self.assertIn(u, track.track_list)
|
||||
|
||||
def test_parallel_add(self):
|
||||
count = 0
|
||||
futures = [ ]
|
||||
done = [ ]
|
||||
none = [ ]
|
||||
for dirname, subdirs, files in os.walk(test_library):
|
||||
for f in files:
|
||||
futures.append(track.add(os.path.join(dirname, f)))
|
||||
futures.append(track.add(os.path.join(dirname, f)))
|
||||
count += 1
|
||||
self.assertLess(len(track.track_list), count)
|
||||
for fs in concurrent.futures.as_completed(futures):
|
||||
if fs.result() is not None:
|
||||
done.append(fs.result())
|
||||
else:
|
||||
none.append(fs.result())
|
||||
self.assertEqual(len(done), count)
|
||||
self.assertEqual(len(none), count)
|
||||
self.assertEqual(len(track.track_list), count)
|
|
@ -1,41 +0,0 @@
|
|||
# Copyright 2019 (c) Anna Schumaker.
|
||||
import tags
|
||||
import concurrent.futures
|
||||
import mutagen
|
||||
import os
|
||||
import re
|
||||
|
||||
discno_map = { "one" : "1", "two" : "2", "three" : "3", "four" : "4", "five" : "5" }
|
||||
track_list = [ ]
|
||||
track_pool = concurrent.futures.ThreadPoolExecutor(max_workers = 1)
|
||||
|
||||
class Track:
|
||||
def __init__(self, path):
|
||||
fileinfo = mutagen.File(path)
|
||||
|
||||
self.path = path
|
||||
self.title = fileinfo.get("title", [os.path.basename(path)])[0]
|
||||
self.artist = fileinfo.get("artist", ["Unknown Artist"])[0]
|
||||
self.tracknumber = int(fileinfo.get("tracknumber", ["0"])[0])
|
||||
self.length = fileinfo.info.length
|
||||
self.album = tags.Album.lookup(fileinfo)
|
||||
self.discnumber = int(fileinfo.get("discnumber", ["1"])[0])
|
||||
|
||||
# Try to detect discnumbers that are embedded in the album name
|
||||
discno = fileinfo.get("album", ["Unknown Album"])[0][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 __add(path):
|
||||
try:
|
||||
if not any(t.path == path for t in track_list):
|
||||
track = Track(path)
|
||||
track_list.append(track)
|
||||
return track
|
||||
except mutagen.MutagenError:
|
||||
return None
|
||||
|
||||
def add(path):
|
||||
return track_pool.submit(__add, path)
|
Loading…
Reference in New Issue