File indexing completed on 2021-12-21 13:27:54
0001 /** 0002 * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org> 0003 * Copyright (C) 2009 Michael Pyne <mpyne@kde.org> 0004 * 0005 * This program is free software; you can redistribute it and/or modify it under 0006 * the terms of the GNU General Public License as published by the Free Software 0007 * Foundation; either version 2 of the License, or (at your option) any later 0008 * version. 0009 * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU General Public License along with 0015 * this program. If not, see <http://www.gnu.org/licenses/>. 0016 */ 0017 0018 #include "juktag.h" 0019 0020 #include <KLocalizedString> 0021 0022 #include <QFile> 0023 0024 #include <tag.h> //taglib 0025 #include <tfile.h> 0026 #include <audioproperties.h> 0027 #include <id3v2framefactory.h> 0028 0029 #include "cache.h" 0030 #include "mediafiles.h" 0031 #include "stringshare.h" 0032 #include "juk_debug.h" 0033 0034 //////////////////////////////////////////////////////////////////////////////// 0035 // public members 0036 //////////////////////////////////////////////////////////////////////////////// 0037 0038 0039 Tag::Tag(const QString &fileName) : 0040 m_fileName(fileName), 0041 m_track(0), 0042 m_year(0), 0043 m_seconds(0), 0044 m_bitrate(0), 0045 m_isValid(false) 0046 { 0047 if(fileName.isEmpty()) { 0048 qCCritical(JUK_LOG) << "Trying to add empty file"; 0049 return; 0050 } 0051 0052 TagLib::File *file = MediaFiles::fileFactoryByType(fileName); 0053 if(file && file->isValid()) { 0054 setup(file); 0055 delete file; 0056 } 0057 else { 0058 qCCritical(JUK_LOG) << "Couldn't resolve the mime type of \"" << 0059 fileName << "\" -- this shouldn't happen."; 0060 } 0061 } 0062 0063 bool Tag::save() const 0064 { 0065 bool result; 0066 TagLib::ID3v2::FrameFactory::instance()->setDefaultTextEncoding(TagLib::String::UTF8); 0067 TagLib::File *file = MediaFiles::fileFactoryByType(m_fileName); 0068 0069 if(file && !file->readOnly() && file->isValid() && file->tag()) { 0070 file->tag()->setTitle(TagLib::String(m_title.toUtf8().constData(), TagLib::String::UTF8)); 0071 file->tag()->setArtist(TagLib::String(m_artist.toUtf8().constData(), TagLib::String::UTF8)); 0072 file->tag()->setAlbum(TagLib::String(m_album.toUtf8().constData(), TagLib::String::UTF8)); 0073 file->tag()->setGenre(TagLib::String(m_genre.toUtf8().constData(), TagLib::String::UTF8)); 0074 file->tag()->setComment(TagLib::String(m_comment.toUtf8().constData(), TagLib::String::UTF8)); 0075 file->tag()->setTrack(m_track); 0076 file->tag()->setYear(m_year); 0077 result = file->save(); 0078 } 0079 else { 0080 qCCritical(JUK_LOG) << "Couldn't save file."; 0081 result = false; 0082 } 0083 0084 delete file; 0085 return result; 0086 } 0087 0088 QString Tag::playingString() const 0089 { 0090 QString str; 0091 if(artist().isEmpty()) 0092 str = title(); 0093 else { 0094 str = i18nc("a playing track, %1 is artist, %2 is song title", 0095 "%1 - <i>%2</i>", artist(), title()); 0096 } 0097 0098 return str; 0099 } 0100 0101 CacheDataStream &Tag::read(CacheDataStream &s) 0102 { 0103 switch(s.cacheVersion()) { 0104 case 1: { 0105 qint32 track; 0106 qint32 year; 0107 qint32 bitrate; 0108 qint32 seconds; 0109 0110 s >> m_title 0111 >> m_artist 0112 >> m_album 0113 >> m_genre 0114 >> track 0115 >> year 0116 >> m_comment 0117 >> bitrate 0118 >> m_lengthString 0119 >> seconds; 0120 0121 m_track = track; 0122 m_year = year; 0123 m_bitrate = bitrate; 0124 m_seconds = seconds; 0125 break; 0126 } 0127 default: { 0128 static QString dummyString; 0129 static int dummyInt; 0130 QString bitrateString; 0131 0132 s >> dummyInt 0133 >> m_title 0134 >> m_artist 0135 >> m_album 0136 >> m_genre 0137 >> dummyInt 0138 >> m_track 0139 >> dummyString 0140 >> m_year 0141 >> dummyString 0142 >> m_comment 0143 >> bitrateString 0144 >> m_lengthString 0145 >> m_seconds 0146 >> dummyString; 0147 0148 bool ok; 0149 m_bitrate = bitrateString.toInt(&ok); 0150 if(!ok) 0151 m_bitrate = 0; 0152 break; 0153 } 0154 } 0155 0156 minimizeMemoryUsage(); 0157 return s; 0158 } 0159 0160 //////////////////////////////////////////////////////////////////////////////// 0161 // private methods 0162 //////////////////////////////////////////////////////////////////////////////// 0163 0164 Tag::Tag(const QString &fileName, bool) : 0165 m_fileName(fileName), 0166 m_track(0), 0167 m_year(0), 0168 m_seconds(0), 0169 m_bitrate(0), 0170 m_isValid(true) 0171 { 0172 0173 } 0174 0175 void Tag::setup(TagLib::File *file) 0176 { 0177 if(!file || !file->tag()) { 0178 qCWarning(JUK_LOG) << "Can't setup invalid file" << m_fileName; 0179 return; 0180 } 0181 0182 m_title = TStringToQString(file->tag()->title()).trimmed(); 0183 m_artist = TStringToQString(file->tag()->artist()).trimmed(); 0184 m_album = TStringToQString(file->tag()->album()).trimmed(); 0185 m_genre = TStringToQString(file->tag()->genre()).trimmed(); 0186 m_comment = TStringToQString(file->tag()->comment()).trimmed(); 0187 0188 m_track = file->tag()->track(); 0189 m_year = file->tag()->year(); 0190 0191 m_seconds = file->audioProperties()->length(); 0192 m_bitrate = file->audioProperties()->bitrate(); 0193 0194 const int seconds = m_seconds % 60; 0195 const int minutes = (m_seconds - seconds) / 60; 0196 0197 m_lengthString = QString::number(minutes) + (seconds >= 10 ? ":" : ":0") + QString::number(seconds); 0198 0199 if(m_title.isEmpty()) { 0200 int i = m_fileName.lastIndexOf('/'); 0201 int j = m_fileName.lastIndexOf('.'); 0202 m_title = i > 0 ? m_fileName.mid(i + 1, j - i - 1) : m_fileName; 0203 } 0204 0205 minimizeMemoryUsage(); 0206 m_isValid = true; 0207 } 0208 0209 void Tag::minimizeMemoryUsage() 0210 { 0211 // Try to reduce memory usage: share tags that frequently repeat, squeeze others 0212 0213 m_title.squeeze(); 0214 m_lengthString.squeeze(); 0215 0216 m_comment = StringShare::tryShare(m_comment); 0217 m_artist = StringShare::tryShare(m_artist); 0218 m_album = StringShare::tryShare(m_album); 0219 m_genre = StringShare::tryShare(m_genre); 0220 } 0221 0222 //////////////////////////////////////////////////////////////////////////////// 0223 // related functions 0224 //////////////////////////////////////////////////////////////////////////////// 0225 0226 QDataStream &operator<<(QDataStream &s, const Tag &t) 0227 { 0228 s << t.title() 0229 << t.artist() 0230 << t.album() 0231 << t.genre() 0232 << qint32(t.track()) 0233 << qint32(t.year()) 0234 << t.comment() 0235 << qint32(t.bitrate()) 0236 << t.lengthString() 0237 << qint32(t.seconds()); 0238 0239 return s; 0240 } 0241 0242 CacheDataStream &operator>>(CacheDataStream &s, Tag &t) 0243 { 0244 return t.read(s); 0245 } 0246 0247 // vim: set et sw=4 tw=0 sta: