Add albumartist, composer, file type and date columns to the playlist. Also add columns to the database for rating, playcount, and lastplayed (not used yet).
Fixes issue #66
This commit is contained in:
parent
030e454d1e
commit
3d34aa240c
@ -65,5 +65,6 @@
|
||||
<file>view-choose.png</file>
|
||||
<file>download.png</file>
|
||||
<file>zoom-in.png</file>
|
||||
<file>schema-3.sql</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
9
data/schema-3.sql
Normal file
9
data/schema-3.sql
Normal file
@ -0,0 +1,9 @@
|
||||
ALTER TABLE songs ADD COLUMN filetype INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN playcount INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN lastplayed INTEGER;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN rating INTEGER;
|
||||
|
||||
UPDATE schema_version SET version=3;
|
@ -12,7 +12,7 @@
|
||||
#include <QThread>
|
||||
|
||||
const char* LibraryBackend::kDatabaseName = "clementine.db";
|
||||
const int LibraryBackend::kSchemaVersion = 2;
|
||||
const int LibraryBackend::kSchemaVersion = 3;
|
||||
|
||||
LibraryBackend::LibraryBackend(QObject* parent, const QString& database_name)
|
||||
: QObject(parent),
|
||||
|
@ -48,12 +48,17 @@ QVariant Playlist::headerData(int section, Qt::Orientation, int role) const {
|
||||
case Column_Disc: return tr("Disc");
|
||||
case Column_Year: return tr("Year");
|
||||
case Column_Genre: return tr("Genre");
|
||||
case Column_AlbumArtist: return tr("Album artist");
|
||||
case Column_Composer: return tr("Composer");
|
||||
|
||||
case Column_BPM: return tr("BPM");
|
||||
case Column_Bitrate: return tr("Bit rate");
|
||||
case Column_Samplerate: return tr("Sample rate");
|
||||
case Column_Filename: return tr("File name");
|
||||
case Column_Filesize: return tr("File size");
|
||||
case Column_Filetype: return tr("File type");
|
||||
case Column_DateModified: return tr("Date modified");
|
||||
case Column_DateCreated: return tr("Date created");
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@ -83,12 +88,17 @@ QVariant Playlist::data(const QModelIndex& index, int role) const {
|
||||
case Column_Disc: return song.disc();
|
||||
case Column_Year: return song.year();
|
||||
case Column_Genre: return song.genre();
|
||||
case Column_AlbumArtist: return song.albumartist();
|
||||
case Column_Composer: return song.composer();
|
||||
|
||||
case Column_BPM: return song.bpm();
|
||||
case Column_Bitrate: return song.bitrate();
|
||||
case Column_Samplerate: return song.samplerate();
|
||||
case Column_Filename: return song.filename();
|
||||
case Column_Filesize: return song.filesize();
|
||||
case Column_Filetype: return song.filetype();
|
||||
case Column_DateModified: return song.mtime();
|
||||
case Column_DateCreated: return song.ctime();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,8 @@ class Playlist : public QAbstractListModel {
|
||||
Column_Title = 0,
|
||||
Column_Artist,
|
||||
Column_Album,
|
||||
Column_AlbumArtist,
|
||||
Column_Composer,
|
||||
Column_Length,
|
||||
Column_Track,
|
||||
Column_Disc,
|
||||
@ -33,6 +35,9 @@ class Playlist : public QAbstractListModel {
|
||||
Column_Samplerate,
|
||||
Column_Filename,
|
||||
Column_Filesize,
|
||||
Column_Filetype,
|
||||
Column_DateCreated,
|
||||
Column_DateModified,
|
||||
|
||||
ColumnCount
|
||||
};
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QScrollBar>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@ -116,6 +117,45 @@ QString SizeItemDelegate::displayText(const QVariant& value, const QLocale&) con
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString DateItemDelegate::displayText(const QVariant &value, const QLocale &locale) const {
|
||||
bool ok = false;
|
||||
int time = value.toInt(&ok);
|
||||
|
||||
if (!ok || time == -1)
|
||||
return QString::null;
|
||||
|
||||
return QDateTime::fromTime_t(time).toString(
|
||||
QLocale::system().dateTimeFormat(QLocale::ShortFormat));
|
||||
}
|
||||
|
||||
QString FileTypeItemDelegate::displayText(const QVariant &value, const QLocale &locale) const {
|
||||
bool ok = false;
|
||||
Song::FileType type = Song::FileType(value.toInt(&ok));
|
||||
|
||||
if (!ok)
|
||||
return tr("Unknown");
|
||||
|
||||
switch (type) {
|
||||
case Song::Type_Asf: return tr("ASF");
|
||||
case Song::Type_Flac: return tr("FLAC");
|
||||
case Song::Type_Mp4: return tr("MP4");
|
||||
case Song::Type_Mpc: return tr("MPC");
|
||||
case Song::Type_Mpeg: return tr("MP3"); // Not technically correct
|
||||
case Song::Type_OggFlac: return tr("Ogg FLAC");
|
||||
case Song::Type_OggSpeex: return tr("Ogg Speex");
|
||||
case Song::Type_OggVorbis: return tr("Ogg Vorbis");
|
||||
case Song::Type_Aiff: return tr("AIFF");
|
||||
case Song::Type_Wav: return tr("WAV");
|
||||
case Song::Type_TrueAudio: return tr("TrueAudio");
|
||||
|
||||
case Song::Type_Stream: return tr("Stream");
|
||||
|
||||
case Song::Type_Unknown:
|
||||
default:
|
||||
return tr("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PlaylistView::PlaylistView(QWidget *parent)
|
||||
: QTreeView(parent),
|
||||
@ -129,6 +169,9 @@ PlaylistView::PlaylistView(QWidget *parent)
|
||||
setItemDelegate(new PlaylistDelegateBase(this));
|
||||
setItemDelegateForColumn(Playlist::Column_Length, new LengthItemDelegate(this));
|
||||
setItemDelegateForColumn(Playlist::Column_Filesize, new SizeItemDelegate(this));
|
||||
setItemDelegateForColumn(Playlist::Column_Filetype, new FileTypeItemDelegate(this));
|
||||
setItemDelegateForColumn(Playlist::Column_DateCreated, new DateItemDelegate(this));
|
||||
setItemDelegateForColumn(Playlist::Column_DateModified, new DateItemDelegate(this));
|
||||
|
||||
setHeader(new PlaylistHeader(Qt::Horizontal, this));
|
||||
header()->setMovable(true);
|
||||
@ -158,6 +201,9 @@ void PlaylistView::LoadGeometry() {
|
||||
header()->hideSection(Playlist::Column_Samplerate);
|
||||
header()->hideSection(Playlist::Column_Filename);
|
||||
header()->hideSection(Playlist::Column_Filesize);
|
||||
header()->hideSection(Playlist::Column_Filetype);
|
||||
header()->hideSection(Playlist::Column_DateCreated);
|
||||
header()->hideSection(Playlist::Column_DateModified);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,18 @@ class SizeItemDelegate : public PlaylistDelegateBase {
|
||||
QString displayText(const QVariant& value, const QLocale& locale) const;
|
||||
};
|
||||
|
||||
class DateItemDelegate : public PlaylistDelegateBase {
|
||||
public:
|
||||
DateItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
|
||||
QString displayText(const QVariant& value, const QLocale& locale) const;
|
||||
};
|
||||
|
||||
class FileTypeItemDelegate : public PlaylistDelegateBase {
|
||||
public:
|
||||
FileTypeItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
|
||||
QString displayText(const QVariant& value, const QLocale& locale) const;
|
||||
};
|
||||
|
||||
|
||||
class PlaylistView : public QTreeView {
|
||||
Q_OBJECT
|
||||
|
@ -45,6 +45,7 @@ void RadioPlaylistItem::InitMetadata() {
|
||||
metadata_.set_title(url_.toString());
|
||||
|
||||
metadata_.set_artist(artist_);
|
||||
metadata_.set_filetype(Song::Type_Stream);
|
||||
}
|
||||
|
||||
Song RadioPlaylistItem::Metadata() const {
|
||||
@ -84,6 +85,7 @@ PlaylistItem::Options RadioPlaylistItem::options() const {
|
||||
|
||||
void RadioPlaylistItem::SetTemporaryMetadata(const Song& metadata) {
|
||||
temp_metadata_ = metadata;
|
||||
temp_metadata_.set_filetype(Song::Type_Stream);
|
||||
}
|
||||
|
||||
void RadioPlaylistItem::ClearTemporaryMetadata() {
|
||||
|
66
src/song.cpp
66
src/song.cpp
@ -8,8 +8,16 @@
|
||||
#include <taglib/mpegfile.h>
|
||||
#include <taglib/id3v2tag.h>
|
||||
#include <taglib/oggfile.h>
|
||||
#include <taglib/oggflacfile.h>
|
||||
#include <taglib/vorbisfile.h>
|
||||
#include <taglib/flacfile.h>
|
||||
#include <taglib/asffile.h>
|
||||
#include <taglib/mp4file.h>
|
||||
#include <taglib/mpcfile.h>
|
||||
#include <taglib/aifffile.h>
|
||||
#include <taglib/wavfile.h>
|
||||
#include <taglib/speexfile.h>
|
||||
#include <taglib/trueaudiofile.h>
|
||||
|
||||
#include <lastfm/Track>
|
||||
|
||||
@ -30,13 +38,15 @@ const char* Song::kColumnSpec =
|
||||
"title, album, artist, albumartist, composer, "
|
||||
"track, disc, bpm, year, genre, comment, compilation, "
|
||||
"length, bitrate, samplerate, directory, filename, "
|
||||
"mtime, ctime, filesize, sampler, art_automatic, art_manual";
|
||||
"mtime, ctime, filesize, sampler, art_automatic, art_manual, "
|
||||
"filetype, playcount, lastplayed, rating";
|
||||
|
||||
const char* Song::kBindSpec =
|
||||
":title, :album, :artist, :albumartist, :composer, "
|
||||
":track, :disc, :bpm, :year, :genre, :comment, :compilation, "
|
||||
":length, :bitrate, :samplerate, :directory_id, :filename, "
|
||||
":mtime, :ctime, :filesize, :sampler, :art_automatic, :art_manual";
|
||||
":mtime, :ctime, :filesize, :sampler, :art_automatic, :art_manual, "
|
||||
":filetype, :playcount, :lastplayed, :rating";
|
||||
|
||||
const char* Song::kUpdateSpec =
|
||||
"title = :title, album = :album, artist = :artist, "
|
||||
@ -46,11 +56,13 @@ const char* Song::kUpdateSpec =
|
||||
"bitrate = :bitrate, samplerate = :samplerate, "
|
||||
"directory = :directory_id, filename = :filename, mtime = :mtime, "
|
||||
"ctime = :ctime, filesize = :filesize, sampler = :sampler, "
|
||||
"art_automatic = :art_automatic, art_manual = :art_manual";
|
||||
"art_automatic = :art_automatic, art_manual = :art_manual, "
|
||||
"filetype = :filetype, playcount = :playcount, lastplayed = :lastplayed, "
|
||||
"rating = :rating";
|
||||
|
||||
TagLibFileRefFactory Song::kDefaultFactory;
|
||||
|
||||
SongData::SongData()
|
||||
Song::Private::Private()
|
||||
: valid_(false),
|
||||
id_(-1),
|
||||
track_(-1),
|
||||
@ -65,7 +77,8 @@ SongData::SongData()
|
||||
directory_id_(-1),
|
||||
mtime_(-1),
|
||||
ctime_(-1),
|
||||
filesize_(-1)
|
||||
filesize_(-1),
|
||||
filetype_(Type_Unknown)
|
||||
{
|
||||
}
|
||||
|
||||
@ -74,7 +87,7 @@ TagLib::FileRef* TagLibFileRefFactory::GetFileRef(const QString& filename) {
|
||||
}
|
||||
|
||||
Song::Song()
|
||||
: d(new SongData),
|
||||
: d(new Private),
|
||||
factory_(&kDefaultFactory)
|
||||
{
|
||||
}
|
||||
@ -86,7 +99,7 @@ Song::Song(const Song &other)
|
||||
}
|
||||
|
||||
Song::Song(FileRefFactory* factory)
|
||||
: d(new SongData),
|
||||
: d(new Private),
|
||||
factory_(factory) {
|
||||
}
|
||||
|
||||
@ -200,6 +213,34 @@ void Song::InitFromFile(const QString& filename, int directory_id) {
|
||||
d->length_ = fileref->audioProperties()->length();
|
||||
d->samplerate_ = fileref->audioProperties()->sampleRate();
|
||||
}
|
||||
|
||||
// Get the filetype if we can
|
||||
GuessFileType(fileref.get());
|
||||
}
|
||||
|
||||
void Song::GuessFileType(TagLib::FileRef* fileref) {
|
||||
if (dynamic_cast<TagLib::ASF::File*>(fileref->file()))
|
||||
d->filetype_ = Type_Asf;
|
||||
if (dynamic_cast<TagLib::FLAC::File*>(fileref->file()))
|
||||
d->filetype_ = Type_Flac;
|
||||
if (dynamic_cast<TagLib::MP4::File*>(fileref->file()))
|
||||
d->filetype_ = Type_Mp4;
|
||||
if (dynamic_cast<TagLib::MPC::File*>(fileref->file()))
|
||||
d->filetype_ = Type_Mpc;
|
||||
if (dynamic_cast<TagLib::MPEG::File*>(fileref->file()))
|
||||
d->filetype_ = Type_Mpeg;
|
||||
if (dynamic_cast<TagLib::Ogg::FLAC::File*>(fileref->file()))
|
||||
d->filetype_ = Type_OggFlac;
|
||||
if (dynamic_cast<TagLib::Ogg::Speex::File*>(fileref->file()))
|
||||
d->filetype_ = Type_OggSpeex;
|
||||
if (dynamic_cast<TagLib::Ogg::Vorbis::File*>(fileref->file()))
|
||||
d->filetype_ = Type_OggVorbis;
|
||||
if (dynamic_cast<TagLib::RIFF::AIFF::File*>(fileref->file()))
|
||||
d->filetype_ = Type_Aiff;
|
||||
if (dynamic_cast<TagLib::RIFF::WAV::File*>(fileref->file()))
|
||||
d->filetype_ = Type_Wav;
|
||||
if (dynamic_cast<TagLib::TrueAudio::File*>(fileref->file()))
|
||||
d->filetype_ = Type_TrueAudio;
|
||||
}
|
||||
|
||||
void Song::InitFromQuery(const QSqlQuery& q) {
|
||||
@ -241,6 +282,11 @@ void Song::InitFromQuery(const QSqlQuery& q) {
|
||||
d->art_automatic_ = q.value(22).toString();
|
||||
d->art_manual_ = q.value(23).toString();
|
||||
|
||||
d->filetype_ = FileType(q.value(24).toInt());
|
||||
// playcount = 25
|
||||
// lastplayed = 26
|
||||
// rating = 27
|
||||
|
||||
#undef tostr
|
||||
#undef toint
|
||||
#undef tofloat
|
||||
@ -248,6 +294,7 @@ void Song::InitFromQuery(const QSqlQuery& q) {
|
||||
|
||||
void Song::InitFromLastFM(const lastfm::Track& track) {
|
||||
d->valid_ = true;
|
||||
d->filetype_ = Type_Stream;
|
||||
|
||||
d->title_ = track.title();
|
||||
d->album_ = track.album();
|
||||
@ -303,6 +350,11 @@ void Song::BindToQuery(QSqlQuery *query) const {
|
||||
query->bindValue(":art_automatic", d->art_automatic_);
|
||||
query->bindValue(":art_manual", d->art_manual_);
|
||||
|
||||
query->bindValue(":filetype", d->filetype_);
|
||||
query->bindValue(":playcount", 0); // TODO
|
||||
query->bindValue(":lastplayed", -1); // TODO
|
||||
query->bindValue(":rating", -1);
|
||||
|
||||
#undef intval
|
||||
}
|
||||
|
||||
|
101
src/song.h
101
src/song.h
@ -19,43 +19,6 @@ namespace TagLib {
|
||||
class FileRef;
|
||||
}
|
||||
|
||||
struct SongData : public QSharedData {
|
||||
SongData();
|
||||
|
||||
bool valid_;
|
||||
int id_;
|
||||
|
||||
QString title_;
|
||||
QString album_;
|
||||
QString artist_;
|
||||
QString albumartist_;
|
||||
QString composer_;
|
||||
int track_;
|
||||
int disc_;
|
||||
float bpm_;
|
||||
int year_;
|
||||
QString genre_;
|
||||
QString comment_;
|
||||
bool compilation_;
|
||||
bool sampler_;
|
||||
|
||||
int length_;
|
||||
int bitrate_;
|
||||
int samplerate_;
|
||||
|
||||
int directory_id_;
|
||||
QString filename_;
|
||||
int mtime_;
|
||||
int ctime_;
|
||||
int filesize_;
|
||||
|
||||
// Filenames to album art for this song.
|
||||
QString art_automatic_; // Guessed by LibraryWatcher
|
||||
QString art_manual_; // Set by the user - should take priority
|
||||
|
||||
QImage image_;
|
||||
};
|
||||
|
||||
class FileRefFactory {
|
||||
public:
|
||||
virtual ~FileRefFactory() {}
|
||||
@ -77,6 +40,24 @@ class Song {
|
||||
static const char* kBindSpec;
|
||||
static const char* kUpdateSpec;
|
||||
|
||||
// Don't change these values - they're stored in the database
|
||||
enum FileType {
|
||||
Type_Unknown = 0,
|
||||
Type_Asf = 1,
|
||||
Type_Flac = 2,
|
||||
Type_Mp4 = 3,
|
||||
Type_Mpc = 4,
|
||||
Type_Mpeg = 5,
|
||||
Type_OggFlac = 6,
|
||||
Type_OggSpeex = 7,
|
||||
Type_OggVorbis = 8,
|
||||
Type_Aiff = 9,
|
||||
Type_Wav = 10,
|
||||
Type_TrueAudio = 11,
|
||||
|
||||
Type_Stream = 99,
|
||||
};
|
||||
|
||||
// Constructors
|
||||
void Init(const QString& title, const QString& artist, int length);
|
||||
void InitFromFile(const QString& filename, int directory_id);
|
||||
@ -114,6 +95,7 @@ class Song {
|
||||
uint mtime() const { return d->mtime_; }
|
||||
uint ctime() const { return d->ctime_; }
|
||||
int filesize() const { return d->filesize_; }
|
||||
FileType filetype() const { return d->filetype_; }
|
||||
|
||||
const QString& art_automatic() const { return d->art_automatic_; }
|
||||
const QString& art_manual() const { return d->art_manual_; }
|
||||
@ -156,6 +138,7 @@ class Song {
|
||||
void set_mtime(int v) { d->mtime_ = v; }
|
||||
void set_ctime(int v) { d->ctime_ = v; }
|
||||
void set_filesize(int v) { d->filesize_ = v; }
|
||||
void set_filetype(FileType v) { d->filetype_ = v; }
|
||||
void set_art_automatic(const QString& v) { d->art_automatic_ = v; }
|
||||
void set_art_manual(const QString& v) { d->art_manual_ = v; }
|
||||
void set_image(const QImage& i) { d->image_ = i; }
|
||||
@ -168,7 +151,49 @@ class Song {
|
||||
bool IsMetadataEqual(const Song& other) const;
|
||||
|
||||
private:
|
||||
QSharedDataPointer<SongData> d;
|
||||
void GuessFileType(TagLib::FileRef* fileref);
|
||||
|
||||
private:
|
||||
struct Private : public QSharedData {
|
||||
Private();
|
||||
|
||||
bool valid_;
|
||||
int id_;
|
||||
|
||||
QString title_;
|
||||
QString album_;
|
||||
QString artist_;
|
||||
QString albumartist_;
|
||||
QString composer_;
|
||||
int track_;
|
||||
int disc_;
|
||||
float bpm_;
|
||||
int year_;
|
||||
QString genre_;
|
||||
QString comment_;
|
||||
bool compilation_;
|
||||
bool sampler_;
|
||||
|
||||
int length_;
|
||||
int bitrate_;
|
||||
int samplerate_;
|
||||
|
||||
int directory_id_;
|
||||
QString filename_;
|
||||
int mtime_;
|
||||
int ctime_;
|
||||
int filesize_;
|
||||
FileType filetype_;
|
||||
|
||||
// Filenames to album art for this song.
|
||||
QString art_automatic_; // Guessed by LibraryWatcher
|
||||
QString art_manual_; // Set by the user - should take priority
|
||||
|
||||
QImage image_;
|
||||
};
|
||||
|
||||
private:
|
||||
QSharedDataPointer<Private> d;
|
||||
FileRefFactory* factory_;
|
||||
|
||||
static TagLibFileRefFactory kDefaultFactory;
|
||||
|
Loading…
x
Reference in New Issue
Block a user