These functions pickle out the entire tag map onto disk. I also add a
stress test for the entire tags module that scans tracks using the
threadqueue, since that's how I intend everything to be used.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
There are cases, mostly during testing, where we might want to check if
a file exists or to remove it if it does. Let's add those functions
now so we can use them.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I've decided that it would work best if Album and Track classes both
inherit from the same parent class. This will give them some
functionality overlap, and it'll also make it conceptually easier to
store them both in the same tag dictionary.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We'll use this for scanning tracks, searching musicbrainz, and fetching
album art. The web services are ratelimited, so it doesn't make sense to
use more than one thread in this case. Additionally, scanning tracks
works best as a single thread since we end up holding a lock the entire
function anyway to prevent duplicates.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Now that we have the DataFile class we can remove this function as its
main use is now hidden from users.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This gives us a convenient way to handle saved data. We use the 'with'
statment to handle any errors without crashing.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I added a make target for code coverage, and used that to identify code
that isn't getting run.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I think it makes sense to do this transparently through the Track code
so higher layers don't have to do as much work. We'll just return a
Future-object corresponding to the track that will be added.
It makes sense to only have one thread in this case, since __add() needs
exclusive access to the track_list for its entire execution. Anything
more would just create conflicts and actually increase execution time.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
It's useful to have a way to override where data gets placed in the
filesystem so we don't accidentally clobber production data with test
data while running tests.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I'm planning to use the asyncio code for running background threads, so
let's switch to it for now to get a feel for how it works.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We'll use this for scanning and updating the library later. For now,
just keep everything in a list and do a uniqueness test whenever
something new is added.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We account for some fallback values, and also attempt to detect
discnumbers from the album name.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We want to be able to pull out just the album name to make a more
accurate musicbrainz search, and so multiple discs link to the same
album object.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We want to share album objects whenever possible, so add a lookup
function for checking this. Python built-in objects (like dictionaries)
are supposedly threadsafe, so we don't need a lock to access them but I
added the threadpool test anyway just in case.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We'll eventually pull out all the fields we need from a Mutagen
FileInfo class, but that has a dictionary-like interface so we can
easily fake one up for testing.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>