plaibuildlib.cpp

Go to the documentation of this file.
00001 // g++ -O3 recursedirs.cpp `taglib-config --cflags --libs` -lsqlite3 -o recursedirs
00002 
00003 // artists with only one song:
00004 // select artist as a from collection where (select count() from collection where artist==a)==1;
00005 // maybe:
00006 // update collection set album=artist where artist in (select artist as a from collection where (select count() from collection where artist==a)==1);
00007 // update collection set artist="(one song)" where artist in (select artist as a from collection where (select count() from collection where artist==a)==1);
00008 // NB this screws up names with "the " and also typos
00009 // plus we lose the album information, which is ugly. better to have a table of
00010 // single song artists?
00011 // thus:
00012 // create table onesongs(track int);
00013 // insert into onesongs select rowid from collection where sortartist in (select sortartist as a from collection where (select count() from collection where sortartist==a)==1);
00014 
00015 // find longest name of a certain artist
00016 // select artist from collection where sortartist=="prodigy" order by length(artist) desc limit 1;
00017 
00018 // and thus
00019 // select distinct sortartist as s,artist from collection where artist in (select artist from collection where sortartist==s  order by length(artist) desc limit 1) order by sortartist
00020 // gets a list of all sortartists and what they should be known as
00021 
00022 // and hence
00023 // create table artists(artist unicode,sortartist unicode)
00024 // insert into artists select distinct artist,sortartist as s from collection where artist in (select artist from collection where sortartist==s  order by length(artist) desc limit 1) order by sortartist
00025 // create index j on artists (artist,sortartist);
00026 // builds the artists table
00027 
00028 #include <iostream>
00029 using std::string; using std::cout; using std::endl; 
00030 #include <vector>
00031 using std::vector;
00032 #include <fstream>
00033 using std::ifstream;
00034 
00035 #include <fileref.h>
00036 using TagLib::FileRef;
00037 #include <tag.h>
00038 using TagLib::AudioProperties; using TagLib::Tag;
00039 
00040 #include "taglib_wmafiletyperesolver.h"
00041 #include "taglib_mp4filetyperesolver.h"
00042 
00043 #include <sqlite3.h>
00044 
00045 #include <sys/stat.h>
00046 
00047 
00048 vector<string> GetCommandOutput(string cmd)
00049 {
00050         const string tempfname="/tmp/recursedirstemp";
00051         
00052         system((cmd+" > "+tempfname).c_str());
00053         
00054         vector<string> ret;
00055         
00056         ifstream f(tempfname.c_str());
00057         while(!f.eof())
00058         {
00059                 string line;
00060                 getline(f,line);
00061                 ret.push_back(line);
00062         }
00063         f.close();
00064         
00065         return ret;
00066 }
00067 
00068 
00069 int GetFileModificationTime(const char* path)
00070 {
00071         struct stat buf;
00072         stat(path,&buf);
00073         return buf.st_mtime;
00074 }
00075 
00076 
00077 class CollectionTrack;
00078 
00079 class CollectionDB
00080 {
00081 public:
00082         CollectionDB(string dbfname);
00083         ~CollectionDB();
00084         void InsertTrack(CollectionTrack track);
00085         void PopulateOneSongsTable();
00086 protected:      
00087         sqlite3* db;
00088         sqlite3_stmt* pStmt;
00089 };
00090 
00091 
00092 class CollectionTrack
00093 {
00094 public:
00095         CollectionTrack(string fname);
00096         void Print();
00097         friend void CollectionDB::InsertTrack(CollectionTrack);
00098 protected:
00099         bool GetInfoTagLib();
00100         string fname,artist,album,title,sortartist;
00101         int length,modified;
00102 };
00103 
00104 
00105 CollectionTrack::CollectionTrack(string f)
00106 {
00107         fname=f;
00108         modified=GetFileModificationTime(f.c_str());
00109         
00110         title=fname.substr(f.rfind('/')+1);
00111         artist=album="(unknown)";
00112         length=-999;
00113         
00114         GetInfoTagLib();
00115 }
00116 
00117 
00118 void CollectionTrack::Print()
00119 {
00120         cout<<"fname - " <<fname <<endl;
00121         cout<<"title - " <<title <<endl;
00122         cout<<"artist - "<<artist<<endl;
00123         cout<<"album - " <<album <<endl;
00124         cout<<"length - "<<length<<endl;
00125 }
00126 
00127 
00128 bool CollectionTrack::GetInfoTagLib()
00129 {
00130         FileRef f(fname.c_str(),true,AudioProperties::Fast);
00131 
00132         if(f.isNull()) return false;
00133 
00134         Tag* tag;                       
00135         if(tag=f.tag())
00136         {
00137                 title =tag->title(). stripWhiteSpace().to8Bit();
00138                 artist=tag->artist().stripWhiteSpace().to8Bit();
00139                 album =tag->album(). stripWhiteSpace().to8Bit();
00140                 sortartist=tag->artist().stripWhiteSpace().upper().to8Bit();
00141                 if(sortartist.substr(0,4)=="THE ") sortartist=sortartist.substr(4);
00142         }
00143                 
00144         AudioProperties* properties;
00145         if(properties=f.audioProperties())
00146         {
00147                 length=properties->length();
00148         }
00149         
00150         return true;
00151 }
00152 
00153 
00154 CollectionDB::CollectionDB(string dbfname)
00155 {
00156         sqlite3_open(dbfname.c_str(),&db);
00157         sqlite3_exec(db,"create table collection(fname unicode,title unicode,artist unicode,sortartist unicode,album unicode,length int,modified int)",0,0,0);          
00158         sqlite3_exec(db,"create index i on collection (sortartist,artist,album,title,length,modified)",0,0,0);
00159         sqlite3_exec(db,"create table onesongs(track int)",0,0,0);
00160         sqlite3_prepare_v2(db,"insert into collection values(?,?,?,?,?,?,?)",-1,&pStmt,0);
00161 }
00162 
00163 
00164 CollectionDB::~CollectionDB()
00165 {
00166         sqlite3_finalize(pStmt);        
00167         sqlite3_close(db);
00168 }
00169 
00170 
00171 void CollectionDB::InsertTrack(CollectionTrack track)
00172 {
00173         sqlite3_bind_text(pStmt,1,track. fname      .c_str(),-1,SQLITE_TRANSIENT);
00174         sqlite3_bind_text(pStmt,2,track. title      .c_str(),-1,SQLITE_TRANSIENT);
00175         sqlite3_bind_text(pStmt,3,track. artist     .c_str(),-1,SQLITE_TRANSIENT);
00176         sqlite3_bind_text(pStmt,4,track. sortartist .c_str(),-1,SQLITE_TRANSIENT);
00177         sqlite3_bind_text(pStmt,5,track. album      .c_str(),-1,SQLITE_TRANSIENT);
00178         sqlite3_bind_int(pStmt, 6,track. length);
00179         sqlite3_bind_int(pStmt, 7,track. modified);
00180         sqlite3_step(pStmt);
00181         sqlite3_reset(pStmt);
00182 }
00183 
00184 
00185 void CollectionDB::PopulateOneSongsTable()
00186 {
00187         sqlite3_exec(db,"insert into onesongs select rowid from collection where sortartist in (select sortartist as a from collection where (select count() from collection where sortartist==a)==1)",0,0,0);
00188 }
00189 
00190 
00191 bool ParseCommandLine(int argc,char** argv,string& dbfname,vector<string>& folders)
00192 {
00193         if(argc<3)
00194         {
00195                 cout<<"Usage : "<<argv[0]<<" DATABASEFILE FOLDER(s)\n";
00196                 return false;
00197         }
00198         dbfname=argv[1];
00199         for(int n=2;n<argc;++n) folders.push_back(argv[n]);
00200                 
00201         return true;
00202 }
00203 
00204 
00205 vector<string> GetSongsInFolders(vector<string> folders)
00206 {
00207         string cmd="find ";
00208         for(int n=0;n<folders.size();++n) cmd+="\""+folders[n]+"\" ";
00209         
00210         vector<string> fnames=GetCommandOutput(cmd);
00211 
00212         vector<string> ret;
00213         for(int n=0;n<fnames.size();++n)
00214         {
00215                 if(fnames[n].size()>=3)
00216                 {
00217                         const string ext=fnames[n].substr(fnames[n].size()-3);
00218                         if(ext=="wma" || ext=="mp3" || ext=="ogg" || ext=="mpc" || ext=="m4a")
00219                                 ret.push_back(fnames[n]);
00220                 }
00221         }
00222         
00223         return ret;
00224 }
00225 
00226 int main(int argc,char** argv)
00227 {
00228         string dbfname;
00229         vector<string> folders;
00230         
00231         if(!ParseCommandLine(argc,argv,dbfname,folders)) return -1;
00232                 
00233         vector<string> files=GetSongsInFolders(folders);
00234         
00235         cout<<"numfiles - "<<files.size()<<endl;
00236         
00237         FileRef::addFileTypeResolver(new WMAFileTypeResolver);
00238         FileRef::addFileTypeResolver(new MP4FileTypeResolver);
00239         
00240         CollectionDB dbinf(dbfname);
00241         
00242         for(int n=0;n<files.size();++n)
00243         {
00244                 CollectionTrack track(files[n]);
00245                 dbinf.InsertTrack(track);       
00246                 track.Print();
00247         }
00248         
00249         cout<<"building onesongs table"<<endl;
00250         dbinf.PopulateOneSongsTable();
00251         
00252         cout<<"done"<<endl;
00253         
00254         return 0;
00255 };
00256 
00257 

Generated on Mon Aug 6 21:24:20 2007 for plai by  doxygen 1.5.1