/* * Cantata * * Copyright (c) 2011-2012 Craig Drummond * */ /* * 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 . */ #include "musiclibraryitemroot.h" #include "musiclibraryitemartist.h" #include "musiclibraryitemalbum.h" #include "musiclibraryitemsong.h" #include "song.h" #ifdef ENABLE_KDE_SUPPORT #include #endif #include #include #include MusicLibraryItemArtist * MusicLibraryItemRoot::artist(const Song &s, bool create) { QString aa=s.albumArtist(); QHash::ConstIterator it=m_indexes.find(aa); if (m_indexes.end()==it) { return create ? createArtist(s) : 0; } return static_cast(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::iterator it=m_childItems.begin(); MusicLibraryItemArtist *various=0; bool created=false; for (; it!=m_childItems.end(); ) { if (various!=(*it) && static_cast(*it)->allSingleTrack()) { if (!various) { Song s; #ifdef ENABLE_KDE_SUPPORT s.artist=i18n("Various Artists"); #else s.artist=QObject::tr("Various Artists"); #endif QHash::ConstIterator it=m_indexes.find(s.albumArtist()); if (m_indexes.end()==it) { various=new MusicLibraryItemArtist(s.albumArtist(), this); created=true; } else { various=static_cast(m_childItems.at(*it)); } } various->addToSingleTracks(static_cast(*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::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::ConstIterator it=m_indexes.find(i18n("Various Artists")); #else QHash::ConstIterator it=m_indexes.find(QObject::tr("Various Artists")); #endif if (m_indexes.end()!=it) { return static_cast(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::Iterator it=m_indexes.begin(); QHash::Iterator end=m_indexes.end(); for (; it!=end; ++it) { if ((*it)>index) { (*it)--; } } m_indexes.remove(artist->data()); delete m_childItems.takeAt(index); } QSet MusicLibraryItemRoot::allSongs() const { QSet songs; foreach (const MusicLibraryItem *artist, m_childItems) { foreach (const MusicLibraryItem *album, artist->children()) { foreach (const MusicLibraryItem *song, album->children()) { songs.insert(static_cast(song)->song()); } } } return songs; } void MusicLibraryItemRoot::getDetails(QSet &artists, QSet &albumArtists, QSet &albums, QSet &genres) { foreach (const MusicLibraryItem *artist, m_childItems) { foreach (const MusicLibraryItem *album, artist->children()) { foreach (const MusicLibraryItem *song, album->children()) { const Song &s=static_cast(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(song)->file()==from.file) { static_cast(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(a); writer.writeStartElement("Artist"); writer.writeAttribute("name", artist->data()); foreach (const MusicLibraryItem *al, artist->children()) { const MusicLibraryItemAlbum *album = static_cast(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(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; }