diff options
author | Jon Bergli Heier <snakebite@jvnv.net> | 2011-01-04 02:10:27 +0100 |
---|---|---|
committer | Jon Bergli Heier <snakebite@jvnv.net> | 2011-01-04 02:10:27 +0100 |
commit | b73c8b20a034a4e8ac9ab8740453e35160c20833 (patch) | |
tree | 350302168da233ddc1eed20ee4bc4ca1fa2c9467 | |
parent | 8149e0487f6e658af71339f41a4f2f8413876cf0 (diff) |
Implemented music::update(), needs some work to make queries work on different engines.
-rw-r--r-- | clear.sql | 3 | ||||
-rw-r--r-- | init.postgresql.sql | 31 | ||||
-rw-r--r-- | music.cpp | 44 | ||||
-rw-r--r-- | tag.cpp | 9 | ||||
-rw-r--r-- | tag.h | 11 |
5 files changed, 94 insertions, 4 deletions
diff --git a/clear.sql b/clear.sql new file mode 100644 index 0000000..b098e4c --- /dev/null +++ b/clear.sql @@ -0,0 +1,3 @@ +DROP TABLE tracks; +DROP TABLE albums; +DROP TABLE artists; diff --git a/init.postgresql.sql b/init.postgresql.sql new file mode 100644 index 0000000..96ddca5 --- /dev/null +++ b/init.postgresql.sql @@ -0,0 +1,31 @@ +BEGIN; + +CREATE SEQUENCE artists_id_seq; +CREATE TABLE artists ( + id INTEGER PRIMARY KEY DEFAULT nextval('artists_id_seq'), + name VARCHAR UNIQUE); +ALTER SEQUENCE artists_id_seq OWNED BY artists.id; + +CREATE SEQUENCE albums_id_seq; +CREATE TABLE albums ( + id INTEGER PRIMARY KEY DEFAULT nextval('albums_id_seq'), + artist_id INTEGER REFERENCES artists (id) NULL, + name VARCHAR, + tracks INTEGER, + UNIQUE(artist_id, name)); +ALTER SEQUENCE albums_id_seq OWNED BY albums.id; + +CREATE SEQUENCE tracks_id_seq; +CREATE TABLE tracks ( + id INTEGER PRIMARY KEY DEFAULT nextval('tracks_id_seq'), + artist_id INTEGER REFERENCES artists (id) NULL, + album_id INTEGER REFERENCES albums (id) NULL, + name VARCHAR, + length INTEGER, + num INTEGER, + file_name VARCHAR, + file_index INTEGER, + UNIQUE(artist_id, name)); +ALTER SEQUENCE tracks_id_seq OWNED BY tracks.id; + +COMMIT; @@ -87,9 +87,49 @@ void music::begin_update(const std::string path) { } void music::update(const MusicDirectory& dir) { + soci::session sql(config::vm["audist.database"].as<std::string>()); + BOOST_FOREACH(fs::path t, dir.tracks) { std::cout << "track " << t << std::endl; + Tag::p tag = Tag::load(t.string()); + BOOST_FOREACH(Tag::Fields::value_type& f, tag->fields) { + std::cout << boost::format(" %s: %s") % f.first % f.second << std::endl; + } + + int artist_id = 0, album_id = 0, track_id = 0; + + if(tag->has_field("artist")) { + sql << "SELECT id FROM artists WHERE name = :name", soci::use(tag->fields["artist"]), soci::into(artist_id); + if(!sql.got_data()) + sql << "INSERT INTO artists (name) VALUES (:name) RETURNING id", soci::use(tag->fields["artist"]), soci::into(artist_id); + } + + if(tag->has_field("album")) { + std::string query(boost::str(boost::format("SELECT id FROM albums WHERE %s AND name = :name") % + (artist_id ? boost::str(boost::format("artist_id = %d") % artist_id) : "artist_id IS NULL"))); + sql << query, soci::use(tag->fields["album"]), soci::into(album_id); + if(!sql.got_data()) { + soci::indicator ind = (artist_id ? soci::i_ok : soci::i_null); + sql << "INSERT INTO albums (artist_id, name) VALUES (:artist_id, :name) RETURNING id", + soci::use(artist_id, ind), soci::use(tag->fields["album"]), soci::into(album_id); + } + } + + if(tag->has_field("title")) { + std::string query(boost::str(boost::format("SELECT id FROM tracks WHERE %s AND %s AND name = :name") % + (artist_id ? boost::str(boost::format("artist_id = %d") % artist_id) : "artist_id IS NULL") % + (album_id ? boost::str(boost::format("album_id = %d") % album_id) : "album_id IS NULL"))); + sql << query, soci::use(tag->fields["title"]), soci::into(track_id); + if(!sql.got_data()) { + soci::indicator artist_ind = (artist_id ? soci::i_ok : soci::i_null), + album_ind = (album_id ? soci::i_ok : soci::i_null); + sql << "INSERT INTO tracks (artist_id, album_id, name, file_name) VALUES (:artist_id, :album_id, :name, :file_name)", + soci::use(artist_id, artist_ind), soci::use(album_id, album_ind), soci::use(tag->fields["title"]), soci::use(t.string()); + } + } } + sql.close(); + std::for_each(dir.directories.begin(), dir.directories.end(), update); } @@ -128,10 +168,6 @@ MusicDirectory::MusicDirectory(const fs::path root) { void MusicTrack::render(HTTP::Connection::p req) { req->add_header("content-type", "application/octet-stream"); - // tag test - Tag *t = new ID3Tag(path.string()); - delete t; - if(req->args.count("decoder") && req->args.count("encoder")) { DecoderFilter::p d = decoder::get_decoder(req->args["decoder"]); EncoderFilter::p e = encoder::get_encoder(req->args["encoder"]); @@ -5,6 +5,15 @@ #include <cstdlib> #include <stdexcept> +// TODO: Make this a "smart" tag loader +Tag::p Tag::load(const std::string filename) { + return Tag::p(new ID3Tag(filename)); +} + +bool Tag::has_field(const std::string name) { + return fields.find(name) != fields.end(); +} + void ID3Tag::tag_add_string(struct id3_tag *id3tag, const char *type, const char *id) { struct id3_frame *frame = id3_tag_findframe(id3tag, id, 0); @@ -1,13 +1,24 @@ #ifndef TAG_H #define TAG_H +#include <boost/shared_ptr.hpp> + #include <string> #include <map> class Tag { public: + typedef boost::shared_ptr<Tag> p; typedef std::map<std::string, std::string> Fields; + + //! Tag fields. Fields fields; + + //! Generic tag loader. + static p load(const std::string filename); + + //! Check for the existence of a specific field. + bool has_field(const std::string name); }; class ID3Tag : public Tag { |