db/simple/Song: Export() merges tags with "target"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1048
This commit is contained in:
parent
3a7c9c7c84
commit
1afa33c3c7
2
NEWS
2
NEWS
|
@ -1,7 +1,7 @@
|
|||
ver 0.22.4 (not yet released)
|
||||
* protocol
|
||||
- fix "readpicture" on 32 bit machines
|
||||
- show duration of songs in virtual playlist (CUE) folders
|
||||
- show duration and tags of songs in virtual playlist (CUE) folders
|
||||
* storage
|
||||
- curl: fix several WebDAV protocol bugs
|
||||
* decoder
|
||||
|
|
|
@ -233,12 +233,12 @@ SimpleDatabase::GetSong(std::string_view uri) const
|
|||
"No such song");
|
||||
|
||||
const Song *song = r.directory->FindSong(r.rest);
|
||||
protect.unlock();
|
||||
if (song == nullptr)
|
||||
throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
|
||||
"No such song");
|
||||
|
||||
exported_song.Construct(song->Export());
|
||||
protect.unlock();
|
||||
|
||||
#ifndef NDEBUG
|
||||
++borrowed_song_count;
|
||||
|
|
|
@ -21,9 +21,12 @@
|
|||
#include "ExportedSong.hxx"
|
||||
#include "Directory.hxx"
|
||||
#include "tag/Tag.hxx"
|
||||
#include "tag/Builder.hxx"
|
||||
#include "song/DetachedSong.hxx"
|
||||
#include "song/LightSong.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
#include "time/ChronoUtil.hxx"
|
||||
#include "util/IterableSplitString.hxx"
|
||||
|
||||
Song::Song(DetachedSong &&other, Directory &_parent) noexcept
|
||||
:tag(std::move(other.WritableTag())),
|
||||
|
@ -54,17 +57,87 @@ Song::GetURI() const noexcept
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Path name traversal of a #Directory.
|
||||
*/
|
||||
gcc_pure
|
||||
static const Directory *
|
||||
FindTargetDirectory(const Directory &base, StringView path) noexcept
|
||||
{
|
||||
const auto *directory = &base;
|
||||
for (const StringView name : IterableSplitString(path, '/')) {
|
||||
if (name.empty() || name.Equals("."))
|
||||
continue;
|
||||
|
||||
directory = name.Equals("..")
|
||||
? directory->parent
|
||||
: directory->FindChild(name);
|
||||
if (directory == nullptr)
|
||||
break;
|
||||
}
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Path name traversal of a #Song.
|
||||
*/
|
||||
gcc_pure
|
||||
static const Song *
|
||||
FindTargetSong(const Directory &_directory, StringView target) noexcept
|
||||
{
|
||||
auto [path, last] = target.SplitLast('/');
|
||||
if (last == nullptr) {
|
||||
last = path;
|
||||
path = nullptr;
|
||||
}
|
||||
|
||||
if (last.empty())
|
||||
return nullptr;
|
||||
|
||||
const auto *directory = FindTargetDirectory(_directory, path);
|
||||
if (directory == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return directory->FindSong(last);
|
||||
}
|
||||
|
||||
ExportedSong
|
||||
Song::Export() const noexcept
|
||||
{
|
||||
ExportedSong dest(filename.c_str(), tag);
|
||||
const auto *target_song = !target.empty()
|
||||
? FindTargetSong(parent, (std::string_view)target)
|
||||
: nullptr;
|
||||
|
||||
Tag merged_tag;
|
||||
if (target_song != nullptr) {
|
||||
/* if we found the target song (which may be the
|
||||
underlying song file of a CUE file), merge the tags
|
||||
from that song with this song's tags (from the CUE
|
||||
file) */
|
||||
TagBuilder builder(tag);
|
||||
builder.Complement(target_song->tag);
|
||||
merged_tag = builder.Commit();
|
||||
}
|
||||
|
||||
ExportedSong dest = merged_tag.IsDefined()
|
||||
? ExportedSong(filename.c_str(), std::move(merged_tag))
|
||||
: ExportedSong(filename.c_str(), tag);
|
||||
if (!parent.IsRoot())
|
||||
dest.directory = parent.GetPath();
|
||||
if (!target.empty())
|
||||
dest.real_uri = target.c_str();
|
||||
dest.mtime = mtime;
|
||||
dest.start_time = start_time;
|
||||
dest.end_time = end_time;
|
||||
dest.audio_format = audio_format;
|
||||
dest.mtime = IsNegative(mtime) && target_song != nullptr
|
||||
? target_song->mtime
|
||||
: mtime;
|
||||
dest.start_time = start_time.IsZero() && target_song != nullptr
|
||||
? target_song->start_time
|
||||
: start_time;
|
||||
dest.end_time = end_time.IsZero() && target_song != nullptr
|
||||
? target_song->end_time
|
||||
: end_time;
|
||||
dest.audio_format = audio_format.IsDefined() || target_song == nullptr
|
||||
? audio_format
|
||||
: target_song->audio_format;
|
||||
return dest;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue