|
MythTV
0.26-pre
|
00001 // c/c++ 00002 #include <iostream> 00003 00004 // qt 00005 #include <QFile> 00006 #include <QRegExp> 00007 #include <QDir> 00008 00009 // mythtv 00010 #include <mythdirs.h> 00011 #include <mythlogging.h> 00012 #include <mythcorecontext.h> 00013 00014 extern "C" { 00015 #include <libavformat/avformat.h> 00016 #include <libavcodec/avcodec.h> 00017 } 00018 00019 // mythmusic 00020 #include "metadata.h" 00021 #include "musicutils.h" 00022 00023 static QRegExp badChars = QRegExp("(/|\\\\|:|\'|\"|\\?|\\|)"); 00024 00025 QString fixFilename(const QString &filename) 00026 { 00027 QString ret = filename; 00028 ret.replace(badChars, "_"); 00029 return ret; 00030 } 00031 00032 QString findIcon(const QString &type, const QString &name) 00033 { 00034 QString cleanName = fixFilename(name); 00035 QString file = GetConfDir() + QString("/MythMusic/Icons/%1/%2").arg(type).arg(cleanName); 00036 00037 if (QFile::exists(file + ".jpg")) 00038 return file + ".jpg"; 00039 00040 if (QFile::exists(file + ".jpeg")) 00041 return file + ".jpeg"; 00042 00043 if (QFile::exists(file + ".png")) 00044 return file + ".png"; 00045 00046 if (QFile::exists(file + ".gif")) 00047 return file + ".gif"; 00048 00049 return QString(); 00050 } 00051 00052 //TODO this needs updating to also use storage groups 00053 uint calcTrackLength(const QString &musicFile) 00054 { 00055 const char *type = NULL; 00056 00057 AVFormatContext *inputFC = NULL; 00058 AVInputFormat *fmt = NULL; 00059 00060 if (type) 00061 fmt = av_find_input_format(type); 00062 00063 // Open recording 00064 LOG(VB_GENERAL, LOG_DEBUG, QString("calcTrackLength: Opening '%1'") 00065 .arg(musicFile)); 00066 00067 QByteArray inFileBA = musicFile.toLocal8Bit(); 00068 00069 int ret = avformat_open_input(&inputFC, inFileBA.constData(), fmt, NULL); 00070 00071 if (ret) 00072 { 00073 LOG(VB_GENERAL, LOG_ERR, "calcTrackLength: Couldn't open input file" + 00074 ENO); 00075 return 0; 00076 } 00077 00078 // Getting stream information 00079 ret = avformat_find_stream_info(inputFC, NULL); 00080 00081 if (ret < 0) 00082 { 00083 LOG(VB_GENERAL, LOG_ERR, 00084 QString("calcTrackLength: Couldn't get stream info, error #%1").arg(ret)); 00085 avformat_close_input(&inputFC); 00086 inputFC = NULL; 00087 return 0; 00088 } 00089 00090 uint duration = 0; 00091 long long time = 0; 00092 00093 for (uint i = 0; i < inputFC->nb_streams; i++) 00094 { 00095 AVStream *st = inputFC->streams[i]; 00096 char buf[256]; 00097 00098 avcodec_string(buf, sizeof(buf), st->codec, false); 00099 00100 switch (inputFC->streams[i]->codec->codec_type) 00101 { 00102 case AVMEDIA_TYPE_AUDIO: 00103 { 00104 AVPacket pkt; 00105 av_init_packet(&pkt); 00106 00107 while (av_read_frame(inputFC, &pkt) >= 0) 00108 { 00109 if (pkt.stream_index == (int)i) 00110 time = time + pkt.duration; 00111 00112 av_free_packet(&pkt); 00113 } 00114 00115 duration = time * av_q2d(inputFC->streams[i]->time_base); 00116 break; 00117 } 00118 00119 default: 00120 LOG(VB_GENERAL, LOG_ERR, 00121 QString("Skipping unsupported codec %1 on stream %2") 00122 .arg(inputFC->streams[i]->codec->codec_type).arg(i)); 00123 break; 00124 } 00125 } 00126 00127 // Close input file 00128 avformat_close_input(&inputFC); 00129 inputFC = NULL; 00130 00131 return duration; 00132 } 00133 00134 inline QString fixFileToken_sl(QString token) 00135 { 00136 // this version doesn't remove fwd-slashes so we can 00137 // pick them up later and create directories as required 00138 token.replace(QRegExp("(\\\\|:|\'|\"|\\?|\\|)"), QString("_")); 00139 return token; 00140 } 00141 00142 QString filenameFromMetadata(Metadata *track, bool createDir) 00143 { 00144 QDir directoryQD(gMusicData->musicDir); 00145 QString filename; 00146 QString fntempl = gCoreContext->GetSetting("FilenameTemplate"); 00147 bool no_ws = gCoreContext->GetNumSetting("NoWhitespace", 0); 00148 00149 QRegExp rx_ws("\\s{1,}"); 00150 QRegExp rx("(GENRE|ARTIST|ALBUM|TRACK|TITLE|YEAR)"); 00151 int i = 0; 00152 int old_i = 0; 00153 while (i >= 0) 00154 { 00155 i = rx.indexIn(fntempl, i); 00156 if (i >= 0) 00157 { 00158 if (i > 0) 00159 filename += fixFileToken_sl(fntempl.mid(old_i,i-old_i)); 00160 i += rx.matchedLength(); 00161 old_i = i; 00162 00163 if ((rx.capturedTexts()[1] == "GENRE") && (!track->Genre().isEmpty())) 00164 filename += fixFilename(track->Genre()); 00165 00166 if ((rx.capturedTexts()[1] == "ARTIST") 00167 && (!track->FormatArtist().isEmpty())) 00168 filename += fixFilename(track->FormatArtist()); 00169 00170 if ((rx.capturedTexts()[1] == "ALBUM") && (!track->Album().isEmpty())) 00171 filename += fixFilename(track->Album()); 00172 00173 if ((rx.capturedTexts()[1] == "TRACK") && (track->Track() >= 0)) 00174 { 00175 QString tempstr = QString::number(track->Track(), 10); 00176 if (track->Track() < 10) 00177 tempstr.prepend('0'); 00178 filename += fixFilename(tempstr); 00179 } 00180 00181 if ((rx.capturedTexts()[1] == "TITLE") 00182 && (!track->FormatTitle().isEmpty())) 00183 filename += fixFilename(track->FormatTitle()); 00184 00185 if ((rx.capturedTexts()[1] == "YEAR") && (track->Year() >= 0)) 00186 filename += fixFilename(QString::number(track->Year(), 10)); 00187 } 00188 } 00189 00190 if (no_ws) 00191 filename.replace(rx_ws, "_"); 00192 00193 00194 if (filename == "" || filename.length() > FILENAME_MAX) 00195 { 00196 QString tempstr = QString::number(track->Track(), 10); 00197 tempstr += " - " + track->FormatTitle(); 00198 filename = fixFilename(tempstr); 00199 LOG(VB_GENERAL, LOG_ERR, "Invalid file storage definition."); 00200 } 00201 00202 if (createDir) 00203 { 00204 QFileInfo fi(filename); 00205 if (!directoryQD.mkpath(gMusicData->musicDir + fi.path())) 00206 LOG(VB_GENERAL, LOG_ERR, 00207 QString("Ripper: Failed to create directory path: '%1'").arg(gMusicData->musicDir + filename)); 00208 } 00209 00210 return filename; 00211 } 00212 00213 bool isNewTune(const QString& artist, const QString& album, const QString& title) 00214 { 00215 00216 QString matchartist = artist; 00217 QString matchalbum = album; 00218 QString matchtitle = title; 00219 00220 if (! matchartist.isEmpty()) 00221 { 00222 matchartist.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"), QString("_")); 00223 } 00224 00225 if (! matchalbum.isEmpty()) 00226 { 00227 matchalbum.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"), QString("_")); 00228 } 00229 00230 if (! matchtitle.isEmpty()) 00231 { 00232 matchtitle.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"), QString("_")); 00233 } 00234 00235 MSqlQuery query(MSqlQuery::InitCon()); 00236 QString queryString("SELECT filename, artist_name," 00237 " album_name, name, song_id " 00238 "FROM music_songs " 00239 "LEFT JOIN music_artists" 00240 " ON music_songs.artist_id=music_artists.artist_id " 00241 "LEFT JOIN music_albums" 00242 " ON music_songs.album_id=music_albums.album_id " 00243 "WHERE artist_name LIKE :ARTIST " 00244 "AND album_name LIKE :ALBUM " 00245 "AND name LIKE :TITLE " 00246 "ORDER BY artist_name, album_name," 00247 " name, song_id, filename"); 00248 00249 query.prepare(queryString); 00250 00251 query.bindValue(":ARTIST", matchartist); 00252 query.bindValue(":ALBUM", matchalbum); 00253 query.bindValue(":TITLE", matchtitle); 00254 00255 if (!query.exec() || !query.isActive()) 00256 { 00257 MythDB::DBError("Search music database", query); 00258 return true; 00259 } 00260 00261 if (query.size() > 0) 00262 return false; 00263 00264 return true; 00265 }
1.7.6.1