This lets me control size and justification of the text. Additionally, I
put everything into a scrolled window just in case a track has a really
long title name.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I switch around the sidebar icons again, and also make the header bar
icons larger to make them easier to press with touchscreens
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Library paths are directories on disk, so it makes sense to use the
folder-music icon to represent them.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I'll eventually make this more complex when I add in more playlists, but
for now it just calls next on the Collection playlist
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Converting between a TreeIter and a playlist is very useful, so
implement that functionality now.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Some tracks in my library aren't formatted as expected, so let's improve
our parsing code to better handle integers.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is a special tree model that translates our Playlist object into a
format that GTK understands.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I was having trouble with bound methods when using notifications, since
all empty playlists were getting identified as the same empty list
object. Removing the inheritance fixes the problem.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This represents all tracks added to the collection, from across all
library paths. We also fix the value of Playlist.loop to "True" and
prevent changing it
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This makes removing tracks from playlists way easier, since there is
only ever one instance of the track.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We want to make sure we get the expected results when calling next() on
empty playlists and with playlists that only have one track.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I try to prevent the same track from getting selected twice in a row by
incrementing the current pointer rather than setting it directly, and
reducing the random range slightly.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Now that we have a "new-track" notification, we can replace the add
function with a lookup function that more closely mirrors how we look up
album tags.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We might want to use these outside of the playlist code, so let's move
this to a generic place so it can be easily used.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The slash in the filepath was being intepreted as a subdirectory, so
let's change it into an underscore so everything is where we expect.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This replaces the code in playlist/__init__.py and turns it into a
class. This should make things easier to handle during testing, since we
can easily tear down the old instance and create a new one.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I expect this will mostly get used by testing code as we create and
delete a bunch of different objects.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is mostly needed by the UI but there are a few cases where we
might need it internally, such as adding newly creating tracks to all
the required playlists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This playlist represents all tracks in a given subdirectory, and is how
we control adding or removing tracks.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The intention is that different playlist types will create a subclass of
this class to do whatever work they need.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This lets us convert string fields into the corresponding track tag. I
intend to use this so playlists can have a custom sort function.
I eventually intend to add the matching __setitem__() function for
changing tags.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I'll eventually need to be able to run everything as a single
application, so let's prepare for that now. This gives us a chance to
get the imports right from the start, rather than needing to go through
and fix things up again.
I also add a test to make sure everything works as expected.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
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>