File indexing completed on 2023-05-30 11:30:47
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 <tag.h> //taglib 0023 #include <tfile.h> 0024 #include <audioproperties.h> 0025 #include <id3v2framefactory.h> 0026 0027 #include "cache.h" 0028 #include "mediafiles.h" 0029 #include "stringshare.h" 0030 #include "juk_debug.h" 0031 0032 //////////////////////////////////////////////////////////////////////////////// 0033 // public members 0034 //////////////////////////////////////////////////////////////////////////////// 0035 0036 0037 Tag::Tag(const QString &fileName) : 0038 m_fileName(fileName), 0039 m_track(0), 0040 m_year(0), 0041 m_seconds(0), 0042 m_bitrate(0), 0043 m_isValid(false) 0044 { 0045 if(fileName.isEmpty()) { 0046 qCCritical(JUK_LOG) << "Trying to add empty file"; 0047 return; 0048 } 0049 0050 TagLib::File *file = MediaFiles::fileFactoryByType(fileName); 0051 if(file && file->isValid()) { 0052 setup(file); 0053 delete file; 0054 } 0055 else { 0056 qCCritical(JUK_LOG) << "Couldn't resolve the mime type of \"" << 0057 fileName << "\" -- this shouldn't happen."; 0058 } 0059 } 0060 0061 bool Tag::save() const 0062 { 0063 bool result; 0064 TagLib::ID3v2::FrameFactory::instance()->setDefaultTextEncoding(TagLib::String::UTF8); 0065 TagLib::File *file = MediaFiles::fileFactoryByType(m_fileName); 0066 0067 if(file && !file->readOnly() && file->isValid() && file->tag()) { 0068 file->tag()->setTitle(TagLib::String(m_title.toUtf8().constData(), TagLib::String::UTF8)); 0069 file->tag()->setArtist(TagLib::String(m_artist.toUtf8().constData(), TagLib::String::UTF8)); 0070 file->tag()->setAlbum(TagLib::String(m_album.toUtf8().constData(), TagLib::String::UTF8)); 0071 file->tag()->setGenre(TagLib::String(m_genre.toUtf8().constData(), TagLib::String::UTF8)); 0072 file->tag()->setComment(TagLib::String(m_comment.toUtf8().constData(), TagLib::String::UTF8)); 0073 file->tag()->setTrack(m_track); 0074 file->tag()->setYear(m_year); 0075 result = file->save(); 0076 } 0077 else { 0078 qCCritical(JUK_LOG) << "Couldn't save file."; 0079 result = false; 0080 } 0081 0082 delete file; 0083 return result; 0084 } 0085 0086 QString Tag::playingString() const 0087 { 0088 QString str; 0089 if(artist().isEmpty()) 0090 str = title(); 0091 else { 0092 str = i18nc("a playing track, %1 is artist, %2 is song title", 0093 "%1 - <i>%2</i>", artist(), title()); 0094 } 0095 0096 return str; 0097 } 0098 0099 CacheDataStream &Tag::read(CacheDataStream &s) 0100 { 0101 switch(s.cacheVersion()) { 0102 case 1: { 0103 qint32 track; 0104 qint32 year; 0105 qint32 bitrate; 0106 qint32 seconds; 0107 0108 s >> m_title 0109 >> m_artist 0110 >> m_album 0111 >> m_genre 0112 >> track 0113 >> year 0114 >> m_comment 0115 >> bitrate 0116 >> m_lengthString 0117 >> seconds; 0118 0119 m_track = track; 0120 m_year = year; 0121 m_bitrate = bitrate; 0122 m_seconds = seconds; 0123 break; 0124 } 0125 default: { 0126 static QString dummyString; 0127 static int dummyInt; 0128 QString bitrateString; 0129 0130 s >> dummyInt 0131 >> m_title 0132 >> m_artist 0133 >> m_album 0134 >> m_genre 0135 >> dummyInt 0136 >> m_track 0137 >> dummyString 0138 >> m_year 0139 >> dummyString 0140 >> m_comment 0141 >> bitrateString 0142 >> m_lengthString 0143 >> m_seconds 0144 >> dummyString; 0145 0146 bool ok; 0147 m_bitrate = bitrateString.toInt(&ok); 0148 if(!ok) 0149 m_bitrate = 0; 0150 break; 0151 } 0152 } 0153 0154 minimizeMemoryUsage(); 0155 return s; 0156 } 0157 0158 //////////////////////////////////////////////////////////////////////////////// 0159 // private methods 0160 //////////////////////////////////////////////////////////////////////////////// 0161 0162 Tag::Tag(const QString &fileName, bool) : 0163 m_fileName(fileName), 0164 m_track(0), 0165 m_year(0), 0166 m_seconds(0), 0167 m_bitrate(0), 0168 m_isValid(true) 0169 { 0170 0171 } 0172 0173 void Tag::setup(TagLib::File *file) 0174 { 0175 if(!file || !file->tag()) { 0176 qCWarning(JUK_LOG) << "Can't setup invalid file" << m_fileName; 0177 return; 0178 } 0179 0180 m_title = TStringToQString(file->tag()->title()).trimmed(); 0181 m_artist = TStringToQString(file->tag()->artist()).trimmed(); 0182 m_album = TStringToQString(file->tag()->album()).trimmed(); 0183 m_genre = TStringToQString(file->tag()->genre()).trimmed(); 0184 m_comment = TStringToQString(file->tag()->comment()).trimmed(); 0185 0186 m_track = file->tag()->track(); 0187 m_year = file->tag()->year(); 0188 0189 m_seconds = file->audioProperties()->length(); 0190 m_bitrate = file->audioProperties()->bitrate(); 0191 0192 const int seconds = m_seconds % 60; 0193 const int minutes = (m_seconds - seconds) / 60; 0194 0195 m_lengthString = QString::number(minutes) + (seconds >= 10 ? ":" : ":0") + QString::number(seconds); 0196 0197 if(m_title.isEmpty()) { 0198 int i = m_fileName.lastIndexOf('/'); 0199 int j = m_fileName.lastIndexOf('.'); 0200 m_title = i > 0 ? m_fileName.mid(i + 1, j - i - 1) : m_fileName; 0201 } 0202 0203 minimizeMemoryUsage(); 0204 m_isValid = true; 0205 } 0206 0207 void Tag::minimizeMemoryUsage() 0208 { 0209 // Try to reduce memory usage: share tags that frequently repeat, squeeze others 0210 0211 m_title.squeeze(); 0212 m_lengthString.squeeze(); 0213 0214 m_comment = StringShare::tryShare(m_comment); 0215 m_artist = StringShare::tryShare(m_artist); 0216 m_album = StringShare::tryShare(m_album); 0217 m_genre = StringShare::tryShare(m_genre); 0218 } 0219 0220 //////////////////////////////////////////////////////////////////////////////// 0221 // related functions 0222 //////////////////////////////////////////////////////////////////////////////// 0223 0224 QDataStream &operator<<(QDataStream &s, const Tag &t) 0225 { 0226 s << t.title() 0227 << t.artist() 0228 << t.album() 0229 << t.genre() 0230 << qint32(t.track()) 0231 << qint32(t.year()) 0232 << t.comment() 0233 << qint32(t.bitrate()) 0234 << t.lengthString() 0235 << qint32(t.seconds()); 0236 0237 return s; 0238 } 0239 0240 CacheDataStream &operator>>(CacheDataStream &s, Tag &t) 0241 { 0242 return t.read(s); 0243 } 0244 0245 // vim: set et sw=4 tw=0 sta: