aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-01-19 10:51:34 +0100
committerMax Kellermann <max@duempel.org>2014-01-19 17:04:51 +0100
commitf5ae1ce00b85699291a7cdf9782574e70a8c28f5 (patch)
tree9cb95dd1d98b1b0cd522ee27d7e8a374a3c8eb4a
parent738d6f10409037fbf8aa30cec5aceb121e21e230 (diff)
downloadmpd-f5ae1ce00b85699291a7cdf9782574e70a8c28f5.tar.gz
mpd-f5ae1ce00b85699291a7cdf9782574e70a8c28f5.tar.xz
mpd-f5ae1ce00b85699291a7cdf9782574e70a8c28f5.zip
LightSong: new class to be used by DatabasePlugin callbacks
Detach the Song class completely from the public API, only to be used by SimpleDatabase and the update thread.
-rw-r--r--Makefile.am1
-rw-r--r--src/DatabaseHelpers.cxx10
-rw-r--r--src/DatabasePlaylist.cxx2
-rw-r--r--src/DatabasePlugin.hxx8
-rw-r--r--src/DatabasePrint.cxx29
-rw-r--r--src/DatabaseQueue.cxx2
-rw-r--r--src/DatabaseSelection.cxx2
-rw-r--r--src/DatabaseSelection.hxx4
-rw-r--r--src/DatabaseSong.cxx2
-rw-r--r--src/DatabaseVisitor.hxx4
-rw-r--r--src/DetachedSong.cxx6
-rw-r--r--src/DetachedSong.hxx6
-rw-r--r--src/Directory.cxx23
-rw-r--r--src/LightSong.cxx (renamed from test/FakeSong.cxx)20
-rw-r--r--src/LightSong.hxx82
-rw-r--r--src/Mapper.cxx2
-rw-r--r--src/Mapper.hxx3
-rw-r--r--src/PlaylistEdit.cxx1
-rw-r--r--src/PlaylistPrint.cxx6
-rw-r--r--src/PlaylistSave.cxx1
-rw-r--r--src/PlaylistSong.cxx1
-rw-r--r--src/PlaylistUpdate.cxx6
-rw-r--r--src/Song.cxx21
-rw-r--r--src/Song.hxx6
-rw-r--r--src/SongFilter.cxx33
-rw-r--r--src/SongFilter.hxx9
-rw-r--r--src/SongPrint.cxx14
-rw-r--r--src/SongPrint.hxx6
-rw-r--r--src/SongSticker.cxx17
-rw-r--r--src/SongSticker.hxx14
-rw-r--r--src/TagPrint.cxx3
-rw-r--r--src/TagSave.cxx3
-rw-r--r--src/UpdateRemove.cxx3
-rw-r--r--src/command/StickerCommands.cxx10
-rw-r--r--src/db/LazyDatabase.cxx4
-rw-r--r--src/db/LazyDatabase.hxx6
-rw-r--r--src/db/ProxyDatabasePlugin.cxx129
-rw-r--r--src/db/SimpleDatabasePlugin.cxx30
-rw-r--r--src/db/SimpleDatabasePlugin.hxx12
-rw-r--r--src/db/UpnpDatabasePlugin.cxx71
-rw-r--r--src/playlist/AsxPlaylistPlugin.cxx1
-rw-r--r--src/playlist/RssPlaylistPlugin.cxx1
-rw-r--r--src/playlist/SoundCloudPlaylistPlugin.cxx1
-rw-r--r--test/DumpDatabase.cxx8
44 files changed, 386 insertions, 237 deletions
diff --git a/Makefile.am b/Makefile.am
index 65ffc300c..882fd4e05 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -196,6 +196,7 @@ src_mpd_SOURCES = \
src/ReplayGainInfo.cxx src/ReplayGainInfo.hxx \
src/SignalHandlers.cxx src/SignalHandlers.hxx \
src/DetachedSong.cxx src/DetachedSong.hxx \
+ src/LightSong.cxx src/LightSong.hxx \
src/Song.cxx src/Song.hxx \
src/SongUpdate.cxx \
src/SongPrint.cxx src/SongPrint.hxx \
diff --git a/src/DatabaseHelpers.cxx b/src/DatabaseHelpers.cxx
index e7bd006f0..58e7aaa3b 100644
--- a/src/DatabaseHelpers.cxx
+++ b/src/DatabaseHelpers.cxx
@@ -19,7 +19,7 @@
#include "DatabaseHelpers.hxx"
#include "DatabasePlugin.hxx"
-#include "Song.hxx"
+#include "LightSong.hxx"
#include "tag/Tag.hxx"
#include <functional>
@@ -37,9 +37,9 @@ struct StringLess {
typedef std::set<const char *, StringLess> StringSet;
static bool
-CollectTags(StringSet &set, TagType tag_type, Song &song)
+CollectTags(StringSet &set, TagType tag_type, const LightSong &song)
{
- const Tag *tag = &song.tag;
+ const Tag *tag = song.tag;
bool found = false;
for (unsigned i = 0; i < tag->num_items; ++i) {
@@ -102,11 +102,11 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
static bool
StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums,
- Song &song)
+ const LightSong &song)
{
++stats.song_count;
- StatsVisitTag(stats, artists, albums, song.tag);
+ StatsVisitTag(stats, artists, albums, *song.tag);
return true;
}
diff --git a/src/DatabasePlaylist.cxx b/src/DatabasePlaylist.cxx
index 5f7c85a78..58742ca64 100644
--- a/src/DatabasePlaylist.cxx
+++ b/src/DatabasePlaylist.cxx
@@ -30,7 +30,7 @@
static bool
AddSong(const char *playlist_path_utf8,
- Song &song, Error &error)
+ const LightSong &song, Error &error)
{
return spl_append_song(playlist_path_utf8, map_song_detach(song),
error);
diff --git a/src/DatabasePlugin.hxx b/src/DatabasePlugin.hxx
index 3af44d7dd..2ded7f736 100644
--- a/src/DatabasePlugin.hxx
+++ b/src/DatabasePlugin.hxx
@@ -35,7 +35,7 @@
struct config_param;
struct DatabaseSelection;
struct db_visitor;
-struct Song;
+struct LightSong;
class Error;
class EventLoop;
class DatabaseListener;
@@ -94,14 +94,14 @@ public:
* @param uri_utf8 the URI of the song within the music
* directory (UTF-8)
*/
- virtual Song *GetSong(const char *uri_utf8,
- Error &error) const = 0;
+ virtual const LightSong *GetSong(const char *uri_utf8,
+ Error &error) const = 0;
/**
* Mark the song object as "unused". Call this on objects
* returned by GetSong().
*/
- virtual void ReturnSong(Song *song) const = 0;
+ virtual void ReturnSong(const LightSong *song) const = 0;
/**
* Visit the selected entities.
diff --git a/src/DatabasePrint.cxx b/src/DatabasePrint.cxx
index 514cf3f7b..7b5975275 100644
--- a/src/DatabasePrint.cxx
+++ b/src/DatabasePrint.cxx
@@ -26,7 +26,7 @@
#include "Directory.hxx"
#include "Client.hxx"
#include "tag/Tag.hxx"
-#include "Song.hxx"
+#include "LightSong.hxx"
#include "DatabaseGlue.hxx"
#include "DatabasePlugin.hxx"
@@ -52,6 +52,17 @@ PrintDirectoryFull(Client &client, const Directory &directory)
return true;
}
+static void
+print_playlist_in_directory(Client &client,
+ const char *directory,
+ const char *name_utf8)
+{
+ if (directory == nullptr)
+ client_printf(client, "playlist: %s\n", name_utf8);
+ else
+ client_printf(client, "playlist: %s/%s\n",
+ directory, name_utf8);
+}
static void
print_playlist_in_directory(Client &client,
@@ -66,25 +77,25 @@ print_playlist_in_directory(Client &client,
}
static bool
-PrintSongBrief(Client &client, const Song &song)
+PrintSongBrief(Client &client, const LightSong &song)
{
song_print_uri(client, song);
- if (song.tag.has_playlist)
+ if (song.tag->has_playlist)
/* this song file has an embedded CUE sheet */
- print_playlist_in_directory(client, song.parent, song.uri);
+ print_playlist_in_directory(client, song.directory, song.uri);
return true;
}
static bool
-PrintSongFull(Client &client, const Song &song)
+PrintSongFull(Client &client, const LightSong &song)
{
song_print_info(client, song);
- if (song.tag.has_playlist)
+ if (song.tag->has_playlist)
/* this song file has an embedded CUE sheet */
- print_playlist_in_directory(client, song.parent, song.uri);
+ print_playlist_in_directory(client, song.directory, song.uri);
return true;
}
@@ -146,7 +157,7 @@ static void printSearchStats(Client &client, SearchStats *stats)
}
static bool
-stats_visitor_song(SearchStats &stats, Song &song)
+stats_visitor_song(SearchStats &stats, const LightSong &song)
{
stats.numberOfSongs++;
stats.playTime += song.GetDuration();
@@ -195,7 +206,7 @@ printInfoForAllIn(Client &client, const char *uri_utf8,
}
static bool
-PrintSongURIVisitor(Client &client, Song &song)
+PrintSongURIVisitor(Client &client, const LightSong &song)
{
song_print_uri(client, song);
diff --git a/src/DatabaseQueue.cxx b/src/DatabaseQueue.cxx
index 0ed073285..ee1dbd57c 100644
--- a/src/DatabaseQueue.cxx
+++ b/src/DatabaseQueue.cxx
@@ -29,7 +29,7 @@
#include <functional>
static bool
-AddToQueue(Partition &partition, const Song &song, Error &error)
+AddToQueue(Partition &partition, const LightSong &song, Error &error)
{
PlaylistResult result =
partition.playlist.AppendSong(partition.pc,
diff --git a/src/DatabaseSelection.cxx b/src/DatabaseSelection.cxx
index 1dedafec0..035321252 100644
--- a/src/DatabaseSelection.cxx
+++ b/src/DatabaseSelection.cxx
@@ -31,7 +31,7 @@ DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
}
bool
-DatabaseSelection::Match(const Song &song) const
+DatabaseSelection::Match(const LightSong &song) const
{
return filter == nullptr || filter->Match(song);
}
diff --git a/src/DatabaseSelection.hxx b/src/DatabaseSelection.hxx
index 3447b5eee..a39ce7afe 100644
--- a/src/DatabaseSelection.hxx
+++ b/src/DatabaseSelection.hxx
@@ -25,7 +25,7 @@
#include <string>
class SongFilter;
-struct Song;
+struct LightSong;
struct DatabaseSelection {
/**
@@ -45,7 +45,7 @@ struct DatabaseSelection {
const SongFilter *_filter=nullptr);
gcc_pure
- bool Match(const Song &song) const;
+ bool Match(const LightSong &song) const;
};
#endif
diff --git a/src/DatabaseSong.cxx b/src/DatabaseSong.cxx
index a8f2188cc..592d38b85 100644
--- a/src/DatabaseSong.cxx
+++ b/src/DatabaseSong.cxx
@@ -31,7 +31,7 @@ DatabaseDetachSong(const char *uri, Error &error)
if (db == nullptr)
return nullptr;
- Song *tmp = db->GetSong(uri, error);
+ const LightSong *tmp = db->GetSong(uri, error);
if (tmp == nullptr)
return nullptr;
diff --git a/src/DatabaseVisitor.hxx b/src/DatabaseVisitor.hxx
index 6f7ff3deb..486407765 100644
--- a/src/DatabaseVisitor.hxx
+++ b/src/DatabaseVisitor.hxx
@@ -23,12 +23,12 @@
#include <functional>
struct Directory;
-struct Song;
+struct LightSong;
struct PlaylistInfo;
class Error;
typedef std::function<bool(const Directory &, Error &)> VisitDirectory;
-typedef std::function<bool(struct Song &, Error &)> VisitSong;
+typedef std::function<bool(const LightSong &, Error &)> VisitSong;
typedef std::function<bool(const PlaylistInfo &, const Directory &,
Error &)> VisitPlaylist;
diff --git a/src/DetachedSong.cxx b/src/DetachedSong.cxx
index e8b75f618..4e52afb0c 100644
--- a/src/DetachedSong.cxx
+++ b/src/DetachedSong.cxx
@@ -19,13 +19,13 @@
#include "config.h"
#include "DetachedSong.hxx"
-#include "Song.hxx"
+#include "LightSong.hxx"
#include "util/UriUtil.hxx"
#include "fs/Traits.hxx"
-DetachedSong::DetachedSong(const Song &other)
+DetachedSong::DetachedSong(const LightSong &other)
:uri(other.GetURI().c_str()),
- tag(other.tag),
+ tag(*other.tag),
mtime(other.mtime),
start_ms(other.start_ms), end_ms(other.end_ms) {}
diff --git a/src/DetachedSong.hxx b/src/DetachedSong.hxx
index 7d841a4c2..2ef3cdf3e 100644
--- a/src/DetachedSong.hxx
+++ b/src/DetachedSong.hxx
@@ -29,10 +29,10 @@
#include <time.h>
-struct Song;
+struct LightSong;
class DetachedSong {
- friend DetachedSong map_song_detach(const Song &song);
+ friend DetachedSong map_song_detach(const LightSong &song);
/**
* An UTF-8-encoded URI referring to the song file. This can
@@ -62,7 +62,7 @@ class DetachedSong {
*/
unsigned end_ms;
- explicit DetachedSong(const Song &other);
+ explicit DetachedSong(const LightSong &other);
public:
explicit DetachedSong(const DetachedSong &other)
diff --git a/src/Directory.cxx b/src/Directory.cxx
index ff2c00b05..210d7cb67 100644
--- a/src/Directory.cxx
+++ b/src/Directory.cxx
@@ -24,6 +24,7 @@
#include "DatabaseLock.hxx"
#include "SongSort.hxx"
#include "Song.hxx"
+#include "LightSong.hxx"
#include "fs/Traits.hxx"
#include "util/Alloc.hxx"
#include "util/Error.hxx"
@@ -251,6 +252,20 @@ Directory::Sort()
child->Sort();
}
+static LightSong
+ExportSong(const Song &src)
+{
+ LightSong dest;
+ dest.directory = src.parent->IsRoot()
+ ? nullptr : src.parent->GetPath();
+ dest.uri = src.uri;
+ dest.tag = &src.tag;
+ dest.mtime = src.mtime;
+ dest.start_ms = src.start_ms;
+ dest.end_ms = src.end_ms;
+ return dest;
+}
+
bool
Directory::Walk(bool recursive, const SongFilter *filter,
VisitDirectory visit_directory, VisitSong visit_song,
@@ -261,10 +276,12 @@ Directory::Walk(bool recursive, const SongFilter *filter,
if (visit_song) {
Song *song;
- directory_for_each_song(song, *this)
- if ((filter == nullptr || filter->Match(*song)) &&
- !visit_song(*song, error))
+ directory_for_each_song(song, *this) {
+ const LightSong song2 = ExportSong(*song);
+ if ((filter == nullptr || filter->Match(song2)) &&
+ !visit_song(song2, error))
return false;
+ }
}
if (visit_playlist) {
diff --git a/test/FakeSong.cxx b/src/LightSong.cxx
index e2fae4d6e..af1e801f8 100644
--- a/test/FakeSong.cxx
+++ b/src/LightSong.cxx
@@ -17,17 +17,17 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include "config.h"
-#include "Song.hxx"
-#include "directory.h"
-#include "Compiler.h"
+#include "LightSong.hxx"
+#include "tag/Tag.hxx"
-#include <stdlib.h>
+double
+LightSong::GetDuration() const
+{
+ if (end_ms > 0)
+ return (end_ms - start_ms) / 1000.0;
-struct directory detached_root;
+ if (tag->time <= 0)
+ return 0;
-Song *
-song_dup_detached(gcc_unused const Song *src)
-{
- abort();
+ return tag->time - start_ms / 1000.0;
}
diff --git a/src/LightSong.hxx b/src/LightSong.hxx
new file mode 100644
index 000000000..b93d5876c
--- /dev/null
+++ b/src/LightSong.hxx
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_LIGHT_SONG_HXX
+#define MPD_LIGHT_SONG_HXX
+
+#include "Compiler.h"
+
+#include <string>
+
+#include <time.h>
+
+struct Tag;
+
+/**
+ * A reference to a song file. Unlike the other "Song" classes in the
+ * MPD code base, this one consists only of pointers. It is supposed
+ * to be as light as possible while still providing all the
+ * information MPD has about a song file. This class does not manage
+ * any memory, and the pointers become invalid quickly. Only to be
+ * used to pass around during well-defined situations.
+ */
+struct LightSong {
+ /**
+ * If this is not nullptr, then it denotes a prefix for the
+ * #uri. To build the full URI, join directory and uri with a
+ * slash.
+ */
+ const char *directory;
+
+ const char *uri;
+
+ /**
+ * Must not be nullptr.
+ */
+ const Tag *tag;
+
+ time_t mtime;
+
+ /**
+ * Start of this sub-song within the file in milliseconds.
+ */
+ unsigned start_ms;
+
+ /**
+ * End of this sub-song within the file in milliseconds.
+ * Unused if zero.
+ */
+ unsigned end_ms;
+
+ gcc_pure
+ std::string GetURI() const {
+ if (directory == nullptr)
+ return std::string(uri);
+
+ std::string result(directory);
+ result.push_back('/');
+ result.append(uri);
+ return result;
+ }
+
+ gcc_pure
+ double GetDuration() const;
+};
+
+#endif
diff --git a/src/Mapper.cxx b/src/Mapper.cxx
index d41fba957..8fafce12d 100644
--- a/src/Mapper.cxx
+++ b/src/Mapper.cxx
@@ -218,7 +218,7 @@ map_detached_song_fs(const char *uri_utf8)
}
DetachedSong
-map_song_detach(const Song &song)
+map_song_detach(const LightSong &song)
{
return DetachedSong(song);
}
diff --git a/src/Mapper.hxx b/src/Mapper.hxx
index 18a5ca3fe..5c01a9aff 100644
--- a/src/Mapper.hxx
+++ b/src/Mapper.hxx
@@ -33,6 +33,7 @@
class AllocatedPath;
struct Directory;
struct Song;
+struct LightSong;
class DetachedSong;
void
@@ -112,7 +113,7 @@ map_directory_child_fs(const Directory &directory, const char *name);
*/
gcc_pure
DetachedSong
-map_song_detach(const Song &song);
+map_song_detach(const LightSong &song);
/**
* Determines the file system path of a song. This must not be a
diff --git a/src/PlaylistEdit.cxx b/src/PlaylistEdit.cxx
index 0eea62e18..cbae02fef 100644
--- a/src/PlaylistEdit.cxx
+++ b/src/PlaylistEdit.cxx
@@ -29,7 +29,6 @@
#include "PlayerControl.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
-#include "Song.hxx"
#include "DetachedSong.hxx"
#include "Mapper.hxx"
#include "Idle.hxx"
diff --git a/src/PlaylistPrint.cxx b/src/PlaylistPrint.cxx
index dcd0953d6..34143d8a8 100644
--- a/src/PlaylistPrint.cxx
+++ b/src/PlaylistPrint.cxx
@@ -30,12 +30,14 @@
#include "DatabasePlugin.hxx"
#include "Client.hxx"
#include "InputStream.hxx"
-#include "Song.hxx"
#include "DetachedSong.hxx"
#include "fs/Traits.hxx"
#include "util/Error.hxx"
#include "thread/Cond.hxx"
+#define SONG_FILE "file: "
+#define SONG_TIME "Time: "
+
void
playlist_print_uris(Client &client, const playlist &playlist)
{
@@ -118,7 +120,7 @@ PrintSongDetails(Client &client, const char *uri_utf8)
if (db == nullptr)
return false;
- Song *song = db->GetSong(uri_utf8, IgnoreError());
+ auto *song = db->GetSong(uri_utf8, IgnoreError());
if (song == nullptr)
return false;
diff --git a/src/PlaylistSave.cxx b/src/PlaylistSave.cxx
index 6d9b41b62..9a01aa954 100644
--- a/src/PlaylistSave.cxx
+++ b/src/PlaylistSave.cxx
@@ -22,7 +22,6 @@
#include "PlaylistFile.hxx"
#include "PlaylistError.hxx"
#include "Playlist.hxx"
-#include "Song.hxx"
#include "DetachedSong.hxx"
#include "Mapper.hxx"
#include "Idle.hxx"
diff --git a/src/PlaylistSong.cxx b/src/PlaylistSong.cxx
index 5d61c7f71..5d3011988 100644
--- a/src/PlaylistSong.cxx
+++ b/src/PlaylistSong.cxx
@@ -29,7 +29,6 @@
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
#include "DetachedSong.hxx"
-#include "Song.hxx"
#include <assert.h>
#include <string.h>
diff --git a/src/PlaylistUpdate.cxx b/src/PlaylistUpdate.cxx
index 55b2e9f0a..755589786 100644
--- a/src/PlaylistUpdate.cxx
+++ b/src/PlaylistUpdate.cxx
@@ -21,7 +21,7 @@
#include "Playlist.hxx"
#include "DatabaseGlue.hxx"
#include "DatabasePlugin.hxx"
-#include "Song.hxx"
+#include "LightSong.hxx"
#include "DetachedSong.hxx"
#include "tag/Tag.hxx"
#include "Idle.hxx"
@@ -35,7 +35,7 @@ UpdatePlaylistSong(const Database &db, DetachedSong &song)
from the Database */
return false;
- Song *original = db.GetSong(song.GetURI(), IgnoreError());
+ const LightSong *original = db.GetSong(song.GetURI(), IgnoreError());
if (original == nullptr)
/* not found - shouldn't happen, because the update
thread should ensure that all stale Song instances
@@ -49,7 +49,7 @@ UpdatePlaylistSong(const Database &db, DetachedSong &song)
}
song.SetLastModified(original->mtime);
- song.SetTag(original->tag);
+ song.SetTag(*original->tag);
db.ReturnSong(original);
return true;
diff --git a/src/Song.cxx b/src/Song.cxx
index 384307642..565b9af98 100644
--- a/src/Song.cxx
+++ b/src/Song.cxx
@@ -23,6 +23,7 @@
#include "tag/Tag.hxx"
#include "util/VarSize.hxx"
#include "DetachedSong.hxx"
+#include "LightSong.hxx"
#include <assert.h>
#include <string.h>
@@ -94,14 +95,16 @@ Song::GetURI() const
}
}
-double
-Song::GetDuration() const
+LightSong
+Song::Export() const
{
- if (end_ms > 0)
- return (end_ms - start_ms) / 1000.0;
-
- if (tag.time <= 0)
- return 0;
-
- return tag.time - start_ms / 1000.0;
+ LightSong dest;
+ dest.directory = parent->IsRoot()
+ ? nullptr : parent->GetPath();
+ dest.uri = uri;
+ dest.tag = &tag;
+ dest.mtime = mtime;
+ dest.start_ms = start_ms;
+ dest.end_ms = end_ms;
+ return dest;
}
diff --git a/src/Song.hxx b/src/Song.hxx
index 81f9f0c90..824fb429c 100644
--- a/src/Song.hxx
+++ b/src/Song.hxx
@@ -29,9 +29,7 @@
#include <assert.h>
#include <time.h>
-#define SONG_FILE "file: "
-#define SONG_TIME "Time: "
-
+struct LightSong;
struct Directory;
class DetachedSong;
@@ -112,7 +110,7 @@ struct Song {
std::string GetURI() const;
gcc_pure
- double GetDuration() const;
+ LightSong Export() const;
};
#endif
diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx
index dccbab925..594ac3abc 100644
--- a/src/SongFilter.cxx
+++ b/src/SongFilter.cxx
@@ -20,6 +20,7 @@
#include "config.h"
#include "SongFilter.hxx"
#include "Song.hxx"
+#include "LightSong.hxx"
#include "DetachedSong.hxx"
#include "tag/Tag.hxx"
#include "util/ASCII.hxx"
@@ -137,7 +138,19 @@ SongFilter::Item::Match(const Tag &_tag) const
}
bool
-SongFilter::Item::Match(const Song &song) const
+SongFilter::Item::Match(const DetachedSong &song) const
+{
+ if (tag == LOCATE_TAG_BASE_TYPE)
+ return uri_is_child_or_same(value.c_str(), song.GetURI());
+
+ if (tag == LOCATE_TAG_FILE_TYPE)
+ return StringMatch(song.GetURI());
+
+ return Match(song.GetTag());
+}
+
+bool
+SongFilter::Item::Match(const LightSong &song) const
{
if (tag == LOCATE_TAG_BASE_TYPE) {
const auto uri = song.GetURI();
@@ -149,19 +162,7 @@ SongFilter::Item::Match(const Song &song) const
return StringMatch(uri.c_str());
}
- return Match(song.tag);
-}
-
-bool
-SongFilter::Item::Match(const DetachedSong &song) const
-{
- if (tag == LOCATE_TAG_BASE_TYPE)
- return uri_is_child_or_same(value.c_str(), song.GetURI());
-
- if (tag == LOCATE_TAG_FILE_TYPE)
- return StringMatch(song.GetURI());
-
- return Match(song.GetTag());
+ return Match(*song.tag);
}
SongFilter::SongFilter(unsigned tag, const char *value, bool fold_case)
@@ -207,7 +208,7 @@ SongFilter::Parse(unsigned argc, char *argv[], bool fold_case)
}
bool
-SongFilter::Match(const Song &song) const
+SongFilter::Match(const DetachedSong &song) const
{
for (const auto &i : items)
if (!i.Match(song))
@@ -217,7 +218,7 @@ SongFilter::Match(const Song &song) const
}
bool
-SongFilter::Match(const DetachedSong &song) const
+SongFilter::Match(const LightSong &song) const
{
for (const auto &i : items)
if (!i.Match(song))
diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx
index d53c98357..74d7187c9 100644
--- a/src/SongFilter.hxx
+++ b/src/SongFilter.hxx
@@ -38,6 +38,7 @@
struct Tag;
struct TagItem;
struct Song;
+struct LightSong;
class DetachedSong;
class SongFilter {
@@ -80,10 +81,10 @@ public:
bool Match(const Tag &tag) const;
gcc_pure
- bool Match(const Song &song) const;
+ bool Match(const DetachedSong &song) const;
gcc_pure
- bool Match(const DetachedSong &song) const;
+ bool Match(const LightSong &song) const;
};
private:
@@ -107,10 +108,10 @@ public:
bool Match(const Tag &tag) const;
gcc_pure
- bool Match(const Song &song) const;
+ bool Match(const DetachedSong &song) const;
gcc_pure
- bool Match(const DetachedSong &song) const;
+ bool Match(const LightSong &song) const;
const std::list<Item> &GetItems() const {
return items;
diff --git a/src/SongPrint.cxx b/src/SongPrint.cxx
index 67b622356..810518c21 100644
--- a/src/SongPrint.cxx
+++ b/src/SongPrint.cxx
@@ -19,7 +19,7 @@
#include "config.h"
#include "SongPrint.hxx"
-#include "Song.hxx"
+#include "LightSong.hxx"
#include "DetachedSong.hxx"
#include "Directory.hxx"
#include "TimePrint.hxx"
@@ -28,6 +28,8 @@
#include "Client.hxx"
#include "util/UriUtil.hxx"
+#define SONG_FILE "file: "
+
static void
song_print_uri(Client &client, const char *uri)
{
@@ -40,11 +42,11 @@ song_print_uri(Client &client, const char *uri)
}
void
-song_print_uri(Client &client, const Song &song)
+song_print_uri(Client &client, const LightSong &song)
{
- if (song.parent != nullptr && !song.parent->IsRoot()) {
+ if (song.directory != nullptr) {
client_printf(client, "%s%s/%s\n", SONG_FILE,
- song.parent->GetPath(), song.uri);
+ song.directory, song.uri);
} else
song_print_uri(client, song.uri);
}
@@ -56,7 +58,7 @@ song_print_uri(Client &client, const DetachedSong &song)
}
void
-song_print_info(Client &client, const Song &song)
+song_print_info(Client &client, const LightSong &song)
{
song_print_uri(client, song);
@@ -74,7 +76,7 @@ song_print_info(Client &client, const Song &song)
if (song.mtime > 0)
time_print(client, "Last-Modified", song.mtime);
- tag_print(client, song.tag);
+ tag_print(client, *song.tag);
}
void
diff --git a/src/SongPrint.hxx b/src/SongPrint.hxx
index 7bbf6e19c..16a9ee6ff 100644
--- a/src/SongPrint.hxx
+++ b/src/SongPrint.hxx
@@ -20,7 +20,7 @@
#ifndef MPD_SONG_PRINT_HXX
#define MPD_SONG_PRINT_HXX
-struct Song;
+struct LightSong;
class DetachedSong;
class Client;
@@ -28,10 +28,10 @@ void
song_print_info(Client &client, const DetachedSong &song);
void
-song_print_info(Client &client, const Song &song);
+song_print_info(Client &client, const LightSong &song);
void
-song_print_uri(Client &client, const Song &song);
+song_print_uri(Client &client, const LightSong &song);
void
song_print_uri(Client &client, const DetachedSong &song);
diff --git a/src/SongSticker.cxx b/src/SongSticker.cxx
index 8c5499bc2..55143d278 100644
--- a/src/SongSticker.cxx
+++ b/src/SongSticker.cxx
@@ -20,6 +20,7 @@
#include "config.h"
#include "SongSticker.hxx"
#include "StickerDatabase.hxx"
+#include "LightSong.hxx"
#include "Song.hxx"
#include "Directory.hxx"
@@ -29,14 +30,14 @@
#include <string.h>
std::string
-sticker_song_get_value(const Song &song, const char *name)
+sticker_song_get_value(const LightSong &song, const char *name)
{
const auto uri = song.GetURI();
return sticker_load_value("song", uri.c_str(), name);
}
bool
-sticker_song_set_value(const Song &song,
+sticker_song_set_value(const LightSong &song,
const char *name, const char *value)
{
const auto uri = song.GetURI();
@@ -44,21 +45,21 @@ sticker_song_set_value(const Song &song,
}
bool
-sticker_song_delete(const Song &song)
+sticker_song_delete(const LightSong &song)
{
const auto uri = song.GetURI();
return sticker_delete("song", uri.c_str());
}
bool
-sticker_song_delete_value(const Song &song, const char *name)
+sticker_song_delete_value(const LightSong &song, const char *name)
{
const auto uri = song.GetURI();
return sticker_delete_value("song", uri.c_str(), name);
}
struct sticker *
-sticker_song_get(const Song &song)
+sticker_song_get(const LightSong &song)
{
const auto uri = song.GetURI();
return sticker_load("song", uri.c_str());
@@ -69,7 +70,7 @@ struct sticker_song_find_data {
const char *base_uri;
size_t base_uri_length;
- void (*func)(Song &song, const char *value,
+ void (*func)(const LightSong &song, const char *value,
void *user_data);
void *user_data;
};
@@ -86,12 +87,12 @@ sticker_song_find_cb(const char *uri, const char *value, void *user_data)
Song *song = data->directory->LookupSong(uri + data->base_uri_length);
if (song != nullptr)
- data->func(*song, value, data->user_data);
+ data->func(song->Export(), value, data->user_data);
}
bool
sticker_song_find(Directory &directory, const char *name,
- void (*func)(Song &song, const char *value,
+ void (*func)(const LightSong &song, const char *value,
void *user_data),
void *user_data)
{
diff --git a/src/SongSticker.hxx b/src/SongSticker.hxx
index b626e63e3..2f977bd21 100644
--- a/src/SongSticker.hxx
+++ b/src/SongSticker.hxx
@@ -24,7 +24,7 @@
#include <string>
-struct Song;
+struct LightSong;
struct Directory;
struct sticker;
@@ -34,28 +34,28 @@ struct sticker;
*/
gcc_pure
std::string
-sticker_song_get_value(const Song &song, const char *name);
+sticker_song_get_value(const LightSong &song, const char *name);
/**
* Sets a sticker value in the specified song. Overwrites existing
* values.
*/
bool
-sticker_song_set_value(const Song &song,
+sticker_song_set_value(const LightSong &song,
const char *name, const char *value);
/**
* Deletes a sticker from the database. All values are deleted.
*/
bool
-sticker_song_delete(const Song &song);
+sticker_song_delete(const LightSong &song);
/**
* Deletes a sticker value. Does nothing if the sticker did not
* exist.
*/
bool
-sticker_song_delete_value(const Song &song, const char *name);
+sticker_song_delete_value(const LightSong &song, const char *name);
/**
* Loads the sticker for the specified song.
@@ -64,7 +64,7 @@ sticker_song_delete_value(const Song &song, const char *name);
* @return a sticker object, or NULL on error or if there is no sticker
*/
sticker *
-sticker_song_get(const Song &song);
+sticker_song_get(const LightSong &song);
/**
* Finds stickers with the specified name below the specified
@@ -79,7 +79,7 @@ sticker_song_get(const Song &song);
*/
bool
sticker_song_find(Directory &directory, const char *name,
- void (*func)(Song &song, const char *value,
+ void (*func)(const LightSong &song, const char *value,
void *user_data),
void *user_data);
diff --git a/src/TagPrint.cxx b/src/TagPrint.cxx
index 14d3abcf0..4f5ea8be3 100644
--- a/src/TagPrint.cxx
+++ b/src/TagPrint.cxx
@@ -21,9 +21,10 @@
#include "TagPrint.hxx"
#include "tag/Tag.hxx"
#include "tag/TagSettings.h"
-#include "Song.hxx"
#include "Client.hxx"
+#define SONG_TIME "Time: "
+
void tag_print_types(Client &client)
{
int i;
diff --git a/src/TagSave.cxx b/src/TagSave.cxx
index 24058906e..3a291e115 100644
--- a/src/TagSave.cxx
+++ b/src/TagSave.cxx
@@ -20,7 +20,8 @@
#include "config.h"
#include "TagSave.hxx"
#include "tag/Tag.hxx"
-#include "Song.hxx"
+
+#define SONG_TIME "Time: "
void
tag_save(FILE *file, const Tag &tag)
diff --git a/src/UpdateRemove.cxx b/src/UpdateRemove.cxx
index cc57fbe94..bed7a92ab 100644
--- a/src/UpdateRemove.cxx
+++ b/src/UpdateRemove.cxx
@@ -24,6 +24,7 @@
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
#include "Song.hxx"
+#include "LightSong.hxx"
#include "Main.hxx"
#include "Instance.hxx"
#include "Log.hxx"
@@ -57,7 +58,7 @@ song_remove_event(void)
#ifdef ENABLE_SQLITE
/* if the song has a sticker, remove it */
if (sticker_enabled())
- sticker_song_delete(*removed_song);
+ sticker_song_delete(removed_song->Export());
#endif
{
diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx
index 93a13140b..4272dee69 100644
--- a/src/command/StickerCommands.cxx
+++ b/src/command/StickerCommands.cxx
@@ -39,7 +39,7 @@ struct sticker_song_find_data {
};
static void
-sticker_song_find_print_cb(Song &song, const char *value,
+sticker_song_find_print_cb(const LightSong &song, const char *value,
void *user_data)
{
struct sticker_song_find_data *data =
@@ -59,7 +59,7 @@ handle_sticker_song(Client &client, int argc, char *argv[])
/* get song song_id key */
if (argc == 5 && strcmp(argv[1], "get") == 0) {
- Song *song = db->GetSong(argv[3], error);
+ const LightSong *song = db->GetSong(argv[3], error);
if (song == nullptr)
return print_error(client, error);
@@ -76,7 +76,7 @@ handle_sticker_song(Client &client, int argc, char *argv[])
return CommandResult::OK;
/* list song song_id */
} else if (argc == 4 && strcmp(argv[1], "list") == 0) {
- Song *song = db->GetSong(argv[3], error);
+ const LightSong *song = db->GetSong(argv[3], error);
if (song == nullptr)
return print_error(client, error);
@@ -90,7 +90,7 @@ handle_sticker_song(Client &client, int argc, char *argv[])
return CommandResult::OK;
/* set song song_id id key */
} else if (argc == 6 && strcmp(argv[1], "set") == 0) {
- Song *song = db->GetSong(argv[3], error);
+ const LightSong *song = db->GetSong(argv[3], error);
if (song == nullptr)
return print_error(client, error);
@@ -106,7 +106,7 @@ handle_sticker_song(Client &client, int argc, char *argv[])
/* delete song song_id [key] */
} else if ((argc == 4 || argc == 5) &&
strcmp(argv[1], "delete") == 0) {
- Song *song = db->GetSong(argv[3], error);
+ const LightSong *song = db->GetSong(argv[3], error);
if (song == nullptr)
return print_error(client, error);
diff --git a/src/db/LazyDatabase.cxx b/src/db/LazyDatabase.cxx
index 0718c3dcd..6a01ffb82 100644
--- a/src/db/LazyDatabase.cxx
+++ b/src/db/LazyDatabase.cxx
@@ -51,7 +51,7 @@ LazyDatabase::Close()
}
}
-Song *
+const LightSong *
LazyDatabase::GetSong(const char *uri, Error &error) const
{
return EnsureOpen(error)
@@ -60,7 +60,7 @@ LazyDatabase::GetSong(const char *uri, Error &error) const
}
void
-LazyDatabase::ReturnSong(Song *song) const
+LazyDatabase::ReturnSong(const LightSong *song) const
{
assert(open);
diff --git a/src/db/LazyDatabase.hxx b/src/db/LazyDatabase.hxx
index 7f97aa40d..f718ecb3f 100644
--- a/src/db/LazyDatabase.hxx
+++ b/src/db/LazyDatabase.hxx
@@ -41,9 +41,9 @@ public:
virtual void Close() override;
- virtual Song *GetSong(const char *uri_utf8,
- Error &error) const override;
- virtual void ReturnSong(Song *song) const;
+ virtual const LightSong *GetSong(const char *uri_utf8,
+ Error &error) const override;
+ virtual void ReturnSong(const LightSong *song) const;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,
diff --git a/src/db/ProxyDatabasePlugin.cxx b/src/db/ProxyDatabasePlugin.cxx
index e5e9ac76f..f65e4f3d0 100644
--- a/src/db/ProxyDatabasePlugin.cxx
+++ b/src/db/ProxyDatabasePlugin.cxx
@@ -24,11 +24,12 @@
#include "DatabaseSelection.hxx"
#include "DatabaseError.hxx"
#include "Directory.hxx"
-#include "Song.hxx"
+#include "LightSong.hxx"
#include "SongFilter.hxx"
#include "Compiler.h"
#include "ConfigData.hxx"
#include "tag/TagBuilder.hxx"
+#include "tag/Tag.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "protocol/Ack.hxx"
@@ -44,6 +45,25 @@
#include <string>
#include <list>
+class ProxySong : public LightSong {
+ Tag tag2;
+
+public:
+ explicit ProxySong(const mpd_song *song);
+};
+
+class AllocatedProxySong : public ProxySong {
+ mpd_song *const song;
+
+public:
+ explicit AllocatedProxySong(mpd_song *_song)
+ :ProxySong(_song), song(_song) {}
+
+ ~AllocatedProxySong() {
+ mpd_song_free(song);
+ }
+};
+
class ProxyDatabase final : public Database, SocketMonitor, IdleMonitor {
DatabaseListener &listener;
@@ -79,9 +99,9 @@ public:
virtual bool Open(Error &error) override;
virtual void Close() override;
- virtual Song *GetSong(const char *uri_utf8,
+ virtual const LightSong *GetSong(const char *uri_utf8,
Error &error) const override;
- virtual void ReturnSong(Song *song) const;
+ virtual void ReturnSong(const LightSong *song) const;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,
@@ -144,6 +164,38 @@ static constexpr struct {
{ TAG_NUM_OF_ITEM_TYPES, MPD_TAG_COUNT }
};
+static void
+Copy(TagBuilder &tag, TagType d_tag,
+ const struct mpd_song *song, enum mpd_tag_type s_tag)
+{
+
+ for (unsigned i = 0;; ++i) {
+ const char *value = mpd_song_get_tag(song, s_tag, i);
+ if (value == nullptr)
+ break;
+
+ tag.AddItem(d_tag, value);
+ }
+}
+
+ProxySong::ProxySong(const mpd_song *song)
+{
+ directory = nullptr;
+ uri = mpd_song_get_uri(song);
+ tag = &tag2;
+ mtime = mpd_song_get_last_modified(song);
+ start_ms = mpd_song_get_start(song) * 1000;
+ end_ms = mpd_song_get_end(song) * 1000;
+
+ TagBuilder tag_builder;
+ tag_builder.SetTime(mpd_song_get_duration(song));
+
+ for (const auto *i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
+ Copy(tag_builder, i->d, song, i->s);
+
+ tag_builder.Commit(tag2);
+}
+
gcc_const
static enum mpd_tag_type
Convert(TagType tag_type)
@@ -424,10 +476,7 @@ ProxyDatabase::OnIdle()
SocketMonitor::ScheduleRead();
}
-static Song *
-Convert(const struct mpd_song *song);
-
-Song *
+const LightSong *
ProxyDatabase::GetSong(const char *uri, Error &error) const
{
// TODO: eliminate the const_cast
@@ -452,18 +501,17 @@ ProxyDatabase::GetSong(const char *uri, Error &error) const
return nullptr;
}
- Song *song2 = Convert(song);
- mpd_song_free(song);
- return song2;
+ return new AllocatedProxySong(song);
}
void
-ProxyDatabase::ReturnSong(Song *song) const
+ProxyDatabase::ReturnSong(const LightSong *_song) const
{
- assert(song != nullptr);
- assert(song->parent == nullptr);
+ assert(_song != nullptr);
- song->Free();
+ AllocatedProxySong *song = (AllocatedProxySong *)
+ const_cast<LightSong *>(_song);
+ delete song;
}
static bool
@@ -493,60 +541,23 @@ Visit(struct mpd_connection *connection, Directory &root,
return true;
}
-static void
-Copy(TagBuilder &tag, TagType d_tag,
- const struct mpd_song *song, enum mpd_tag_type s_tag)
-{
-
- for (unsigned i = 0;; ++i) {
- const char *value = mpd_song_get_tag(song, s_tag, i);
- if (value == nullptr)
- break;
-
- tag.AddItem(d_tag, value);
- }
-}
-
-static Song *
-Convert(const struct mpd_song *song)
-{
- Song *s = Song::NewFile(mpd_song_get_uri(song), nullptr);
-
- s->mtime = mpd_song_get_last_modified(song);
- s->start_ms = mpd_song_get_start(song) * 1000;
- s->end_ms = mpd_song_get_end(song) * 1000;
-
- TagBuilder tag;
- tag.SetTime(mpd_song_get_duration(song));
-
- for (const auto *i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
- Copy(tag, i->d, song, i->s);
-
- tag.Commit(s->tag);
-
- return s;
-}
-
gcc_pure
static bool
-Match(const SongFilter *filter, const Song &song)
+Match(const SongFilter *filter, const LightSong &song)
{
return filter == nullptr || filter->Match(song);
}
static bool
Visit(const SongFilter *filter,
- const struct mpd_song *song,
+ const mpd_song *_song,
VisitSong visit_song, Error &error)
{
if (!visit_song)
return true;
- Song *s = Convert(song);
- bool success = !Match(filter, *s) || visit_song(*s, error);
- s->Free();
-
- return success;
+ const ProxySong song(_song);
+ return !Match(filter, song) || visit_song(song, error);
}
static bool
@@ -664,12 +675,10 @@ SearchSongs(struct mpd_connection *connection,
bool result = true;
struct mpd_song *song;
while (result && (song = mpd_recv_song(connection)) != nullptr) {
- Song *song2 = Convert(song);
- mpd_song_free(song);
+ AllocatedProxySong song2(song);
- result = !Match(selection.filter, *song2) ||
- visit_song(*song2, error);
- song2->Free();
+ result = !Match(selection.filter, song2) ||
+ visit_song(song2, error);
}
mpd_response_finish(connection);
diff --git a/src/db/SimpleDatabasePlugin.cxx b/src/db/SimpleDatabasePlugin.cxx
index c33db3831..3d947c042 100644
--- a/src/db/SimpleDatabasePlugin.cxx
+++ b/src/db/SimpleDatabasePlugin.cxx
@@ -22,6 +22,7 @@
#include "DatabaseSelection.hxx"
#include "DatabaseHelpers.hxx"
#include "Directory.hxx"
+#include "Song.hxx"
#include "SongFilter.hxx"
#include "DatabaseSave.hxx"
#include "DatabaseLock.hxx"
@@ -193,29 +194,34 @@ SimpleDatabase::Close()
delete root;
}
-Song *
+const LightSong *
SimpleDatabase::GetSong(const char *uri, Error &error) const
{
assert(root != nullptr);
+ assert(borrowed_song_count == 0);
db_lock();
- Song *song = root->LookupSong(uri);
+ const Song *song = root->LookupSong(uri);
db_unlock();
- if (song == nullptr)
+ if (song == nullptr) {
error.Format(db_domain, DB_NOT_FOUND,
"No such song: %s", uri);
+ return nullptr;
+ }
+
+ light_song = song->Export();
+
#ifndef NDEBUG
- else
- ++borrowed_song_count;
+ ++borrowed_song_count;
#endif
- return song;
+ return &light_song;
}
void
-SimpleDatabase::ReturnSong(gcc_unused Song *song) const
+SimpleDatabase::ReturnSong(gcc_unused const LightSong *song) const
{
- assert(song != nullptr);
+ assert(song == &light_song);
#ifndef NDEBUG
assert(borrowed_song_count > 0);
@@ -247,9 +253,11 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
if (directory == nullptr) {
if (visit_song) {
Song *song = root->LookupSong(selection.uri.c_str());
- if (song != nullptr)
- return !selection.Match(*song) ||
- visit_song(*song, error);
+ if (song != nullptr) {
+ const LightSong song2 = song->Export();
+ return !selection.Match(song2) ||
+ visit_song(song2, error);
+ }
}
error.Set(db_domain, DB_NOT_FOUND, "No such directory");
diff --git a/src/db/SimpleDatabasePlugin.hxx b/src/db/SimpleDatabasePlugin.hxx
index d51174194..509b91e4e 100644
--- a/src/db/SimpleDatabasePlugin.hxx
+++ b/src/db/SimpleDatabasePlugin.hxx
@@ -22,6 +22,7 @@
#include "DatabasePlugin.hxx"
#include "fs/AllocatedPath.hxx"
+#include "LightSong.hxx"
#include "Compiler.h"
#include <cassert>
@@ -36,6 +37,11 @@ class SimpleDatabase : public Database {
time_t mtime;
+ /**
+ * A buffer for GetSong().
+ */
+ mutable LightSong light_song;
+
#ifndef NDEBUG
mutable unsigned borrowed_song_count;
#endif
@@ -60,9 +66,9 @@ public:
virtual bool Open(Error &error) override;
virtual void Close() override;
- virtual Song *GetSong(const char *uri_utf8,
- Error &error) const override;
- virtual void ReturnSong(Song *song) const;
+ virtual const LightSong *GetSong(const char *uri_utf8,
+ Error &error) const override;
+ virtual void ReturnSong(const LightSong *song) const;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,
diff --git a/src/db/UpnpDatabasePlugin.cxx b/src/db/UpnpDatabasePlugin.cxx
index dbf04f818..0768488a3 100644
--- a/src/db/UpnpDatabasePlugin.cxx
+++ b/src/db/UpnpDatabasePlugin.cxx
@@ -31,7 +31,7 @@
#include "DatabaseError.hxx"
#include "PlaylistVector.hxx"
#include "Directory.hxx"
-#include "Song.hxx"
+#include "LightSong.hxx"
#include "ConfigData.hxx"
#include "tag/TagBuilder.hxx"
#include "tag/TagTable.hxx"
@@ -49,6 +49,31 @@
static const char *const rootid = "0";
+class UpnpSong : public LightSong {
+ std::string uri2;
+
+ Tag tag2;
+
+public:
+ explicit UpnpSong(UPnPDirObject &&object)
+ :uri2(std::move(object.url)), tag2(std::move(object.tag)) {
+ directory = nullptr;
+ uri = uri2.c_str();
+ tag = &tag2;
+ mtime = 0;
+ start_ms = end_ms = 0;
+ }
+
+ UpnpSong(UPnPDirObject &&object, const char *_uri)
+ :uri2(_uri), tag2(std::move(object.tag)) {
+ directory = nullptr;
+ uri = uri2.c_str();
+ tag = &tag2;
+ mtime = 0;
+ start_ms = end_ms = 0;
+ }
+};
+
class UpnpDatabase : public Database {
LibUPnP *m_lib;
UPnPDeviceDirectory *m_superdir;
@@ -61,9 +86,9 @@ public:
virtual bool Open(Error &error) override;
virtual void Close() override;
- virtual Song *GetSong(const char *uri_utf8,
- Error &error) const override;
- virtual void ReturnSong(Song *song) const;
+ virtual const LightSong *GetSong(const char *uri_utf8,
+ Error &error) const override;
+ virtual void ReturnSong(const LightSong *song) const;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,
@@ -187,34 +212,20 @@ UpnpDatabase::Close()
}
void
-UpnpDatabase::ReturnSong(Song *song) const
-{
- assert(song != nullptr);
-
- song->Free();
-}
-
-// If uri is empty, we use the object's url instead. This happens
-// when the target of a Visit() is a song, which only happens when
-// "add"ing AFAIK. Visit() calls us with a null uri so that the url
-// appropriate for fetching is used instead.
-static Song *
-upnpItemToSong(UPnPDirObject &&dirent, const char *uri)
+UpnpDatabase::ReturnSong(const LightSong *_song) const
{
- if (*uri == 0)
- uri = dirent.url.c_str();
+ assert(_song != nullptr);
- Song *s = Song::NewFile(uri, nullptr);
- s->tag = std::move(dirent.tag);
- return s;
+ UpnpSong *song = (UpnpSong *)const_cast<LightSong *>(_song);
+ delete song;
}
// Get song info by path. We can receive either the id path, or the titles
// one
-Song *
+const LightSong *
UpnpDatabase::GetSong(const char *uri, Error &error) const
{
- Song *song = nullptr;
+ UpnpSong *song = nullptr;
auto vpath = stringToTokens(uri, "/", true);
if (vpath.size() >= 2) {
ContentDirectoryService server;
@@ -232,7 +243,8 @@ UpnpDatabase::GetSong(const char *uri, Error &error) const
error))
return nullptr;
}
- song = upnpItemToSong(std::move(dirent), "");
+
+ song = new UpnpSong(std::move(dirent));
}
if (song == nullptr)
error.Format(db_domain, DB_NOT_FOUND, "No such song: %s", uri);
@@ -357,12 +369,9 @@ visitSong(UPnPDirObject &&meta, const char *path,
{
if (!visit_song)
return true;
- Song *s = upnpItemToSong(std::move(meta), path);
- if (!selection.Match(*s))
- return true;
- bool success = visit_song(*s, error);
- s->Free();
- return success;
+
+ const UpnpSong song(std::move(meta), path);
+ return !selection.Match(song) || visit_song(song, error);
}
/**
diff --git a/src/playlist/AsxPlaylistPlugin.cxx b/src/playlist/AsxPlaylistPlugin.cxx
index 7c988a539..24eb26077 100644
--- a/src/playlist/AsxPlaylistPlugin.cxx
+++ b/src/playlist/AsxPlaylistPlugin.cxx
@@ -21,7 +21,6 @@
#include "AsxPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
-#include "Song.hxx"
#include "tag/TagBuilder.hxx"
#include "util/ASCII.hxx"
#include "util/Error.hxx"
diff --git a/src/playlist/RssPlaylistPlugin.cxx b/src/playlist/RssPlaylistPlugin.cxx
index 253ff7ad2..550a4630e 100644
--- a/src/playlist/RssPlaylistPlugin.cxx
+++ b/src/playlist/RssPlaylistPlugin.cxx
@@ -21,7 +21,6 @@
#include "RssPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
-#include "Song.hxx"
#include "tag/TagBuilder.hxx"
#include "util/ASCII.hxx"
#include "util/Error.hxx"
diff --git a/src/playlist/SoundCloudPlaylistPlugin.cxx b/src/playlist/SoundCloudPlaylistPlugin.cxx
index b0282b5da..bf68acd3b 100644
--- a/src/playlist/SoundCloudPlaylistPlugin.cxx
+++ b/src/playlist/SoundCloudPlaylistPlugin.cxx
@@ -23,7 +23,6 @@
#include "MemorySongEnumerator.hxx"
#include "ConfigData.hxx"
#include "InputStream.hxx"
-#include "Song.hxx"
#include "tag/TagBuilder.hxx"
#include "util/StringUtil.hxx"
#include "util/Error.hxx"
diff --git a/test/DumpDatabase.cxx b/test/DumpDatabase.cxx
index ade6b5345..60c20e4ae 100644
--- a/test/DumpDatabase.cxx
+++ b/test/DumpDatabase.cxx
@@ -23,7 +23,7 @@
#include "DatabaseSelection.hxx"
#include "DatabaseListener.hxx"
#include "Directory.hxx"
-#include "Song.hxx"
+#include "LightSong.hxx"
#include "PlaylistVector.hxx"
#include "ConfigGlobal.hxx"
#include "ConfigData.hxx"
@@ -65,11 +65,11 @@ DumpDirectory(const Directory &directory, Error &)
}
static bool
-DumpSong(Song &song, Error &)
+DumpSong(const LightSong &song, Error &)
{
cout << "S ";
- if (song.parent != nullptr && !song.parent->IsRoot())
- cout << song.parent->path << "/";
+ if (song.directory != nullptr)
+ cout << song.directory << "/";
cout << song.uri << endl;
return true;
}