Files
cantata/models/musiclibraryitemroot.cpp
craig d75a9843e6 When saving cache file, if a track is filed under 'single artists' then
store its acutal album name in the cache file. Then when cache is loaded,
we have the correct album to use for the tag editor.
2012-02-20 18:02:16 +00:00

376 lines
13 KiB
C++

/*
* Cantata
*
* Copyright (c) 2011-2012 Craig Drummond <craig.p.drummond@gmail.com>
*
*/
/*
* Copyright (c) 2008 Sander Knopper (sander AT knopper DOT tk) and
* Roeland Douma (roeland AT rullzer DOT com)
*
* This file is part of QtMPC.
*
* QtMPC 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.
*
* QtMPC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QtMPC. If not, see <http://www.gnu.org/licenses/>.
*/
#include "musiclibraryitemroot.h"
#include "musiclibraryitemartist.h"
#include "musiclibraryitemalbum.h"
#include "musiclibraryitemsong.h"
#include "song.h"
#ifdef ENABLE_KDE_SUPPORT
#include <KDE/KLocale>
#endif
#include <QtXml/QXmlStreamReader>
#include <QtXml/QXmlStreamWriter>
#include <QtCore/QFile>
MusicLibraryItemArtist * MusicLibraryItemRoot::artist(const Song &s, bool create)
{
QString aa=s.albumArtist();
QHash<QString, int>::ConstIterator it=m_indexes.find(aa);
if (m_indexes.end()==it) {
return create ? createArtist(s) : 0;
}
return static_cast<MusicLibraryItemArtist *>(m_childItems.at(*it));
}
MusicLibraryItemArtist * MusicLibraryItemRoot::createArtist(const Song &s)
{
QString aa=s.albumArtist();
MusicLibraryItemArtist *item=new MusicLibraryItemArtist(aa, this);
m_indexes.insert(aa, m_childItems.count());
m_childItems.append(item);
return item;
}
void MusicLibraryItemRoot::groupSingleTracks()
{
QList<MusicLibraryItem *>::iterator it=m_childItems.begin();
MusicLibraryItemArtist *various=0;
bool created=false;
for (; it!=m_childItems.end(); ) {
if (various!=(*it) && static_cast<MusicLibraryItemArtist *>(*it)->allSingleTrack()) {
if (!various) {
Song s;
#ifdef ENABLE_KDE_SUPPORT
s.artist=i18n("Various Artists");
#else
s.artist=QObject::tr("Various Artists");
#endif
QHash<QString, int>::ConstIterator it=m_indexes.find(s.albumArtist());
if (m_indexes.end()==it) {
various=new MusicLibraryItemArtist(s.albumArtist(), this);
created=true;
} else {
various=static_cast<MusicLibraryItemArtist *>(m_childItems.at(*it));
}
}
various->addToSingleTracks(static_cast<MusicLibraryItemArtist *>(*it));
delete (*it);
it=m_childItems.erase(it);
} else {
++it;
}
}
if (various) {
m_indexes.clear();
if (created) {
m_childItems.append(various);
}
it=m_childItems.begin();
QList<MusicLibraryItem *>::iterator end=m_childItems.end();
for (int i=0; it!=end; ++it, ++i) {
m_indexes.insert((*it)->data(), i);
}
}
}
bool MusicLibraryItemRoot::isFromSingleTracks(const Song &s) const
{
if (!s.file.isEmpty()) {
#ifdef ENABLE_KDE_SUPPORT
QHash<QString, int>::ConstIterator it=m_indexes.find(i18n("Various Artists"));
#else
QHash<QString, int>::ConstIterator it=m_indexes.find(QObject::tr("Various Artists"));
#endif
if (m_indexes.end()!=it) {
return static_cast<MusicLibraryItemArtist *>(m_childItems.at(*it))->isFromSingleTracks(s);
}
}
return false;
}
void MusicLibraryItemRoot::refreshIndexes()
{
m_indexes.clear();
int i=0;
foreach (MusicLibraryItem *item, m_childItems) {
m_indexes.insert(item->data(), i++);
}
}
void MusicLibraryItemRoot::remove(MusicLibraryItemArtist *artist)
{
int index=m_childItems.indexOf(artist);
if (index<0 || index>=m_childItems.count()) {
return;
}
QHash<QString, int>::Iterator it=m_indexes.begin();
QHash<QString, int>::Iterator end=m_indexes.end();
for (; it!=end; ++it) {
if ((*it)>index) {
(*it)--;
}
}
m_indexes.remove(artist->data());
delete m_childItems.takeAt(index);
}
QSet<Song> MusicLibraryItemRoot::allSongs() const
{
QSet<Song> songs;
foreach (const MusicLibraryItem *artist, m_childItems) {
foreach (const MusicLibraryItem *album, artist->children()) {
foreach (const MusicLibraryItem *song, album->children()) {
songs.insert(static_cast<const MusicLibraryItemSong *>(song)->song());
}
}
}
return songs;
}
void MusicLibraryItemRoot::getDetails(QSet<QString> &artists, QSet<QString> &albumArtists, QSet<QString> &albums, QSet<QString> &genres)
{
foreach (const MusicLibraryItem *artist, m_childItems) {
foreach (const MusicLibraryItem *album, artist->children()) {
foreach (const MusicLibraryItem *song, album->children()) {
const Song &s=static_cast<const MusicLibraryItemSong *>(song)->song();
artists.insert(s.artist);
albumArtists.insert(s.albumArtist());
albums.insert(s.album);
if (!s.genre.isEmpty()) {
genres.insert(s.genre);
}
}
}
}
}
void MusicLibraryItemRoot::updateSongFile(const Song &from, const Song &to)
{
MusicLibraryItemArtist *art=artist(from, false);
if (art) {
MusicLibraryItemAlbum *alb=art->album(from, false);
if (alb) {
foreach (MusicLibraryItem *song, alb->children()) {
if (static_cast<MusicLibraryItemSong *>(song)->file()==from.file) {
static_cast<MusicLibraryItemSong *>(song)->setFile(to.file);
return;
}
}
}
}
}
static quint32 constVersion=7;
static QLatin1String constTopTag("CantataLibrary");
void MusicLibraryItemRoot::toXML(const QString &filename, const QString &pathRemove, const QDateTime &date, bool groupSingle) const
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
return;
}
//Write the header info
QXmlStreamWriter writer(&file);
writer.setAutoFormatting(true);
writer.writeStartDocument();
//Start with the document
writer.writeStartElement(constTopTag);
writer.writeAttribute("version", QString::number(constVersion));
writer.writeAttribute("date", QString::number(date.toTime_t()));
writer.writeAttribute("groupSingle", groupSingle ? "true" : "false");
//Loop over all artist, albums and tracks.
foreach (const MusicLibraryItem *a, children()) {
const MusicLibraryItemArtist *artist = static_cast<const MusicLibraryItemArtist *>(a);
writer.writeStartElement("Artist");
writer.writeAttribute("name", artist->data());
foreach (const MusicLibraryItem *al, artist->children()) {
const MusicLibraryItemAlbum *album = static_cast<const MusicLibraryItemAlbum *>(al);
writer.writeStartElement("Album");
writer.writeAttribute("name", album->data());
writer.writeAttribute("year", QString::number(album->year()));
if (album->isSingleTracks()) {
writer.writeAttribute("singleTracks", "true");
}
foreach (const MusicLibraryItem *t, album->children()) {
const MusicLibraryItemSong *track = static_cast<const MusicLibraryItemSong *>(t);
writer.writeEmptyElement("Track");
writer.writeAttribute("name", track->data());
if (pathRemove.isEmpty() || !track->file().startsWith(pathRemove)) {
writer.writeAttribute("file", track->file());
} else {
writer.writeAttribute("file", track->file().mid(pathRemove.length()));
}
writer.writeAttribute("time", QString::number(track->time()));
//Only write track number if it is set
if (track->track() != 0) {
writer.writeAttribute("track", QString::number(track->track()));
}
if (track->disc() != 0) {
writer.writeAttribute("disc", QString::number(track->disc()));
}
if (track->song().artist!=artist->data()) {
writer.writeAttribute("artist", track->song().artist);
}
if (track->song().albumartist!=artist->data()) {
writer.writeAttribute("albumartist", track->song().albumartist);
}
// writer.writeAttribute("id", QString::number(track->song().id));
if (!track->song().genre.isEmpty()) {
writer.writeAttribute("genre", track->song().genre);
}
if (album->isSingleTracks()) {
writer.writeAttribute("album", track->song().album);
}
}
writer.writeEndElement();
}
writer.writeEndElement();
}
writer.writeEndElement();
writer.writeEndDocument();
file.close();
}
quint32 MusicLibraryItemRoot::fromXML(const QString &filename, const QString &pathAppend, const QDateTime &date, bool groupSingle)
{
QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) {
return false;
}
MusicLibraryItemArtist *artistItem = 0;
MusicLibraryItemAlbum *albumItem = 0;
MusicLibraryItemSong *songItem = 0;
Song song;
QXmlStreamReader reader(&file);
quint32 xmlDate=0;
while (!reader.atEnd()) {
reader.readNext();
/**
* TODO: CHECK FOR ERRORS
*/
if (!reader.error() && reader.isStartElement()) {
QString element = reader.name().toString();
QXmlStreamAttributes attributes=reader.attributes();
if (constTopTag == element) {
quint32 version = attributes.value("version").toString().toUInt();
xmlDate = attributes.value("date").toString().toUInt();
bool gs = QLatin1String("true")==attributes.value("groupSingle").toString();
if ( version < constVersion || (date.isValid() && xmlDate < date.toTime_t()) || gs!=groupSingle) {
return 0;
}
}
if (QLatin1String("Artist")==element) {
song.albumartist=attributes.value("name").toString();
artistItem = createArtist(song);
}
else if (QLatin1String("Album")==element) {
song.album=attributes.value("name").toString();
song.year=attributes.value("year").toString().toUInt();
if (!song.file.isEmpty()) {
song.file.append("dummy.mp3");
}
albumItem = artistItem->createAlbum(song);
if (QLatin1String("true")==attributes.value("singleTracks").toString()) {
albumItem->setIsSingleTracks();
}
}
else if (QLatin1String("Track")==element) {
song.title=attributes.value("name").toString();
song.file=attributes.value("file").toString();
if (!pathAppend.isEmpty()) {
song.file=pathAppend+song.file;
}
if (attributes.hasAttribute("artist")) {
song.artist=attributes.value("artist").toString();
} else {
song.artist=artistItem->data();
}
if (attributes.hasAttribute("albumartist")) {
song.albumartist=attributes.value("albumartist").toString();
} else {
song.albumartist=artistItem->data();
}
QString str=attributes.value("track").toString();
song.track=str.isEmpty() ? 0 : str.toUInt();
str=attributes.value("disc").toString();
song.disc=str.isEmpty() ? 0 : str.toUInt();
str=attributes.value("time").toString();
song.time=str.isEmpty() ? 0 : str.toUInt();
// str=attributes.value("id").toString();
// song.id=str.isEmpty() ? 0 : str.toUInt();
if (albumItem->isSingleTracks()) {
str=attributes.value("album").toString();
if (!str.isEmpty()) {
song.album=str;
}
}
songItem = new MusicLibraryItemSong(song, albumItem);
albumItem->append(songItem);
QString genre = attributes.value("genre").toString().trimmed();
if (genre.isEmpty()) {
#ifdef ENABLE_KDE_SUPPORT
genre=i18n("Unknown");
#else
genre=QObject::tr("Unknown");
#endif
} else {
song.genre=genre;
}
albumItem->addGenre(genre);
artistItem->addGenre(genre);
songItem->addGenre(genre);
addGenre(genre);
}
}
}
file.close();
return xmlDate;
}