Tag: use SignedSongTime for the song duration
This commit is contained in:
parent
8ce30c6a69
commit
7c25d83f1c
@ -58,11 +58,16 @@ DetachedSong::IsInDatabase() const
|
|||||||
return !uri_has_scheme(_uri) && !PathTraitsUTF8::IsAbsolute(_uri);
|
return !uri_has_scheme(_uri) && !PathTraitsUTF8::IsAbsolute(_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
SignedSongTime
|
||||||
DetachedSong::GetDuration() const
|
DetachedSong::GetDuration() const
|
||||||
{
|
{
|
||||||
if (end_time.IsPositive())
|
SongTime a = start_time, b = end_time;
|
||||||
return (end_time - start_time).ToDoubleS();
|
if (!b.IsPositive()) {
|
||||||
|
if (tag.duration.IsNegative())
|
||||||
|
return tag.duration;
|
||||||
|
|
||||||
return tag.time - start_time.ToDoubleS();
|
b = SongTime(tag.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SignedSongTime(b - a);
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
double GetDuration() const;
|
SignedSongTime GetDuration() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the #tag and #mtime.
|
* Update the #tag and #mtime.
|
||||||
|
@ -349,7 +349,7 @@ Player::WaitForDecoder()
|
|||||||
decoder_starting = true;
|
decoder_starting = true;
|
||||||
|
|
||||||
/* update PlayerControl's song information */
|
/* update PlayerControl's song information */
|
||||||
pc.total_time = pc.next_song->GetDuration();
|
pc.total_time = pc.next_song->GetDuration().ToDoubleS();
|
||||||
pc.bit_rate = 0;
|
pc.bit_rate = 0;
|
||||||
pc.audio_format.Clear();
|
pc.audio_format.Clear();
|
||||||
|
|
||||||
@ -374,7 +374,7 @@ real_song_duration(const DetachedSong &song, double decoder_duration)
|
|||||||
if (decoder_duration <= 0.0)
|
if (decoder_duration <= 0.0)
|
||||||
/* the decoder plugin didn't provide information; fall
|
/* the decoder plugin didn't provide information; fall
|
||||||
back to Song::GetDuration() */
|
back to Song::GetDuration() */
|
||||||
return song.GetDuration();
|
return song.GetDuration().ToDoubleS();
|
||||||
|
|
||||||
const SongTime start_time = song.GetStartTime();
|
const SongTime start_time = song.GetStartTime();
|
||||||
const SongTime end_time = song.GetEndTime();
|
const SongTime end_time = song.GetEndTime();
|
||||||
|
@ -119,7 +119,7 @@ song_print_info(Client &client, const DetachedSong &song, bool base)
|
|||||||
|
|
||||||
tag_print_values(client, song.GetTag());
|
tag_print_values(client, song.GetTag());
|
||||||
|
|
||||||
double duration = song.GetDuration();
|
const auto duration = song.GetDuration();
|
||||||
if (duration >= 0)
|
if (!duration.IsNegative())
|
||||||
client_printf(client, "Time: %u\n", unsigned(duration + 0.5));
|
client_printf(client, "Time: %u\n", duration.RoundS());
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ song_load(TextFile &file, const char *uri,
|
|||||||
if ((type = tag_name_parse(line)) != TAG_NUM_OF_ITEM_TYPES) {
|
if ((type = tag_name_parse(line)) != TAG_NUM_OF_ITEM_TYPES) {
|
||||||
tag.AddItem(type, value);
|
tag.AddItem(type, value);
|
||||||
} else if (strcmp(line, "Time") == 0) {
|
} else if (strcmp(line, "Time") == 0) {
|
||||||
tag.SetTime(atoi(value));
|
tag.SetDuration(SignedSongTime::FromS(atof(value)));
|
||||||
} else if (strcmp(line, "Playlist") == 0) {
|
} else if (strcmp(line, "Playlist") == 0) {
|
||||||
tag.SetHasPlaylist(strcmp(value, "yes") == 0);
|
tag.SetHasPlaylist(strcmp(value, "yes") == 0);
|
||||||
} else if (strcmp(line, SONG_MTIME) == 0) {
|
} else if (strcmp(line, SONG_MTIME) == 0) {
|
||||||
|
@ -52,8 +52,8 @@ tag_print_values(Client &client, const Tag &tag)
|
|||||||
|
|
||||||
void tag_print(Client &client, const Tag &tag)
|
void tag_print(Client &client, const Tag &tag)
|
||||||
{
|
{
|
||||||
if (tag.time >= 0)
|
if (!tag.duration.IsNegative())
|
||||||
client_printf(client, SONG_TIME "%i\n", tag.time);
|
client_printf(client, SONG_TIME "%i\n", tag.duration.RoundS());
|
||||||
|
|
||||||
tag_print_values(client, tag);
|
tag_print_values(client, tag);
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@
|
|||||||
void
|
void
|
||||||
tag_save(BufferedOutputStream &os, const Tag &tag)
|
tag_save(BufferedOutputStream &os, const Tag &tag)
|
||||||
{
|
{
|
||||||
if (tag.time >= 0)
|
if (!tag.duration.IsNegative())
|
||||||
os.Format(SONG_TIME "%i\n", tag.time);
|
os.Format(SONG_TIME "%f\n", tag.duration.ToDoubleS());
|
||||||
|
|
||||||
if (tag.has_playlist)
|
if (tag.has_playlist)
|
||||||
os.Format("Playlist: yes\n");
|
os.Format("Playlist: yes\n");
|
||||||
|
@ -64,7 +64,10 @@ static bool
|
|||||||
stats_visitor_song(SearchStats &stats, const LightSong &song)
|
stats_visitor_song(SearchStats &stats, const LightSong &song)
|
||||||
{
|
{
|
||||||
stats.n_songs++;
|
stats.n_songs++;
|
||||||
stats.total_time_s += song.GetDuration();
|
|
||||||
|
const auto duration = song.GetDuration();
|
||||||
|
if (!duration.IsNegative())
|
||||||
|
stats.total_time_s += duration.ToS();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -79,8 +82,8 @@ CollectGroupCounts(TagCountMap &map, TagType group, const Tag &tag)
|
|||||||
SearchStats()));
|
SearchStats()));
|
||||||
SearchStats &s = r.first->second;
|
SearchStats &s = r.first->second;
|
||||||
++s.n_songs;
|
++s.n_songs;
|
||||||
if (tag.time > 0)
|
if (!tag.duration.IsNegative())
|
||||||
s.total_time_s += tag.time;
|
s.total_time_s += tag.duration.ToS();
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,8 @@ static void
|
|||||||
StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
|
StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
|
||||||
const Tag &tag)
|
const Tag &tag)
|
||||||
{
|
{
|
||||||
if (tag.time > 0)
|
if (!tag.duration.IsNegative())
|
||||||
stats.total_duration += tag.time;
|
stats.total_duration += tag.duration.ToS();
|
||||||
|
|
||||||
for (const auto &item : tag) {
|
for (const auto &item : tag) {
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
|
@ -20,14 +20,16 @@
|
|||||||
#include "LightSong.hxx"
|
#include "LightSong.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
|
|
||||||
double
|
SignedSongTime
|
||||||
LightSong::GetDuration() const
|
LightSong::GetDuration() const
|
||||||
{
|
{
|
||||||
if (end_time.IsPositive())
|
SongTime a = start_time, b = end_time;
|
||||||
return (end_time - start_time).ToDoubleS();
|
if (!b.IsPositive()) {
|
||||||
|
if (tag->duration.IsNegative())
|
||||||
|
return tag->duration;
|
||||||
|
|
||||||
if (tag->time <= 0)
|
b = SongTime(tag->duration);
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
return tag->time - start_time.ToDoubleS();
|
return SignedSongTime(b - a);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ struct LightSong {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
double GetDuration() const;
|
SignedSongTime GetDuration() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -199,7 +199,10 @@ ProxySong::ProxySong(const mpd_song *song)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
TagBuilder tag_builder;
|
TagBuilder tag_builder;
|
||||||
tag_builder.SetTime(mpd_song_get_duration(song));
|
|
||||||
|
const unsigned duration = mpd_song_get_duration(song);
|
||||||
|
if (duration > 0)
|
||||||
|
tag_builder.SetDuration(SignedSongTime::FromS(duration));
|
||||||
|
|
||||||
for (const auto *i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
|
for (const auto *i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
|
||||||
Copy(tag_builder, i->d, song, i->s);
|
Copy(tag_builder, i->d, song, i->s);
|
||||||
|
@ -59,28 +59,28 @@ ParseItemClass(const char *name, size_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static int
|
static SignedSongTime
|
||||||
ParseDuration(const char *duration)
|
ParseDuration(const char *duration)
|
||||||
{
|
{
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
|
||||||
unsigned result = ParseUnsigned(duration, &endptr);
|
unsigned result = ParseUnsigned(duration, &endptr);
|
||||||
if (endptr == duration || *endptr != ':')
|
if (endptr == duration || *endptr != ':')
|
||||||
return 0;
|
return SignedSongTime::Negative();
|
||||||
|
|
||||||
result *= 60;
|
result *= 60;
|
||||||
duration = endptr + 1;
|
duration = endptr + 1;
|
||||||
result += ParseUnsigned(duration, &endptr);
|
result += ParseUnsigned(duration, &endptr);
|
||||||
if (endptr == duration || *endptr != ':')
|
if (endptr == duration || *endptr != ':')
|
||||||
return 0;
|
return SignedSongTime::Negative();
|
||||||
|
|
||||||
result *= 60;
|
result *= 60;
|
||||||
duration = endptr + 1;
|
duration = endptr + 1;
|
||||||
result += ParseUnsigned(duration, &endptr);
|
result += ParseUnsigned(duration, &endptr);
|
||||||
if (endptr == duration || *endptr != 0)
|
if (endptr == duration || *endptr != 0)
|
||||||
return 0;
|
return SignedSongTime::Negative();
|
||||||
|
|
||||||
return result;
|
return SignedSongTime::FromS(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,7 +183,7 @@ protected:
|
|||||||
const char *duration =
|
const char *duration =
|
||||||
GetAttribute(attrs, "duration");
|
GetAttribute(attrs, "duration");
|
||||||
if (duration != nullptr)
|
if (duration != nullptr)
|
||||||
tag.SetTime(ParseDuration(duration));
|
tag.SetDuration(ParseDuration(duration));
|
||||||
|
|
||||||
state = RES;
|
state = RES;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ mpd_despotify_tag_from_track(const ds_track &track)
|
|||||||
tag.AddItem(TAG_ALBUM, track.album);
|
tag.AddItem(TAG_ALBUM, track.album);
|
||||||
tag.AddItem(TAG_DATE, date);
|
tag.AddItem(TAG_DATE, date);
|
||||||
tag.AddItem(TAG_COMMENT, comment);
|
tag.AddItem(TAG_COMMENT, comment);
|
||||||
tag.SetTime(track.length / 1000);
|
tag.SetDuration(SignedSongTime::FromMS(track.length));
|
||||||
|
|
||||||
return tag.Commit();
|
return tag.Commit();
|
||||||
}
|
}
|
||||||
|
@ -363,16 +363,20 @@ RoarOutput::SendTag(const Tag &tag)
|
|||||||
|
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
size_t cnt = 1;
|
size_t cnt = 0;
|
||||||
struct roar_keyval vals[32];
|
struct roar_keyval vals[32];
|
||||||
char uuid_buf[32][64];
|
char uuid_buf[32][64];
|
||||||
|
|
||||||
char timebuf[16];
|
char timebuf[16];
|
||||||
snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d",
|
if (!tag.duration.IsNegative()) {
|
||||||
tag.time / 3600, (tag.time % 3600) / 60, tag.time % 60);
|
const unsigned seconds = tag.duration.ToS();
|
||||||
|
snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d",
|
||||||
|
seconds / 3600, (seconds % 3600) / 60, seconds % 60);
|
||||||
|
|
||||||
vals[0].key = const_cast<char *>("LENGTH");
|
vals[cnt].key = const_cast<char *>("LENGTH");
|
||||||
vals[0].value = timebuf;
|
vals[cnt].value = timebuf;
|
||||||
|
++cnt;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &item : tag) {
|
for (const auto &item : tag) {
|
||||||
if (cnt >= 32)
|
if (cnt >= 32)
|
||||||
|
@ -89,7 +89,7 @@ extm3u_parse_tag(const char *line)
|
|||||||
return Tag();
|
return Tag();
|
||||||
|
|
||||||
TagBuilder tag;
|
TagBuilder tag;
|
||||||
tag.SetTime(duration);
|
tag.SetDuration(SignedSongTime::FromS(unsigned(duration)));
|
||||||
|
|
||||||
/* unfortunately, there is no real specification for the
|
/* unfortunately, there is no real specification for the
|
||||||
EXTM3U format, so we must assume that the string after the
|
EXTM3U format, so we must assume that the string after the
|
||||||
|
@ -85,7 +85,7 @@ pls_parser(GKeyFile *keyfile, std::forward_list<DetachedSong> &songs)
|
|||||||
int length = g_key_file_get_integer(keyfile, "playlist", key,
|
int length = g_key_file_get_integer(keyfile, "playlist", key,
|
||||||
nullptr);
|
nullptr);
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
tag.SetTime(length);
|
tag.SetDuration(SignedSongTime::FromS(length));
|
||||||
|
|
||||||
songs.emplace_front(uri, tag.Commit());
|
songs.emplace_front(uri, tag.Commit());
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
|
@ -215,7 +215,7 @@ handle_end_map(void *ctx)
|
|||||||
soundcloud_config.apikey.c_str(), nullptr);
|
soundcloud_config.apikey.c_str(), nullptr);
|
||||||
|
|
||||||
TagBuilder tag;
|
TagBuilder tag;
|
||||||
tag.SetTime(data->duration / 1000);
|
tag.SetDuration(SignedSongTime::FromMS(data->duration));
|
||||||
if (data->title != nullptr)
|
if (data->title != nullptr)
|
||||||
tag.AddItem(TAG_NAME, data->title);
|
tag.AddItem(TAG_NAME, data->title);
|
||||||
|
|
||||||
|
@ -463,18 +463,19 @@ playlist::SetSongIdRange(PlayerControl &pc, unsigned id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DetachedSong &song = queue.Get(position);
|
DetachedSong &song = queue.Get(position);
|
||||||
if (song.GetTag().time > 0) {
|
|
||||||
|
const auto duration = song.GetTag().duration;
|
||||||
|
if (!duration.IsNegative()) {
|
||||||
/* validate the offsets */
|
/* validate the offsets */
|
||||||
|
|
||||||
const unsigned duration = song.GetTag().time;
|
if (start > duration) {
|
||||||
if (start.ToMS() / 1000u > duration) {
|
|
||||||
error.Set(playlist_domain,
|
error.Set(playlist_domain,
|
||||||
int(PlaylistResult::BAD_RANGE),
|
int(PlaylistResult::BAD_RANGE),
|
||||||
"Invalid start offset");
|
"Invalid start offset");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end.ToMS() / 1000u > duration)
|
if (end >= duration)
|
||||||
end = SongTime::zero();
|
end = SongTime::zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ tag_name_parse_i(const char *name)
|
|||||||
void
|
void
|
||||||
Tag::Clear()
|
Tag::Clear()
|
||||||
{
|
{
|
||||||
time = -1;
|
duration = SignedSongTime::Negative();
|
||||||
has_playlist = false;
|
has_playlist = false;
|
||||||
|
|
||||||
tag_pool_lock.lock();
|
tag_pool_lock.lock();
|
||||||
@ -75,7 +75,7 @@ Tag::Clear()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Tag::Tag(const Tag &other)
|
Tag::Tag(const Tag &other)
|
||||||
:time(other.time), has_playlist(other.has_playlist),
|
:duration(other.duration), has_playlist(other.has_playlist),
|
||||||
num_items(other.num_items),
|
num_items(other.num_items),
|
||||||
items(nullptr)
|
items(nullptr)
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "TagType.h" // IWYU pragma: export
|
#include "TagType.h" // IWYU pragma: export
|
||||||
#include "TagItem.hxx" // IWYU pragma: export
|
#include "TagItem.hxx" // IWYU pragma: export
|
||||||
|
#include "Chrono.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -35,12 +36,10 @@
|
|||||||
*/
|
*/
|
||||||
struct Tag {
|
struct Tag {
|
||||||
/**
|
/**
|
||||||
* The duration of the song (in seconds). A value of zero
|
* The duration of the song. A negative value means that the
|
||||||
* means that the length is unknown. If the duration is
|
* length is unknown.
|
||||||
* really between zero and one second, you should round up to
|
|
||||||
* 1.
|
|
||||||
*/
|
*/
|
||||||
int time;
|
SignedSongTime duration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this file have an embedded playlist (e.g. embedded CUE
|
* Does this file have an embedded playlist (e.g. embedded CUE
|
||||||
@ -57,13 +56,13 @@ struct Tag {
|
|||||||
/**
|
/**
|
||||||
* Create an empty tag.
|
* Create an empty tag.
|
||||||
*/
|
*/
|
||||||
Tag():time(-1), has_playlist(false),
|
Tag():duration(SignedSongTime::Negative()), has_playlist(false),
|
||||||
num_items(0), items(nullptr) {}
|
num_items(0), items(nullptr) {}
|
||||||
|
|
||||||
Tag(const Tag &other);
|
Tag(const Tag &other);
|
||||||
|
|
||||||
Tag(Tag &&other)
|
Tag(Tag &&other)
|
||||||
:time(other.time), has_playlist(other.has_playlist),
|
:duration(other.duration), has_playlist(other.has_playlist),
|
||||||
num_items(other.num_items), items(other.items) {
|
num_items(other.num_items), items(other.items) {
|
||||||
other.items = nullptr;
|
other.items = nullptr;
|
||||||
other.num_items = 0;
|
other.num_items = 0;
|
||||||
@ -79,7 +78,7 @@ struct Tag {
|
|||||||
Tag &operator=(const Tag &other) = delete;
|
Tag &operator=(const Tag &other) = delete;
|
||||||
|
|
||||||
Tag &operator=(Tag &&other) {
|
Tag &operator=(Tag &&other) {
|
||||||
time = other.time;
|
duration = other.duration;
|
||||||
has_playlist = other.has_playlist;
|
has_playlist = other.has_playlist;
|
||||||
std::swap(items, other.items);
|
std::swap(items, other.items);
|
||||||
std::swap(num_items, other.num_items);
|
std::swap(num_items, other.num_items);
|
||||||
@ -87,8 +86,8 @@ struct Tag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the tag contains no items. This ignores the "time"
|
* Returns true if the tag contains no items. This ignores
|
||||||
* attribute.
|
* the "duration" attribute.
|
||||||
*/
|
*/
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const {
|
||||||
return num_items == 0;
|
return num_items == 0;
|
||||||
@ -98,7 +97,7 @@ struct Tag {
|
|||||||
* Returns true if the tag contains any information.
|
* Returns true if the tag contains any information.
|
||||||
*/
|
*/
|
||||||
bool IsDefined() const {
|
bool IsDefined() const {
|
||||||
return !IsEmpty() || time >= 0;
|
return !IsEmpty() || !duration.IsNegative();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
TagBuilder::TagBuilder(const Tag &other)
|
TagBuilder::TagBuilder(const Tag &other)
|
||||||
:time(other.time), has_playlist(other.has_playlist)
|
:duration(other.duration), has_playlist(other.has_playlist)
|
||||||
{
|
{
|
||||||
items.reserve(other.num_items);
|
items.reserve(other.num_items);
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ TagBuilder::TagBuilder(const Tag &other)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TagBuilder::TagBuilder(Tag &&other)
|
TagBuilder::TagBuilder(Tag &&other)
|
||||||
:time(other.time), has_playlist(other.has_playlist)
|
:duration(other.duration), has_playlist(other.has_playlist)
|
||||||
{
|
{
|
||||||
/* move all TagItem pointers from the Tag object; we don't
|
/* move all TagItem pointers from the Tag object; we don't
|
||||||
need to contact the tag pool, because all we do is move
|
need to contact the tag pool, because all we do is move
|
||||||
@ -58,7 +58,7 @@ TagBuilder &
|
|||||||
TagBuilder::operator=(const TagBuilder &other)
|
TagBuilder::operator=(const TagBuilder &other)
|
||||||
{
|
{
|
||||||
/* copy all attributes */
|
/* copy all attributes */
|
||||||
time = other.time;
|
duration = other.duration;
|
||||||
has_playlist = other.has_playlist;
|
has_playlist = other.has_playlist;
|
||||||
items = other.items;
|
items = other.items;
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ TagBuilder::operator=(const TagBuilder &other)
|
|||||||
TagBuilder &
|
TagBuilder &
|
||||||
TagBuilder::operator=(TagBuilder &&other)
|
TagBuilder::operator=(TagBuilder &&other)
|
||||||
{
|
{
|
||||||
time = other.time;
|
duration = other.duration;
|
||||||
has_playlist = other.has_playlist;
|
has_playlist = other.has_playlist;
|
||||||
items = std::move(other.items);
|
items = std::move(other.items);
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ TagBuilder::operator=(TagBuilder &&other)
|
|||||||
TagBuilder &
|
TagBuilder &
|
||||||
TagBuilder::operator=(Tag &&other)
|
TagBuilder::operator=(Tag &&other)
|
||||||
{
|
{
|
||||||
time = other.time;
|
duration = other.duration;
|
||||||
has_playlist = other.has_playlist;
|
has_playlist = other.has_playlist;
|
||||||
|
|
||||||
/* move all TagItem pointers from the Tag object; we don't
|
/* move all TagItem pointers from the Tag object; we don't
|
||||||
@ -105,7 +105,7 @@ TagBuilder::operator=(Tag &&other)
|
|||||||
void
|
void
|
||||||
TagBuilder::Clear()
|
TagBuilder::Clear()
|
||||||
{
|
{
|
||||||
time = -1;
|
duration = SignedSongTime::Negative();
|
||||||
has_playlist = false;
|
has_playlist = false;
|
||||||
RemoveAll();
|
RemoveAll();
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ TagBuilder::Commit(Tag &tag)
|
|||||||
{
|
{
|
||||||
tag.Clear();
|
tag.Clear();
|
||||||
|
|
||||||
tag.time = time;
|
tag.duration = duration;
|
||||||
tag.has_playlist = has_playlist;
|
tag.has_playlist = has_playlist;
|
||||||
|
|
||||||
/* move all TagItem pointers to the new Tag object without
|
/* move all TagItem pointers to the new Tag object without
|
||||||
@ -162,8 +162,8 @@ TagBuilder::HasType(TagType type) const
|
|||||||
void
|
void
|
||||||
TagBuilder::Complement(const Tag &other)
|
TagBuilder::Complement(const Tag &other)
|
||||||
{
|
{
|
||||||
if (time <= 0)
|
if (duration.IsNegative())
|
||||||
time = other.time;
|
duration = other.duration;
|
||||||
|
|
||||||
has_playlist |= other.has_playlist;
|
has_playlist |= other.has_playlist;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define MPD_TAG_BUILDER_HXX
|
#define MPD_TAG_BUILDER_HXX
|
||||||
|
|
||||||
#include "TagType.h"
|
#include "TagType.h"
|
||||||
|
#include "Chrono.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -35,12 +36,10 @@ struct Tag;
|
|||||||
*/
|
*/
|
||||||
class TagBuilder {
|
class TagBuilder {
|
||||||
/**
|
/**
|
||||||
* The duration of the song (in seconds). A value of zero
|
* The duration of the song. A negative value means that the
|
||||||
* means that the length is unknown. If the duration is
|
* length is unknown.
|
||||||
* really between zero and one second, you should round up to
|
|
||||||
* 1.
|
|
||||||
*/
|
*/
|
||||||
int time;
|
SignedSongTime duration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this file have an embedded playlist (e.g. embedded CUE
|
* Does this file have an embedded playlist (e.g. embedded CUE
|
||||||
@ -56,7 +55,7 @@ public:
|
|||||||
* Create an empty tag.
|
* Create an empty tag.
|
||||||
*/
|
*/
|
||||||
TagBuilder()
|
TagBuilder()
|
||||||
:time(-1), has_playlist(false) {}
|
:duration(SignedSongTime::Negative()), has_playlist(false) {}
|
||||||
|
|
||||||
~TagBuilder() {
|
~TagBuilder() {
|
||||||
Clear();
|
Clear();
|
||||||
@ -73,8 +72,8 @@ public:
|
|||||||
TagBuilder &operator=(Tag &&other);
|
TagBuilder &operator=(Tag &&other);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the tag contains no items. This ignores the "time"
|
* Returns true if the tag contains no items. This ignores
|
||||||
* attribute.
|
* the "duration" attribute.
|
||||||
*/
|
*/
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const {
|
||||||
return items.empty();
|
return items.empty();
|
||||||
@ -85,7 +84,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsDefined() const {
|
bool IsDefined() const {
|
||||||
return time >= 0 || has_playlist || !IsEmpty();
|
return !duration.IsNegative() || has_playlist || !IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
@ -109,8 +108,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
Tag *CommitNew();
|
Tag *CommitNew();
|
||||||
|
|
||||||
void SetTime(int _time) {
|
void SetDuration(SignedSongTime _duration) {
|
||||||
time = _time;
|
duration = _duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetHasPlaylist(bool _has_playlist) {
|
void SetHasPlaylist(bool _has_playlist) {
|
||||||
|
@ -27,7 +27,7 @@ add_tag_duration(unsigned seconds, void *ctx)
|
|||||||
{
|
{
|
||||||
TagBuilder &tag = *(TagBuilder *)ctx;
|
TagBuilder &tag = *(TagBuilder *)ctx;
|
||||||
|
|
||||||
tag.SetTime(seconds);
|
tag.SetDuration(SignedSongTime::FromS(seconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -155,10 +155,13 @@ Client::AllowFile(gcc_unused Path path_fs, gcc_unused Error &error) const
|
|||||||
static std::string
|
static std::string
|
||||||
ToString(const Tag &tag)
|
ToString(const Tag &tag)
|
||||||
{
|
{
|
||||||
char buffer[64];
|
std::string result;
|
||||||
sprintf(buffer, "%d", tag.time);
|
|
||||||
|
|
||||||
std::string result = buffer;
|
if (!tag.duration.IsNegative()) {
|
||||||
|
char buffer[64];
|
||||||
|
sprintf(buffer, "%d", tag.duration.ToMS());
|
||||||
|
result.append(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &item : tag) {
|
for (const auto &item : tag) {
|
||||||
result.push_back('|');
|
result.push_back('|');
|
||||||
|
Loading…
Reference in New Issue
Block a user