00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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