/* * Cantata * * Copyright (c) 2011 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 #include #include #include "dirviewitemroot.h" #include "dirviewitemdir.h" #include "dirviewitemfile.h" #include "musiclibraryitemartist.h" #include "musiclibraryitemalbum.h" #include "musiclibraryitemsong.h" #include "musiclibraryitemroot.h" #include "mpdparseutils.h" #include "mpdstats.h" #include "mpdstatus.h" #include "playlist.h" #include "song.h" #include "output.h" #include "covers.h" #ifdef ENABLE_KDE_SUPPORT #include #endif QString MPDParseUtils::getDir(const QString &f) { QString d(f); int slashPos(d.lastIndexOf('/')); if(slashPos!=-1) d.remove(slashPos+1, d.length()); if (!d.isEmpty() && !d.endsWith("/")) { d=d+"/"; } return d; } QList MPDParseUtils::parsePlaylists(const QByteArray &data) { QList playlists; QList lines = data.split('\n'); QList tokens; int amountOfLines = lines.size(); for (int i = 0; i < amountOfLines; i++) { tokens = lines.at(i).split(':'); if (tokens.at(0) == "playlist") { Playlist playlist; playlist.m_name = tokens.at(1).simplified(); i++; tokens = lines.at(i).split(':'); if (tokens.at(0) == "Last-Modified") { QByteArray last_modified(tokens.at(1)); last_modified += tokens.at(2); last_modified += tokens.at(3); playlist.m_last_modified.fromString(last_modified, Qt::ISODate); playlists.append(playlist); } } } return playlists; } void MPDParseUtils::parseStats(const QByteArray &data) { MPDStats * const stats = MPDStats::self(); stats->acquireWriteLock(); QList lines = data.split('\n'); QList tokens; int amountOfLines = lines.size(); for (int i = 0; i < amountOfLines; i++) { tokens = lines.at(i).split(':'); if (tokens.at(0) == "artists") { stats->setArtists(tokens.at(1).toUInt()); } else if (tokens.at(0) == "albums") { stats->setAlbums(tokens.at(1).toUInt()); } else if (tokens.at(0) == "songs") { stats->setSongs(tokens.at(1).toUInt()); } else if (tokens.at(0) == "uptime") { stats->setUptime(tokens.at(1).toUInt()); } else if (tokens.at(0) == "playtime") { stats->setPlaytime(tokens.at(1).toUInt()); } else if (tokens.at(0) == "db_playtime") { stats->setDbPlaytime(tokens.at(1).toUInt()); } else if (tokens.at(0) == "db_update") { stats->setDbUpdate(tokens.at(1).toUInt()); } } stats->releaseWriteLock(); } void MPDParseUtils::parseStatus(const QByteArray &data) { MPDStatus * const status = MPDStatus::self(); QList lines = data.split('\n'); QList tokens; status->acquireWriteLock(); int amountOfLines = lines.size(); for (int i = 0; i < amountOfLines; i++) { tokens = lines.at(i).split(':'); if (tokens.at(0) == "volume") { status->setVolume(tokens.at(1).toUInt()); } else if (tokens.at(0) == "consume") { if (tokens.at(1).trimmed() == "1") { status->setConsume(true); } else { status->setConsume(false); } } else if (tokens.at(0) == "repeat") { if (tokens.at(1).trimmed() == "1") { status->setRepeat(true); } else { status->setRepeat(false); } } else if (tokens.at(0) == "random") { if (tokens.at(1).trimmed() == "1") { status->setRandom(true); } else { status->setRandom(false); } } else if (tokens.at(0) == "playlist") { status->setPlaylist(tokens.at(1).toUInt()); } else if (tokens.at(0) == "playlistlength") { status->setPlaylistLength(tokens.at(1).toInt()); } else if (tokens.at(0) == "playlistqueue") { status->setPlaylistQueue(tokens.at(1).toInt()); } else if (tokens.at(0) == "xfade") { status->setCrossFade(tokens.at(1).toInt()); } else if (tokens.at(0) == "state") { if (tokens.at(1).contains("play")) { status->setState(MPDStatus::State_Playing); } else if (tokens.at(1).contains("stop")) { status->setState(MPDStatus::State_Stopped); } else { status->setState(MPDStatus::State_Paused); } } else if (tokens.at(0) == "song") { status->setSong(tokens.at(1).toInt()); } else if (tokens.at(0) == "songid") { status->setSongId(tokens.at(1).toInt()); } else if (tokens.at(0) == "time") { status->setTimeElapsed(tokens.at(1).toInt()); status->setTimeTotal(tokens.at(2).toInt()); } else if (tokens.at(0) == "bitrate") { status->setBitrate(tokens.at(1).toUInt()); } else if (tokens.at(0) == "audio") { } else if (tokens.at(0) == "updating_db") { status->setUpdatingDb(tokens.at(1).toInt()); } else if (tokens.at(0) == "error") { status->setError(tokens.at(1)); } } status->releaseWriteLock(); } Song MPDParseUtils::parseSong(const QByteArray &data) { Song song; QString tmpData = QString::fromUtf8(data.constData()); QStringList lines = tmpData.split('\n'); QStringList tokens; QString element; QString value; QString albumartist; int amountOfLines = lines.size(); for (int i = 0; i < amountOfLines; i++) { tokens = lines.at(i).split(':'); element = tokens.takeFirst(); value = tokens.join(":"); value = value.trimmed(); if (element == "file") { song.file = value; song.file.replace("\"", "\\\""); } else if (element == "Time") { song.time = value.toUInt(); } else if (element == "Album") { song.album = value; } else if (element == "Artist") { song.artist = value; } else if (element == "AlbumArtist") { song.albumartist = value; } else if (element == "Title") { song.title = value; } else if (element == "Track") { song.track = value.split("/").at(0).toInt(); } else if (element == "Pos") { song.pos = value.toInt(); } else if (element == "Id") { song.id = value.toUInt(); } else if (element == "Disc") { song.disc = value.split("/").at(0).toUInt(); } else if (element == "Date") { song.year = value.toUInt(); } else if (element == "Genre") { song.genre = value; } } if (song.genre.isEmpty()) { #ifdef ENABLE_KDE_SUPPORT song.genre = i18n("Unknown"); #else song.genre = "Unknown"; #endif } if (!albumartist.isEmpty() && albumartist != song.artist) { song.modifiedtitle = song.artist + " - " + song.title; } return song; } QList MPDParseUtils::parseSongs(const QByteArray &data) { QList songs; QByteArray song; QList lines = data.split('\n'); int amountOfLines = lines.size(); for (int i = 0; i < amountOfLines; i++) { song += lines.at(i); // Skip the "OK" line, this is NOT a song!!! if("OK"==song) { continue; } song += "\n"; if (i == lines.size() - 1 || lines.at(i + 1).startsWith("file:")) { songs.append(parseSong(song)); song.clear(); } } return songs; } MusicLibraryItemRoot * MPDParseUtils::parseLibraryItems(const QByteArray &data) { MusicLibraryItemRoot * const rootItem = new MusicLibraryItemRoot; QByteArray currentItem; QList lines = data.split('\n'); int amountOfLines = lines.size(); MusicLibraryItemArtist *prevArtist=0; MusicLibraryItemAlbum *prevAlbum=0; for (int i = 0; i < amountOfLines; i++) { currentItem += lines.at(i); currentItem += "\n"; if (i == lines.size() - 1 || lines.at(i + 1).startsWith("file:")) { Song currentSong = parseSong(currentItem); currentItem.clear(); if (currentSong.isEmpty()) { continue; } currentSong.fillEmptyFields(); const QString &albumArtist=currentSong.albumArtist(); MusicLibraryItemArtist *artistItem = 0; if (!prevArtist || prevArtist->data(0) != albumArtist) { prevArtist=0; prevAlbum=0; int amountOfArtists = rootItem->childCount(); // Check if artist already exists for (int i = amountOfArtists - 1; i >= 0 && !artistItem; i--) { if (rootItem->child(i)->data(0) == albumArtist) { artistItem = static_cast(rootItem->child(i)); } } } if (!artistItem) { artistItem = new MusicLibraryItemArtist(albumArtist, rootItem); rootItem->appendChild(artistItem); } prevArtist=artistItem; MusicLibraryItemAlbum *albumItem = 0; if (!prevAlbum || prevAlbum->data(0) != currentSong.album) { int amountOfAlbums = artistItem->childCount(); // Check if album already exists for (int i = amountOfAlbums - 1; i >= 0 && !albumItem; i--) { if (artistItem->child(i)->data(0) == currentSong.album) { albumItem = static_cast(artistItem->child(i)); } } } if (!albumItem) { albumItem = new MusicLibraryItemAlbum(currentSong.album, getDir(currentSong.file), artistItem); artistItem->appendChild(albumItem); } prevAlbum=albumItem; // Add song to album (possibly in track order) MusicLibraryItemSong *songItem = new MusicLibraryItemSong(currentSong.displayTitle(), albumItem); songItem->setFile(currentSong.file); songItem->setTrack(currentSong.track); songItem->setDisc(currentSong.disc); albumItem->appendChild(songItem); albumItem->addGenre(currentSong.genre); artistItem->addGenre(currentSong.genre); songItem->addGenre(currentSong.genre); rootItem->addGenre(currentSong.genre); } } return rootItem; } DirViewItemRoot * MPDParseUtils::parseDirViewItems(const QByteArray &data) { QList lines = data.split('\n'); DirViewItemRoot * rootItem = new DirViewItemRoot; DirViewItem * currentDir = rootItem; QStringList currentDirList; int amountOfLines = lines.size(); for (int i = 0; i < amountOfLines; i++) { QString line = QString::fromUtf8(lines.at(i)); if (line.startsWith("file: ")) { line.remove(0, 6); QStringList parts = line.split("/"); if (currentDir->type() == DirViewItem::Type_Root) static_cast(currentDir)->insertFile(parts.at(parts.size() - 1)); else static_cast(currentDir)->insertFile(parts.at(parts.size() - 1)); } else if (line.startsWith("directory: ")) { line.remove(0, 11); QStringList parts = line.split("/"); /* Check how much matches */ int depth = 0; for (int j = 0; j < currentDirList.size() && j < parts.size(); j++) { if (currentDirList.at(j) != parts.at(j)) break; depth++; } for (int j = currentDirList.size(); j > depth; j--) { currentDir = currentDir->parent(); } if (currentDir->type() == DirViewItem::Type_Root) currentDir = static_cast(currentDir)->createDirectory(parts.at(parts.size() - 1)); else currentDir = static_cast(currentDir)->createDirectory(parts.at(parts.size() - 1)); currentDirList = parts; } } return rootItem; } /** * Convert a number of seconds to a readable time format * d days hh:mm:ss * * @param totalseconds Total number of seconds to convert * @return A fromatted string */ QString MPDParseUtils::seconds2formattedString(const quint32 totalseconds) { QString string; //Get the days,hours,minutes and seconds out of the total seconds quint32 days = totalseconds / 86400; quint32 rest = totalseconds - (days * 86400); quint32 hours = rest / 3600; rest = rest - (hours * 3600); quint32 minutes = rest / 60; quint32 seconds = rest - (minutes * 60); //Convert hour,minutes and seconds to a QTime for easier parsing QTime time(hours, minutes, seconds); if (days == 1) { string.append(QString::number(days) + " day "); } else if (days > 1) { string.append(QString::number(days) + " days "); } string.append(time.toString("hh:mm:ss")); return string; } QList MPDParseUtils::parseOuputs(const QByteArray &data) { QList outputs; QList lines = data.split('\n'); for (int i = 0; i < lines.size();) { if (lines.at(i) == "OK") { break; } quint8 id = lines.at(i).mid(10).toInt(); QString name = QString(lines.at(i + 1).mid(12)); bool enabled = lines.at(i + 2).mid(15).toInt() == 0 ? false : true; outputs << Output(id, enabled, name); i += 3; } return outputs; }