Logo Search packages:      
Sourcecode: zinf version File versions  Download package

musicdb.cpp

/* -*- c++ -*-________________________________________________________________
 
        Zinf - Zinf Is Not FreeA*p (The Free MP3 Player)

        Portions Copyright (C) 1999 EMusic.com

        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

        $Id: musicdb.cpp,v 1.4 2003/11/29 13:38:10 enxrah Exp $
 ____________________________________________________________________________*/



#include "utility.h"
#include "musicdb.h"

#include "metadatadb.h"
#include "filemetadb.h"
#include "gdbmdatabase.h"
#include "mkdatabase.h"
#include "cachedb.h"
#include "mbdb.h"
#include "filepathdb.h"

//#ifdef HAVE_BOOST_FILESYSTEM_PATH_HPP
#include "boost/filesystem/operations.hpp" 
#include "boost/filesystem/fstream.hpp"    
namespace fs = boost::filesystem;
//#endif



using namespace std;

extern "C" {
    void Initialize(FAContext *context) {
    }
}


inline bool 
ends_with(const string&s, const string& m) 
{
    return s.substr(s.size()-m.size()) == m;
}

struct music_search_data {
    MusicCollection *m_db;
    string   m_path;
    Thread  *m_thread;
    music_search_data(MusicCollection*db, string path, Thread*t)
        : m_db(db), m_path(path), m_thread(t) 
        {}
};

void MusicCollection::searchPath(const string& dir)
{
    search(dir);
}


void MusicCollection::search(const string& dir)
{
    Thread *thread = Thread::CreateThread();
    music_search_data *msd = new music_search_data(this, dir, thread);

    thread->Create(MusicCollection::search_thread, msd, true);
}

void MusicCollection::search_thread(void *arg)
{
    music_search_data *msd = (music_search_data*)arg;
    vector<fs::path> pending;

    pending.push_back(fs::path(msd->m_path));

    while (!pending.empty()) {
        fs::path dir_path = pending.front(); 
        pending.erase(pending.begin());

        fs::directory_iterator enddir;
        fs::directory_iterator di(dir_path);
        string url;
        Metadata md;
        for (; di != enddir; di++){
            if (fs::is_directory(*di)){
                pending.push_back(*di);
            } else {
                md.clear();
                //FilePathToURL(di->leaf(), url);
                url = "file://";
                url += di->native_file_string();
                fprintf(stderr, "adding %s\n", url.c_str());
                msd->m_db->addURL(url, md);
            }
        }
    }
    msd->m_db->AcceptEvent(new Event(INFO_SearchMusicDone));
}


MusicCollection::MusicCollection(FAContext *context)
    : m_context(context),
      m_mbdb(0), m_tags(0), m_localdb(0)
{
    enum { NONE, SIMPLE, MEDIUM, ADVANCED } mdlevel = ADVANCED;

    m_collection.reserve(4);

    m_local = m_collection.insert(m_collection.end(),
                                  MetadataCollection("local"));
    m_stream= m_collection.insert(m_collection.end(),
                                  MetadataCollection("stream"));
    m_cd = m_collection.insert(m_collection.end(), 
                               MetadataCollection("cd"));


    string dbpath;
    m_context->prefs->GetPrefString(kDatabaseDirPref, dbpath);
    dbpath += DIR_MARKER_STR;
    dbpath += "metadb";

    m_mbdb    = new MusicBrainzDB();
    m_tags    = new FileMetadataDB(context->plm);
    m_paths   = new FilepathDB();
    m_localdb = new MKDatabase(dbpath);
    
    // Stream info is only stored in a local DB 
    // TODO:  Read stream catalog from Shoutcast, etc..
    (*m_stream).append(m_localdb);

    // CD metadata acts as if it's comming from
    // the file.  However, it's really looked up
    // on musicbrainz.. this probably needs to be 
    // restructured.
    (*m_cd).append(m_localdb);
    (*m_cd).append(m_tags);
    (*m_cd).append(m_mbdb);
    

    // Song metadata can be managed in several layers.
    switch(mdlevel){
    case NONE:
        // No Metadata support at all... only filenames support
        (*m_local).append(m_paths);
        
        break;
    case SIMPLE:
        (*m_local).append(m_localdb);
        (*m_local).append(m_tags);
        (*m_local).append(m_paths);
        break;
    case MEDIUM:
    case ADVANCED:
        (*m_local).append(m_localdb);
        (*m_local).append(m_tags);
        (*m_local).append(m_paths);
        (*m_local).append(m_mbdb);
        break;
    }
}



MusicCollection::~MusicCollection()
{
    //delete m_cache;
    delete m_paths;
    delete m_tags;
    delete m_localdb;
    delete m_mbdb;
}


bool 
MusicCollection::readMetadata(const url_t&url, Metadata&md)
{
    // Find a collection that manages this url.
    vcollection_t::iterator cols;
    for (cols = m_collection.begin(); cols != m_collection.end(); cols++){
        MetadataCollection& mdb = *cols;
        if (mdb.contains(url)) {
            mdb.readMetadata(url, md);
            return true;
        }
    }
    return false;
}


bool
MusicCollection::saveMetadata(const url_t&url, const Metadata&md)
{
    return false;
}

bool MusicCollection::containsURL(const url_t&url)
{
    return (*m_local).contains(url);
}

void MusicCollection::addURL(const url_t&url, Metadata&md)
{
    if (!md.hasKey(Metadata::kType)) {
        // TODO
        // Is playlist as playlist readers if supported
        // or is it a stream  format or CD.
        // Or is it music format .. ask media converters
        
        if (ends_with(url,".m3u") || ends_with(url, ".pls"))
            md[Metadata::kType] = "P";
        else if (url.substr(0,7) == "http://")
            md[Metadata::kType] = "S";
        else 
            md[Metadata::kType] = "F";
    }
    (*m_local).add(url, md);
}

