summaryrefslogtreecommitdiff
path: root/src/command/FileCommands.cxx
diff options
context:
space:
mode:
authorRyan Walklin <tokyovigilante@users.noreply.github.com>2017-07-21 19:49:28 +1000
committerRyan Walklin <tokyovigilante@users.noreply.github.com>2017-08-15 20:38:33 +1000
commit9df8b32f10a1b5a007f492981597abfb3f424e1b (patch)
tree8d9909dde8b834113c401689c4d5bd38e145e432 /src/command/FileCommands.cxx
parent6f37f5752bbf316f6fdfdd0bd25fae432f7e48e6 (diff)
Add albumart command
Add API documentation Support 64 bit offsets Use InputStream for all reads
Diffstat (limited to 'src/command/FileCommands.cxx')
-rw-r--r--src/command/FileCommands.cxx114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx
index b7e4bbbbf..ac8e805e3 100644
--- a/src/command/FileCommands.cxx
+++ b/src/command/FileCommands.cxx
@@ -36,8 +36,11 @@
#include "fs/AllocatedPath.hxx"
#include "fs/FileInfo.hxx"
#include "fs/DirectoryReader.hxx"
+#include "input/InputStream.hxx"
#include "LocateUri.hxx"
#include "TimePrint.hxx"
+#include "thread/Mutex.hxx"
+#include "thread/Cond.hxx"
#include <assert.h>
#include <inttypes.h> /* for PRIu64 */
@@ -233,3 +236,114 @@ handle_read_comments(Client &client, Request args, Response &r)
gcc_unreachable();
}
+
+/**
+ * Searches for the files listed in #artnames in the UTF8 folder
+ * URI #directory. This can be a local path or protocol-based
+ * URI that #InputStream supports. Returns the first successfully
+ * opened file or #nullptr on failure.
+ */
+static InputStreamPtr
+find_stream_art(const char *directory, Mutex &mutex, Cond &cond)
+{
+ static constexpr char const * art_names[] = {
+ "cover.png",
+ "cover.jpg",
+ "cover.tiff",
+ "cover.bmp"
+ };
+
+ for(const auto name: art_names) {
+ std::string art_file = PathTraitsUTF8::Build(directory, name);
+
+ try {
+ return InputStream::OpenReady(art_file.c_str(), mutex, cond);
+ } catch (const std::exception &e) {}
+ }
+ return nullptr;
+}
+
+static CommandResult
+read_stream_art(Response &r, const char *uri, size_t offset)
+{
+ const char *art_directory = PathTraitsUTF8::GetParent(uri).c_str();
+
+ Mutex mutex;
+ Cond cond;
+
+ InputStreamPtr is = find_stream_art(art_directory, mutex, cond);
+
+ if (is == nullptr) {
+ r.Error(ACK_ERROR_NO_EXIST, "No file exists");
+ return CommandResult::ERROR;
+ }
+ if (!is->KnownSize()) {
+ r.Error(ACK_ERROR_NO_EXIST, "Cannot get size for stream");
+ return CommandResult::ERROR;
+ }
+
+ const size_t art_file_size = is->GetSize();
+
+ constexpr size_t CHUNK_SIZE = 8192;
+ uint8_t buffer[CHUNK_SIZE];
+ size_t read_size;
+
+ is->Seek(offset);
+ read_size = is->Read(&buffer, CHUNK_SIZE);
+
+ r.Format("size: %" PRIu64 "\n"
+ "binary: %u\n",
+ art_file_size,
+ read_size
+ );
+
+ r.Write(buffer, read_size);
+ r.Write("\n");
+
+ return CommandResult::OK;
+}
+
+#ifdef ENABLE_DATABASE
+static CommandResult
+read_db_art(Client &client, Response &r, const char *uri, const uint64_t offset)
+{
+ const Storage *storage = client.GetStorage();
+ if (storage == nullptr) {
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
+ return CommandResult::ERROR;
+ }
+ std::string uri2 = storage->MapUTF8(uri);
+ return read_stream_art(r, uri2.c_str(), offset);
+}
+#endif
+
+CommandResult
+handle_album_art(Client &client, Request args, Response &r)
+{
+ assert(args.size == 2);
+
+ const char *uri = args.front();
+ size_t offset = args.ParseUnsigned(1);
+
+ const auto located_uri = LocateUri(uri, &client
+#ifdef ENABLE_DATABASE
+ , nullptr
+#endif
+ );
+
+ switch (located_uri.type) {
+ case LocatedUri::Type::ABSOLUTE:
+ case LocatedUri::Type::PATH:
+ return read_stream_art(r, located_uri.canonical_uri, offset);
+ case LocatedUri::Type::RELATIVE:
+#ifdef ENABLE_DATABASE
+ return read_db_art(client, r, located_uri.canonical_uri, offset);
+#else
+ r.Error(ACK_ERROR_NO_EXIST, "Database disabled");
+ return CommandResult::ERROR;
+#endif
+ }
+ r.Error(ACK_ERROR_NO_EXIST, "No art file exists");
+ return CommandResult::ERROR;
+}
+