2021-02-16 17:15:10 +02:00
/* album.c
*
* Copyright 2021 Joshua Strobl
*
* Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
# include <glib-2.0/glib.h>
# include <magic.h>
2021-03-02 19:12:12 +02:00
# include <sqlite3.h>
2021-02-16 17:15:10 +02:00
# include <stdio.h>
2021-03-23 19:50:09 +02:00
# include "../db/cartographer.h"
2021-06-22 16:48:13 +03:00
# include "../db/db.h"
2021-03-10 13:44:08 +02:00
# include "../playlist/current.h"
# include "../playlist/playlist.h"
2021-06-22 16:48:13 +03:00
# include "../koto-utils.h"
2021-03-02 19:12:12 +02:00
# include "structs.h"
2021-06-22 16:48:13 +03:00
# include "track-helpers.h"
2021-02-16 17:15:10 +02:00
2021-05-11 20:05:04 +03:00
extern KotoCartographer * koto_maps ;
extern KotoCurrentPlaylist * current_playlist ;
2021-06-22 16:48:13 +03:00
extern magic_t magic_cookie ;
2021-05-11 20:05:04 +03:00
extern sqlite3 * koto_db ;
2021-03-02 19:12:12 +02:00
2021-06-22 16:48:13 +03:00
enum {
PROP_0 ,
PROP_UUID ,
PROP_DO_INITIAL_INDEX ,
PROP_ALBUM_NAME ,
PROP_ART_PATH ,
PROP_ARTIST_UUID ,
2021-07-08 18:37:52 +03:00
PROP_ALBUM_PREPARED_GENRES ,
2021-06-22 16:48:13 +03:00
N_PROPERTIES
} ;
static GParamSpec * props [ N_PROPERTIES ] = {
NULL ,
} ;
enum {
SIGNAL_TRACK_ADDED ,
SIGNAL_TRACK_REMOVED ,
N_SIGNALS
} ;
static guint album_signals [ N_SIGNALS ] = {
0
} ;
2021-05-11 20:08:39 +03:00
struct _KotoAlbum {
2021-02-16 17:15:10 +02:00
GObject parent_instance ;
2021-05-11 20:05:04 +03:00
gchar * uuid ;
2021-02-16 17:15:10 +02:00
2021-05-11 20:05:04 +03:00
gchar * name ;
gchar * art_path ;
gchar * artist_uuid ;
2021-06-22 16:48:13 +03:00
2021-07-08 18:37:52 +03:00
GList * genres ;
2021-05-11 20:05:04 +03:00
GList * tracks ;
2021-06-22 16:48:13 +03:00
GHashTable * paths ;
2021-02-16 17:15:10 +02:00
gboolean has_album_art ;
2021-03-02 19:12:12 +02:00
gboolean do_initial_index ;
2021-02-16 17:15:10 +02:00
} ;
2021-06-22 16:48:13 +03:00
struct _KotoAlbumClass {
GObjectClass parent_class ;
2021-02-16 17:15:10 +02:00
2021-06-22 16:48:13 +03:00
void ( * track_added ) (
KotoAlbum * album ,
KotoTrack * track
) ;
void ( * track_removed ) (
KotoAlbum * album ,
KotoTrack * track
) ;
2021-02-16 17:15:10 +02:00
} ;
2021-06-22 16:48:13 +03:00
G_DEFINE_TYPE ( KotoAlbum , koto_album , G_TYPE_OBJECT ) ;
2021-05-11 20:05:04 +03:00
2021-05-11 20:08:39 +03:00
static void koto_album_get_property (
2021-05-11 20:05:04 +03:00
GObject * obj ,
guint prop_id ,
GValue * val ,
GParamSpec * spec
) ;
2021-05-11 20:08:39 +03:00
static void koto_album_set_property (
2021-05-11 20:05:04 +03:00
GObject * obj ,
guint prop_id ,
const GValue * val ,
GParamSpec * spec
) ;
2021-05-11 20:08:39 +03:00
static void koto_album_class_init ( KotoAlbumClass * c ) {
2021-05-11 20:05:04 +03:00
GObjectClass * gobject_class ;
2021-02-16 17:15:10 +02:00
gobject_class = G_OBJECT_CLASS ( c ) ;
2021-05-11 20:08:39 +03:00
gobject_class - > set_property = koto_album_set_property ;
gobject_class - > get_property = koto_album_get_property ;
2021-02-16 17:15:10 +02:00
2021-03-02 19:12:12 +02:00
props [ PROP_UUID ] = g_param_spec_string (
" uuid " ,
" UUID to Album in database " ,
" UUID to Album in database " ,
NULL ,
2021-05-11 20:05:04 +03:00
G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE
2021-03-02 19:12:12 +02:00
) ;
props [ PROP_DO_INITIAL_INDEX ] = g_param_spec_boolean (
" do-initial-index " ,
" Do an initial indexing operating instead of pulling from the database " ,
" Do an initial indexing operating instead of pulling from the database " ,
FALSE ,
2021-05-11 20:05:04 +03:00
G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE
2021-03-02 19:12:12 +02:00
) ;
2021-02-16 17:15:10 +02:00
props [ PROP_ALBUM_NAME ] = g_param_spec_string (
" name " ,
" Name " ,
" Name of Album " ,
NULL ,
2021-05-11 20:05:04 +03:00
G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE
2021-02-16 17:15:10 +02:00
) ;
props [ PROP_ART_PATH ] = g_param_spec_string (
" art-path " ,
" Path to Artwork " ,
" Path to Artwork " ,
NULL ,
2021-05-11 20:05:04 +03:00
G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE
2021-02-16 17:15:10 +02:00
) ;
2021-03-23 19:50:09 +02:00
props [ PROP_ARTIST_UUID ] = g_param_spec_string (
" artist-uuid " ,
" UUID of Artist associated with Album " ,
" UUID of Artist associated with Album " ,
NULL ,
2021-05-11 20:05:04 +03:00
G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE
2021-03-23 19:50:09 +02:00
) ;
2021-07-08 18:37:52 +03:00
props [ PROP_ALBUM_PREPARED_GENRES ] = g_param_spec_string (
" preparsed-genres " ,
" Preparsed Genres " ,
" Preparsed Genres " ,
NULL ,
G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_WRITABLE
) ;
2021-02-16 17:15:10 +02:00
g_object_class_install_properties ( gobject_class , N_PROPERTIES , props ) ;
2021-06-22 16:48:13 +03:00
album_signals [ SIGNAL_TRACK_ADDED ] = g_signal_new (
" track-added " ,
G_TYPE_FROM_CLASS ( gobject_class ) ,
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION ,
G_STRUCT_OFFSET ( KotoAlbumClass , track_added ) ,
NULL ,
NULL ,
NULL ,
G_TYPE_NONE ,
1 ,
KOTO_TYPE_TRACK
) ;
album_signals [ SIGNAL_TRACK_REMOVED ] = g_signal_new (
" track-removed " ,
G_TYPE_FROM_CLASS ( gobject_class ) ,
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION ,
G_STRUCT_OFFSET ( KotoAlbumClass , track_removed ) ,
NULL ,
NULL ,
NULL ,
G_TYPE_NONE ,
1 ,
KOTO_TYPE_TRACK
) ;
2021-02-16 17:15:10 +02:00
}
2021-05-11 20:08:39 +03:00
static void koto_album_init ( KotoAlbum * self ) {
2021-02-16 17:15:10 +02:00
self - > has_album_art = FALSE ;
2021-07-08 18:37:52 +03:00
self - > genres = NULL ;
2021-03-23 19:50:09 +02:00
self - > tracks = NULL ;
2021-06-22 16:48:13 +03:00
self - > paths = g_hash_table_new ( g_str_hash , g_str_equal ) ;
2021-02-16 17:15:10 +02:00
}
2021-05-11 20:08:39 +03:00
void koto_album_add_track (
KotoAlbum * self ,
KotoTrack * track
2021-05-11 20:05:04 +03:00
) {
2021-06-22 16:48:13 +03:00
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
return ;
}
if ( ! KOTO_IS_TRACK ( track ) ) { // Not a track
2021-02-16 17:15:10 +02:00
return ;
}
2021-06-22 16:48:13 +03:00
gchar * track_uuid = koto_track_get_uuid ( track ) ;
2021-05-11 20:05:04 +03:00
2021-07-08 18:37:52 +03:00
if ( g_list_index ( self - > tracks , track_uuid ) ! = - 1 ) { // Have added it already
return ;
}
2021-02-16 17:15:10 +02:00
2021-07-08 18:37:52 +03:00
koto_cartographer_add_track ( koto_maps , track ) ; // Add the track to cartographer if necessary
self - > tracks = g_list_insert_sorted_with_data ( self - > tracks , track_uuid , koto_track_helpers_sort_tracks_by_uuid , NULL ) ;
GList * track_genres = koto_track_get_genres ( track ) ; // Get the genres for the track
GList * current_genre_list ;
gchar * existing_genres_as_string = koto_utils_join_string_list ( self - > genres , " ; " ) ;
for ( current_genre_list = track_genres ; current_genre_list ! = NULL ; current_genre_list = current_genre_list - > next ) { // Iterate over each item in the track genres
gchar * track_genre = current_genre_list - > data ; // Get this genre
if ( koto_utils_string_contains_substring ( existing_genres_as_string , track_genre ) ) { // Genres list contains this genre
continue ;
}
self - > genres = g_list_append ( self - > genres , g_strdup ( track_genre ) ) ; // Duplicate the genre and add it to our list
2021-02-16 17:15:10 +02:00
}
2021-07-08 18:37:52 +03:00
g_signal_emit (
self ,
album_signals [ SIGNAL_TRACK_ADDED ] ,
0 ,
track
) ;
2021-02-16 17:15:10 +02:00
}
2021-05-11 20:08:39 +03:00
void koto_album_commit ( KotoAlbum * self ) {
2021-03-02 19:12:12 +02:00
if ( self - > art_path = = NULL ) { // If art_path isn't defined when committing
2021-05-11 20:08:39 +03:00
koto_album_set_album_art ( self , " " ) ; // Set to an empty string
2021-03-02 19:12:12 +02:00
}
2021-02-16 17:15:10 +02:00
2021-07-08 18:37:52 +03:00
gchar * genres_string = koto_utils_join_string_list ( self - > genres , " ; " ) ;
2021-05-11 20:05:04 +03:00
gchar * commit_op = g_strdup_printf (
2021-07-08 18:37:52 +03:00
" INSERT INTO albums(id, artist_id, name, art_path, genres) "
" VALUES('%s', '%s', quote( \" %s \" ), quote( \" %s \" ), '%s') "
" ON CONFLICT(id) DO UPDATE SET artist_id=excluded.artist_id, name=excluded.name, art_path=excluded.art_path, genres=excluded.genres; " ,
2021-03-02 19:12:12 +02:00
self - > uuid ,
2021-03-23 19:50:09 +02:00
self - > artist_uuid ,
2021-03-02 19:12:12 +02:00
self - > name ,
2021-07-08 18:37:52 +03:00
self - > art_path ,
genres_string
2021-03-02 19:12:12 +02:00
) ;
2021-02-16 17:15:10 +02:00
2021-06-22 16:48:13 +03:00
new_transaction ( commit_op , " Failed to write our album to the database " , FALSE ) ;
2021-02-16 17:15:10 +02:00
2021-07-08 18:37:52 +03:00
g_free ( genres_string ) ;
2021-06-22 16:48:13 +03:00
GHashTableIter paths_iter ;
g_hash_table_iter_init ( & paths_iter , self - > paths ) ; // Create an iterator for our paths
gpointer lib_uuid_ptr , album_rel_path_ptr ;
while ( g_hash_table_iter_next ( & paths_iter , & lib_uuid_ptr , & album_rel_path_ptr ) ) {
gchar * lib_uuid = lib_uuid_ptr ;
gchar * album_rel_path = album_rel_path_ptr ;
2021-02-16 17:15:10 +02:00
2021-06-22 16:48:13 +03:00
gchar * commit_op = g_strdup_printf (
" INSERT INTO libraries_albums(id, album_id, path) "
" VALUES ('%s', '%s', quote( \" %s \" )) "
" ON CONFLICT(id, album_id) DO UPDATE SET path=excluded.path; " ,
lib_uuid ,
self - > uuid ,
album_rel_path
) ;
2021-03-02 19:12:12 +02:00
2021-06-22 16:48:13 +03:00
new_transaction ( commit_op , " Failed to add this path for the album " , FALSE ) ;
2021-02-16 17:15:10 +02:00
}
2021-06-22 16:48:13 +03:00
}
2021-02-16 17:15:10 +02:00
2021-06-22 16:48:13 +03:00
void koto_album_find_album_art ( KotoAlbum * self ) {
if ( self - > has_album_art ) { // If we already have album art
2021-03-02 19:12:12 +02:00
return ;
2021-02-16 17:15:10 +02:00
}
2021-06-22 16:48:13 +03:00
gchar * optimal_album_path = koto_album_get_path ( self ) ;
DIR * dir = opendir ( optimal_album_path ) ; // Attempt to open our directory
2021-05-11 20:05:04 +03:00
2021-02-25 18:15:36 +02:00
if ( dir = = NULL ) {
return ;
}
2021-05-11 20:05:04 +03:00
struct dirent * entry ;
2021-02-25 18:15:36 +02:00
while ( ( entry = readdir ( dir ) ) ) {
2021-03-02 19:12:12 +02:00
if ( entry - > d_type ! = DT_REG ) { // Not a regular file
continue ; // SKIP
2021-02-25 18:15:36 +02:00
}
2021-03-02 19:12:12 +02:00
if ( g_str_has_prefix ( entry - > d_name , " . " ) ) { // Reference to parent dir, self, or a hidden item
2021-02-25 18:15:36 +02:00
continue ; // Skip
}
2021-06-22 16:48:13 +03:00
gchar * full_path = g_strdup_printf ( " %s%s%s " , optimal_album_path , G_DIR_SEPARATOR_S , entry - > d_name ) ;
2021-03-02 19:12:12 +02:00
2021-05-11 20:05:04 +03:00
const char * mime_type = magic_file ( magic_cookie , full_path ) ;
2021-02-25 18:15:36 +02:00
2021-06-22 16:48:13 +03:00
if (
( mime_type = = NULL ) | | // Failed to get the mimetype
( ( mime_type ! = NULL ) & & ! g_str_has_prefix ( mime_type , " image/ " ) ) // Got the mimetype but it is not an image
) {
2021-02-25 18:15:36 +02:00
g_free ( full_path ) ;
continue ; // Skip
}
2021-06-22 16:48:13 +03:00
gchar * album_art_no_ext = g_strdup ( koto_utils_get_filename_without_extension ( entry - > d_name ) ) ; // Get the name of the file without the extension
2021-03-02 19:12:12 +02:00
2021-06-22 16:48:13 +03:00
gchar * lower_art = g_strdup ( g_utf8_strdown ( album_art_no_ext , - 1 ) ) ; // Lowercase
g_free ( album_art_no_ext ) ;
2021-03-02 19:12:12 +02:00
2021-06-22 16:48:13 +03:00
gboolean should_set = ( g_strrstr ( lower_art , " Small " ) = = NULL ) & & ( g_strrstr ( lower_art , " back " ) = = NULL ) ; // Not back or small
2021-05-11 20:05:04 +03:00
2021-06-22 16:48:13 +03:00
g_free ( lower_art ) ;
2021-03-02 19:12:12 +02:00
2021-06-22 16:48:13 +03:00
if ( should_set ) {
koto_album_set_album_art ( self , full_path ) ;
2021-03-02 19:12:12 +02:00
g_free ( full_path ) ;
2021-06-22 16:48:13 +03:00
break ;
2021-02-25 18:15:36 +02:00
}
g_free ( full_path ) ;
}
2021-06-22 16:48:13 +03:00
closedir ( dir ) ;
2021-02-25 18:15:36 +02:00
}
2021-07-08 18:37:52 +03:00
GList * koto_album_get_genres ( KotoAlbum * self ) {
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
return NULL ;
}
return self - > genres ;
}
2021-05-11 20:08:39 +03:00
static void koto_album_get_property (
2021-05-11 20:05:04 +03:00
GObject * obj ,
guint prop_id ,
GValue * val ,
GParamSpec * spec
) {
2021-05-11 20:08:39 +03:00
KotoAlbum * self = KOTO_ALBUM ( obj ) ;
2021-05-11 20:05:04 +03:00
2021-03-02 19:12:12 +02:00
switch ( prop_id ) {
case PROP_UUID :
g_value_set_string ( val , self - > uuid ) ;
break ;
case PROP_DO_INITIAL_INDEX :
g_value_set_boolean ( val , self - > do_initial_index ) ;
break ;
case PROP_ALBUM_NAME :
g_value_set_string ( val , self - > name ) ;
break ;
case PROP_ART_PATH :
2021-06-22 16:48:13 +03:00
g_value_set_string ( val , koto_album_get_art ( self ) ) ;
2021-03-02 19:12:12 +02:00
break ;
2021-03-23 19:50:09 +02:00
case PROP_ARTIST_UUID :
g_value_set_string ( val , self - > artist_uuid ) ;
break ;
2021-03-02 19:12:12 +02:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( obj , prop_id , spec ) ;
break ;
}
}
2021-05-11 20:08:39 +03:00
static void koto_album_set_property (
2021-05-11 20:05:04 +03:00
GObject * obj ,
guint prop_id ,
const GValue * val ,
GParamSpec * spec
) {
2021-05-11 20:08:39 +03:00
KotoAlbum * self = KOTO_ALBUM ( obj ) ;
2021-05-11 20:05:04 +03:00
2021-03-23 19:50:09 +02:00
switch ( prop_id ) {
case PROP_UUID :
self - > uuid = g_strdup ( g_value_get_string ( val ) ) ;
g_object_notify_by_pspec ( G_OBJECT ( self ) , props [ PROP_UUID ] ) ;
break ;
case PROP_DO_INITIAL_INDEX :
self - > do_initial_index = g_value_get_boolean ( val ) ;
break ;
case PROP_ALBUM_NAME : // Name of album
2021-05-11 20:08:39 +03:00
koto_album_set_album_name ( self , g_value_get_string ( val ) ) ;
2021-03-23 19:50:09 +02:00
break ;
case PROP_ART_PATH : // Path to art
2021-05-11 20:08:39 +03:00
koto_album_set_album_art ( self , g_value_get_string ( val ) ) ;
2021-03-23 19:50:09 +02:00
break ;
case PROP_ARTIST_UUID :
2021-05-11 20:08:39 +03:00
koto_album_set_artist_uuid ( self , g_value_get_string ( val ) ) ;
2021-03-23 19:50:09 +02:00
break ;
2021-07-08 18:37:52 +03:00
case PROP_ALBUM_PREPARED_GENRES :
koto_album_set_preparsed_genres ( self , g_strdup ( g_value_get_string ( val ) ) ) ;
break ;
2021-03-23 19:50:09 +02:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( obj , prop_id , spec ) ;
break ;
2021-03-02 19:12:12 +02:00
}
2021-03-23 19:50:09 +02:00
}
2021-03-02 19:12:12 +02:00
2021-06-22 16:48:13 +03:00
gchar * koto_album_get_art ( KotoAlbum * self ) {
2021-05-11 20:08:39 +03:00
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-05-07 16:45:57 +03:00
return g_strdup ( " " ) ;
}
2021-05-07 21:52:42 +03:00
return g_strdup ( ( self - > has_album_art & & koto_utils_is_string_valid ( self - > art_path ) ) ? self - > art_path : " " ) ;
2021-05-07 16:45:57 +03:00
}
2021-06-22 16:48:13 +03:00
gchar * koto_album_get_name ( KotoAlbum * self ) {
2021-05-11 20:08:39 +03:00
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-05-07 16:45:57 +03:00
return NULL ;
}
2021-05-07 21:52:42 +03:00
if ( ! koto_utils_is_string_valid ( self - > name ) ) { // Not set
2021-05-07 16:45:57 +03:00
return NULL ;
}
return g_strdup ( self - > name ) ; // Return duplicate of the name
}
2021-05-11 20:08:39 +03:00
gchar * koto_album_get_album_uuid ( KotoAlbum * self ) {
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-05-07 21:52:42 +03:00
return NULL ;
}
if ( ! koto_utils_is_string_valid ( self - > uuid ) ) { // Not set
2021-05-07 16:45:57 +03:00
return NULL ;
}
return g_strdup ( self - > uuid ) ; // Return a duplicate of the UUID
2021-03-23 19:50:09 +02:00
}
2021-06-22 16:48:13 +03:00
gchar * koto_album_get_path ( KotoAlbum * self ) {
if ( ! KOTO_IS_ALBUM ( self ) | | ( KOTO_IS_ALBUM ( self ) & & ( g_list_length ( g_hash_table_get_keys ( self - > paths ) ) = = 0 ) ) ) { // If this is not an album or is but we have no paths associated with it
return NULL ;
}
GList * libs = koto_cartographer_get_libraries ( koto_maps ) ; // Get all of our libraries
GList * cur_lib_list ;
for ( cur_lib_list = libs ; cur_lib_list ! = NULL ; cur_lib_list = libs - > next ) { // Iterate over our libraries
KotoLibrary * cur_library = libs - > data ; // Get this as a KotoLibrary
gchar * library_relative_path = g_hash_table_lookup ( self - > paths , koto_library_get_uuid ( cur_library ) ) ; // Get any relative path in our paths based on the current UUID
if ( ! koto_utils_is_string_valid ( library_relative_path ) ) { // Not a valid path
continue ;
}
return g_strdup ( g_build_path ( G_DIR_SEPARATOR_S , koto_library_get_path ( cur_library ) , library_relative_path , NULL ) ) ; // Build our full library path using library's path and our file relative path
}
return NULL ;
}
2021-05-11 20:08:39 +03:00
GList * koto_album_get_tracks ( KotoAlbum * self ) {
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-05-07 16:45:57 +03:00
return NULL ;
}
2021-06-01 12:58:23 +03:00
return self - > tracks ; // Return the tracks
}
2021-06-22 16:48:13 +03:00
gchar * koto_album_get_uuid ( KotoAlbum * self ) {
2021-06-01 12:58:23 +03:00
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
return NULL ;
}
return self - > uuid ; // Return the UUID
2021-03-02 19:12:12 +02:00
}
2021-05-11 20:08:39 +03:00
void koto_album_set_album_art (
KotoAlbum * self ,
2021-05-11 20:05:04 +03:00
const gchar * album_art
) {
2021-05-11 20:08:39 +03:00
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-05-07 16:45:57 +03:00
return ;
}
2021-03-02 19:12:12 +02:00
if ( album_art = = NULL ) { // Not valid album art
return ;
}
if ( self - > art_path ! = NULL ) {
g_free ( self - > art_path ) ;
}
self - > art_path = g_strdup ( album_art ) ;
self - > has_album_art = TRUE ;
}
2021-06-22 16:48:13 +03:00
void koto_album_set_path (
2021-05-11 20:08:39 +03:00
KotoAlbum * self ,
2021-06-22 16:48:13 +03:00
KotoLibrary * lib ,
const gchar * fixed_path
2021-05-11 20:05:04 +03:00
) {
2021-05-11 20:08:39 +03:00
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-05-07 16:45:57 +03:00
return ;
}
2021-06-22 16:48:13 +03:00
gchar * path = g_strdup ( fixed_path ) ; // Duplicate our fixed_path
gchar * relative_path = koto_library_get_relative_path_to_file ( lib , path ) ; // Get the relative path to the file for the given library
gchar * library_uuid = koto_library_get_uuid ( lib ) ; // Get the library for this path
g_hash_table_replace ( self - > paths , library_uuid , relative_path ) ; // Replace any existing value or add this one
koto_album_set_album_name ( self , g_path_get_basename ( relative_path ) ) ; // Update our album name based on the base name
if ( ! self - > do_initial_index ) { // Not doing our initial index
return ;
}
koto_album_find_album_art ( self ) ; // Update our path for the album art
self - > do_initial_index = FALSE ;
}
void koto_album_remove_track (
KotoAlbum * self ,
KotoTrack * track
) {
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-02-16 17:15:10 +02:00
return ;
}
2021-06-22 16:48:13 +03:00
if ( ! KOTO_IS_TRACK ( track ) ) { // Not a track
return ;
}
2021-05-11 20:05:04 +03:00
2021-06-22 16:48:13 +03:00
self - > tracks = g_list_remove ( self - > tracks , koto_track_get_uuid ( track ) ) ;
g_signal_emit (
self ,
album_signals [ SIGNAL_TRACK_REMOVED ] ,
0 ,
track
) ;
2021-02-16 17:15:10 +02:00
}
2021-05-11 20:08:39 +03:00
void koto_album_set_album_name (
KotoAlbum * self ,
2021-05-11 20:05:04 +03:00
const gchar * album_name
) {
2021-05-11 20:08:39 +03:00
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-05-07 16:45:57 +03:00
return ;
}
2021-02-16 17:15:10 +02:00
if ( album_name = = NULL ) { // Not valid album name
return ;
}
if ( self - > name ! = NULL ) {
g_free ( self - > name ) ;
}
self - > name = g_strdup ( album_name ) ;
}
2021-05-11 20:08:39 +03:00
void koto_album_set_artist_uuid (
KotoAlbum * self ,
2021-05-11 20:05:04 +03:00
const gchar * artist_uuid
) {
2021-05-11 20:08:39 +03:00
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-05-07 16:45:57 +03:00
return ;
}
2021-03-23 19:50:09 +02:00
if ( artist_uuid = = NULL ) {
return ;
}
if ( self - > artist_uuid ! = NULL ) {
g_free ( self - > artist_uuid ) ;
}
self - > artist_uuid = g_strdup ( artist_uuid ) ;
}
2021-05-11 20:08:39 +03:00
void koto_album_set_as_current_playlist ( KotoAlbum * self ) {
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
2021-05-07 16:45:57 +03:00
return ;
}
2021-03-16 08:51:35 +02:00
if ( self - > tracks = = NULL ) { // No files to add to the playlist
2021-03-10 13:44:08 +02:00
return ;
}
2021-05-11 20:05:04 +03:00
KotoPlaylist * new_album_playlist = koto_playlist_new ( ) ; // Create a new playlist
2021-03-23 19:50:09 +02:00
g_object_set ( new_album_playlist , " ephemeral " , TRUE , NULL ) ; // Set as ephemeral / temporary
2021-03-10 13:44:08 +02:00
2021-05-07 16:45:57 +03:00
// The following section effectively reverses our tracks, so the first is now last.
// It then adds them in reverse order, since our playlist add function will prepend to our queue
// This enables the preservation and defaulting of "newest" first everywhere else, while in albums preserving the rightful order of the album
// e.g. first track (0) being added last is actually first in the playlist's tracks
2021-05-11 20:05:04 +03:00
GList * reversed_tracks = g_list_copy ( self - > tracks ) ; // Copy our tracks so we can reverse the order
2021-05-07 16:45:57 +03:00
reversed_tracks = g_list_reverse ( reversed_tracks ) ; // Actually reverse it
2021-05-11 20:05:04 +03:00
GList * t ;
2021-05-07 16:45:57 +03:00
for ( t = reversed_tracks ; t ! = NULL ; t = t - > next ) { // For each of the tracks
2021-05-27 16:58:28 +03:00
gchar * track_uuid = t - > data ;
2021-05-07 16:45:57 +03:00
koto_playlist_add_track_by_uuid ( new_album_playlist , track_uuid , FALSE , FALSE ) ; // Add the UUID, skip commit to table since it is temporary
2021-03-10 13:44:08 +02:00
}
2021-05-07 16:45:57 +03:00
g_list_free ( t ) ;
g_list_free ( reversed_tracks ) ;
koto_playlist_apply_model ( new_album_playlist , KOTO_PREFERRED_MODEL_TYPE_DEFAULT ) ; // Ensure we are using our default model
2021-03-10 13:44:08 +02:00
koto_current_playlist_set_playlist ( current_playlist , new_album_playlist ) ; // Set our new current playlist
}
2021-07-08 18:37:52 +03:00
void koto_album_set_preparsed_genres (
KotoAlbum * self ,
gchar * genrelist
) {
if ( ! KOTO_IS_ALBUM ( self ) ) { // Not an album
return ;
}
if ( ! koto_utils_is_string_valid ( genrelist ) ) { // If it is an empty string
return ;
}
GList * preparsed_genres_list = koto_utils_string_to_string_list ( genrelist , " ; " ) ;
if ( g_list_length ( preparsed_genres_list ) = = 0 ) { // No genres
g_list_free ( preparsed_genres_list ) ;
return ;
}
// TODO: Do a pass on in first memory optimization phase to ensure string elements are freed.
g_list_free_full ( self - > genres , NULL ) ; // Free the existing genres list
self - > genres = preparsed_genres_list ;
} ;
2021-06-22 16:48:13 +03:00
KotoAlbum * koto_album_new ( gchar * artist_uuid ) {
if ( ! koto_utils_is_string_valid ( artist_uuid ) ) { // Invalid artist UUID provided
return NULL ;
2021-02-16 17:15:10 +02:00
}
2021-05-27 16:58:28 +03:00
KotoAlbum * album = g_object_new (
2021-05-11 20:08:39 +03:00
KOTO_TYPE_ALBUM ,
2021-05-11 20:05:04 +03:00
" artist-uuid " ,
artist_uuid ,
" uuid " ,
g_strdup ( g_uuid_string_random ( ) ) ,
" do-initial-index " ,
TRUE ,
2021-03-02 19:12:12 +02:00
NULL
) ;
2021-02-16 17:15:10 +02:00
2021-03-02 19:12:12 +02:00
return album ;
2021-02-16 17:15:10 +02:00
}
2021-05-11 20:08:39 +03:00
KotoAlbum * koto_album_new_with_uuid (
KotoArtist * artist ,
2021-05-11 20:05:04 +03:00
const gchar * uuid
) {
gchar * artist_uuid = NULL ;
2021-03-23 19:50:09 +02:00
g_object_get ( artist , " uuid " , & artist_uuid , NULL ) ;
2021-05-11 20:05:04 +03:00
return g_object_new (
2021-05-11 20:08:39 +03:00
KOTO_TYPE_ALBUM ,
2021-05-11 20:05:04 +03:00
" artist-uuid " ,
artist ,
" uuid " ,
g_strdup ( uuid ) ,
" do-initial-index " ,
FALSE ,
2021-02-16 17:15:10 +02:00
NULL
) ;
}