void MusicCollection::removeURL(const url_t& url)
{
    (*m_local).remove(url);
}

Error
MusicCollection::query(const std::string&target, params_t&p, resultlist_t&r)
{
    fprintf(stderr, "MusicCollection::query %s %d\n", target.c_str(), p.size());
    //KGK Design choice: 
    //KGK   should we try all sources or only local music

    return (*m_local).query(target, p, r);
}



Error
00250 MusicCollection::getArtistList(resultlist_t& artistlist)
{
    params_t params;
    return query(Metadata::kArtist, params, artistlist);
}
Error 
MusicCollection::getAlbumList (const std::string& artist, resultlist_t&albums)
{
    params_t params;
    params[Metadata::kArtist] = artist;
    return query(Metadata::kAlbum, params, albums);
}
Error
MusicCollection::getTrackList(resultlist_t& tracks)
{
    params_t params;
    params[Metadata::kType] = "F";
    return query(Metadata::kUrl, params, tracks);
}
Error
MusicCollection::getTrackList(const string&artist, resultlist_t&tracks)
{
    params_t params;
    params[Metadata::kArtist] = artist;
    return query(Metadata::kUrl, params, tracks);
}
Error
MusicCollection::getTrackList(const string&artist, 
                              const string&album,
                              resultlist_t&tracks )
{
    params_t params;
    params[Metadata::kArtist] = artist;
    params[Metadata::kAlbum] = album;
    return query(Metadata::kUrl, params, tracks);
}

Error
MusicCollection::getStreamList(resultlist_t& r)
{
    params_t params;
    params[Metadata::kType] = "S";
    return query(Metadata::kUrl, params, r);
}
Error
MusicCollection::getPlaylists(resultlist_t& r)
{
    params_t params;
    params[Metadata::kType] = "P";
    return query(Metadata::kUrl, params, r);
}

Error 
MusicCollection::getGenres(resultlist_t& list)
{
    params_t params;
    return query(Metadata::kGenre, params, list);
}


Error 
00311 MusicCollection::getUncategorized(resultlist_t& list)
{
    params_t params;
    params[Metadata::kType] = "F";
    params[Metadata::kArtist] = "";
    params[Metadata::kAlbum] = "";
    return query(Metadata::kUrl, params, list);
}



Error 
00323 MusicCollection::readEntries(const url_t& url, resultlist_t&entries) 
{
    if (url.find("file://")==0) {
        string spath = url.substr(7);

        if (ends_with(spath, ".m3u")
            || ends_with(spath, ".pls")) {
            return readPlaylistEntries(url, entries);
        } else { 
            return readDirEntries(url, entries);
        }
    } else if (url.find("zinf://") == 0) {
        return readZinfEntries(url, entries);
    }

    return kError_NoErr;
}



Error 
00344 MusicCollection::readDirEntries(const url_t& url, resultlist_t&entries)
{
#ifdef HAVE_BOOST_FILESYSTEM_PATH_HPP
    // Remove "file://"
    string spath = url.substr(7);
    
    // Directory spec
    fs::path dir_path(spath);
    
    if (!fs::exists(dir_path)){
        return kError_NoErr;
    }
    
    if (fs::is_directory(dir_path)){
        fs::directory_iterator enddir;
        for (fs::directory_iterator di(dir_path);
             di != enddir;
             di++){
            string entry = "file://";
            entry +=(const string&)*di;
            entries.push_back(entry);
        }
    }
#endif
    return kError_NoErr;
}

/**
 *  Parse a path expression with query operators
 *  path?p1=val;p2=val
 */
int32_t
MusicCollection::parseQueryPath(const string& path, 
                                string& target, params_t& params)
{
    string::size_type pos, next;
    string buffer = path;

    pos = buffer.find('?');
    target = buffer.substr(0, pos);
    if (pos == string::npos)
        return 1;

    buffer = buffer.substr(pos+1);
    string pair;
    string key,val;
    int count = 1;
    while (pos != string::npos){
        pos = buffer.find(';');
        pair = buffer.substr(0,pos);
        buffer = buffer.substr(pos+1);

        next = pair.find('=');
        if (next == string::npos)
            return 0;
        key = pair.substr(0,next);
        val = pair.substr(next+1);

        params[key] = val;
        count++;
    }
    return count;
}

/** 
 *  Parse the given URL and translate to a Database query
 *  @param: url is URL of the form zinf://[result].m3u?[param list]
 *
 */
Error 
00414 MusicCollection::readZinfEntries(const url_t& url, resultlist_t&entries)
{

    string target;
    params_t params;
    parseQueryPath (url.substr(7), target, params);

    query(target, params, entries);

    return kError_NoErr;
}

/** Read the url specified as a playlist and fill the track
 * array
 */
Error 
00430 MusicCollection::readPlaylistEntries(const url_t&url, resultlist_t&tracks)
{
    m_context->plm->ReadPlaylist(url, tracks);
    return kError_NoErr;
}



00438 Error MusicCollection::AcceptEvent(Event *e)
{
    switch (e->Type()) {
    case INFO_SearchMusicDone:
        m_context->target->AcceptEvent(new Event(INFO_MusicCatalogRegenerating));
        m_localdb->commit();
        m_context->target->AcceptEvent(new Event(INFO_MusicCatalogDoneRegenerating));
        break;
    }
    return kError_NoErr;
}
/* arch-tag: 2b0bff36-4cb6-4aeb-abbf-dfeeca764059 */

Generated by  Doxygen 1.6.0   Back to index