This includes both creating new Tracks and updating existing Tracks when
their tags have changed. New tracks are added to playlists using
idle=True so Gtk can spread out UI updates for each playlist so we don't
slow things down too much for the user.
This patch also adds a library argument to the Tagger thread
get_result() function which we pass to the Tagger class to be used by
Tracks.creat(). I also add an mtime argument to the Tagger thread
tag_file() function to pass down to the audio.tagger layer so we can
skip updating tracks that have not changed since the last scan.
Implements: #41 (Check for new or modified tags during startup)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I expand on the libraries_view to include additional playlist
properties, and configure the default sort order to sort by filepath.
I then set up the library_tracks_view to make it easy to select tracks
that belong to a specific Library.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I expand on the years_view to include additional playlist properties,
and configure the default sort order to stort by release date first.
I then set up the year_tracks_view to make it easy to select tracks that
belong to a specific year.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I expand on the decades_view to include additional playlist properties,
and configure the default sort order to sort by year first.
I then set up the decade_tracks_view to make it easy to select tracks
that belong to a specific decade.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I expand on the genres_view to include additional playlist properties,
and configure the default sort order to sort by artist, album, and track
number.
I then configure the Genres table to use the system_tracks table to
manage each genre's associated tracks and set up the genre_tracks_view
to make it easy for Tracks to find their Genres.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I expand on the media_view to include additional playlist properties,
and configure the default sort order to sort by track number.
I then set up the medium_tracks_view to make it easy to select tracks
that belong to a specific medium.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I expand on the albums_view to include additional playlist properties,
and configure the default sort order to sort by track numbers in an
intuitive way.
I then set up the album_tracks_view to make it easy to select tracks
that belong to a specific album.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I expand on the artists_view to include additional playlist properties,
and configure the default sort_order to sort albums in an intuitive way.
I then configure the Artists table to us the system_tracks table to
manage each artist's associated tracks and set up the artist_tracks_view
to make it easy for Tracks to find their Artists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I need to do something slightly different for each Playlist.
* Collection: I load tracks from the collection_view, which filters
tracks to those where the library is enabled but not deleting.
* Favorite Tracks: I load tracks from the favorites_view, which filters
tracks based on the tracks.favorite and library.deleting column.
* Most Played Tracks: I load tracks with a playcount greater than the
average playcount of all tracks (rounded up to the nearest integer).
* New Tracks: I load tracks that have been added within the last week.
* Previous Tracks: I load tracks that have been played since startup
using the system_tracks table. I take care to clear these entries
in the table during startup.
* Queued Tracks: Load tracks from the user_tracks table.
* Unplayed Tracks: I load tracks with a playcount equal to 0 and remove
when they are played.
* User-Defined Playlists: Load tracks from the track_playlist_link
table.
Additionally, I implement move_track_up() and move_track_down() support
for user playlists and queued tracks.
Finally, I update the have-next-track property to take into account if
the Collection has tracks too.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I need to do something slightly different for each system Playlist:
* Collection: I disallow setting loop to "None".
* Favorite Tracks: I set the user-tracks property to "True"
* Most Played Tracks: I add playcount as the first sort field.
* Previous Tracks: I disallow changing loop, shuffle, and sort-order.
* Queued Tracks: I set the user-tracks and tracks-movable properties to "True"
User created playlists also set the user-tracks and tracks-movable
properties to "True". I also disable autodelete on the Table so
playlists aren't deleted unexpectedly.
New Tracks and Unplayed Tracks have no special properties set.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
* loop is based on the mpris loop property, and can be set to "None",
"Track", or "Playlist".
* shuffle is a boolean True / False value.
* sort-order saves a user-configured sort order for each playlist.
* current-trackid is an integer referring to the trackid of the currently
playing track.
* user-tracks: is a boolean representing if the user should be allowed
to manually add and remove tracks.
I also use the sort-order property to implement a get_track_order()
function to get the sort keys for tracks in a Playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I implement add_track(), get_trackids(), and remove_track() functions that
either modify the 'system_playlist_tracks' table or call a virtual function
depending on the value of the 'system-tracks' property.
I also add the "autodelete" property. When set to True, Playlists will
be deleted when they have 0 tracks remaining.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Playlists use a tracks.TrackidSet to manage a set of trackids
representing the Tracks in this Playlist.
I have two functions for loading tracks: load_tracks() and
reload_tracks(). Calling load_tracks() checks if the tracks have been
loaded first before doing any work, but calling reload_tracks() will
force the Playlist to go to the database to load the latest tracks.
Finally, I add a have-next-track property to the main database
connection. This is set to True whenever the active playlist has one or
more tracks.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The TrackidSet is intened to be used by Playlists to keep track of which
Tracks have been added without much overhead.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This includes the favorite status, playcount, last played timestamp, and
last started timestamp. These values will be restored if a Track with
the same mbid is created at a later time.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This patch adds extra handling for changing the value of the
Track:favorite property, if the Track is the current track. This lets us
have the Now Playing card bind to the current-favorite property to
update the UI (and have the UI update the Track).
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Tracks now have start(), stop(), and restart() functions that can be
used by the application to update the laststarted, lastplayed,
playcount, active, and restarted properties.
The track Table implements their half of these functions in addition to
a mark_path_active() function so opening Emmental with a filepath can
update the current track before the database is loaded. The Table also
adjusts the necessary system playlists when tracks are marked as played.
Finally, the Table now has have-current-track and current-track
properties that can be wired up to the Now Playing card.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The Track Table does all the work for saving, loading, and managing
Track objects. I also create a SQLite View to link tracks to their
associated artists, albums, and mediums.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The Track object represents a single track in the Library along with all
their corresponding metadata.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I extract the artist, length, mbid, mtime, tracknumber, and title from
the tags to use when constructing Tracks.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I am going to use this to determine if a track has been played or not.
Gstreamer resets the clock when seeking, so I do some extra work to save
the play time just before seeking and add it back later.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This section shows a list of library path playlists. I also add an extra
widget that opens a Gtk.FileDialogso users can add music to their
collections.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This section shows a tree of Decade and Year playlists. I use the
year-alt icon from the gnome icon-library as the section header.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This section uses the default Row for displaying genre playlists. I use
the theater icon from the gnome icon-library as the section header.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I make sure to save the "show-all" property to the settings so it can be
preserved across sessions.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This section shows a tree of Artist and Album playlists. I use the
library-artists icon from the gnome icon-library as the section header,
and the music-artist / music-artist2 icons for the "show all" button to
indicate state..
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I created a section Group with this section as the only member for now, and
bind the "selected-playlist" property to the sidebar.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This section creates PlaylistRows for displaying user and system
playlists. We also hook into the database playlist table to provide a
way to create new playlists. I add several new icons from the
icon-library to use for the section header and playlists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This group manages a list of sections so only one is active at a time.
Additionally, it adjusts the animation property of each section to match
the direction the header moves when activated.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This class combines a header with an initially hidden ListView that can
be configured to list our playlists. It also implements
"playlist-activated" and "playlist-selected" signals to signal user
interaction.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The TreeRow is a factory.TreeRow configured for binding playlists to a
child widget. Individual sections are expected to inherit from this to
set up their section-specific widgets and bind any extra properties.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is a preconfigured row for displaying library paths. It includes a
switch to enable & disable the path, buttons for removing and updating a
path, and a progress bar for displaying scan progress.
I use the "update-symbolic" and "stop-sign-large-symbolic" icons from
the gnome icon library for this widget.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This row is configured for showing user and system playlists. This means
we use a SettableIcon, and EditableTitle, and an extra button for
deleting playlists. I use the big-x-symbolic icon from the gnome icon
library for deleting playlists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is a basic Row widget with an Icon as a prefix widget, and no
postfix widget. You can set the "year" property to set a year value to
the icon text.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is intended to be used as a base class for our playlist Row
widgets, and sets up some common variables needed by both.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This will be used to display different types of playlists in the
sidebar, such as artist or genre. It also has a revealer that shows its
child when the header is active.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This widget allows users to change the displayed image by selecting a
new one from the filesystem.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This widget sets the Title::subtitle property to a nicely formatted
string based on the number set to the 'count' property.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The TreeRow is used to display rows from a Gtk.TreeListModel. I adjust
the TreeRow "item" and "child" properties so they still access the
underlying item or child widget instead of the Gtk.TreeRow or
Gtk.TreeExpander.
I also give the TreeRow widget "n-children" and "have-children" properties
which are used to dynamically show or hide the expander arrow when there
aren't any children.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
It only contains a FilterEntry for filtering future playlists. The
application will save its size when resized.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>