library: Implement basic path management

I can add and remove root-level directories from the library database.
I do not save the database when modified, and I don't yet run an update
on all the files.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
Anna Schumaker 2013-10-27 17:25:26 -04:00 committed by Anna Schumaker
parent fc3b5db59e
commit 9ddbaf0b97
9 changed files with 253 additions and 36 deletions

1
config
View File

@ -40,6 +40,7 @@ class Config:
self.GROUP = False
self.IDLE = False
self.INDEX = False
self.LIBRARY = False
self.TEST = TEST
self.reconfigure()

View File

@ -22,6 +22,15 @@ Library: (lib/library.cpp)
When a library : Track is created, it should be added to the "Library"
group if it is NOT a member of the banned songs group.
- Databases:
enum DB_Type {
DB_ALBUM,
DB_ARTIST,
DB_GENRE,
DB_LIBRARY,
DB_TRACK,
};
- Album:
class library :: Album : public DatabaseEntry {
public:
@ -47,8 +56,8 @@ Library: (lib/library.cpp)
File << name
- Path:
class library :: Path : public DatabaseEntry {
- Library:
class library :: Library : public DatabaseEntry {
public:
string root_path;
bool enabled;
@ -70,6 +79,7 @@ Library: (lib/library.cpp)
short last_day;
unsigned int play_count;
unsigned int length;
bool banned;
string title;
string length_str;
@ -119,39 +129,33 @@ Library: (lib/library.cpp)
happen while idle.
- Testing:
A test library should be created to test adding tags and anything else.
The command `arecord -d 10 </dev/zero | lame - -b 32 -h silence.mp3`
will create a 10 second long, silent mp3 file. Do something with this
command and figure out how to apply tags!
The script tests/library/gen_library.sh will create a sample library
in the /tmp/ directory for testing purposes. All the track files are
complete silence, but the script will fake up tags for each file.
- API
library :: init();
void library :: init();
Initialize databases and read files from disk. Fill out
groups and prepare filter as tracks are read.
library :: add_path(string dir);
Add new row to paths table, update
bool library :: add_path(string dir);
If dir is not a directory:
return false
library :: del_path(unsigned int lib_id);
Invalidate a path row and all tracks owned by that path
Add new row to the library_db table, begin an update only
on the new path.
return true
library :: update_path(lib_id);
Update the given library path, if valid.
void library :: del_path(unsigned int lib_id);
Invalidate a library_db row and all tracks owned by that path
struct Track library :: resolve(track_id)
void library :: update_path(lib_id);
Update the given library_db row, if valid.
struct Track library :: lookup(track_id)
Fill out a Track structure for the provided track_id
const Database<library :: Album> &library :: get_albums();
Return the album database.
const Database<library :: Artist> &library :: get_artists();
Return the artist database.
const Database<library :: Genre> &library :: get_genres();
Return the genre database.
const Database<library :: Library> &library :: get_libraries();
Return the library database.
const Database<library :: Track> &library :: get_tracks();
Return the track database.
#ifdef CONFIG_DEBUG
void library :: print_db(DB_Type);
Print the database corresponding to DB_Type
endif /* CONFIG_DEBUG */

44
include/library.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#ifndef OCARINA_LIBRARY_H
#define OCARINA_LIBRARY_H
#include <database.h>
#include <string>
namespace library
{
enum DB_Type {
DB_ALBUM,
DB_ARTIST,
DB_GENRE,
DB_LIBRARY,
DB_TRACK,
};
class Library : public DatabaseEntry {
public:
std::string root_path;
bool enabled;
Library(const std::string &, bool);
void read(File &);
void write(File &);
#ifdef CONFIG_DEBUG
void print();
#endif /* CONFIG_DEBUG */
bool operator==(Library &);
};
bool add_path(const std::string &);
void del_path(unsigned int);
#ifdef CONFIG_DEBUG
void print_db(DB_Type);
void reset();
#endif /* CONFIG_DEBUG */
};
#endif /* OCARINA_LIBRARY_H */

View File

@ -2,7 +2,7 @@
Import("env", "CONFIG")
class Module:
def __init__(self, source = None, package = "", depends = ""):
def __init__(self, source = None, package = "", depends = []):
self.depends = depends
self.package = package
self.source = source
@ -15,12 +15,13 @@ modules = {
# #
###########################
"DATABASE" : Module("database.cpp", depends = "FILE"),
"DATABASE" : Module("database.cpp", depends = [ "FILE" ]),
"FILE" : Module("file.cpp", package = "glib-2.0"),
"FILTER" : Module("filter.cpp", depends = "INDEX"),
"GROUP" : Module("group.cpp", depends = "INDEX"),
"FILTER" : Module("filter.cpp", depends = [ "INDEX" ]),
"GROUP" : Module("group.cpp", depends = [ "INDEX" ]),
"IDLE" : Module("idle.cpp"),
"INDEX" : Module("index.cpp", depends = "FILE"),
"INDEX" : Module("index.cpp", depends = [ "FILE" ]),
"LIBRARY" : Module("library.cpp", depends = [ "DATABASE", "IDLE" ]),
###########################
###########################
@ -38,8 +39,10 @@ def resolve(name):
CONFIG.package(mod.package)
res = [ env.Object(mod.source) ]
if CONFIG.__dict__.get(mod.depends) == False:
res += resolve(mod.depends)
for dep in mod.depends:
if CONFIG.__dict__.get(dep) == False:
res += resolve(dep)
return res

82
lib/library.cpp Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <library.h>
#include <glib.h>
static Database<library :: Library> library_db("library.db", DB_NORMAL);
/*
* library :: Library: Basic information about each directory in the library
*/
library :: Library :: Library(const std::string &path, bool is_enabled)
: root_path(path), enabled(is_enabled)
{
}
void library :: Library :: read(File &f)
{
}
void library :: Library :: write(File &f)
{
}
#ifdef CONFIG_DEBUG
void library :: Library :: print()
{
:: print("%s", root_path.c_str());
if (enabled == true)
:: print(" (enabled)");
else
:: print(" (disabled)");
}
#endif /* CONFIG_DEBUG */
bool library :: Library :: operator==(library :: Library &rhs)
{
return root_path == rhs.root_path;
}
/*
* API used by the GUI begins here
*/
bool library :: add_path(const std::string &dir)
{
if (g_file_test(dir.c_str(), G_FILE_TEST_IS_DIR) == false)
return false;
library_db.insert(library :: Library(dir, true));
return true;
}
void library :: del_path(unsigned int id)
{
library_db.remove(id);
}
#ifdef CONFIG_DEBUG
void library :: print_db(DB_Type type)
{
switch (type) {
case DB_LIBRARY:
library_db.print();
break;
default:
break;
}
}
void library :: reset()
{
library_db.clear();
}
#endif /* CONFIG_DEBUG */

View File

@ -57,7 +57,7 @@ rm_test_dir(xdg.BaseDirectory.xdg_data_home);
#
# Read SConscript files
#
scripts = [ "database", "file", "filter", "group", "idle", "index", "print" ]
scripts = [ "database", "file", "filter", "group", "idle", "index", "library", "print" ]
for s in scripts:
CONFIG.reset(TEST = True)
SConscript("%s/Sconscript" % s)

6
tests/library/Sconscript Normal file
View File

@ -0,0 +1,6 @@
#!/usr/bin/python
Import("Test", "CONFIG")
CONFIG.LIBRARY = True
Test("library", "library.cpp")

View File

@ -29,6 +29,11 @@ function gen_tracks()
for i in $(seq 10); do
track="Track $i"
let remainder=$i%4
out="/tmp/$library/$artist/$album/$i - $track.ogg"
if [ -f "$out" ]; then
continue
fi
case $remainder in
0) OGG="1.ogg" ;;
@ -74,3 +79,5 @@ for i in $(seq 0 4); do
echo "Generating library: $i"
gen_artists $i
done
touch /tmp/library/file

70
tests/library/library.cpp Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <library.h>
#include <print.h>
#include <stdlib.h>
void gen_library()
{
system("tests/library/gen_library.sh");
print("\n");
}
void test_add_dir(const std::string &test, const std::string &dir, bool expected)
{
print("Test %s: ", test.c_str());
if (library :: add_path(dir.c_str()) == expected)
print("PASSED\n");
else
print("FAILED\n");
library :: print_db(library :: DB_LIBRARY);
}
void test_del_dir(const std::string &test, const unsigned int path_id)
{
print("Test %s\n", test.c_str());
library :: del_path(path_id);
library :: print_db(library :: DB_LIBRARY);
}
/* Add paths library that SHOULD fail */
void test_0()
{
test_add_dir("0a", "/tmp/library/error", false);
test_add_dir("0b", "/tmp/library/file", false);
print("\n");
}
/* Simple library path operations */
void test_1()
{
test_add_dir("1a", "/tmp/library/0", true);
library :: del_path(0);
print("\n");
}
/* Test multiple paths */
void test_2()
{
library :: reset();
test_add_dir("2a", "/tmp/library/0", true);
test_add_dir("2b", "/tmp/library/1", true);
test_add_dir("2c", "/tmp/library/2", true);
test_del_dir("2d", 1);
test_del_dir("2e", 0);
test_del_dir("2f", 2);
print("\n");
}
int main(int argc, char **argv)
{
gen_library();
test_0();
test_1();
test_2();
return 0;
}