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/ReplayGainInfo.cxx src/ReplayGainInfo.hxx \
|
||||||
src/SignalHandlers.cxx src/SignalHandlers.hxx \
|
src/SignalHandlers.cxx src/SignalHandlers.hxx \
|
||||||
src/DetachedSong.cxx src/DetachedSong.hxx \
|
src/DetachedSong.cxx src/DetachedSong.hxx \
|
||||||
|
src/LightSong.cxx src/LightSong.hxx \
|
||||||
src/Song.cxx src/Song.hxx \
|
src/Song.cxx src/Song.hxx \
|
||||||
src/SongUpdate.cxx \
|
src/SongUpdate.cxx \
|
||||||
src/SongPrint.cxx src/SongPrint.hxx \
|
src/SongPrint.cxx src/SongPrint.hxx \
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "DatabaseHelpers.hxx"
|
#include "DatabaseHelpers.hxx"
|
||||||
#include "DatabasePlugin.hxx"
|
#include "DatabasePlugin.hxx"
|
||||||
#include "Song.hxx"
|
#include "LightSong.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -37,9 +37,9 @@ struct StringLess {
|
|||||||
typedef std::set<const char *, StringLess> StringSet;
|
typedef std::set<const char *, StringLess> StringSet;
|
||||||
|
|
||||||
static bool
|
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;
|
bool found = false;
|
||||||
for (unsigned i = 0; i < tag->num_items; ++i) {
|
for (unsigned i = 0; i < tag->num_items; ++i) {
|
||||||
@ -102,11 +102,11 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums,
|
StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums,
|
||||||
Song &song)
|
const LightSong &song)
|
||||||
{
|
{
|
||||||
++stats.song_count;
|
++stats.song_count;
|
||||||
|
|
||||||
StatsVisitTag(stats, artists, albums, song.tag);
|
StatsVisitTag(stats, artists, albums, *song.tag);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
AddSong(const char *playlist_path_utf8,
|
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),
|
return spl_append_song(playlist_path_utf8, map_song_detach(song),
|
||||||
error);
|
error);
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
struct config_param;
|
struct config_param;
|
||||||
struct DatabaseSelection;
|
struct DatabaseSelection;
|
||||||
struct db_visitor;
|
struct db_visitor;
|
||||||
struct Song;
|
struct LightSong;
|
||||||
class Error;
|
class Error;
|
||||||
class EventLoop;
|
class EventLoop;
|
||||||
class DatabaseListener;
|
class DatabaseListener;
|
||||||
@ -94,14 +94,14 @@ public:
|
|||||||
* @param uri_utf8 the URI of the song within the music
|
* @param uri_utf8 the URI of the song within the music
|
||||||
* directory (UTF-8)
|
* directory (UTF-8)
|
||||||
*/
|
*/
|
||||||
virtual Song *GetSong(const char *uri_utf8,
|
virtual const LightSong *GetSong(const char *uri_utf8,
|
||||||
Error &error) const = 0;
|
Error &error) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark the song object as "unused". Call this on objects
|
* Mark the song object as "unused". Call this on objects
|
||||||
* returned by GetSong().
|
* returned by GetSong().
|
||||||
*/
|
*/
|
||||||
virtual void ReturnSong(Song *song) const = 0;
|
virtual void ReturnSong(const LightSong *song) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit the selected entities.
|
* Visit the selected entities.
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
#include "Client.hxx"
|
#include "Client.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "Song.hxx"
|
#include "LightSong.hxx"
|
||||||
#include "DatabaseGlue.hxx"
|
#include "DatabaseGlue.hxx"
|
||||||
#include "DatabasePlugin.hxx"
|
#include "DatabasePlugin.hxx"
|
||||||
|
|
||||||
@ -52,6 +52,17 @@ PrintDirectoryFull(Client &client, const Directory &directory)
|
|||||||
return true;
|
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
|
static void
|
||||||
print_playlist_in_directory(Client &client,
|
print_playlist_in_directory(Client &client,
|
||||||
@ -66,25 +77,25 @@ print_playlist_in_directory(Client &client,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
PrintSongBrief(Client &client, const Song &song)
|
PrintSongBrief(Client &client, const LightSong &song)
|
||||||
{
|
{
|
||||||
song_print_uri(client, song);
|
song_print_uri(client, song);
|
||||||
|
|
||||||
if (song.tag.has_playlist)
|
if (song.tag->has_playlist)
|
||||||
/* this song file has an embedded CUE sheet */
|
/* 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
PrintSongFull(Client &client, const Song &song)
|
PrintSongFull(Client &client, const LightSong &song)
|
||||||
{
|
{
|
||||||
song_print_info(client, song);
|
song_print_info(client, song);
|
||||||
|
|
||||||
if (song.tag.has_playlist)
|
if (song.tag->has_playlist)
|
||||||
/* this song file has an embedded CUE sheet */
|
/* 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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -146,7 +157,7 @@ static void printSearchStats(Client &client, SearchStats *stats)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
stats_visitor_song(SearchStats &stats, Song &song)
|
stats_visitor_song(SearchStats &stats, const LightSong &song)
|
||||||
{
|
{
|
||||||
stats.numberOfSongs++;
|
stats.numberOfSongs++;
|
||||||
stats.playTime += song.GetDuration();
|
stats.playTime += song.GetDuration();
|
||||||
@ -195,7 +206,7 @@ printInfoForAllIn(Client &client, const char *uri_utf8,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
PrintSongURIVisitor(Client &client, Song &song)
|
PrintSongURIVisitor(Client &client, const LightSong &song)
|
||||||
{
|
{
|
||||||
song_print_uri(client, song);
|
song_print_uri(client, song);
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
AddToQueue(Partition &partition, const Song &song, Error &error)
|
AddToQueue(Partition &partition, const LightSong &song, Error &error)
|
||||||
{
|
{
|
||||||
PlaylistResult result =
|
PlaylistResult result =
|
||||||
partition.playlist.AppendSong(partition.pc,
|
partition.playlist.AppendSong(partition.pc,
|
||||||
|
@ -31,7 +31,7 @@ DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DatabaseSelection::Match(const Song &song) const
|
DatabaseSelection::Match(const LightSong &song) const
|
||||||
{
|
{
|
||||||
return filter == nullptr || filter->Match(song);
|
return filter == nullptr || filter->Match(song);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class SongFilter;
|
class SongFilter;
|
||||||
struct Song;
|
struct LightSong;
|
||||||
|
|
||||||
struct DatabaseSelection {
|
struct DatabaseSelection {
|
||||||
/**
|
/**
|
||||||
@ -45,7 +45,7 @@ struct DatabaseSelection {
|
|||||||
const SongFilter *_filter=nullptr);
|
const SongFilter *_filter=nullptr);
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const Song &song) const;
|
bool Match(const LightSong &song) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,7 +31,7 @@ DatabaseDetachSong(const char *uri, Error &error)
|
|||||||
if (db == nullptr)
|
if (db == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Song *tmp = db->GetSong(uri, error);
|
const LightSong *tmp = db->GetSong(uri, error);
|
||||||
if (tmp == nullptr)
|
if (tmp == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -23,12 +23,12 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
struct Directory;
|
struct Directory;
|
||||||
struct Song;
|
struct LightSong;
|
||||||
struct PlaylistInfo;
|
struct PlaylistInfo;
|
||||||
class Error;
|
class Error;
|
||||||
|
|
||||||
typedef std::function<bool(const Directory &, Error &)> VisitDirectory;
|
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 &,
|
typedef std::function<bool(const PlaylistInfo &, const Directory &,
|
||||||
Error &)> VisitPlaylist;
|
Error &)> VisitPlaylist;
|
||||||
|
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "Song.hxx"
|
#include "LightSong.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriUtil.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
|
|
||||||
DetachedSong::DetachedSong(const Song &other)
|
DetachedSong::DetachedSong(const LightSong &other)
|
||||||
:uri(other.GetURI().c_str()),
|
:uri(other.GetURI().c_str()),
|
||||||
tag(other.tag),
|
tag(*other.tag),
|
||||||
mtime(other.mtime),
|
mtime(other.mtime),
|
||||||
start_ms(other.start_ms), end_ms(other.end_ms) {}
|
start_ms(other.start_ms), end_ms(other.end_ms) {}
|
||||||
|
|
||||||
|
@ -29,10 +29,10 @@
|
|||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
struct Song;
|
struct LightSong;
|
||||||
|
|
||||||
class DetachedSong {
|
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
|
* An UTF-8-encoded URI referring to the song file. This can
|
||||||
@ -62,7 +62,7 @@ class DetachedSong {
|
|||||||
*/
|
*/
|
||||||
unsigned end_ms;
|
unsigned end_ms;
|
||||||
|
|
||||||
explicit DetachedSong(const Song &other);
|
explicit DetachedSong(const LightSong &other);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DetachedSong(const DetachedSong &other)
|
explicit DetachedSong(const DetachedSong &other)
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "DatabaseLock.hxx"
|
#include "DatabaseLock.hxx"
|
||||||
#include "SongSort.hxx"
|
#include "SongSort.hxx"
|
||||||
#include "Song.hxx"
|
#include "Song.hxx"
|
||||||
|
#include "LightSong.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
#include "util/Alloc.hxx"
|
#include "util/Alloc.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
@ -251,6 +252,20 @@ Directory::Sort()
|
|||||||
child->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
|
bool
|
||||||
Directory::Walk(bool recursive, const SongFilter *filter,
|
Directory::Walk(bool recursive, const SongFilter *filter,
|
||||||
VisitDirectory visit_directory, VisitSong visit_song,
|
VisitDirectory visit_directory, VisitSong visit_song,
|
||||||
@ -261,11 +276,13 @@ Directory::Walk(bool recursive, const SongFilter *filter,
|
|||||||
|
|
||||||
if (visit_song) {
|
if (visit_song) {
|
||||||
Song *song;
|
Song *song;
|
||||||
directory_for_each_song(song, *this)
|
directory_for_each_song(song, *this) {
|
||||||
if ((filter == nullptr || filter->Match(*song)) &&
|
const LightSong song2 = ExportSong(*song);
|
||||||
!visit_song(*song, error))
|
if ((filter == nullptr || filter->Match(song2)) &&
|
||||||
|
!visit_song(song2, error))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (visit_playlist) {
|
if (visit_playlist) {
|
||||||
for (const PlaylistInfo &p : playlists)
|
for (const PlaylistInfo &p : playlists)
|
||||||
|
@ -17,17 +17,17 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "LightSong.hxx"
|
||||||
#include "Song.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "directory.h"
|
|
||||||
#include "Compiler.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
double
|
||||||
|
LightSong::GetDuration() const
|
||||||
struct directory detached_root;
|
|
||||||
|
|
||||||
Song *
|
|
||||||
song_dup_detached(gcc_unused const Song *src)
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
82
src/LightSong.hxx
Normal file
82
src/LightSong.hxx
Normal file
@ -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
|
DetachedSong
|
||||||
map_song_detach(const Song &song)
|
map_song_detach(const LightSong &song)
|
||||||
{
|
{
|
||||||
return DetachedSong(song);
|
return DetachedSong(song);
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
class AllocatedPath;
|
class AllocatedPath;
|
||||||
struct Directory;
|
struct Directory;
|
||||||
struct Song;
|
struct Song;
|
||||||
|
struct LightSong;
|
||||||
class DetachedSong;
|
class DetachedSong;
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -112,7 +113,7 @@ map_directory_child_fs(const Directory &directory, const char *name);
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
DetachedSong
|
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
|
* Determines the file system path of a song. This must not be a
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
#include "PlayerControl.hxx"
|
#include "PlayerControl.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriUtil.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
#include "Song.hxx"
|
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
#include "Idle.hxx"
|
#include "Idle.hxx"
|
||||||
|
@ -30,12 +30,14 @@
|
|||||||
#include "DatabasePlugin.hxx"
|
#include "DatabasePlugin.hxx"
|
||||||
#include "Client.hxx"
|
#include "Client.hxx"
|
||||||
#include "InputStream.hxx"
|
#include "InputStream.hxx"
|
||||||
#include "Song.hxx"
|
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
|
|
||||||
|
#define SONG_FILE "file: "
|
||||||
|
#define SONG_TIME "Time: "
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_print_uris(Client &client, const playlist &playlist)
|
playlist_print_uris(Client &client, const playlist &playlist)
|
||||||
{
|
{
|
||||||
@ -118,7 +120,7 @@ PrintSongDetails(Client &client, const char *uri_utf8)
|
|||||||
if (db == nullptr)
|
if (db == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Song *song = db->GetSong(uri_utf8, IgnoreError());
|
auto *song = db->GetSong(uri_utf8, IgnoreError());
|
||||||
if (song == nullptr)
|
if (song == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include "PlaylistFile.hxx"
|
#include "PlaylistFile.hxx"
|
||||||
#include "PlaylistError.hxx"
|
#include "PlaylistError.hxx"
|
||||||
#include "Playlist.hxx"
|
#include "Playlist.hxx"
|
||||||
#include "Song.hxx"
|
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
#include "Idle.hxx"
|
#include "Idle.hxx"
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
#include "util/UriUtil.hxx"
|
#include "util/UriUtil.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "Song.hxx"
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#include "Playlist.hxx"
|
#include "Playlist.hxx"
|
||||||
#include "DatabaseGlue.hxx"
|
#include "DatabaseGlue.hxx"
|
||||||
#include "DatabasePlugin.hxx"
|
#include "DatabasePlugin.hxx"
|
||||||
#include "Song.hxx"
|
#include "LightSong.hxx"
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "Idle.hxx"
|
#include "Idle.hxx"
|
||||||
@ -35,7 +35,7 @@ UpdatePlaylistSong(const Database &db, DetachedSong &song)
|
|||||||
from the Database */
|
from the Database */
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Song *original = db.GetSong(song.GetURI(), IgnoreError());
|
const LightSong *original = db.GetSong(song.GetURI(), IgnoreError());
|
||||||
if (original == nullptr)
|
if (original == nullptr)
|
||||||
/* not found - shouldn't happen, because the update
|
/* not found - shouldn't happen, because the update
|
||||||
thread should ensure that all stale Song instances
|
thread should ensure that all stale Song instances
|
||||||
@ -49,7 +49,7 @@ UpdatePlaylistSong(const Database &db, DetachedSong &song)
|
|||||||
}
|
}
|
||||||
|
|
||||||
song.SetLastModified(original->mtime);
|
song.SetLastModified(original->mtime);
|
||||||
song.SetTag(original->tag);
|
song.SetTag(*original->tag);
|
||||||
|
|
||||||
db.ReturnSong(original);
|
db.ReturnSong(original);
|
||||||
return true;
|
return true;
|
||||||
|
21
src/Song.cxx
21
src/Song.cxx
@ -23,6 +23,7 @@
|
|||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "util/VarSize.hxx"
|
#include "util/VarSize.hxx"
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
|
#include "LightSong.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -94,14 +95,16 @@ Song::GetURI() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
LightSong
|
||||||
Song::GetDuration() const
|
Song::Export() const
|
||||||
{
|
{
|
||||||
if (end_ms > 0)
|
LightSong dest;
|
||||||
return (end_ms - start_ms) / 1000.0;
|
dest.directory = parent->IsRoot()
|
||||||
|
? nullptr : parent->GetPath();
|
||||||
if (tag.time <= 0)
|
dest.uri = uri;
|
||||||
return 0;
|
dest.tag = &tag;
|
||||||
|
dest.mtime = mtime;
|
||||||
return tag.time - start_ms / 1000.0;
|
dest.start_ms = start_ms;
|
||||||
|
dest.end_ms = end_ms;
|
||||||
|
return dest;
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#define SONG_FILE "file: "
|
struct LightSong;
|
||||||
#define SONG_TIME "Time: "
|
|
||||||
|
|
||||||
struct Directory;
|
struct Directory;
|
||||||
class DetachedSong;
|
class DetachedSong;
|
||||||
|
|
||||||
@ -112,7 +110,7 @@ struct Song {
|
|||||||
std::string GetURI() const;
|
std::string GetURI() const;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
double GetDuration() const;
|
LightSong Export() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "SongFilter.hxx"
|
#include "SongFilter.hxx"
|
||||||
#include "Song.hxx"
|
#include "Song.hxx"
|
||||||
|
#include "LightSong.hxx"
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
@ -137,7 +138,19 @@ SongFilter::Item::Match(const Tag &_tag) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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) {
|
if (tag == LOCATE_TAG_BASE_TYPE) {
|
||||||
const auto uri = song.GetURI();
|
const auto uri = song.GetURI();
|
||||||
@ -149,19 +162,7 @@ SongFilter::Item::Match(const Song &song) const
|
|||||||
return StringMatch(uri.c_str());
|
return StringMatch(uri.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Match(song.tag);
|
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SongFilter::SongFilter(unsigned tag, const char *value, bool fold_case)
|
SongFilter::SongFilter(unsigned tag, const char *value, bool fold_case)
|
||||||
@ -207,7 +208,7 @@ SongFilter::Parse(unsigned argc, char *argv[], bool fold_case)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Match(const Song &song) const
|
SongFilter::Match(const DetachedSong &song) const
|
||||||
{
|
{
|
||||||
for (const auto &i : items)
|
for (const auto &i : items)
|
||||||
if (!i.Match(song))
|
if (!i.Match(song))
|
||||||
@ -217,7 +218,7 @@ SongFilter::Match(const Song &song) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Match(const DetachedSong &song) const
|
SongFilter::Match(const LightSong &song) const
|
||||||
{
|
{
|
||||||
for (const auto &i : items)
|
for (const auto &i : items)
|
||||||
if (!i.Match(song))
|
if (!i.Match(song))
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
struct Tag;
|
struct Tag;
|
||||||
struct TagItem;
|
struct TagItem;
|
||||||
struct Song;
|
struct Song;
|
||||||
|
struct LightSong;
|
||||||
class DetachedSong;
|
class DetachedSong;
|
||||||
|
|
||||||
class SongFilter {
|
class SongFilter {
|
||||||
@ -80,10 +81,10 @@ public:
|
|||||||
bool Match(const Tag &tag) const;
|
bool Match(const Tag &tag) const;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const Song &song) const;
|
bool Match(const DetachedSong &song) const;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const DetachedSong &song) const;
|
bool Match(const LightSong &song) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -107,10 +108,10 @@ public:
|
|||||||
bool Match(const Tag &tag) const;
|
bool Match(const Tag &tag) const;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const Song &song) const;
|
bool Match(const DetachedSong &song) const;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const DetachedSong &song) const;
|
bool Match(const LightSong &song) const;
|
||||||
|
|
||||||
const std::list<Item> &GetItems() const {
|
const std::list<Item> &GetItems() const {
|
||||||
return items;
|
return items;
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "SongPrint.hxx"
|
#include "SongPrint.hxx"
|
||||||
#include "Song.hxx"
|
#include "LightSong.hxx"
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
#include "TimePrint.hxx"
|
#include "TimePrint.hxx"
|
||||||
@ -28,6 +28,8 @@
|
|||||||
#include "Client.hxx"
|
#include "Client.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriUtil.hxx"
|
||||||
|
|
||||||
|
#define SONG_FILE "file: "
|
||||||
|
|
||||||
static void
|
static void
|
||||||
song_print_uri(Client &client, const char *uri)
|
song_print_uri(Client &client, const char *uri)
|
||||||
{
|
{
|
||||||
@ -40,11 +42,11 @@ song_print_uri(Client &client, const char *uri)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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,
|
client_printf(client, "%s%s/%s\n", SONG_FILE,
|
||||||
song.parent->GetPath(), song.uri);
|
song.directory, song.uri);
|
||||||
} else
|
} else
|
||||||
song_print_uri(client, song.uri);
|
song_print_uri(client, song.uri);
|
||||||
}
|
}
|
||||||
@ -56,7 +58,7 @@ song_print_uri(Client &client, const DetachedSong &song)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
song_print_info(Client &client, const Song &song)
|
song_print_info(Client &client, const LightSong &song)
|
||||||
{
|
{
|
||||||
song_print_uri(client, song);
|
song_print_uri(client, song);
|
||||||
|
|
||||||
@ -74,7 +76,7 @@ song_print_info(Client &client, const Song &song)
|
|||||||
if (song.mtime > 0)
|
if (song.mtime > 0)
|
||||||
time_print(client, "Last-Modified", song.mtime);
|
time_print(client, "Last-Modified", song.mtime);
|
||||||
|
|
||||||
tag_print(client, song.tag);
|
tag_print(client, *song.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#ifndef MPD_SONG_PRINT_HXX
|
#ifndef MPD_SONG_PRINT_HXX
|
||||||
#define MPD_SONG_PRINT_HXX
|
#define MPD_SONG_PRINT_HXX
|
||||||
|
|
||||||
struct Song;
|
struct LightSong;
|
||||||
class DetachedSong;
|
class DetachedSong;
|
||||||
class Client;
|
class Client;
|
||||||
|
|
||||||
@ -28,10 +28,10 @@ void
|
|||||||
song_print_info(Client &client, const DetachedSong &song);
|
song_print_info(Client &client, const DetachedSong &song);
|
||||||
|
|
||||||
void
|
void
|
||||||
song_print_info(Client &client, const Song &song);
|
song_print_info(Client &client, const LightSong &song);
|
||||||
|
|
||||||
void
|
void
|
||||||
song_print_uri(Client &client, const Song &song);
|
song_print_uri(Client &client, const LightSong &song);
|
||||||
|
|
||||||
void
|
void
|
||||||
song_print_uri(Client &client, const DetachedSong &song);
|
song_print_uri(Client &client, const DetachedSong &song);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "SongSticker.hxx"
|
#include "SongSticker.hxx"
|
||||||
#include "StickerDatabase.hxx"
|
#include "StickerDatabase.hxx"
|
||||||
|
#include "LightSong.hxx"
|
||||||
#include "Song.hxx"
|
#include "Song.hxx"
|
||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
|
|
||||||
@ -29,14 +30,14 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
std::string
|
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();
|
const auto uri = song.GetURI();
|
||||||
return sticker_load_value("song", uri.c_str(), name);
|
return sticker_load_value("song", uri.c_str(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sticker_song_set_value(const Song &song,
|
sticker_song_set_value(const LightSong &song,
|
||||||
const char *name, const char *value)
|
const char *name, const char *value)
|
||||||
{
|
{
|
||||||
const auto uri = song.GetURI();
|
const auto uri = song.GetURI();
|
||||||
@ -44,21 +45,21 @@ sticker_song_set_value(const Song &song,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sticker_song_delete(const Song &song)
|
sticker_song_delete(const LightSong &song)
|
||||||
{
|
{
|
||||||
const auto uri = song.GetURI();
|
const auto uri = song.GetURI();
|
||||||
return sticker_delete("song", uri.c_str());
|
return sticker_delete("song", uri.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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();
|
const auto uri = song.GetURI();
|
||||||
return sticker_delete_value("song", uri.c_str(), name);
|
return sticker_delete_value("song", uri.c_str(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sticker *
|
struct sticker *
|
||||||
sticker_song_get(const Song &song)
|
sticker_song_get(const LightSong &song)
|
||||||
{
|
{
|
||||||
const auto uri = song.GetURI();
|
const auto uri = song.GetURI();
|
||||||
return sticker_load("song", uri.c_str());
|
return sticker_load("song", uri.c_str());
|
||||||
@ -69,7 +70,7 @@ struct sticker_song_find_data {
|
|||||||
const char *base_uri;
|
const char *base_uri;
|
||||||
size_t base_uri_length;
|
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);
|
||||||
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);
|
Song *song = data->directory->LookupSong(uri + data->base_uri_length);
|
||||||
if (song != nullptr)
|
if (song != nullptr)
|
||||||
data->func(*song, value, data->user_data);
|
data->func(song->Export(), value, data->user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sticker_song_find(Directory &directory, const char *name,
|
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),
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct Song;
|
struct LightSong;
|
||||||
struct Directory;
|
struct Directory;
|
||||||
struct sticker;
|
struct sticker;
|
||||||
|
|
||||||
@ -34,28 +34,28 @@ struct sticker;
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
std::string
|
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
|
* Sets a sticker value in the specified song. Overwrites existing
|
||||||
* values.
|
* values.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
sticker_song_set_value(const Song &song,
|
sticker_song_set_value(const LightSong &song,
|
||||||
const char *name, const char *value);
|
const char *name, const char *value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a sticker from the database. All values are deleted.
|
* Deletes a sticker from the database. All values are deleted.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
sticker_song_delete(const Song &song);
|
sticker_song_delete(const LightSong &song);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a sticker value. Does nothing if the sticker did not
|
* Deletes a sticker value. Does nothing if the sticker did not
|
||||||
* exist.
|
* exist.
|
||||||
*/
|
*/
|
||||||
bool
|
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.
|
* 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
|
* @return a sticker object, or NULL on error or if there is no sticker
|
||||||
*/
|
*/
|
||||||
sticker *
|
sticker *
|
||||||
sticker_song_get(const Song &song);
|
sticker_song_get(const LightSong &song);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds stickers with the specified name below the specified
|
* Finds stickers with the specified name below the specified
|
||||||
@ -79,7 +79,7 @@ sticker_song_get(const Song &song);
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
sticker_song_find(Directory &directory, const char *name,
|
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),
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
|
@ -21,9 +21,10 @@
|
|||||||
#include "TagPrint.hxx"
|
#include "TagPrint.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "tag/TagSettings.h"
|
#include "tag/TagSettings.h"
|
||||||
#include "Song.hxx"
|
|
||||||
#include "Client.hxx"
|
#include "Client.hxx"
|
||||||
|
|
||||||
|
#define SONG_TIME "Time: "
|
||||||
|
|
||||||
void tag_print_types(Client &client)
|
void tag_print_types(Client &client)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "TagSave.hxx"
|
#include "TagSave.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "Song.hxx"
|
|
||||||
|
#define SONG_TIME "Time: "
|
||||||
|
|
||||||
void
|
void
|
||||||
tag_save(FILE *file, const Tag &tag)
|
tag_save(FILE *file, const Tag &tag)
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "Song.hxx"
|
#include "Song.hxx"
|
||||||
|
#include "LightSong.hxx"
|
||||||
#include "Main.hxx"
|
#include "Main.hxx"
|
||||||
#include "Instance.hxx"
|
#include "Instance.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
@ -57,7 +58,7 @@ song_remove_event(void)
|
|||||||
#ifdef ENABLE_SQLITE
|
#ifdef ENABLE_SQLITE
|
||||||
/* if the song has a sticker, remove it */
|
/* if the song has a sticker, remove it */
|
||||||
if (sticker_enabled())
|
if (sticker_enabled())
|
||||||
sticker_song_delete(*removed_song);
|
sticker_song_delete(removed_song->Export());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,7 @@ struct sticker_song_find_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
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)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct sticker_song_find_data *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 */
|
/* get song song_id key */
|
||||||
if (argc == 5 && strcmp(argv[1], "get") == 0) {
|
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)
|
if (song == nullptr)
|
||||||
return print_error(client, error);
|
return print_error(client, error);
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ handle_sticker_song(Client &client, int argc, char *argv[])
|
|||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
/* list song song_id */
|
/* list song song_id */
|
||||||
} else if (argc == 4 && strcmp(argv[1], "list") == 0) {
|
} 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)
|
if (song == nullptr)
|
||||||
return print_error(client, error);
|
return print_error(client, error);
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ handle_sticker_song(Client &client, int argc, char *argv[])
|
|||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
/* set song song_id id key */
|
/* set song song_id id key */
|
||||||
} else if (argc == 6 && strcmp(argv[1], "set") == 0) {
|
} 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)
|
if (song == nullptr)
|
||||||
return print_error(client, error);
|
return print_error(client, error);
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ handle_sticker_song(Client &client, int argc, char *argv[])
|
|||||||
/* delete song song_id [key] */
|
/* delete song song_id [key] */
|
||||||
} else if ((argc == 4 || argc == 5) &&
|
} else if ((argc == 4 || argc == 5) &&
|
||||||
strcmp(argv[1], "delete") == 0) {
|
strcmp(argv[1], "delete") == 0) {
|
||||||
Song *song = db->GetSong(argv[3], error);
|
const LightSong *song = db->GetSong(argv[3], error);
|
||||||
if (song == nullptr)
|
if (song == nullptr)
|
||||||
return print_error(client, error);
|
return print_error(client, error);
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ LazyDatabase::Close()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Song *
|
const LightSong *
|
||||||
LazyDatabase::GetSong(const char *uri, Error &error) const
|
LazyDatabase::GetSong(const char *uri, Error &error) const
|
||||||
{
|
{
|
||||||
return EnsureOpen(error)
|
return EnsureOpen(error)
|
||||||
@ -60,7 +60,7 @@ LazyDatabase::GetSong(const char *uri, Error &error) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LazyDatabase::ReturnSong(Song *song) const
|
LazyDatabase::ReturnSong(const LightSong *song) const
|
||||||
{
|
{
|
||||||
assert(open);
|
assert(open);
|
||||||
|
|
||||||
|
@ -41,9 +41,9 @@ public:
|
|||||||
|
|
||||||
virtual void Close() override;
|
virtual void Close() override;
|
||||||
|
|
||||||
virtual Song *GetSong(const char *uri_utf8,
|
virtual const LightSong *GetSong(const char *uri_utf8,
|
||||||
Error &error) const override;
|
Error &error) const override;
|
||||||
virtual void ReturnSong(Song *song) const;
|
virtual void ReturnSong(const LightSong *song) const;
|
||||||
|
|
||||||
virtual bool Visit(const DatabaseSelection &selection,
|
virtual bool Visit(const DatabaseSelection &selection,
|
||||||
VisitDirectory visit_directory,
|
VisitDirectory visit_directory,
|
||||||
|
@ -24,11 +24,12 @@
|
|||||||
#include "DatabaseSelection.hxx"
|
#include "DatabaseSelection.hxx"
|
||||||
#include "DatabaseError.hxx"
|
#include "DatabaseError.hxx"
|
||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
#include "Song.hxx"
|
#include "LightSong.hxx"
|
||||||
#include "SongFilter.hxx"
|
#include "SongFilter.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
#include "ConfigData.hxx"
|
#include "ConfigData.hxx"
|
||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
|
#include "tag/Tag.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "protocol/Ack.hxx"
|
#include "protocol/Ack.hxx"
|
||||||
@ -44,6 +45,25 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#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 {
|
class ProxyDatabase final : public Database, SocketMonitor, IdleMonitor {
|
||||||
DatabaseListener &listener;
|
DatabaseListener &listener;
|
||||||
|
|
||||||
@ -79,9 +99,9 @@ public:
|
|||||||
|
|
||||||
virtual bool Open(Error &error) override;
|
virtual bool Open(Error &error) override;
|
||||||
virtual void Close() override;
|
virtual void Close() override;
|
||||||
virtual Song *GetSong(const char *uri_utf8,
|
virtual const LightSong *GetSong(const char *uri_utf8,
|
||||||
Error &error) const override;
|
Error &error) const override;
|
||||||
virtual void ReturnSong(Song *song) const;
|
virtual void ReturnSong(const LightSong *song) const;
|
||||||
|
|
||||||
virtual bool Visit(const DatabaseSelection &selection,
|
virtual bool Visit(const DatabaseSelection &selection,
|
||||||
VisitDirectory visit_directory,
|
VisitDirectory visit_directory,
|
||||||
@ -144,6 +164,38 @@ static constexpr struct {
|
|||||||
{ TAG_NUM_OF_ITEM_TYPES, MPD_TAG_COUNT }
|
{ 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
|
gcc_const
|
||||||
static enum mpd_tag_type
|
static enum mpd_tag_type
|
||||||
Convert(TagType tag_type)
|
Convert(TagType tag_type)
|
||||||
@ -424,10 +476,7 @@ ProxyDatabase::OnIdle()
|
|||||||
SocketMonitor::ScheduleRead();
|
SocketMonitor::ScheduleRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Song *
|
const LightSong *
|
||||||
Convert(const struct mpd_song *song);
|
|
||||||
|
|
||||||
Song *
|
|
||||||
ProxyDatabase::GetSong(const char *uri, Error &error) const
|
ProxyDatabase::GetSong(const char *uri, Error &error) const
|
||||||
{
|
{
|
||||||
// TODO: eliminate the const_cast
|
// TODO: eliminate the const_cast
|
||||||
@ -452,18 +501,17 @@ ProxyDatabase::GetSong(const char *uri, Error &error) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Song *song2 = Convert(song);
|
return new AllocatedProxySong(song);
|
||||||
mpd_song_free(song);
|
|
||||||
return song2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ProxyDatabase::ReturnSong(Song *song) const
|
ProxyDatabase::ReturnSong(const LightSong *_song) const
|
||||||
{
|
{
|
||||||
assert(song != nullptr);
|
assert(_song != nullptr);
|
||||||
assert(song->parent == nullptr);
|
|
||||||
|
|
||||||
song->Free();
|
AllocatedProxySong *song = (AllocatedProxySong *)
|
||||||
|
const_cast<LightSong *>(_song);
|
||||||
|
delete song;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -493,60 +541,23 @@ Visit(struct mpd_connection *connection, Directory &root,
|
|||||||
return true;
|
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
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
Match(const SongFilter *filter, const Song &song)
|
Match(const SongFilter *filter, const LightSong &song)
|
||||||
{
|
{
|
||||||
return filter == nullptr || filter->Match(song);
|
return filter == nullptr || filter->Match(song);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
Visit(const SongFilter *filter,
|
Visit(const SongFilter *filter,
|
||||||
const struct mpd_song *song,
|
const mpd_song *_song,
|
||||||
VisitSong visit_song, Error &error)
|
VisitSong visit_song, Error &error)
|
||||||
{
|
{
|
||||||
if (!visit_song)
|
if (!visit_song)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Song *s = Convert(song);
|
const ProxySong song(_song);
|
||||||
bool success = !Match(filter, *s) || visit_song(*s, error);
|
return !Match(filter, song) || visit_song(song, error);
|
||||||
s->Free();
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -664,12 +675,10 @@ SearchSongs(struct mpd_connection *connection,
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
struct mpd_song *song;
|
struct mpd_song *song;
|
||||||
while (result && (song = mpd_recv_song(connection)) != nullptr) {
|
while (result && (song = mpd_recv_song(connection)) != nullptr) {
|
||||||
Song *song2 = Convert(song);
|
AllocatedProxySong song2(song);
|
||||||
mpd_song_free(song);
|
|
||||||
|
|
||||||
result = !Match(selection.filter, *song2) ||
|
result = !Match(selection.filter, song2) ||
|
||||||
visit_song(*song2, error);
|
visit_song(song2, error);
|
||||||
song2->Free();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mpd_response_finish(connection);
|
mpd_response_finish(connection);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "DatabaseSelection.hxx"
|
#include "DatabaseSelection.hxx"
|
||||||
#include "DatabaseHelpers.hxx"
|
#include "DatabaseHelpers.hxx"
|
||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
|
#include "Song.hxx"
|
||||||
#include "SongFilter.hxx"
|
#include "SongFilter.hxx"
|
||||||
#include "DatabaseSave.hxx"
|
#include "DatabaseSave.hxx"
|
||||||
#include "DatabaseLock.hxx"
|
#include "DatabaseLock.hxx"
|
||||||
@ -193,29 +194,34 @@ SimpleDatabase::Close()
|
|||||||
delete root;
|
delete root;
|
||||||
}
|
}
|
||||||
|
|
||||||
Song *
|
const LightSong *
|
||||||
SimpleDatabase::GetSong(const char *uri, Error &error) const
|
SimpleDatabase::GetSong(const char *uri, Error &error) const
|
||||||
{
|
{
|
||||||
assert(root != nullptr);
|
assert(root != nullptr);
|
||||||
|
assert(borrowed_song_count == 0);
|
||||||
|
|
||||||
db_lock();
|
db_lock();
|
||||||
Song *song = root->LookupSong(uri);
|
const Song *song = root->LookupSong(uri);
|
||||||
db_unlock();
|
db_unlock();
|
||||||
if (song == nullptr)
|
if (song == nullptr) {
|
||||||
error.Format(db_domain, DB_NOT_FOUND,
|
error.Format(db_domain, DB_NOT_FOUND,
|
||||||
"No such song: %s", uri);
|
"No such song: %s", uri);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
light_song = song->Export();
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
else
|
|
||||||
++borrowed_song_count;
|
++borrowed_song_count;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return song;
|
return &light_song;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
#ifndef NDEBUG
|
||||||
assert(borrowed_song_count > 0);
|
assert(borrowed_song_count > 0);
|
||||||
@ -247,9 +253,11 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
|
|||||||
if (directory == nullptr) {
|
if (directory == nullptr) {
|
||||||
if (visit_song) {
|
if (visit_song) {
|
||||||
Song *song = root->LookupSong(selection.uri.c_str());
|
Song *song = root->LookupSong(selection.uri.c_str());
|
||||||
if (song != nullptr)
|
if (song != nullptr) {
|
||||||
return !selection.Match(*song) ||
|
const LightSong song2 = song->Export();
|
||||||
visit_song(*song, error);
|
return !selection.Match(song2) ||
|
||||||
|
visit_song(song2, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error.Set(db_domain, DB_NOT_FOUND, "No such directory");
|
error.Set(db_domain, DB_NOT_FOUND, "No such directory");
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "DatabasePlugin.hxx"
|
#include "DatabasePlugin.hxx"
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
|
#include "LightSong.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -36,6 +37,11 @@ class SimpleDatabase : public Database {
|
|||||||
|
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffer for GetSong().
|
||||||
|
*/
|
||||||
|
mutable LightSong light_song;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
mutable unsigned borrowed_song_count;
|
mutable unsigned borrowed_song_count;
|
||||||
#endif
|
#endif
|
||||||
@ -60,9 +66,9 @@ public:
|
|||||||
virtual bool Open(Error &error) override;
|
virtual bool Open(Error &error) override;
|
||||||
virtual void Close() override;
|
virtual void Close() override;
|
||||||
|
|
||||||
virtual Song *GetSong(const char *uri_utf8,
|
virtual const LightSong *GetSong(const char *uri_utf8,
|
||||||
Error &error) const override;
|
Error &error) const override;
|
||||||
virtual void ReturnSong(Song *song) const;
|
virtual void ReturnSong(const LightSong *song) const;
|
||||||
|
|
||||||
virtual bool Visit(const DatabaseSelection &selection,
|
virtual bool Visit(const DatabaseSelection &selection,
|
||||||
VisitDirectory visit_directory,
|
VisitDirectory visit_directory,
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#include "DatabaseError.hxx"
|
#include "DatabaseError.hxx"
|
||||||
#include "PlaylistVector.hxx"
|
#include "PlaylistVector.hxx"
|
||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
#include "Song.hxx"
|
#include "LightSong.hxx"
|
||||||
#include "ConfigData.hxx"
|
#include "ConfigData.hxx"
|
||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
#include "tag/TagTable.hxx"
|
#include "tag/TagTable.hxx"
|
||||||
@ -49,6 +49,31 @@
|
|||||||
|
|
||||||
static const char *const rootid = "0";
|
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 {
|
class UpnpDatabase : public Database {
|
||||||
LibUPnP *m_lib;
|
LibUPnP *m_lib;
|
||||||
UPnPDeviceDirectory *m_superdir;
|
UPnPDeviceDirectory *m_superdir;
|
||||||
@ -61,9 +86,9 @@ public:
|
|||||||
|
|
||||||
virtual bool Open(Error &error) override;
|
virtual bool Open(Error &error) override;
|
||||||
virtual void Close() override;
|
virtual void Close() override;
|
||||||
virtual Song *GetSong(const char *uri_utf8,
|
virtual const LightSong *GetSong(const char *uri_utf8,
|
||||||
Error &error) const override;
|
Error &error) const override;
|
||||||
virtual void ReturnSong(Song *song) const;
|
virtual void ReturnSong(const LightSong *song) const;
|
||||||
|
|
||||||
virtual bool Visit(const DatabaseSelection &selection,
|
virtual bool Visit(const DatabaseSelection &selection,
|
||||||
VisitDirectory visit_directory,
|
VisitDirectory visit_directory,
|
||||||
@ -187,34 +212,20 @@ UpnpDatabase::Close()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UpnpDatabase::ReturnSong(Song *song) const
|
UpnpDatabase::ReturnSong(const LightSong *_song) const
|
||||||
{
|
{
|
||||||
assert(song != nullptr);
|
assert(_song != nullptr);
|
||||||
|
|
||||||
song->Free();
|
UpnpSong *song = (UpnpSong *)const_cast<LightSong *>(_song);
|
||||||
}
|
delete song;
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get song info by path. We can receive either the id path, or the titles
|
// Get song info by path. We can receive either the id path, or the titles
|
||||||
// one
|
// one
|
||||||
Song *
|
const LightSong *
|
||||||
UpnpDatabase::GetSong(const char *uri, Error &error) const
|
UpnpDatabase::GetSong(const char *uri, Error &error) const
|
||||||
{
|
{
|
||||||
Song *song = nullptr;
|
UpnpSong *song = nullptr;
|
||||||
auto vpath = stringToTokens(uri, "/", true);
|
auto vpath = stringToTokens(uri, "/", true);
|
||||||
if (vpath.size() >= 2) {
|
if (vpath.size() >= 2) {
|
||||||
ContentDirectoryService server;
|
ContentDirectoryService server;
|
||||||
@ -232,7 +243,8 @@ UpnpDatabase::GetSong(const char *uri, Error &error) const
|
|||||||
error))
|
error))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
song = upnpItemToSong(std::move(dirent), "");
|
|
||||||
|
song = new UpnpSong(std::move(dirent));
|
||||||
}
|
}
|
||||||
if (song == nullptr)
|
if (song == nullptr)
|
||||||
error.Format(db_domain, DB_NOT_FOUND, "No such song: %s", uri);
|
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)
|
if (!visit_song)
|
||||||
return true;
|
return true;
|
||||||
Song *s = upnpItemToSong(std::move(meta), path);
|
|
||||||
if (!selection.Match(*s))
|
const UpnpSong song(std::move(meta), path);
|
||||||
return true;
|
return !selection.Match(song) || visit_song(song, error);
|
||||||
bool success = visit_song(*s, error);
|
|
||||||
s->Free();
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "AsxPlaylistPlugin.hxx"
|
#include "AsxPlaylistPlugin.hxx"
|
||||||
#include "PlaylistPlugin.hxx"
|
#include "PlaylistPlugin.hxx"
|
||||||
#include "MemorySongEnumerator.hxx"
|
#include "MemorySongEnumerator.hxx"
|
||||||
#include "Song.hxx"
|
|
||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "RssPlaylistPlugin.hxx"
|
#include "RssPlaylistPlugin.hxx"
|
||||||
#include "PlaylistPlugin.hxx"
|
#include "PlaylistPlugin.hxx"
|
||||||
#include "MemorySongEnumerator.hxx"
|
#include "MemorySongEnumerator.hxx"
|
||||||
#include "Song.hxx"
|
|
||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "MemorySongEnumerator.hxx"
|
#include "MemorySongEnumerator.hxx"
|
||||||
#include "ConfigData.hxx"
|
#include "ConfigData.hxx"
|
||||||
#include "InputStream.hxx"
|
#include "InputStream.hxx"
|
||||||
#include "Song.hxx"
|
|
||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
#include "util/StringUtil.hxx"
|
#include "util/StringUtil.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include "DatabaseSelection.hxx"
|
#include "DatabaseSelection.hxx"
|
||||||
#include "DatabaseListener.hxx"
|
#include "DatabaseListener.hxx"
|
||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
#include "Song.hxx"
|
#include "LightSong.hxx"
|
||||||
#include "PlaylistVector.hxx"
|
#include "PlaylistVector.hxx"
|
||||||
#include "ConfigGlobal.hxx"
|
#include "ConfigGlobal.hxx"
|
||||||
#include "ConfigData.hxx"
|
#include "ConfigData.hxx"
|
||||||
@ -65,11 +65,11 @@ DumpDirectory(const Directory &directory, Error &)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
DumpSong(Song &song, Error &)
|
DumpSong(const LightSong &song, Error &)
|
||||||
{
|
{
|
||||||
cout << "S ";
|
cout << "S ";
|
||||||
if (song.parent != nullptr && !song.parent->IsRoot())
|
if (song.directory != nullptr)
|
||||||
cout << song.parent->path << "/";
|
cout << song.directory << "/";
|
||||||
cout << song.uri << endl;
|
cout << song.uri << endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user