DetachedSong: fork of struct Song
From now on, struct Song will be used by the database only, and DetachedSong will be used by everybody else. DetachedSong is easier to use, but Song has lower overhead.
This commit is contained in:
@@ -43,7 +43,7 @@ struct AsxParser {
|
||||
* The list of songs (in reverse order because that's faster
|
||||
* while adding).
|
||||
*/
|
||||
std::forward_list<SongPointer> songs;
|
||||
std::forward_list<DetachedSong> songs;
|
||||
|
||||
/**
|
||||
* The current position in the XML file.
|
||||
@@ -60,10 +60,9 @@ struct AsxParser {
|
||||
TagType tag_type;
|
||||
|
||||
/**
|
||||
* The current song. It is allocated after the "location"
|
||||
* element.
|
||||
* The current song URI. It is set by the "ref" element.
|
||||
*/
|
||||
Song *song;
|
||||
std::string location;
|
||||
|
||||
TagBuilder tag_builder;
|
||||
|
||||
@@ -96,7 +95,7 @@ asx_start_element(gcc_unused GMarkupParseContext *context,
|
||||
case AsxParser::ROOT:
|
||||
if (StringEqualsCaseASCII(element_name, "entry")) {
|
||||
parser->state = AsxParser::ENTRY;
|
||||
parser->song = Song::NewRemote("asx:");
|
||||
parser->location.clear();
|
||||
parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
|
||||
}
|
||||
|
||||
@@ -107,17 +106,8 @@ asx_start_element(gcc_unused GMarkupParseContext *context,
|
||||
const gchar *href = get_attribute(attribute_names,
|
||||
attribute_values,
|
||||
"href");
|
||||
if (href != nullptr) {
|
||||
/* create new song object; we cannot
|
||||
replace the existing song's URI,
|
||||
because that attribute is
|
||||
immutable */
|
||||
Song *song = Song::NewRemote(href);
|
||||
if (parser->song != nullptr)
|
||||
parser->song->Free();
|
||||
|
||||
parser->song = song;
|
||||
}
|
||||
if (href != nullptr)
|
||||
parser->location = href;
|
||||
} else if (StringEqualsCaseASCII(element_name, "author"))
|
||||
/* is that correct? or should it be COMPOSER
|
||||
or PERFORMER? */
|
||||
@@ -142,12 +132,9 @@ asx_end_element(gcc_unused GMarkupParseContext *context,
|
||||
|
||||
case AsxParser::ENTRY:
|
||||
if (StringEqualsCaseASCII(element_name, "entry")) {
|
||||
if (strcmp(parser->song->uri, "asx:") != 0) {
|
||||
assert(parser->song->tag == nullptr);
|
||||
parser->song->tag = parser->tag_builder.CommitNew();
|
||||
parser->songs.emplace_front(parser->song);
|
||||
} else
|
||||
parser->song->Free();
|
||||
if (!parser->location.empty())
|
||||
parser->songs.emplace_front(std::move(parser->location),
|
||||
parser->tag_builder.Commit());
|
||||
|
||||
parser->state = AsxParser::ROOT;
|
||||
} else
|
||||
@@ -186,15 +173,6 @@ static const GMarkupParser asx_parser = {
|
||||
nullptr,
|
||||
};
|
||||
|
||||
static void
|
||||
asx_parser_destroy(gpointer data)
|
||||
{
|
||||
AsxParser *parser = (AsxParser *)data;
|
||||
|
||||
if (parser->state >= AsxParser::ENTRY)
|
||||
parser->song->Free();
|
||||
}
|
||||
|
||||
/*
|
||||
* The playlist object
|
||||
*
|
||||
@@ -215,7 +193,7 @@ asx_open_stream(InputStream &is)
|
||||
|
||||
context = g_markup_parse_context_new(&asx_parser,
|
||||
G_MARKUP_TREAT_CDATA_AS_TEXT,
|
||||
&parser, asx_parser_destroy);
|
||||
&parser, nullptr);
|
||||
|
||||
while (true) {
|
||||
nbytes = is.LockRead(buffer, sizeof(buffer), error2);
|
||||
|
@@ -36,7 +36,7 @@ class CuePlaylist final : public SongEnumerator {
|
||||
:is(_is), tis(is) {
|
||||
}
|
||||
|
||||
virtual Song *NextSong() override;
|
||||
virtual DetachedSong *NextSong() override;
|
||||
};
|
||||
|
||||
static SongEnumerator *
|
||||
@@ -45,10 +45,10 @@ cue_playlist_open_stream(InputStream &is)
|
||||
return new CuePlaylist(is);
|
||||
}
|
||||
|
||||
Song *
|
||||
DetachedSong *
|
||||
CuePlaylist::NextSong()
|
||||
{
|
||||
Song *song = parser.Get();
|
||||
DetachedSong *song = parser.Get();
|
||||
if (song != nullptr)
|
||||
return song;
|
||||
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include "PlaylistPlugin.hxx"
|
||||
#include "MemorySongEnumerator.hxx"
|
||||
#include "tag/Tag.hxx"
|
||||
#include "Song.hxx"
|
||||
#include "DetachedSong.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
extern "C" {
|
||||
@@ -34,10 +34,9 @@ extern "C" {
|
||||
#include <stdlib.h>
|
||||
|
||||
static void
|
||||
add_song(std::forward_list<SongPointer> &songs, ds_track &track)
|
||||
add_song(std::forward_list<DetachedSong> &songs, ds_track &track)
|
||||
{
|
||||
const char *dsp_scheme = despotify_playlist_plugin.schemes[0];
|
||||
Song *song;
|
||||
char uri[128];
|
||||
char *ds_uri;
|
||||
|
||||
@@ -52,15 +51,12 @@ add_song(std::forward_list<SongPointer> &songs, ds_track &track)
|
||||
return;
|
||||
}
|
||||
|
||||
song = Song::NewRemote(uri);
|
||||
song->tag = new Tag(mpd_despotify_tag_from_track(track));
|
||||
|
||||
songs.emplace_front(song);
|
||||
songs.emplace_front(uri, mpd_despotify_tag_from_track(track));
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_track(struct despotify_session *session,
|
||||
std::forward_list<SongPointer> &songs,
|
||||
std::forward_list<DetachedSong> &songs,
|
||||
struct ds_link *link)
|
||||
{
|
||||
struct ds_track *track = despotify_link_get_track(session, link);
|
||||
@@ -73,7 +69,7 @@ parse_track(struct despotify_session *session,
|
||||
|
||||
static bool
|
||||
parse_playlist(struct despotify_session *session,
|
||||
std::forward_list<SongPointer> &songs,
|
||||
std::forward_list<DetachedSong> &songs,
|
||||
struct ds_link *link)
|
||||
{
|
||||
ds_playlist *playlist = despotify_link_get_playlist(session, link);
|
||||
@@ -103,7 +99,7 @@ despotify_playlist_open_uri(const char *url,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::forward_list<SongPointer> songs;
|
||||
std::forward_list<DetachedSong> songs;
|
||||
|
||||
bool parse_result;
|
||||
switch (link->type) {
|
||||
|
@@ -30,7 +30,7 @@
|
||||
#include "tag/TagHandler.hxx"
|
||||
#include "tag/TagId3.hxx"
|
||||
#include "tag/ApeTag.hxx"
|
||||
#include "Song.hxx"
|
||||
#include "DetachedSong.hxx"
|
||||
#include "TagFile.hxx"
|
||||
#include "cue/CueParser.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
delete parser;
|
||||
}
|
||||
|
||||
virtual Song *NextSong() override;
|
||||
virtual DetachedSong *NextSong() override;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -124,10 +124,10 @@ embcue_playlist_open_uri(const char *uri,
|
||||
return playlist;
|
||||
}
|
||||
|
||||
Song *
|
||||
DetachedSong *
|
||||
EmbeddedCuePlaylist::NextSong()
|
||||
{
|
||||
Song *song = parser->Get();
|
||||
DetachedSong *song = parser->Get();
|
||||
if (song != nullptr)
|
||||
return song;
|
||||
|
||||
@@ -145,14 +145,16 @@ EmbeddedCuePlaylist::NextSong()
|
||||
|
||||
parser->Feed(line);
|
||||
song = parser->Get();
|
||||
if (song != nullptr)
|
||||
return song->ReplaceURI(filename.c_str());
|
||||
if (song != nullptr) {
|
||||
song->SetURI(filename);
|
||||
return song;
|
||||
}
|
||||
}
|
||||
|
||||
parser->Finish();
|
||||
song = parser->Get();
|
||||
if (song != nullptr)
|
||||
song = song->ReplaceURI(filename.c_str());
|
||||
song->SetURI(filename);
|
||||
return song;
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#include "ExtM3uPlaylistPlugin.hxx"
|
||||
#include "PlaylistPlugin.hxx"
|
||||
#include "SongEnumerator.hxx"
|
||||
#include "Song.hxx"
|
||||
#include "DetachedSong.hxx"
|
||||
#include "tag/Tag.hxx"
|
||||
#include "tag/TagBuilder.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
strcmp(line.c_str(), "#EXTM3U") == 0;
|
||||
}
|
||||
|
||||
virtual Song *NextSong() override;
|
||||
virtual DetachedSong *NextSong() override;
|
||||
};
|
||||
|
||||
static SongEnumerator *
|
||||
@@ -101,20 +101,19 @@ extm3u_parse_tag(const char *line)
|
||||
return tag.CommitNew();
|
||||
}
|
||||
|
||||
Song *
|
||||
DetachedSong *
|
||||
ExtM3uPlaylist::NextSong()
|
||||
{
|
||||
Tag *tag = NULL;
|
||||
std::string line;
|
||||
const char *line_s;
|
||||
Song *song;
|
||||
|
||||
do {
|
||||
if (!tis.ReadLine(line)) {
|
||||
delete tag;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
line_s = line.c_str();
|
||||
|
||||
if (StringStartsWith(line_s, "#EXTINF:")) {
|
||||
@@ -126,8 +125,8 @@ ExtM3uPlaylist::NextSong()
|
||||
line_s = strchug_fast(line_s);
|
||||
} while (line_s[0] == '#' || *line_s == 0);
|
||||
|
||||
song = Song::NewRemote(line_s);
|
||||
song->tag = tag;
|
||||
DetachedSong *song = new DetachedSong(line_s, std::move(*tag));
|
||||
delete tag;
|
||||
return song;
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#include "M3uPlaylistPlugin.hxx"
|
||||
#include "PlaylistPlugin.hxx"
|
||||
#include "SongEnumerator.hxx"
|
||||
#include "Song.hxx"
|
||||
#include "DetachedSong.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
#include "TextInputStream.hxx"
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
:tis(is) {
|
||||
}
|
||||
|
||||
virtual Song *NextSong() override;
|
||||
virtual DetachedSong *NextSong() override;
|
||||
};
|
||||
|
||||
static SongEnumerator *
|
||||
@@ -42,7 +42,7 @@ m3u_open_stream(InputStream &is)
|
||||
return new M3uPlaylist(is);
|
||||
}
|
||||
|
||||
Song *
|
||||
DetachedSong *
|
||||
M3uPlaylist::NextSong()
|
||||
{
|
||||
std::string line;
|
||||
@@ -56,7 +56,7 @@ M3uPlaylist::NextSong()
|
||||
line_s = strchug_fast(line_s);
|
||||
} while (line_s[0] == '#' || *line_s == 0);
|
||||
|
||||
return Song::NewRemote(line_s);
|
||||
return new DetachedSong(line_s);
|
||||
}
|
||||
|
||||
static const char *const m3u_suffixes[] = {
|
||||
|
@@ -22,7 +22,7 @@
|
||||
#include "PlaylistPlugin.hxx"
|
||||
#include "MemorySongEnumerator.hxx"
|
||||
#include "InputStream.hxx"
|
||||
#include "Song.hxx"
|
||||
#include "DetachedSong.hxx"
|
||||
#include "tag/TagBuilder.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
@@ -37,7 +37,7 @@
|
||||
static constexpr Domain pls_domain("pls");
|
||||
|
||||
static void
|
||||
pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
|
||||
pls_parser(GKeyFile *keyfile, std::forward_list<DetachedSong> &songs)
|
||||
{
|
||||
gchar *value;
|
||||
GError *error = nullptr;
|
||||
@@ -61,8 +61,8 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
|
||||
for (; num_entries > 0; --num_entries) {
|
||||
char key[64];
|
||||
sprintf(key, "File%u", num_entries);
|
||||
value = g_key_file_get_string(keyfile, "playlist", key,
|
||||
&error);
|
||||
char *uri = g_key_file_get_string(keyfile, "playlist", key,
|
||||
&error);
|
||||
if(error) {
|
||||
FormatError(pls_domain, "Invalid PLS entry %s: '%s'",
|
||||
key, error->message);
|
||||
@@ -70,9 +70,6 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
|
||||
return;
|
||||
}
|
||||
|
||||
Song *song = Song::NewRemote(value);
|
||||
g_free(value);
|
||||
|
||||
TagBuilder tag;
|
||||
|
||||
sprintf(key, "Title%u", num_entries);
|
||||
@@ -89,8 +86,8 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
|
||||
if (length > 0)
|
||||
tag.SetTime(length);
|
||||
|
||||
song->tag = tag.CommitNew();
|
||||
songs.emplace_front(song);
|
||||
songs.emplace_front(uri, tag.Commit());
|
||||
g_free(uri);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -135,7 +132,7 @@ pls_open_stream(InputStream &is)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::forward_list<SongPointer> songs;
|
||||
std::forward_list<DetachedSong> songs;
|
||||
pls_parser(keyfile, songs);
|
||||
g_key_file_free(keyfile);
|
||||
|
||||
|
@@ -43,7 +43,7 @@ struct RssParser {
|
||||
* The list of songs (in reverse order because that's faster
|
||||
* while adding).
|
||||
*/
|
||||
std::forward_list<SongPointer> songs;
|
||||
std::forward_list<DetachedSong> songs;
|
||||
|
||||
/**
|
||||
* The current position in the XML file.
|
||||
@@ -60,10 +60,10 @@ struct RssParser {
|
||||
TagType tag_type;
|
||||
|
||||
/**
|
||||
* The current song. It is allocated after the "location"
|
||||
* The current song URI. It is set by the "enclosure"
|
||||
* element.
|
||||
*/
|
||||
Song *song;
|
||||
std::string location;
|
||||
|
||||
TagBuilder tag_builder;
|
||||
|
||||
@@ -95,7 +95,7 @@ rss_start_element(gcc_unused GMarkupParseContext *context,
|
||||
case RssParser::ROOT:
|
||||
if (StringEqualsCaseASCII(element_name, "item")) {
|
||||
parser->state = RssParser::ITEM;
|
||||
parser->song = Song::NewRemote("rss:");
|
||||
parser->location.clear();
|
||||
parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
|
||||
}
|
||||
|
||||
@@ -106,18 +106,8 @@ rss_start_element(gcc_unused GMarkupParseContext *context,
|
||||
const gchar *href = get_attribute(attribute_names,
|
||||
attribute_values,
|
||||
"url");
|
||||
if (href != nullptr) {
|
||||
/* create new song object; we cannot
|
||||
replace the existing song's URI,
|
||||
because that attribute is
|
||||
immutable */
|
||||
Song *song = Song::NewRemote(href);
|
||||
|
||||
if (parser->song != nullptr)
|
||||
parser->song->Free();
|
||||
|
||||
parser->song = song;
|
||||
}
|
||||
if (href != nullptr)
|
||||
parser->location = href;
|
||||
} else if (StringEqualsCaseASCII(element_name, "title"))
|
||||
parser->tag_type = TAG_TITLE;
|
||||
else if (StringEqualsCaseASCII(element_name, "itunes:author"))
|
||||
@@ -140,12 +130,9 @@ rss_end_element(gcc_unused GMarkupParseContext *context,
|
||||
|
||||
case RssParser::ITEM:
|
||||
if (StringEqualsCaseASCII(element_name, "item")) {
|
||||
if (strcmp(parser->song->uri, "rss:") != 0) {
|
||||
assert(parser->song->tag == nullptr);
|
||||
parser->song->tag = parser->tag_builder.CommitNew();
|
||||
parser->songs.emplace_front(parser->song);
|
||||
} else
|
||||
parser->song->Free();
|
||||
if (!parser->location.empty())
|
||||
parser->songs.emplace_front(std::move(parser->location),
|
||||
parser->tag_builder.Commit());
|
||||
|
||||
parser->state = RssParser::ROOT;
|
||||
} else
|
||||
@@ -183,15 +170,6 @@ static const GMarkupParser rss_parser = {
|
||||
nullptr,
|
||||
};
|
||||
|
||||
static void
|
||||
rss_parser_destroy(gpointer data)
|
||||
{
|
||||
RssParser *parser = (RssParser *)data;
|
||||
|
||||
if (parser->state >= RssParser::ITEM)
|
||||
parser->song->Free();
|
||||
}
|
||||
|
||||
/*
|
||||
* The playlist object
|
||||
*
|
||||
@@ -212,7 +190,7 @@ rss_open_stream(InputStream &is)
|
||||
|
||||
context = g_markup_parse_context_new(&rss_parser,
|
||||
G_MARKUP_TREAT_CDATA_AS_TEXT,
|
||||
&parser, rss_parser_destroy);
|
||||
&parser, nullptr);
|
||||
|
||||
while (true) {
|
||||
nbytes = is.LockRead(buffer, sizeof(buffer), error2);
|
||||
|
@@ -108,7 +108,7 @@ struct parse_data {
|
||||
char* title;
|
||||
int got_url; /* nesting level of last stream_url */
|
||||
|
||||
std::forward_list<SongPointer> songs;
|
||||
std::forward_list<DetachedSong> songs;
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -214,16 +214,14 @@ handle_end_map(void *ctx)
|
||||
|
||||
char *u = g_strconcat(data->stream_url, "?client_id=",
|
||||
soundcloud_config.apikey.c_str(), nullptr);
|
||||
Song *s = Song::NewRemote(u);
|
||||
g_free(u);
|
||||
|
||||
TagBuilder tag;
|
||||
tag.SetTime(data->duration / 1000);
|
||||
if (data->title != nullptr)
|
||||
tag.AddItem(TAG_NAME, data->title);
|
||||
s->tag = tag.CommitNew();
|
||||
|
||||
data->songs.emplace_front(s);
|
||||
data->songs.emplace_front(u, tag.Commit());
|
||||
g_free(u);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "XspfPlaylistPlugin.hxx"
|
||||
#include "PlaylistPlugin.hxx"
|
||||
#include "MemorySongEnumerator.hxx"
|
||||
#include "DetachedSong.hxx"
|
||||
#include "InputStream.hxx"
|
||||
#include "tag/TagBuilder.hxx"
|
||||
#include "util/Error.hxx"
|
||||
@@ -41,7 +42,7 @@ struct XspfParser {
|
||||
* The list of songs (in reverse order because that's faster
|
||||
* while adding).
|
||||
*/
|
||||
std::forward_list<SongPointer> songs;
|
||||
std::forward_list<DetachedSong> songs;
|
||||
|
||||
/**
|
||||
* The current position in the XML file.
|
||||
@@ -59,10 +60,9 @@ struct XspfParser {
|
||||
TagType tag_type;
|
||||
|
||||
/**
|
||||
* The current song. It is allocated after the "location"
|
||||
* element.
|
||||
* The current song URI. It is set by the "location" element.
|
||||
*/
|
||||
Song *song;
|
||||
std::string location;
|
||||
|
||||
TagBuilder tag_builder;
|
||||
|
||||
@@ -95,7 +95,7 @@ xspf_start_element(gcc_unused GMarkupParseContext *context,
|
||||
case XspfParser::TRACKLIST:
|
||||
if (strcmp(element_name, "track") == 0) {
|
||||
parser->state = XspfParser::TRACK;
|
||||
parser->song = nullptr;
|
||||
parser->location.clear();
|
||||
parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
|
||||
}
|
||||
|
||||
@@ -149,11 +149,9 @@ xspf_end_element(gcc_unused GMarkupParseContext *context,
|
||||
|
||||
case XspfParser::TRACK:
|
||||
if (strcmp(element_name, "track") == 0) {
|
||||
if (parser->song != nullptr) {
|
||||
assert(parser->song->tag == nullptr);
|
||||
parser->song->tag = parser->tag_builder.CommitNew();
|
||||
parser->songs.emplace_front(parser->song);
|
||||
}
|
||||
if (!parser->location.empty())
|
||||
parser->songs.emplace_front(std::move(parser->location),
|
||||
parser->tag_builder.Commit());
|
||||
|
||||
parser->state = XspfParser::TRACKLIST;
|
||||
} else
|
||||
@@ -181,7 +179,7 @@ xspf_text(gcc_unused GMarkupParseContext *context,
|
||||
break;
|
||||
|
||||
case XspfParser::TRACK:
|
||||
if (parser->song != nullptr &&
|
||||
if (!parser->location.empty() &&
|
||||
parser->tag_type != TAG_NUM_OF_ITEM_TYPES)
|
||||
parser->tag_builder.AddItem(parser->tag_type,
|
||||
text, text_len);
|
||||
@@ -189,11 +187,7 @@ xspf_text(gcc_unused GMarkupParseContext *context,
|
||||
break;
|
||||
|
||||
case XspfParser::LOCATION:
|
||||
if (parser->song == nullptr) {
|
||||
char *uri = g_strndup(text, text_len);
|
||||
parser->song = Song::NewRemote(uri);
|
||||
g_free(uri);
|
||||
}
|
||||
parser->location.assign(text, text_len);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -207,15 +201,6 @@ static const GMarkupParser xspf_parser = {
|
||||
nullptr,
|
||||
};
|
||||
|
||||
static void
|
||||
xspf_parser_destroy(gpointer data)
|
||||
{
|
||||
XspfParser *parser = (XspfParser *)data;
|
||||
|
||||
if (parser->state >= XspfParser::TRACK && parser->song != nullptr)
|
||||
parser->song->Free();
|
||||
}
|
||||
|
||||
/*
|
||||
* The playlist object
|
||||
*
|
||||
@@ -236,7 +221,7 @@ xspf_open_stream(InputStream &is)
|
||||
|
||||
context = g_markup_parse_context_new(&xspf_parser,
|
||||
G_MARKUP_TREAT_CDATA_AS_TEXT,
|
||||
&parser, xspf_parser_destroy);
|
||||
&parser, nullptr);
|
||||
|
||||
while (true) {
|
||||
nbytes = is.LockRead(buffer, sizeof(buffer), error2);
|
||||
|
Reference in New Issue
Block a user