File indexing completed on 2023-05-30 11:30:48
0001 /** 0002 * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org> 0003 * 0004 * This program is free software; you can redistribute it and/or modify it under 0005 * the terms of the GNU General Public License as published by the Free Software 0006 * Foundation; either version 2 of the License, or (at your option) any later 0007 * version. 0008 * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. 0012 * 0013 * You should have received a copy of the GNU General Public License along with 0014 * this program. If not, see <http://www.gnu.org/licenses/>. 0015 */ 0016 0017 #include "mediafiles.h" 0018 0019 #include <KLocalizedString> 0020 #include <KIO/StatJob> 0021 #include <KJobWidgets> 0022 0023 #include <QWidget> 0024 #include <QFile> 0025 #include <QUrl> 0026 #include <QFileDialog> 0027 #include <QStandardPaths> 0028 #include <QMimeType> 0029 #include <QMimeDatabase> 0030 0031 #include <taglib.h> 0032 #include <taglib_config.h> 0033 #include <tag.h> 0034 #include <mpegfile.h> 0035 #include <vorbisfile.h> 0036 #include <flacfile.h> 0037 #include <xiphcomment.h> 0038 #include <oggflacfile.h> 0039 #include <mpcfile.h> 0040 #include <opusfile.h> 0041 #include <asffile.h> 0042 #include <mp4file.h> 0043 0044 #include "juk_debug.h" 0045 0046 namespace MediaFiles { 0047 static QStringList savedMimeTypes; 0048 0049 static const char mp3Type[] = "audio/mpeg"; 0050 static const char oggType[] = "audio/ogg"; 0051 static const char flacType[] = "audio/x-flac"; 0052 static const char mpcType[] = "audio/x-musepack"; 0053 static const char m3uType[] = "audio/x-mpegurl"; 0054 0055 static const char vorbisType[] = "audio/x-vorbis+ogg"; 0056 static const char oggflacType[] = "audio/x-flac+ogg"; 0057 static const char oggopusType[] = "audio/x-opus+ogg"; 0058 0059 static const char asfType[] = "video/x-ms-asf"; 0060 0061 static const char mp4Type[] = "audio/mp4"; 0062 static const char mp4AudiobookType[] = "audio/x-m4b"; 0063 0064 static const char *const mediaTypes[] = { 0065 mp3Type, oggType, flacType, mpcType, vorbisType, oggflacType 0066 ,asfType 0067 ,mp4Type 0068 ,mp4AudiobookType 0069 ,oggopusType 0070 }; 0071 0072 static const char playlistExtension[] = ".m3u"; 0073 } 0074 0075 #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) 0076 0077 static QString getMusicDir() 0078 { 0079 const auto musicLocation = 0080 QStandardPaths::writableLocation(QStandardPaths::MusicLocation); 0081 0082 QDir musicDir(musicLocation); 0083 if (Q_UNLIKELY( 0084 !musicDir.exists() && 0085 musicDir.isAbsolute() && // safety precaution here 0086 !musicDir.mkpath(musicLocation))) 0087 { 0088 qCWarning(JUK_LOG) << "Failed to create music dir:" << musicLocation; 0089 } 0090 0091 return musicLocation; 0092 } 0093 0094 QStringList MediaFiles::openDialog(QWidget *parent) 0095 { 0096 QFileDialog dialog(parent); 0097 0098 dialog.setFileMode(QFileDialog::ExistingFiles); 0099 dialog.setMimeTypeFilters(mimeTypes()); 0100 // limit to only file:// for now 0101 dialog.setSupportedSchemes(QStringList() << QStringLiteral("file")); 0102 dialog.setDirectory(getMusicDir()); 0103 dialog.setWindowTitle(i18nc("open audio file", "Open")); 0104 0105 if(dialog.exec()) { 0106 return dialog.selectedFiles(); 0107 } 0108 0109 return QStringList(); 0110 } 0111 0112 QString MediaFiles::savePlaylistDialog(const QString &playlistName, QWidget *parent) 0113 { 0114 QString fileName = QFileDialog::getSaveFileName( 0115 parent, 0116 i18n("Save Playlist") + QStringLiteral(" ") + playlistName, 0117 getMusicDir(), 0118 i18nc("For save dialog, %1 is always .m3u", "Playlists (*%1)", playlistExtension) 0119 ); 0120 return fileName; 0121 } 0122 0123 TagLib::File *MediaFiles::fileFactoryByType(const QString &fileName) 0124 { 0125 QMimeDatabase db; 0126 QMimeType result = db.mimeTypeForFile(fileName); 0127 if(!result.isValid()) 0128 return nullptr; 0129 0130 TagLib::File *file(nullptr); 0131 QByteArray encodedFileName(QFile::encodeName(fileName)); 0132 0133 if(result.inherits(QLatin1String(mp3Type))) 0134 file = new TagLib::MPEG::File(encodedFileName.constData()); 0135 else if(result.inherits(QLatin1String(flacType))) 0136 file = new TagLib::FLAC::File(encodedFileName.constData()); 0137 else if(result.inherits(QLatin1String(vorbisType))) 0138 file = new TagLib::Vorbis::File(encodedFileName.constData()); 0139 else if(result.inherits(QLatin1String(asfType))) 0140 file = new TagLib::ASF::File(encodedFileName.constData()); 0141 else if(result.inherits(QLatin1String(mp4Type)) || result.inherits(QLatin1String(mp4AudiobookType))) 0142 file = new TagLib::MP4::File(encodedFileName.constData()); 0143 else if(result.inherits(QLatin1String(mpcType))) 0144 file = new TagLib::MPC::File(encodedFileName.constData()); 0145 else if(result.inherits(QLatin1String(oggflacType))) 0146 file = new TagLib::Ogg::FLAC::File(encodedFileName.constData()); 0147 else if(result.inherits(QLatin1String(oggopusType)) || 0148 (result.inherits(QLatin1String(oggType)) && fileName.endsWith(QLatin1String(".opus"))) 0149 ) 0150 { 0151 file = new TagLib::Ogg::Opus::File(encodedFileName.constData()); 0152 } 0153 0154 return file; 0155 } 0156 0157 bool MediaFiles::isMediaFile(const QString &fileName) 0158 { 0159 QMimeDatabase db; 0160 QMimeType result = db.mimeTypeForFile(fileName); 0161 if(!result.isValid()) 0162 return false; 0163 0164 // Search through our table of media types for a match 0165 const auto validMimeTypes(mimeTypes()); 0166 for(const auto &mimeType : validMimeTypes) { 0167 if(result.inherits(mimeType)) 0168 return true; 0169 } 0170 0171 return false; 0172 } 0173 0174 static bool isFileOfMimeType(const QString &fileName, const QString &mimeType) 0175 { 0176 QMimeDatabase db; 0177 QMimeType result = db.mimeTypeForFile(fileName); 0178 return result.isValid() && result.inherits(mimeType); 0179 } 0180 0181 bool MediaFiles::isPlaylistFile(const QString &fileName) 0182 { 0183 return isFileOfMimeType(fileName, m3uType); 0184 } 0185 0186 bool MediaFiles::isMP3(const QString &fileName) 0187 { 0188 return isFileOfMimeType(fileName, mp3Type); 0189 } 0190 0191 bool MediaFiles::isOgg(const QString &fileName) 0192 { 0193 return isFileOfMimeType(fileName, oggType); 0194 } 0195 0196 bool MediaFiles::isFLAC(const QString &fileName) 0197 { 0198 return isFileOfMimeType(fileName, flacType); 0199 } 0200 0201 bool MediaFiles::isMPC(const QString &fileName) 0202 { 0203 return isFileOfMimeType(fileName, mpcType); 0204 } 0205 0206 bool MediaFiles::isVorbis(const QString &fileName) 0207 { 0208 return isFileOfMimeType(fileName, vorbisType); 0209 } 0210 0211 bool MediaFiles::isASF(const QString &fileName) 0212 { 0213 return isFileOfMimeType(fileName, asfType); 0214 } 0215 0216 bool MediaFiles::isMP4(const QString &fileName) 0217 { 0218 return isFileOfMimeType(fileName, mp4Type) || isFileOfMimeType(fileName, mp4AudiobookType); 0219 } 0220 0221 bool MediaFiles::isOggFLAC(const QString &fileName) 0222 { 0223 return isFileOfMimeType(fileName, oggflacType); 0224 } 0225 0226 QStringList MediaFiles::mimeTypes() 0227 { 0228 if(!savedMimeTypes.isEmpty()) 0229 return savedMimeTypes; 0230 0231 for(unsigned i = 0; i < ARRAY_SIZE(mediaTypes); ++i) { 0232 savedMimeTypes << QLatin1String(mediaTypes[i]); 0233 } 0234 0235 return savedMimeTypes; 0236 } 0237 0238 QStringList MediaFiles::convertURLsToLocal(const QList<QUrl> &urlList, QWidget *w) 0239 { 0240 QStringList result; 0241 QUrl localUrl; 0242 0243 for(const auto &url : urlList) { 0244 auto localizerJob = KIO::mostLocalUrl(url); 0245 KJobWidgets::setWindow(localizerJob, w); 0246 0247 if(localizerJob->exec() && (localUrl = localizerJob->mostLocalUrl()).isLocalFile()) 0248 result.append(localUrl.path()); 0249 else 0250 qCDebug(JUK_LOG) << url << " is not a local file, skipping."; 0251 } 0252 0253 return result; 0254 } 0255 0256 // vim: set et sw=4 tw=0 sta: