diff --git a/src/Config.h b/src/Config.h index 5197914c..72ba6c76 100644 --- a/src/Config.h +++ b/src/Config.h @@ -25,8 +25,8 @@ #define VER_LAMEXP_MAJOR 4 #define VER_LAMEXP_MINOR_HI 0 #define VER_LAMEXP_MINOR_LO 0 -#define VER_LAMEXP_BUILD 279 -#define VER_LAMEXP_SUFFIX Beta-2 +#define VER_LAMEXP_BUILD 282 +#define VER_LAMEXP_SUFFIX Beta-3 /* * Tools versions diff --git a/src/Thread_FileAnalyzer.cpp b/src/Thread_FileAnalyzer.cpp index 8390718d..ee7559cf 100644 --- a/src/Thread_FileAnalyzer.cpp +++ b/src/Thread_FileAnalyzer.cpp @@ -78,8 +78,11 @@ void FileAnalyzer::run() AudioFileModel file = analyzeFile(currentFile); if(file.fileName().isEmpty() || file.formatContainerType().isEmpty() || file.formatAudioType().isEmpty()) { - m_filesRejected++; - qDebug("Skipped: %s", file.filePath().toUtf8().constData()); + if(!importPlaylist(m_inputFiles, currentFile)) + { + m_filesRejected++; + qDebug("Skipped: %s", file.filePath().toUtf8().constData()); + } continue; } m_filesAccepted++; @@ -91,7 +94,7 @@ void FileAnalyzer::run() } //////////////////////////////////////////////////////////// -// Public Functions +// Privtae Functions //////////////////////////////////////////////////////////// const AudioFileModel FileAnalyzer::analyzeFile(const QString &filePath) @@ -355,6 +358,246 @@ unsigned int FileAnalyzer::parseDuration(const QString &str) return 0; } + +bool FileAnalyzer::importPlaylist(QStringList &fileList, const QString &playlistFile) +{ + QFileInfo file(playlistFile); + QDir baseDir(file.canonicalPath()); + + QDir rootDir(baseDir); + while(rootDir.cdUp()); + + //Sanity check + if(file.size() < 3 || file.size() > 512000) + { + return false; + } + + //Detect playlist type + playlist_t playlistType = isPlaylist(file.canonicalFilePath()); + + //Exit if not a playlist + if(playlistType == noPlaylist) + { + return false; + } + + QFile data(playlistFile); + + //Open file for reading + if(!data.open(QIODevice::ReadOnly)) + { + return false; + } + + //Parse playlist depending on type + switch(playlistType) + { + case m3uPlaylist: + return parsePlaylist_m3u(data, fileList, baseDir, rootDir); + break; + case plsPlaylist: + return parsePlaylist_pls(data, fileList, baseDir, rootDir); + break; + case wplPlaylist: + return parsePlaylist_wpl(data, fileList, baseDir, rootDir); + break; + default: + return false; + break; + } +} + +bool FileAnalyzer::parsePlaylist_m3u(QFile &data, QStringList &fileList, const QDir &baseDir, const QDir &rootDir) +{ + QByteArray line = data.readLine(); + + while(line.size() > 0) + { + QFileInfo filename1(QDir::fromNativeSeparators(QString::fromUtf8(line.constData(), line.size()).trimmed())); + QFileInfo filename2(QDir::fromNativeSeparators(QString::fromLatin1(line.constData(), line.size()).trimmed())); + + filename1.setCaching(false); + filename2.setCaching(false); + + if(!(filename1.filePath().startsWith("#") || filename2.filePath().startsWith("#"))) + { + fixFilePath(filename1, baseDir, rootDir); + fixFilePath(filename2, baseDir, rootDir); + + if(filename1.exists()) + { + if(isPlaylist(filename1.canonicalFilePath()) == noPlaylist) + { + fileList << filename1.canonicalFilePath(); + } + } + else if(filename2.exists()) + { + if(isPlaylist(filename2.canonicalFilePath()) == noPlaylist) + { + fileList << filename2.canonicalFilePath(); + } + } + } + + line = data.readLine(); + } + + return true; +} + +bool FileAnalyzer::parsePlaylist_pls(QFile &data, QStringList &fileList, const QDir &baseDir, const QDir &rootDir) +{ + QRegExp plsEntry("File(\\d+)=(.+)", Qt::CaseInsensitive); + QByteArray line = data.readLine(); + + while(line.size() > 0) + { + bool flag = false; + + QString temp1(QDir::fromNativeSeparators(QString::fromUtf8(line.constData(), line.size()).trimmed())); + QString temp2(QDir::fromNativeSeparators(QString::fromLatin1(line.constData(), line.size()).trimmed())); + + if(!flag && plsEntry.indexIn(temp1) >= 0) + { + QFileInfo filename(QDir::fromNativeSeparators(plsEntry.cap(2)).trimmed()); + filename.setCaching(false); + fixFilePath(filename, baseDir, rootDir); + + if(filename.exists()) + { + if(isPlaylist(filename.canonicalFilePath()) == noPlaylist) + { + fileList << filename.canonicalFilePath(); + flag = true; + } + } + } + + if(!flag && plsEntry.indexIn(temp2) >= 0) + { + QFileInfo filename(QDir::fromNativeSeparators(plsEntry.cap(2)).trimmed()); + filename.setCaching(false); + fixFilePath(filename, baseDir, rootDir); + + if(filename.exists()) + { + if(isPlaylist(filename.canonicalFilePath()) == noPlaylist) + { + fileList << filename.canonicalFilePath(); + flag = true; + } + } + } + + line = data.readLine(); + } + + return true; +} + +bool FileAnalyzer::parsePlaylist_wpl(QFile &data, QStringList &fileList, const QDir &baseDir, const QDir &rootDir) +{ + QRegExp wplEntry("<(media|ref)[^<>]*(src|href)=\"([^\"]+)\"[^<>]*>", Qt::CaseInsensitive); + QByteArray line = data.readLine(); + + while(line.size() > 0) + { + bool flag = false; + + QString temp1(QDir::fromNativeSeparators(QString::fromUtf8(line.constData(), line.size()).trimmed())); + QString temp2(QDir::fromNativeSeparators(QString::fromLatin1(line.constData(), line.size()).trimmed())); + + if(!flag && wplEntry.indexIn(temp1) >= 0) + { + QFileInfo filename(QDir::fromNativeSeparators(wplEntry.cap(3)).trimmed()); + filename.setCaching(false); + fixFilePath(filename, baseDir, rootDir); + + if(filename.exists()) + { + if(isPlaylist(filename.canonicalFilePath()) == noPlaylist) + { + fileList << filename.canonicalFilePath(); + flag = true; + } + } + } + + if(!flag && wplEntry.indexIn(temp2) >= 0) + { + QFileInfo filename(QDir::fromNativeSeparators(wplEntry.cap(3)).trimmed()); + filename.setCaching(false); + fixFilePath(filename, baseDir, rootDir); + + if(filename.exists()) + { + if(isPlaylist(filename.canonicalFilePath()) == noPlaylist) + { + fileList << filename.canonicalFilePath(); + flag = true; + } + } + } + + line = data.readLine(); + } + + return true; +} + +FileAnalyzer::playlist_t FileAnalyzer::isPlaylist(const QString &fileName) +{ + QFileInfo file (fileName); + + if(file.suffix().compare("m3u", Qt::CaseInsensitive) == 0) + { + return m3uPlaylist; + } + else if(file.suffix().compare("m3u8", Qt::CaseInsensitive) == 0) + { + return m3uPlaylist; + } + else if(file.suffix().compare("pls", Qt::CaseInsensitive) == 0) + { + return plsPlaylist; + } + else if(file.suffix().compare("asx", Qt::CaseInsensitive) == 0) + { + return wplPlaylist; + } + else if(file.suffix().compare("wpl", Qt::CaseInsensitive) == 0) + { + return wplPlaylist; + } + else + { + return noPlaylist; + } +} + +void FileAnalyzer::fixFilePath(QFileInfo &filename, const QDir &baseDir, const QDir &rootDir) +{ + if(filename.filePath().startsWith("/")) + { + while(filename.filePath().startsWith("/")) + { + filename.setFile(filename.filePath().mid(1)); + } + filename.setFile(rootDir.filePath(filename.filePath())); + } + + if(!filename.isAbsolute()) + { + filename.setFile(baseDir.filePath(filename.filePath())); + } +} + +//////////////////////////////////////////////////////////// +// Public Functions +//////////////////////////////////////////////////////////// + unsigned int FileAnalyzer::filesAccepted(void) { return m_filesAccepted; diff --git a/src/Thread_FileAnalyzer.h b/src/Thread_FileAnalyzer.h index aa47346a..d3d2bf9c 100644 --- a/src/Thread_FileAnalyzer.h +++ b/src/Thread_FileAnalyzer.h @@ -27,6 +27,9 @@ #include class AudioFileModel; +class QFile; +class QDir; +class QFileInfo; //////////////////////////////////////////////////////////// // Splash Thread @@ -55,12 +58,27 @@ private: sectionAudio, sectionOther }; + + enum playlist_t + { + noPlaylist, + m3uPlaylist, + plsPlaylist, + wplPlaylist + }; const AudioFileModel analyzeFile(const QString &filePath); void updateInfo(AudioFileModel &audioFile, const QString &key, const QString &value); void updateSection(const QString §ion); unsigned int parseYear(const QString &str); unsigned int parseDuration(const QString &str); + bool importPlaylist(QStringList &fileList, const QString &playlistFile); + bool parsePlaylist_m3u(QFile &data, QStringList &fileList, const QDir &baseDir, const QDir &rootDir); + bool parsePlaylist_pls(QFile &data, QStringList &fileList, const QDir &baseDir, const QDir &rootDir); + bool parsePlaylist_wpl(QFile &data, QStringList &fileList, const QDir &baseDir, const QDir &rootDir); + playlist_t isPlaylist(const QString &fileName); + void fixFilePath(QFileInfo &filename, const QDir &baseDir, const QDir &rootDir); + QStringList m_inputFiles; const QString m_mediaInfoBin_x86;