You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
3.1 KiB
C++
140 lines
3.1 KiB
C++
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
// Copyright The Music Player Daemon Project
|
|
|
|
#include "config.h"
|
|
#include "LocateUri.hxx"
|
|
#include "Print.hxx"
|
|
#include "PlaylistAny.hxx"
|
|
#include "PlaylistSong.hxx"
|
|
#include "SongEnumerator.hxx"
|
|
#include "SongPrint.hxx"
|
|
#include "song/Filter.hxx"
|
|
#include "song/DetachedSong.hxx"
|
|
#include "song/LightSong.hxx"
|
|
#include "input/Error.hxx"
|
|
#include "fs/Traits.hxx"
|
|
#include "thread/Mutex.hxx"
|
|
#include "Partition.hxx"
|
|
#include "Instance.hxx"
|
|
#include "PlaylistError.hxx"
|
|
#include <fmt/format.h>
|
|
#include "client/Response.hxx"
|
|
|
|
static void
|
|
playlist_provider_print(Response &r,
|
|
const SongLoader &loader,
|
|
const char *uri,
|
|
SongEnumerator &e,
|
|
unsigned start_index,
|
|
unsigned end_index,
|
|
bool detail) noexcept
|
|
{
|
|
const auto base_uri = uri != nullptr
|
|
? PathTraitsUTF8::GetParent(uri)
|
|
: ".";
|
|
|
|
std::unique_ptr<DetachedSong> song;
|
|
|
|
for (unsigned i = 0;
|
|
i < end_index && (song = e.NextSong()) != nullptr;
|
|
++i) {
|
|
if (i < start_index) {
|
|
/* skip songs before the start index */
|
|
continue;
|
|
}
|
|
|
|
if (playlist_check_translate_song(*song, base_uri,
|
|
loader) &&
|
|
detail)
|
|
song_print_info(r, *song);
|
|
else
|
|
/* fallback if no detail was requested or no
|
|
detail was available */
|
|
song_print_uri(r, *song);
|
|
}
|
|
}
|
|
|
|
static void
|
|
playlist_provider_search_print(Response &r,
|
|
const SongLoader &loader,
|
|
const char *uri,
|
|
SongEnumerator &e,
|
|
unsigned start_index,
|
|
unsigned end_index,
|
|
SongFilter *filter) noexcept
|
|
{
|
|
const auto base_uri = uri != nullptr
|
|
? PathTraitsUTF8::GetParent(uri)
|
|
: ".";
|
|
|
|
std::unique_ptr<DetachedSong> song;
|
|
|
|
unsigned skip = start_index;
|
|
unsigned n = end_index - start_index;
|
|
unsigned position = 0;
|
|
|
|
while ((song = e.NextSong()) != nullptr) {
|
|
const bool detail = playlist_check_translate_song(*song, base_uri,
|
|
loader);
|
|
if (!filter->Match(static_cast<LightSong>(*song))) {
|
|
++position;
|
|
continue;
|
|
}
|
|
|
|
if (skip > 0) {
|
|
--skip;
|
|
++position;
|
|
continue;
|
|
}
|
|
|
|
if (detail) {
|
|
song_print_info(r, *song);
|
|
r.Fmt("Pos: {}\n", position);
|
|
} else
|
|
/* fallback if no detail was requested or no
|
|
detail was available */
|
|
song_print_uri(r, *song);
|
|
|
|
if (--n == 0)
|
|
break;
|
|
|
|
++position;
|
|
}
|
|
}
|
|
|
|
void
|
|
playlist_file_print(Response &r, Partition &partition,
|
|
const SongLoader &loader,
|
|
const LocatedUri &uri,
|
|
unsigned start_index,
|
|
unsigned end_index,
|
|
bool detail,
|
|
SongFilter *filter)
|
|
try {
|
|
Mutex mutex;
|
|
|
|
#ifndef ENABLE_DATABASE
|
|
(void)partition;
|
|
#endif
|
|
|
|
auto playlist = playlist_open_any(uri,
|
|
#ifdef ENABLE_DATABASE
|
|
partition.instance.storage,
|
|
#endif
|
|
mutex);
|
|
if (playlist == nullptr)
|
|
throw PlaylistError::NoSuchList();
|
|
|
|
if (filter == nullptr)
|
|
playlist_provider_print(r, loader, uri.canonical_uri, *playlist,
|
|
start_index, end_index, detail);
|
|
else
|
|
playlist_provider_search_print(r, loader, uri.canonical_uri, *playlist,
|
|
start_index, end_index, filter);
|
|
} catch (...) {
|
|
if (IsFileNotFound(std::current_exception()))
|
|
throw PlaylistError::NoSuchList();
|
|
|
|
throw;
|
|
}
|