core/tags/track: Add support for allocating external tracks
There might be rare occasions where users want to play a track that exists outside their music library. This patch adds support for allocating and freeing these external tracks without adding them to the track database. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
f9a573b6a3
commit
cc464ed198
|
@ -41,26 +41,18 @@ static struct track *__track_alloc()
|
|||
return track;
|
||||
}
|
||||
|
||||
|
||||
struct db_entry *track_alloc(const gchar *key, unsigned int index)
|
||||
static struct track *__track_alloc_filepath(const gchar *filepath)
|
||||
{
|
||||
TagLib_File *file = taglib_file_new(filepath);
|
||||
const TagLib_AudioProperties *audio;
|
||||
struct library *library;
|
||||
struct track *track = NULL;
|
||||
struct artist *artist;
|
||||
struct genre *genre;
|
||||
struct track *track = NULL;
|
||||
unsigned int lib_id;
|
||||
TagLib_File *file;
|
||||
TagLib_Tag *tag;
|
||||
char *fullpath, *path;
|
||||
TagLib_Tag *tag;
|
||||
|
||||
sscanf(key, "%u/%m[^\n]", &lib_id, &path);
|
||||
library = library_get(lib_id);
|
||||
fullpath = library_file(library, path);
|
||||
file = taglib_file_new(fullpath);
|
||||
if (!file || !taglib_file_is_valid(file)) {
|
||||
g_printerr("WARNING: Could not read tags for: %s\n", fullpath);
|
||||
goto out;
|
||||
g_printerr("WARNING: Could not read tags for: %s\n", filepath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
track = __track_alloc();
|
||||
|
@ -69,24 +61,50 @@ struct db_entry *track_alloc(const gchar *key, unsigned int index)
|
|||
artist = artist_find(taglib_tag_artist(tag));
|
||||
genre = genre_find(taglib_tag_genre(tag));
|
||||
|
||||
track->tr_album = album_find(artist, genre, taglib_tag_album(tag),
|
||||
taglib_tag_year(tag));
|
||||
track->tr_library = library;
|
||||
track->tr_album = album_find(artist, genre, taglib_tag_album(tag),
|
||||
taglib_tag_year(tag));
|
||||
|
||||
unplayed_count++;
|
||||
track->tr_count = 0;
|
||||
track->tr_length = taglib_audioproperties_length(audio);
|
||||
track->tr_track = taglib_tag_track(tag);
|
||||
date_set(&track->tr_date, 0, 0, 0);
|
||||
|
||||
track->tr_path = g_strdup(key);
|
||||
track->tr_title = g_strdup(taglib_tag_title(tag));
|
||||
track->tr_tokens = g_str_tokenize_and_fold(track->tr_title, NULL,
|
||||
&track->tr_alts);
|
||||
|
||||
taglib_tag_free_strings();
|
||||
taglib_file_free(file);
|
||||
out:
|
||||
return track;
|
||||
}
|
||||
|
||||
static void __track_free(struct track *track)
|
||||
{
|
||||
g_strfreev(track->tr_tokens);
|
||||
g_strfreev(track->tr_alts);
|
||||
g_free(track->tr_title);
|
||||
g_free(track);
|
||||
}
|
||||
|
||||
|
||||
struct db_entry *track_alloc(const gchar *key, unsigned int index)
|
||||
{
|
||||
struct library *library;
|
||||
char *fullpath, *path;
|
||||
struct track *track;
|
||||
unsigned int lib_id;
|
||||
|
||||
sscanf(key, "%u/%m[^\n]", &lib_id, &path);
|
||||
library = library_get(lib_id);
|
||||
fullpath = library_file(library, path);
|
||||
track = __track_alloc_filepath(fullpath);
|
||||
|
||||
if (track) {
|
||||
track->tr_library = library;
|
||||
track->tr_path = g_strdup(key);
|
||||
unplayed_count++;
|
||||
}
|
||||
|
||||
g_free(path);
|
||||
g_free(fullpath);
|
||||
return track ? &track->tr_dbe : NULL;
|
||||
|
@ -100,10 +118,7 @@ static void track_free(struct db_entry *dbe)
|
|||
if (track->tr_count == 0)
|
||||
unplayed_count--;
|
||||
|
||||
g_strfreev(track->tr_tokens);
|
||||
g_strfreev(track->tr_alts);
|
||||
g_free(track->tr_title);
|
||||
g_free(track);
|
||||
__track_free(track);
|
||||
}
|
||||
|
||||
static gchar *track_key(struct db_entry *dbe)
|
||||
|
@ -251,6 +266,24 @@ unsigned int track_db_average_plays()
|
|||
return play_count / (track_db.db_size - unplayed_count);
|
||||
}
|
||||
|
||||
struct track *track_alloc_external(const gchar *filepath)
|
||||
{
|
||||
struct track *track = __track_alloc_filepath(filepath);
|
||||
if (track) {
|
||||
track->tr_library = NULL;
|
||||
track->tr_path = g_strdup(filepath);
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
void track_free_external(struct track *track)
|
||||
{
|
||||
if (TRACK_IS_EXTERNAL(track)) {
|
||||
g_free(track->tr_path);
|
||||
__track_free(track);
|
||||
}
|
||||
}
|
||||
|
||||
struct track *track_add(struct library *library, const gchar *filepath)
|
||||
{
|
||||
unsigned int offset = strlen(library->li_path) + 1;
|
||||
|
@ -346,11 +379,13 @@ gchar *track_path(struct track *track)
|
|||
g_free(path);
|
||||
return res;
|
||||
}
|
||||
return g_strdup("");
|
||||
return g_strdup(track->tr_path);
|
||||
}
|
||||
|
||||
void track_played(struct track *track)
|
||||
{
|
||||
if (TRACK_IS_EXTERNAL(track))
|
||||
return;
|
||||
if (track->tr_count == 0)
|
||||
unplayed_count--;
|
||||
track->tr_count++;
|
||||
|
|
|
@ -58,6 +58,7 @@ struct track {
|
|||
};
|
||||
|
||||
#define TRACK(dbe) ((struct track *)DBE_DATA(dbe))
|
||||
#define TRACK_IS_EXTERNAL(track) (track->tr_library == NULL)
|
||||
|
||||
|
||||
/* Called to initialize the track database. */
|
||||
|
@ -87,6 +88,12 @@ unsigned int track_db_count_plays();
|
|||
/* Called to find the average play count of tracks in the database. */
|
||||
unsigned int track_db_average_plays();
|
||||
|
||||
/* Called to allocate a track without adding it to the database. */
|
||||
struct track *track_alloc_external(const gchar *);
|
||||
|
||||
/* Called to free an external track. */
|
||||
void track_free_external(struct track *);
|
||||
|
||||
/* Called to add a track tag to the database. */
|
||||
struct track *track_add(struct library *, const gchar *);
|
||||
|
||||
|
|
|
@ -17,27 +17,38 @@ static struct track *test_alloc(const gchar *key)
|
|||
return TRACK(dbe);
|
||||
}
|
||||
|
||||
static void test_verify_tags(struct track *track)
|
||||
static void test_verify_tags(struct track *track, bool external)
|
||||
{
|
||||
g_assert_cmpstr(track->tr_album->al_name, ==, "Hyrule Symphony");
|
||||
g_assert_cmpuint(track->tr_album->al_year, ==, 1998);
|
||||
g_assert_cmpstr(track->tr_album->al_artist->ar_name, ==, "Koji Kondo");
|
||||
g_assert_cmpstr(track->tr_album->al_genre->ge_name, ==, "Game");
|
||||
g_assert_cmpstr(track->tr_library->li_path, ==, "tests/Music");
|
||||
|
||||
if (external) {
|
||||
g_assert_true(TRACK_IS_EXTERNAL(track));
|
||||
g_assert_null(track->tr_library);
|
||||
} else {
|
||||
g_assert_false(TRACK_IS_EXTERNAL(track));
|
||||
g_assert_cmpstr(track->tr_library->li_path, ==, "tests/Music");
|
||||
}
|
||||
}
|
||||
|
||||
static void test_verify_track(struct track *track)
|
||||
static void test_verify_track(struct track *track, bool external)
|
||||
{
|
||||
const struct db_ops *track_ops = test_track_ops();
|
||||
test_verify_tags(track);
|
||||
|
||||
if (!external)
|
||||
track_free_external(track);
|
||||
test_verify_tags(track, external);
|
||||
|
||||
g_assert_cmpstr(track->tr_title, ==, "Title Theme");
|
||||
g_assert_cmpstr(track->tr_tokens[0], ==, "title");
|
||||
g_assert_cmpstr(track->tr_tokens[1], ==, "theme");
|
||||
g_assert_null(track->tr_tokens[2]);
|
||||
g_assert_null(track->tr_alts[0]);
|
||||
g_assert_cmpstr(track_ops->dbe_key(&track->tr_dbe), ==,
|
||||
"0/Hyrule Symphony/01 - Title Theme.ogg");
|
||||
if (!external)
|
||||
g_assert_cmpstr(track_ops->dbe_key(&track->tr_dbe), ==,
|
||||
"0/Hyrule Symphony/01 - Title Theme.ogg");
|
||||
g_assert_cmpstr_free(track_path(track), ==,
|
||||
"tests/Music/Hyrule Symphony/01 - Title Theme.ogg");
|
||||
g_assert_cmpstr_free(track_last_play(track), ==, "Never");
|
||||
|
@ -50,7 +61,7 @@ static void test_verify_track(struct track *track)
|
|||
static void test_verify_notrack(struct track *track)
|
||||
{
|
||||
const struct db_ops *track_ops = test_track_ops();
|
||||
test_verify_tags(track);
|
||||
test_verify_tags(track, false);
|
||||
|
||||
g_assert_cmpstr(track->tr_title, ==, "");
|
||||
g_assert_null(track->tr_tokens[0]);
|
||||
|
@ -82,7 +93,7 @@ static void test_track()
|
|||
track = test_alloc("0/Hyrule Symphony/01 - Title Theme.ogg");
|
||||
g_assert_nonnull(track);
|
||||
track->tr_dbe.dbe_index = 0;
|
||||
test_verify_track(track);
|
||||
test_verify_track(track, false);
|
||||
|
||||
g_assert_true( track_match_token(track, "title"));
|
||||
g_assert_true( track_match_token(track, "theme"));
|
||||
|
@ -107,7 +118,7 @@ static void test_track()
|
|||
|
||||
track = TRACK(track_ops->dbe_read(&f, 0));
|
||||
track->tr_dbe.dbe_index = 0;
|
||||
test_verify_track(track);
|
||||
test_verify_track(track, false);
|
||||
file_close(&f);
|
||||
|
||||
track_played(track);
|
||||
|
@ -119,6 +130,27 @@ static void test_track()
|
|||
g_free(date);
|
||||
}
|
||||
|
||||
static void test_track_external()
|
||||
{
|
||||
struct track *track = track_alloc_external(
|
||||
"tests/Music/Hyrule Symphony/01 - Title Theme.ogg");
|
||||
|
||||
g_assert_nonnull(track);
|
||||
test_verify_track(track, true);
|
||||
g_assert_cmpuint(track_db_get()->db_size, ==, 0);
|
||||
g_assert_cmpuint(track_db_count_unplayed(), ==, 0);
|
||||
|
||||
track_played(track);
|
||||
g_assert_cmpuint(track_db_count_unplayed(), ==, 0);
|
||||
g_assert_cmpuint(track_db_count_plays(), ==, 0);
|
||||
|
||||
track_free_external(track);
|
||||
g_assert_cmpuint(track_db_count_unplayed(), ==, 0);
|
||||
g_assert_cmpuint(track_db_count_plays(), ==, 0);
|
||||
|
||||
g_assert_null(track_alloc_external("/home/Zelda/Music/ocarina.ogg"));
|
||||
}
|
||||
|
||||
static void test_track_compare()
|
||||
{
|
||||
const struct db_ops *track_ops = test_track_ops();
|
||||
|
@ -215,7 +247,7 @@ static void __test_track_db_subprocess()
|
|||
g_assert_null(track_lookup(path));
|
||||
|
||||
track = track_add(library, path);
|
||||
test_verify_track(track);
|
||||
test_verify_track(track, false);
|
||||
g_assert(track_lookup(path) == track);
|
||||
g_assert_cmpuint(track_db_count_unplayed(), ==, 1);
|
||||
|
||||
|
@ -232,7 +264,7 @@ static void __test_track_db_subprocess()
|
|||
track_db_commit();
|
||||
db_load(&track_db);
|
||||
g_assert_cmpuint(track_db.db_size, ==, 1);
|
||||
test_verify_track(TRACK(db_first(&track_db)));
|
||||
test_verify_track(TRACK(db_first(&track_db)), false);
|
||||
/* Make sure our unplayed count isn't skewed */
|
||||
db_deinit(&track_db);
|
||||
|
||||
|
@ -314,6 +346,7 @@ int main(int argc, char **argv)
|
|||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func("/Core/Tags/Track", test_track);
|
||||
g_test_add_func("/Core/Tags/Track/External", test_track_external);
|
||||
g_test_add_func("/Core/Tags/Track/Comparison", test_track_compare);
|
||||
g_test_add_func("/Core/Tags/Track/Database", test_track_db);
|
||||
ret = g_test_run();
|
||||
|
|
Loading…
Reference in New Issue