Add "added" timestamp to song database
- added is set to current time, if a new song is added to the database. - GetAdded falls back to mtime. Code for proxy plugin is missing, this needs a patch for libmpdclient. closes #378
This commit is contained in:
parent
97da29cc90
commit
7bf43a9712
@ -77,6 +77,9 @@ song_print_info(Response &r, const LightSong &song, bool base) noexcept
|
|||||||
if (!IsNegative(song.mtime))
|
if (!IsNegative(song.mtime))
|
||||||
time_print(r, "Last-Modified", song.mtime);
|
time_print(r, "Last-Modified", song.mtime);
|
||||||
|
|
||||||
|
if (!IsNegative(song.added))
|
||||||
|
time_print(r, "Added", song.added);
|
||||||
|
|
||||||
if (song.audio_format.IsDefined())
|
if (song.audio_format.IsDefined())
|
||||||
r.Fmt(FMT_STRING("Format: {}\n"), song.audio_format);
|
r.Fmt(FMT_STRING("Format: {}\n"), song.audio_format);
|
||||||
|
|
||||||
@ -100,6 +103,9 @@ song_print_info(Response &r, const DetachedSong &song, bool base) noexcept
|
|||||||
if (!IsNegative(song.GetLastModified()))
|
if (!IsNegative(song.GetLastModified()))
|
||||||
time_print(r, "Last-Modified", song.GetLastModified());
|
time_print(r, "Last-Modified", song.GetLastModified());
|
||||||
|
|
||||||
|
if (!IsNegative(song.GetAdded()))
|
||||||
|
time_print(r, "Added", song.GetAdded());
|
||||||
|
|
||||||
if (const auto &f = song.GetAudioFormat(); f.IsDefined())
|
if (const auto &f = song.GetAudioFormat(); f.IsDefined())
|
||||||
r.Fmt(FMT_STRING("Format: {}\n"), f);
|
r.Fmt(FMT_STRING("Format: {}\n"), f);
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define SONG_MTIME "mtime"
|
#define SONG_MTIME "mtime"
|
||||||
|
#define SONG_ADDED "added"
|
||||||
#define SONG_END "song_end"
|
#define SONG_END "song_end"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -54,6 +55,10 @@ song_save(BufferedOutputStream &os, const Song &song)
|
|||||||
if (!IsNegative(song.mtime))
|
if (!IsNegative(song.mtime))
|
||||||
os.Fmt(FMT_STRING(SONG_MTIME ": {}\n"),
|
os.Fmt(FMT_STRING(SONG_MTIME ": {}\n"),
|
||||||
std::chrono::system_clock::to_time_t(song.mtime));
|
std::chrono::system_clock::to_time_t(song.mtime));
|
||||||
|
|
||||||
|
if (!IsNegative(song.added))
|
||||||
|
os.Fmt(FMT_STRING(SONG_ADDED ": {}\n"),
|
||||||
|
std::chrono::system_clock::to_time_t(song.added));
|
||||||
os.Write(SONG_END "\n");
|
os.Write(SONG_END "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +74,10 @@ song_save(BufferedOutputStream &os, const DetachedSong &song)
|
|||||||
if (!IsNegative(song.GetLastModified()))
|
if (!IsNegative(song.GetLastModified()))
|
||||||
os.Fmt(FMT_STRING(SONG_MTIME ": {}\n"),
|
os.Fmt(FMT_STRING(SONG_MTIME ": {}\n"),
|
||||||
std::chrono::system_clock::to_time_t(song.GetLastModified()));
|
std::chrono::system_clock::to_time_t(song.GetLastModified()));
|
||||||
|
|
||||||
|
if (!IsNegative(song.GetAdded()))
|
||||||
|
os.Fmt(FMT_STRING(SONG_ADDED ": {}\n"),
|
||||||
|
std::chrono::system_clock::to_time_t(song.GetAdded()));
|
||||||
os.Write(SONG_END "\n");
|
os.Write(SONG_END "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +118,8 @@ song_load(LineReader &file, const char *uri,
|
|||||||
tag.SetHasPlaylist(StringIsEqual(value, "yes"));
|
tag.SetHasPlaylist(StringIsEqual(value, "yes"));
|
||||||
} else if (StringIsEqual(line, SONG_MTIME)) {
|
} else if (StringIsEqual(line, SONG_MTIME)) {
|
||||||
song.SetLastModified(std::chrono::system_clock::from_time_t(atoi(value)));
|
song.SetLastModified(std::chrono::system_clock::from_time_t(atoi(value)));
|
||||||
|
} else if (StringIsEqual(line, SONG_ADDED)) {
|
||||||
|
song.SetAdded(std::chrono::system_clock::from_time_t(atoi(value)));
|
||||||
} else if (StringIsEqual(line, "Range")) {
|
} else if (StringIsEqual(line, "Range")) {
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
|
||||||
|
@ -51,6 +51,9 @@ ParseSortTag(const char *s)
|
|||||||
if (StringIsEqualIgnoreCase(s, "Last-Modified"))
|
if (StringIsEqualIgnoreCase(s, "Last-Modified"))
|
||||||
return TagType(SORT_TAG_LAST_MODIFIED);
|
return TagType(SORT_TAG_LAST_MODIFIED);
|
||||||
|
|
||||||
|
if (StringIsEqualIgnoreCase(s, "Added"))
|
||||||
|
return TagType(SORT_TAG_ADDED);
|
||||||
|
|
||||||
TagType tag = tag_name_parse_i(s);
|
TagType tag = tag_name_parse_i(s);
|
||||||
if (tag == TAG_NUM_OF_ITEM_TYPES)
|
if (tag == TAG_NUM_OF_ITEM_TYPES)
|
||||||
throw ProtocolError(ACK_ERROR_ARG, "Unknown sort tag");
|
throw ProtocolError(ACK_ERROR_ARG, "Unknown sort tag");
|
||||||
|
@ -276,6 +276,9 @@ ParseSortTag(const char *s)
|
|||||||
if (StringIsEqualIgnoreCase(s, "Last-Modified"))
|
if (StringIsEqualIgnoreCase(s, "Last-Modified"))
|
||||||
return TagType(SORT_TAG_LAST_MODIFIED);
|
return TagType(SORT_TAG_LAST_MODIFIED);
|
||||||
|
|
||||||
|
if (StringIsEqualIgnoreCase(s, "Added"))
|
||||||
|
return TagType(SORT_TAG_ADDED);
|
||||||
|
|
||||||
if (StringIsEqualIgnoreCase(s, "prio"))
|
if (StringIsEqualIgnoreCase(s, "prio"))
|
||||||
return TagType(SORT_TAG_PRIO);
|
return TagType(SORT_TAG_PRIO);
|
||||||
|
|
||||||
|
@ -60,6 +60,13 @@ DatabaseVisitorHelper::Commit()
|
|||||||
? a.GetLastModified() > b.GetLastModified()
|
? a.GetLastModified() > b.GetLastModified()
|
||||||
: a.GetLastModified() < b.GetLastModified();
|
: a.GetLastModified() < b.GetLastModified();
|
||||||
});
|
});
|
||||||
|
else if (sort == TagType(SORT_TAG_ADDED))
|
||||||
|
std::stable_sort(songs.begin(), songs.end(),
|
||||||
|
[descending](const DetachedSong &a, const DetachedSong &b){
|
||||||
|
return descending
|
||||||
|
? a.GetAdded() > b.GetAdded()
|
||||||
|
: a.GetAdded() < b.GetAdded();
|
||||||
|
});
|
||||||
else
|
else
|
||||||
std::stable_sort(songs.begin(), songs.end(),
|
std::stable_sort(songs.begin(), songs.end(),
|
||||||
[sort, descending](const DetachedSong &a,
|
[sort, descending](const DetachedSong &a,
|
||||||
|
@ -19,6 +19,7 @@ Song::Song(DetachedSong &&other, Directory &_parent) noexcept
|
|||||||
filename(other.GetURI()),
|
filename(other.GetURI()),
|
||||||
tag(std::move(other.WritableTag())),
|
tag(std::move(other.WritableTag())),
|
||||||
mtime(other.GetLastModified()),
|
mtime(other.GetLastModified()),
|
||||||
|
added(other.GetAdded()),
|
||||||
start_time(other.GetStartTime()),
|
start_time(other.GetStartTime()),
|
||||||
end_time(other.GetEndTime()),
|
end_time(other.GetEndTime()),
|
||||||
audio_format(other.GetAudioFormat())
|
audio_format(other.GetAudioFormat())
|
||||||
@ -117,6 +118,9 @@ Song::Export() const noexcept
|
|||||||
dest.mtime = IsNegative(mtime) && target_song != nullptr
|
dest.mtime = IsNegative(mtime) && target_song != nullptr
|
||||||
? target_song->mtime
|
? target_song->mtime
|
||||||
: mtime;
|
: mtime;
|
||||||
|
dest.added = IsNegative(added) && target_song != nullptr
|
||||||
|
? target_song->added
|
||||||
|
: added;
|
||||||
dest.start_time = start_time.IsZero() && target_song != nullptr
|
dest.start_time = start_time.IsZero() && target_song != nullptr
|
||||||
? target_song->start_time
|
? target_song->start_time
|
||||||
: start_time;
|
: start_time;
|
||||||
|
@ -56,6 +56,13 @@ struct Song : IntrusiveListHook<> {
|
|||||||
std::chrono::system_clock::time_point mtime =
|
std::chrono::system_clock::time_point mtime =
|
||||||
std::chrono::system_clock::time_point::min();
|
std::chrono::system_clock::time_point::min();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time stamp when the file was added. A negative
|
||||||
|
* value means that this is unknown/unavailable.
|
||||||
|
*/
|
||||||
|
std::chrono::system_clock::time_point added =
|
||||||
|
std::chrono::system_clock::time_point::min();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start of this sub-song within the file.
|
* Start of this sub-song within the file.
|
||||||
*/
|
*/
|
||||||
|
@ -50,6 +50,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
new_song->mark = true;
|
new_song->mark = true;
|
||||||
|
new_song->added = std::chrono::system_clock::now();
|
||||||
|
|
||||||
{
|
{
|
||||||
const ScopeDatabaseLock protect;
|
const ScopeDatabaseLock protect;
|
||||||
|
@ -25,6 +25,7 @@ merge_song_metadata(DetachedSong &add, const DetachedSong &base) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
add.SetLastModified(base.GetLastModified());
|
add.SetLastModified(base.GetLastModified());
|
||||||
|
add.SetAdded(base.GetAdded());
|
||||||
|
|
||||||
if (add.GetStartTime().IsZero()) {
|
if (add.GetStartTime().IsZero()) {
|
||||||
add.SetStartTime(base.GetStartTime());
|
add.SetStartTime(base.GetStartTime());
|
||||||
|
@ -33,6 +33,7 @@ UpdatePlaylistSong(const Database &db, DetachedSong &song)
|
|||||||
}
|
}
|
||||||
|
|
||||||
song.SetLastModified(original->mtime);
|
song.SetLastModified(original->mtime);
|
||||||
|
song.SetAdded(original->added);
|
||||||
song.SetTag(original->tag);
|
song.SetTag(original->tag);
|
||||||
|
|
||||||
db.ReturnSong(original);
|
db.ReturnSong(original);
|
||||||
|
@ -127,6 +127,17 @@ PrintSortedQueue(Response &r, const Queue &queue,
|
|||||||
|
|
||||||
return a.GetLastModified() < b.GetLastModified();
|
return a.GetLastModified() < b.GetLastModified();
|
||||||
});
|
});
|
||||||
|
else if (sort == TagType(SORT_TAG_ADDED))
|
||||||
|
std::stable_sort(v.begin(), v.end(),
|
||||||
|
[&queue, descending](unsigned a_pos, unsigned b_pos){
|
||||||
|
if (descending)
|
||||||
|
std::swap(a_pos, b_pos);
|
||||||
|
|
||||||
|
const auto &a = queue.Get(a_pos);
|
||||||
|
const auto &b = queue.Get(b_pos);
|
||||||
|
|
||||||
|
return a.GetAdded() < b.GetAdded();
|
||||||
|
});
|
||||||
else if (sort == TagType(SORT_TAG_PRIO))
|
else if (sort == TagType(SORT_TAG_PRIO))
|
||||||
std::stable_sort(v.begin(), v.end(),
|
std::stable_sort(v.begin(), v.end(),
|
||||||
[&queue, descending](unsigned a_pos, unsigned b_pos){
|
[&queue, descending](unsigned a_pos, unsigned b_pos){
|
||||||
|
@ -11,6 +11,7 @@ DetachedSong::DetachedSong(const LightSong &other) noexcept
|
|||||||
real_uri(other.real_uri != nullptr ? other.real_uri : ""),
|
real_uri(other.real_uri != nullptr ? other.real_uri : ""),
|
||||||
tag(other.tag),
|
tag(other.tag),
|
||||||
mtime(other.mtime),
|
mtime(other.mtime),
|
||||||
|
added(other.added),
|
||||||
start_time(other.start_time),
|
start_time(other.start_time),
|
||||||
end_time(other.end_time),
|
end_time(other.end_time),
|
||||||
audio_format(other.audio_format) {}
|
audio_format(other.audio_format) {}
|
||||||
@ -21,6 +22,7 @@ DetachedSong::operator LightSong() const noexcept
|
|||||||
result.directory = nullptr;
|
result.directory = nullptr;
|
||||||
result.real_uri = real_uri.empty() ? nullptr : real_uri.c_str();
|
result.real_uri = real_uri.empty() ? nullptr : real_uri.c_str();
|
||||||
result.mtime = mtime;
|
result.mtime = mtime;
|
||||||
|
result.added = added;
|
||||||
result.start_time = start_time;
|
result.start_time = start_time;
|
||||||
result.end_time = end_time;
|
result.end_time = end_time;
|
||||||
return result;
|
return result;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "pcm/AudioFormat.hxx"
|
#include "pcm/AudioFormat.hxx"
|
||||||
#include "Chrono.hxx"
|
#include "Chrono.hxx"
|
||||||
|
#include "time/ChronoUtil.hxx"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -58,6 +59,13 @@ class DetachedSong {
|
|||||||
std::chrono::system_clock::time_point mtime =
|
std::chrono::system_clock::time_point mtime =
|
||||||
std::chrono::system_clock::time_point::min();
|
std::chrono::system_clock::time_point::min();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time stamp when the file was added to db. A negative
|
||||||
|
* value means that this is unknown/unavailable.
|
||||||
|
*/
|
||||||
|
std::chrono::system_clock::time_point added =
|
||||||
|
std::chrono::system_clock::time_point::min();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start of this sub-song within the file.
|
* Start of this sub-song within the file.
|
||||||
*/
|
*/
|
||||||
@ -212,6 +220,16 @@ public:
|
|||||||
mtime = _value;
|
mtime = _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point GetAdded() const noexcept {
|
||||||
|
return IsNegative(added)
|
||||||
|
? mtime
|
||||||
|
: added;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAdded(std::chrono::system_clock::time_point _value) noexcept {
|
||||||
|
added = _value;
|
||||||
|
}
|
||||||
|
|
||||||
SongTime GetStartTime() const noexcept {
|
SongTime GetStartTime() const noexcept {
|
||||||
return start_time;
|
return start_time;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
*/
|
*/
|
||||||
#define SORT_TAG_PRIO (TAG_NUM_OF_ITEM_TYPES + 4)
|
#define SORT_TAG_PRIO (TAG_NUM_OF_ITEM_TYPES + 4)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special value for the db_selection_print() sort parameter.
|
||||||
|
*/
|
||||||
|
#define SORT_TAG_ADDED (TAG_NUM_OF_ITEM_TYPES + 5)
|
||||||
|
|
||||||
enum TagType : uint8_t;
|
enum TagType : uint8_t;
|
||||||
struct LightSong;
|
struct LightSong;
|
||||||
|
|
||||||
|
@ -51,6 +51,12 @@ struct LightSong {
|
|||||||
*/
|
*/
|
||||||
std::chrono::system_clock::time_point mtime = std::chrono::system_clock::time_point::min();
|
std::chrono::system_clock::time_point mtime = std::chrono::system_clock::time_point::min();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time stamp when the file was added. A negative
|
||||||
|
* value means that this is unknown/unavailable.
|
||||||
|
*/
|
||||||
|
std::chrono::system_clock::time_point added = std::chrono::system_clock::time_point::min();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start of this sub-song within the file.
|
* Start of this sub-song within the file.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user