tag.cpp 6.65 KB
Newer Older
1 2 3 4 5
/***************************************************************************
                          tag.cpp  -  description
                             -------------------
    begin                : Sun Feb 17 2002
    copyright            : (C) 2002 by Scott Wheeler
6
    email                : wheeler@kde.org
7
***************************************************************************/
8 9 10 11 12 13 14 15 16 17

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

18
#include <kdebug.h>
19

20
#include <qregexp.h>
21
#include <qfile.h>
22

23 24 25
#include <taglib/tag.h>
#include <taglib/mpegfile.h>
#include <taglib/vorbisfile.h>
26
#include <taglib/flacfile.h>
27
#include <taglib/xiphcomment.h>
28
#include <taglib/id3v2framefactory.h>
29

30
#include "cache.h"
31
#include "tag.h"
32
#include "mediafiles.h"
33
#include "stringshare.h"
34

35 36 37 38
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

39 40 41 42 43 44 45 46

Tag::Tag(const QString &fileName) :
    m_fileName(fileName),
    m_track(0),
    m_year(0),
    m_seconds(0),
    m_bitrate(0),
    m_isValid(false)
47
{
48
    if(MediaFiles::isMP3(fileName)) {
49
        TagLib::MPEG::File file(QFile::encodeName(fileName).data());
50
        if(file.isValid())
51
            setup(&file);
52
    }
53

54
    else if(MediaFiles::isOgg(fileName)) {
55
        TagLib::Vorbis::File file(QFile::encodeName(fileName).data());
56
        if(file.isValid())
57
            setup(&file);
58
    }
59

60
    else if(MediaFiles::isFLAC(fileName)) {
61
        TagLib::FLAC::File file(QFile::encodeName(fileName).data());
62
        if(file.isOpen())
63
            setup(&file);
64 65
    }

66
    else {
67 68
        kdError(65432) << "Couldn't resolve the mime type of \"" <<
            fileName << "\" -- this shouldn't happen." << endl;
69
    }
70 71
}

72 73
void Tag::save()
{
74 75
    TagLib::ID3v2::FrameFactory::instance()->setDefaultTextEncoding(TagLib::String::UTF8);

76 77 78
    TagLib::File *file = 0;

    if(MediaFiles::isMP3(m_fileName))
79
        file = new TagLib::MPEG::File(QFile::encodeName(m_fileName).data());
80
    else if(MediaFiles::isOgg(m_fileName))
81
        file = new TagLib::Vorbis::File(QFile::encodeName(m_fileName).data());
82 83
    else if(MediaFiles::isFLAC(m_fileName))
        file = new TagLib::FLAC::File(QFile::encodeName(m_fileName).data());
84

85
    if(file && file->isValid() && file->tag() && !file->readOnly()) {
86 87 88 89 90 91 92 93 94
        file->tag()->setTitle(QStringToTString(m_title));
        file->tag()->setArtist(QStringToTString(m_artist));
        file->tag()->setAlbum(QStringToTString(m_album));
        file->tag()->setGenre(QStringToTString(m_genre));
        file->tag()->setComment(QStringToTString(m_comment));
        file->tag()->setTrack(m_track);
        file->tag()->setYear(m_year);

        file->save();
95 96
    }
    else
97 98
        kdError(65432) << "Couldn't save file." << endl;

99

100
    delete file;
101 102
}

103 104 105 106
CacheDataStream &Tag::read(CacheDataStream &s)
{
    switch(s.cacheVersion()) {
    case 1: {
107 108 109 110 111 112 113 114 115 116 117 118 119 120
        Q_INT32 track;
        Q_INT32 year;
        Q_INT32 bitrate;
        Q_INT32 seconds;

        s >> m_title
          >> m_artist
          >> m_album
          >> m_genre
          >> track
          >> year
          >> m_comment
          >> bitrate
          >> m_lengthString
121
          >> seconds;
122 123 124 125 126 127

        m_track = track;
        m_year = year;
        m_bitrate = bitrate;
        m_seconds = seconds;
        break;
128 129
    }
    default: {
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
        static QString dummyString;
        static int dummyInt;
        QString bitrateString;

        s >> dummyInt
          >> m_title
          >> m_artist
          >> m_album
          >> m_genre
          >> dummyInt
          >> m_track
          >> dummyString
          >> m_year
          >> dummyString
          >> m_comment
          >> bitrateString
          >> m_lengthString
          >> m_seconds
148
          >> dummyString;
149 150 151 152 153 154

        bool ok;
        m_bitrate = bitrateString.toInt(&ok);
        if(!ok)
            m_bitrate = 0;
        break;
155 156
    }
    }
157 158

    // Try to reduce memory usage: share tags that frequently repeat, squeeze others
159

160
    m_title.squeeze();
161 162
    m_lengthString.squeeze();

163 164 165 166
    m_comment = StringShare::tryShare(m_comment);
    m_artist  = StringShare::tryShare(m_artist);
    m_album   = StringShare::tryShare(m_album);
    m_genre   = StringShare::tryShare(m_genre);
167

168
    return s;
169 170
}

171 172 173
////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////
174

175 176
Tag::Tag(const QString &fileName, bool) :
    m_fileName(fileName),
177 178 179
    m_track(0),
    m_year(0),
    m_seconds(0),
180 181
    m_bitrate(0),
    m_isValid(true)
182
{
183

184 185
}

186
void Tag::setup(TagLib::File *file)
187
{
188 189 190 191 192
    m_title   = TStringToQString(file->tag()->title()).stripWhiteSpace();
    m_artist  = TStringToQString(file->tag()->artist()).stripWhiteSpace();
    m_album   = TStringToQString(file->tag()->album()).stripWhiteSpace();
    m_genre   = TStringToQString(file->tag()->genre()).stripWhiteSpace();
    m_comment = TStringToQString(file->tag()->comment()).stripWhiteSpace();
193

194 195
    m_track = file->tag()->track();
    m_year  = file->tag()->year();
196

197
    m_seconds = file->audioProperties()->length();
198
    m_bitrate = file->audioProperties()->bitrate();
199

200 201
    const int seconds = m_seconds % 60;
    const int minutes = (m_seconds - seconds) / 60;
202

203
    m_lengthString = QString::number(minutes) + (seconds >= 10 ? ":" : ":0") + QString::number(seconds);
204

205
    if(m_title.isEmpty()) {
206 207 208
        int i = m_fileName.findRev('/');
        int j = m_fileName.findRev('.');
        m_title = i > 0 ? m_fileName.mid(i + 1, j - i - 1) : m_fileName;
209
    }
210 211

    m_isValid = true;
212 213 214 215 216 217
}

////////////////////////////////////////////////////////////////////////////////
// related functions
////////////////////////////////////////////////////////////////////////////////

Scott Wheeler's avatar
Scott Wheeler committed
218
QDataStream &operator<<(QDataStream &s, const Tag &t)
219
{
220
    s << t.title()
221 222 223
      << t.artist()
      << t.album()
      << t.genre()
224 225
      << Q_INT32(t.track())
      << Q_INT32(t.year())
226
      << t.comment()
227
      << Q_INT32(t.bitrate())
228
      << t.lengthString()
229
      << Q_INT32(t.seconds());
230

231
    return s;
232
}
233

234
CacheDataStream &operator>>(CacheDataStream &s, Tag &t)
235 236 237
{
    return t.read(s);
}