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.
This commit is contained in:
parent
738d6f1040
commit
f5ae1ce00b
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
||||
struct directory detached_root;
|
||||
|
||||
Song *
|
||||
song_dup_detached(gcc_unused const Song *src)
|
||||
double
|
||||
LightSong::GetDuration() const
|
||||
{
|
||||
abort();
|
||||
if (end_ms > 0)
|
||||
return (end_ms - start_ms) / 1000.0;
|
||||
|
||||
if (tag->time <= 0)
|
||||
return 0;
|
||||
|
||||
return tag->time - start_ms / 1000.0;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "util/UriUtil.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "DetachedSong.hxx"
|
||||
#include "Song.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
|
|
@ -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;
|
||||
|
|
21
src/Song.cxx
21
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
UpnpDatabase::ReturnSong(const LightSong *_song) const
|
||||
{
|
||||
assert(song != nullptr);
|
||||
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)
|
||||
{
|
||||
if (*uri == 0)
|
||||
uri = dirent.url.c_str();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue