core/tags/album: Add artist and genre information to saved data

And perform an upgrade when reading back in.  After track tags are read,
we can save the database in the new format and remove the old tags.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2016-08-12 11:14:51 -04:00
parent 0ea75ccb29
commit 0cefd158d9
4 changed files with 87 additions and 34 deletions

View File

@ -15,7 +15,10 @@
#define OCARINA_AGENT OCARINA_NAME
#endif
#define ALBUM_DB_MIN 0 /* Ocarina 6.0 */
#define ALBUM_DB_CUR 1 /* Ocarina 6.5 */
static struct database album_db;
static bool album_db_upgraded = false;
static inline void __album_init_file(struct album *al, struct cache_file *f)
@ -185,7 +188,7 @@ static struct album *__album_alloc(struct artist *artist, struct genre *genre,
album->al_artist = artist;
album->al_genre = genre;
if (!album_artwork_exists(album))
if (!album_artwork_exists(album) && artist && genre)
idle_schedule(IDLE_ASYNC, IDLE_FUNC(__album_fetch_artwork), album);
return album;
}
@ -229,22 +232,49 @@ static gchar *album_key(struct db_entry *dbe)
ALBUM(dbe)->al_name, ALBUM(dbe)->al_year);
}
static struct db_entry *album_read(struct file *file)
static struct album *__album_parse_v0(gchar *line)
{
unsigned int year;
gchar *name;
if (sscanf(line, "%u %m[^\n]", &year, &name) == 1)
name = g_strdup("");
return __album_alloc(NULL, NULL, name, year);
}
static struct db_entry *album_read(struct file *file)
{
unsigned int year, artist_id, genre_id, n;
struct album *album;
gchar *line, *name;
line = file_readl(file);
if (sscanf(line, "%u %m[^\n]", &year, &name) == 1)
if (file_version(file) == 0) {
album = __album_parse_v0(line);
album_db_upgraded = true;
goto out;
}
n = sscanf(line, "%u %u %u %m[^\n]", &artist_id, &genre_id, &year, &name);
if (n == 3)
name = g_strdup("");
album = __album_alloc(artist_get(artist_id),
genre_get(genre_id), name, year);
out:
g_free(line);
return &__album_alloc(NULL, NULL, name, year)->al_dbe;
return &album->al_dbe;
}
static void album_write(struct file *file, struct db_entry *dbe)
{
file_writef(file, "%u %s", ALBUM(dbe)->al_year, ALBUM(dbe)->al_name);
struct album *album = ALBUM(dbe);
struct artist *artist = album->al_artist;
struct genre *genre = album->al_genre;
file_writef(file, "%u %u %u %s", artist ? artist_index(artist) : 0,
genre ? genre_index(genre) : 0,
album->al_year, album->al_name);
}
@ -260,7 +290,8 @@ static const struct db_ops album_ops = {
void album_db_init()
{
db_init(&album_db, "album.db", true, &album_ops, 0, 0);
db_init(&album_db, "album.db", true, &album_ops, ALBUM_DB_MIN,
ALBUM_DB_CUR);
db_load_idle(&album_db);
}
@ -269,6 +300,21 @@ void album_db_deinit()
db_deinit(&album_db);
}
bool album_db_upgrade_done()
{
struct db_entry *dbe, *next;
if (album_db_upgraded == false)
return false;
db_for_each(dbe, next, &album_db) {
if (!ALBUM(dbe)->al_artist && !ALBUM(dbe)->al_genre)
db_remove(&album_db, dbe);
}
return true;
}
struct album *album_find(struct artist *artist, struct genre *genre,
const gchar *name, unsigned int year)
{

View File

@ -1,6 +1,7 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/tags/album.h>
#include <core/tags/artist.h>
#include <core/tags/genre.h>
@ -8,13 +9,22 @@
#include <core/tags/tags.h>
#include <core/tags/track.h>
static bool tags_upgrade_done(void *data)
{
if (album_db_upgrade_done())
track_db_commit();
return true;
}
void tags_init()
{
artist_db_init();
album_db_init();
genre_db_init();
album_db_init();
library_db_init();
track_db_init();
idle_schedule(IDLE_SYNC, tags_upgrade_done, NULL);
}
void tags_deinit()

View File

@ -4,12 +4,12 @@
* The album tag is used to store the name and year of albums
* added to the tag database.
*
* When writing an album tag to disk, write out the album_year field
* followed by the album_name on the same line:
* When writing an album tag to disk, write out the album_artist, album_genre,
* and album_year fields followed by the album_name on the same line:
*
* ... 1998 Hyrule Symphony
* ... 2006 Twilight Princess
* ... 2011 Skyward Sword
* ...0 0 1998 Hyrule Symphony
* ...0 0 2006 Twilight Princess
* ...0 0 2011 Skyward Sword
*/
#ifndef OCARINA_CORE_TAGS_ALBUM_H
#define OCARINA_CORE_TAGS_ALBUM_H
@ -36,6 +36,9 @@ void album_db_init();
/* Called to clean up the album database. */
void album_db_deinit();
/* Called to clean up the album database after an upgrade. */
bool album_db_upgrade_done();
/* Called to find an album tag by artist, name and year. */
struct album *album_find(struct artist *, struct genre *,
const gchar *, unsigned int);

View File

@ -12,9 +12,10 @@ static void test_verify_empty(struct album *album)
g_assert_cmpstr(album->al_name, ==, "");
g_assert_null(album->al_tokens[0]);
g_assert_null(album->al_alts[0]);
g_assert_null(album->al_artist);
g_assert(album->al_artist == artist_get(0));
g_assert(album->al_genre == genre_get(0));
g_assert_cmpuint(album->al_year, ==, 0);
g_assert_cmpstr_free(album_ops->dbe_key(&album->al_dbe), ==, "0/");
g_assert_cmpstr_free(album_ops->dbe_key(&album->al_dbe), ==, "0/0/0/");
}
static void test_verify_hyrule(struct album *album, struct artist *artist,
@ -51,16 +52,15 @@ static void test_album()
koji = artist_find("Koji Kondo");
genre = genre_find("Video Game Music");
album = ALBUM(album_ops->dbe_alloc("0/0/1998/Hyrule Symphony"));
test_verify_hyrule(album, koji, genre);
g_assert_true( album_match_token(album, "hyrule"));
g_assert_true( album_match_token(album, "symphony"));
g_assert_false(album_match_token(album, "skyward"));
file_init(&f, "album_tag", 0, 0);
file_init(&f, "album_tag", 1, 1);
file_open(&f, OPEN_WRITE);
file_writef(&f, "0 \n");
file_writef(&f, "0 0 0 \n");
album_ops->dbe_write(&f, &album->al_dbe);
file_close(&f);
album_ops->dbe_free(&album->al_dbe);
@ -72,7 +72,7 @@ static void test_album()
album = ALBUM(album_ops->dbe_read(&f));
file_close(&f);
test_verify_hyrule(album, NULL, NULL);
test_verify_hyrule(album, koji, genre);
album_ops->dbe_free(&album->al_dbe);
}
@ -109,25 +109,17 @@ static void test_album_db()
struct genre *genre;
struct album *album;
album = album_find(NULL, NULL, "Hyrule Symphony", 1998);
test_verify_hyrule(album, NULL, NULL);
g_assert(album_find(NULL, NULL, "Hyrule Symphony", 1998) == album);
g_assert(album_get(0) == album);
g_assert_null(album_get(1));
koji = artist_find("Koji Kondo");
genre = genre_find("Video Game Music");
album = album_find(koji, genre, "Hyrule Symphony", 1998);
test_verify_hyrule(album, koji, genre);
g_assert(album_find(NULL, NULL, "Hyrule Symphony", 1998) != album);
g_assert(album_find(koji, genre, "Hyrule Symphony", 1998) == album);
g_assert(album_get(0) != album);
g_assert(album_get(1) == album);
g_assert_null(album_get(2));
g_assert(album_get(0) == album);
g_assert_null(album_get(1));
db_init(&album_db, "album.db", false, album_ops, 0, 0);
db_init(&album_db, "album.db", false, album_ops, 1, 1);
db_load(&album_db);
g_assert_cmpuint(album_db.db_size, ==, 2);
g_assert_cmpuint(album_db.db_size, ==, 1);
db_deinit(&album_db);
}
@ -138,6 +130,7 @@ static void test_album_artwork()
struct album *ocarina, *majora, *wind, *ocarina_3d;
gchar *o_path, *m_path, *w_path;
struct artist *koji;
struct genre *genre;
const gchar *cache;
idle_deinit();
@ -149,9 +142,10 @@ static void test_album_artwork()
w_path = g_build_filename(cache, "ocarina-test", "core", "tags", "album", "0", "Wind Waker.jpg", NULL);
koji = artist_find("Koji Kondo");
ocarina = album_find(koji, NULL, "Ocarina of Time", 1998);
majora = album_find(NULL, NULL, "Majora's Mask", 2000);
wind = album_find(NULL, NULL, "Wind Waker", 0);
genre = genre_find("Video Game Music");
ocarina = album_find(koji, genre, "Ocarina of Time", 1998);
majora = album_find(koji, genre, "Majora's Mask", 2000);
wind = album_find(koji, genre, "Wind Waker", 0);
ocarina->al_artist = koji;
g_assert_false(album_artwork_exists(ocarina));
@ -171,7 +165,7 @@ static void test_album_artwork()
g_assert_cmpstr_free(album_artwork_path(wind), ==, w_path);
/* Import the original Ocarina of Time album art. */
ocarina_3d = album_find(NULL, NULL, "Ocarina of Time 3D", 2011);
ocarina_3d = album_find(koji, genre, "Ocarina of Time 3D", 2011);
g_assert_false(album_artwork_exists(ocarina_3d));
album_artwork_import(ocarina_3d, NULL);
g_assert_false(album_artwork_exists(ocarina_3d));