From 43537798108ce240f1d1131db8611d0bf11a3e0c Mon Sep 17 00:00:00 2001 From: ailurux Date: Thu, 12 Sep 2024 17:35:22 +1000 Subject: [PATCH 1/8] WIP: Add last_position field to track data and start on implementation --- src/tangara/audio/audio_fsm.cpp | 25 +++++++++++++++++++++++++ src/tangara/audio/audio_fsm.hpp | 2 ++ src/tangara/database/database.cpp | 19 +++++++++++++++++++ src/tangara/database/database.hpp | 5 ++++- src/tangara/database/records.cpp | 4 ++++ src/tangara/database/track.hpp | 8 +++++--- 6 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/tangara/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp index 5a91c6f9..d9b81832 100644 --- a/src/tangara/audio/audio_fsm.cpp +++ b/src/tangara/audio/audio_fsm.cpp @@ -80,6 +80,10 @@ auto AudioState::emitPlaybackUpdate(bool paused) -> void { current.first->start_offset.value_or(0); } + if (position) { + // Update position if the duration has been long enough + } + PlaybackUpdate event{ .current_track = current.first, .track_position = position, @@ -374,6 +378,27 @@ void AudioState::react(const OutputModeChanged& ev) { } } +auto AudioState::updateSavedPosition(std::string uri, uint32_t position) + -> void { + sServices->bg_worker().Dispatch([=]() { + auto db = sServices->database().lock(); + if (!db) { + return; + } + auto id = db->getTrackID(uri); + if (!id) { + return; + } + auto track = db->getTrack(*id); + if (!track) { + return; + } + database::TrackData data = track->data(); + data.last_position = position; + db->setTrackData(*id, data); + }); +} + auto AudioState::commitVolume() -> void { auto mode = sServices->nvs().OutputMode(); auto vol = sOutput->GetVolume(); diff --git a/src/tangara/audio/audio_fsm.hpp b/src/tangara/audio/audio_fsm.hpp index 0644375f..0c8f4d26 100644 --- a/src/tangara/audio/audio_fsm.hpp +++ b/src/tangara/audio/audio_fsm.hpp @@ -73,6 +73,8 @@ class AudioState : public tinyfsm::Fsm { auto emitPlaybackUpdate(bool paused) -> void; auto commitVolume() -> void; + auto updateSavedPosition(std::string uri, uint32_t position) -> void; + static std::shared_ptr sServices; static std::shared_ptr sStreamFactory; diff --git a/src/tangara/database/database.cpp b/src/tangara/database/database.cpp index 64451f48..9d0de695 100644 --- a/src/tangara/database/database.cpp +++ b/src/tangara/database/database.cpp @@ -44,6 +44,7 @@ #include "memory_resource.hpp" #include "result.hpp" #include "tasks.hpp" +#include "database.hpp" namespace database { @@ -269,6 +270,24 @@ auto Database::getTrack(TrackId id) -> std::shared_ptr { return std::make_shared(data, tags); } +auto Database::getTrackID(std::string path) -> std::optional { + std::string raw_data; + if (!db_->Get(leveldb::ReadOptions(), EncodePathKey(path), &raw_data).ok()) { + return {}; + } + return BytesToTrackId(raw_data); +} + +auto Database::setTrackData(TrackId id, const TrackData& data) -> void { + std::string key = EncodeDataKey(id); + std::string raw_val = EncodeDataValue(data); + + auto res = db_->Put(leveldb::WriteOptions(), key, raw_val); + if (!res.ok()) { + ESP_LOGI(kTag, "Updating track data failed for track ID: %lu", id); + } +} + auto Database::getIndexes() -> std::vector { // TODO(jacqueline): This probably needs to be async? When we have runtime // configurable indexes, they will need to come from somewhere. diff --git a/src/tangara/database/database.hpp b/src/tangara/database/database.hpp index 18070353..6dd13b0d 100644 --- a/src/tangara/database/database.hpp +++ b/src/tangara/database/database.hpp @@ -37,7 +37,7 @@ namespace database { -const uint8_t kCurrentDbVersion = 7; +const uint8_t kCurrentDbVersion = 8; struct SearchKey; class Record; @@ -78,6 +78,9 @@ class Database { auto getTrackPath(TrackId id) -> std::optional; auto getTrack(TrackId id) -> std::shared_ptr; + auto getTrackID(std::string path) -> std::optional; + + auto setTrackData(TrackId id, const TrackData& data) -> void; auto getIndexes() -> std::vector; auto updateIndexes() -> void; diff --git a/src/tangara/database/records.cpp b/src/tangara/database/records.cpp index 17009cd8..9e898c0b 100644 --- a/src/tangara/database/records.cpp +++ b/src/tangara/database/records.cpp @@ -93,6 +93,7 @@ auto EncodeDataValue(const TrackData& track) -> std::string { cppbor::Uint{track.modified_at.first}, cppbor::Uint{track.modified_at.second}, tag_hashes, + cppbor::Uint{track.last_position}, }; return val.toString(); } @@ -127,6 +128,9 @@ auto ParseDataValue(const leveldb::Slice& slice) -> std::shared_ptr { auto tag = static_cast(entry.first->asUint()->unsignedValue()); res->individual_tag_hashes[tag] = entry.second->asUint()->unsignedValue(); } + + res->last_position = vals->get(7)->asUint()->unsignedValue(); + return res; } diff --git a/src/tangara/database/track.hpp b/src/tangara/database/track.hpp index 6501e31f..2bcf4db1 100644 --- a/src/tangara/database/track.hpp +++ b/src/tangara/database/track.hpp @@ -159,7 +159,8 @@ struct TrackData { tags_hash(0), individual_tag_hashes(&memory::kSpiRamResource), is_tombstoned(false), - modified_at() {} + modified_at(), + last_position(0) {} TrackId id; std::pmr::string filepath; @@ -167,9 +168,10 @@ struct TrackData { std::pmr::unordered_map individual_tag_hashes; bool is_tombstoned; std::pair modified_at; + uint32_t last_position; - TrackData(TrackData&& other) = delete; - TrackData& operator=(TrackData& other) = delete; + TrackData(const TrackData& other) = default; + TrackData& operator=(TrackData& other) = default; bool operator==(const TrackData&) const = default; }; From d4bad111302f4603386fe4462a0b29590822cff8 Mon Sep 17 00:00:00 2001 From: ailurux Date: Thu, 12 Sep 2024 21:08:11 +1000 Subject: [PATCH 2/8] WIP: Fixed errors, cleanup --- src/tangara/audio/audio_fsm.cpp | 6 +++--- src/tangara/database/records.cpp | 5 +++-- src/tangara/database/track.cpp | 12 ++++++++++++ src/tangara/database/track.hpp | 7 ++++--- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/tangara/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp index d9b81832..131e0a06 100644 --- a/src/tangara/audio/audio_fsm.cpp +++ b/src/tangara/audio/audio_fsm.cpp @@ -393,9 +393,9 @@ auto AudioState::updateSavedPosition(std::string uri, uint32_t position) if (!track) { return; } - database::TrackData data = track->data(); - data.last_position = position; - db->setTrackData(*id, data); + auto data = track->data().clone(); + data->last_position = position; + db->setTrackData(*id, *data); }); } diff --git a/src/tangara/database/records.cpp b/src/tangara/database/records.cpp index 9e898c0b..012cda64 100644 --- a/src/tangara/database/records.cpp +++ b/src/tangara/database/records.cpp @@ -105,13 +105,14 @@ auto ParseDataValue(const leveldb::Slice& slice) -> std::shared_ptr { return nullptr; } auto vals = item->asArray(); - if (vals->size() != 7 || vals->get(0)->type() != cppbor::UINT || + if (vals->size() != 8 || vals->get(0)->type() != cppbor::UINT || vals->get(1)->type() != cppbor::TSTR || vals->get(2)->type() != cppbor::UINT || vals->get(3)->type() != cppbor::SIMPLE || vals->get(4)->type() != cppbor::UINT || vals->get(5)->type() != cppbor::UINT || - vals->get(6)->type() != cppbor::MAP) { + vals->get(6)->type() != cppbor::MAP || + vals->get(7)->type() != cppbor::UINT) { return {}; } auto res = std::make_shared(); diff --git a/src/tangara/database/track.cpp b/src/tangara/database/track.cpp index cdb7543c..e737dd37 100644 --- a/src/tangara/database/track.cpp +++ b/src/tangara/database/track.cpp @@ -293,4 +293,16 @@ auto TrackTags::Hash() const -> uint64_t { return komihash_stream_final(&stream); } +auto database::TrackData::clone() const -> std::shared_ptr { + auto data = std::make_shared(); + data->id = id; + data->filepath = filepath; + data->tags_hash = tags_hash; + data->individual_tag_hashes = individual_tag_hashes; + data->is_tombstoned = is_tombstoned; + data->modified_at = modified_at; + data->last_position = last_position; + return data; +} + } // namespace database diff --git a/src/tangara/database/track.hpp b/src/tangara/database/track.hpp index 2bcf4db1..6e2bacce 100644 --- a/src/tangara/database/track.hpp +++ b/src/tangara/database/track.hpp @@ -170,10 +170,11 @@ struct TrackData { std::pair modified_at; uint32_t last_position; - TrackData(const TrackData& other) = default; - TrackData& operator=(TrackData& other) = default; + TrackData(const TrackData&& other) = delete; + TrackData& operator=(TrackData& other) = delete; + auto clone() const -> std::shared_ptr; - bool operator==(const TrackData&) const = default; + bool operator==(const TrackData&) const = delete; }; /* From f58679983e0854e2f976f2c5bbea1a8755c70bc3 Mon Sep 17 00:00:00 2001 From: ailurux Date: Fri, 13 Sep 2024 15:23:03 +1000 Subject: [PATCH 3/8] Save positions over 5 minutes, every minute --- src/tangara/audio/audio_fsm.cpp | 12 ++++++++++-- src/tangara/audio/audio_fsm.hpp | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/tangara/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp index 131e0a06..210f9afd 100644 --- a/src/tangara/audio/audio_fsm.cpp +++ b/src/tangara/audio/audio_fsm.cpp @@ -70,6 +70,8 @@ StreamCues AudioState::sStreamCues; bool AudioState::sIsPaused = true; +uint8_t AudioState::sUpdateCounter = 0; + auto AudioState::emitPlaybackUpdate(bool paused) -> void { std::optional position; auto current = sStreamCues.current(); @@ -80,8 +82,14 @@ auto AudioState::emitPlaybackUpdate(bool paused) -> void { current.first->start_offset.value_or(0); } - if (position) { - // Update position if the duration has been long enough + // If we've got an elapsed duration and it's more than 5 minutes + // increment a counter. Every 60 counts (ie, every minute) save the current elapsed position + if (position && *position > (5 * 60)) { + sUpdateCounter++; + if (sUpdateCounter > 60) { + sUpdateCounter = 0; + updateSavedPosition(current.first->uri, *position); + } } PlaybackUpdate event{ diff --git a/src/tangara/audio/audio_fsm.hpp b/src/tangara/audio/audio_fsm.hpp index 0c8f4d26..99824b4c 100644 --- a/src/tangara/audio/audio_fsm.hpp +++ b/src/tangara/audio/audio_fsm.hpp @@ -90,6 +90,7 @@ class AudioState : public tinyfsm::Fsm { static std::optional sDrainFormat; static bool sIsPaused; + static uint8_t sUpdateCounter; }; namespace states { From c4ec089a90ae4a61a50a03cf8338d63488edfd62 Mon Sep 17 00:00:00 2001 From: ailurux Date: Tue, 17 Sep 2024 11:56:19 +1000 Subject: [PATCH 4/8] Added lua methods to access track data --- lua/browser.lua | 5 +++ src/tangara/lua/lua_database.cpp | 72 +++++++++++++++++++++++++++++++- src/tangara/lua/lua_database.hpp | 2 + src/tangara/lua/property.cpp | 24 +---------- 4 files changed, 79 insertions(+), 24 deletions(-) diff --git a/lua/browser.lua b/lua/browser.lua index bd743152..731c1dc6 100644 --- a/lua/browser.lua +++ b/lua/browser.lua @@ -8,6 +8,7 @@ local styles = require("styles") local playback = require("playback") local theme = require("theme") local screen = require("screen") +local database = require("database") return screen:new{ create_ui = function(self) @@ -101,6 +102,10 @@ return screen:new{ }) else queue.clear() + local track = database.track_by_id(contents) + if (track) then + print("Track saved position: ", track.saved_position) + end queue.add(contents) playback.playing:set(true) backstack.push(playing:new()) diff --git a/src/tangara/lua/lua_database.cpp b/src/tangara/lua/lua_database.cpp index bf84a399..e184265a 100644 --- a/src/tangara/lua/lua_database.cpp +++ b/src/tangara/lua/lua_database.cpp @@ -73,6 +73,56 @@ static auto indexes(lua_State* state) -> int { return 1; } +auto pushTagValue(lua_State* L, const database::TagValue& val) -> void { + std::visit( + [&](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + lua_pushlstring(L, arg.data(), arg.size()); + } else if constexpr (std::is_same_v< + T, std::span>) { + lua_createtable(L, 0, arg.size()); + for (const auto& i : arg) { + lua_pushlstring(L, i.data(), i.size()); + lua_pushboolean(L, true); + lua_rawset(L, -3); + } + } else if constexpr (std::is_same_v) { + lua_pushinteger(L, arg); + } else { + lua_pushnil(L); + } + }, + val); +} + +static void pushTrack(lua_State* L, const database::Track& track) { + lua_newtable(L); + + lua_pushliteral(L, "tags"); + lua_newtable(L); + for (const auto& tag : track.tags().allPresent()) { + lua_pushstring(L, database::tagName(tag).c_str()); + pushTagValue(L, track.tags().get(tag)); + lua_settable(L, -3); + } + lua_settable(L, -3); + + lua_pushliteral(L, "id"); + lua_pushinteger(L, track.data().id); + lua_settable(L, -3); + + lua_pushliteral(L, "filepath"); + lua_pushstring(L, track.data().filepath.c_str()); + lua_settable(L, -3); + + lua_pushliteral(L, "saved_position"); + lua_pushinteger(L, track.data().last_position); + lua_settable(L, -3); + + +} + static auto version(lua_State* L) -> int { Bridge* instance = Bridge::Get(L); auto db = instance->services().database().lock(); @@ -111,9 +161,29 @@ static auto update(lua_State* L) -> int { return 0; } +static auto track_by_id(lua_State* L) -> int { + auto id = luaL_checkinteger(L, -1); + + Bridge* instance = Bridge::Get(L); + auto db = instance->services().database().lock(); + if (!db) { + return 0; + } + + auto track = db->getTrack(id); + if (!track) { + return 0; + } + + pushTrack(L, *track); + + return 1; +} + static const struct luaL_Reg kDatabaseFuncs[] = { {"indexes", indexes}, {"version", version}, {"size", size}, - {"recreate", recreate}, {"update", update}, {NULL, NULL}}; + {"recreate", recreate}, {"update", update}, {"track_by_id", track_by_id}, + {NULL, NULL}}; /* * Struct to be used as userdata for the Lua representation of database records. diff --git a/src/tangara/lua/lua_database.hpp b/src/tangara/lua/lua_database.hpp index 328004ef..51e71758 100644 --- a/src/tangara/lua/lua_database.hpp +++ b/src/tangara/lua/lua_database.hpp @@ -14,6 +14,8 @@ namespace lua { auto db_check_iterator(lua_State*, int stack_pos) -> database::Iterator*; +auto pushTagValue(lua_State* L, const database::TagValue& val) -> void; + auto RegisterDatabaseModule(lua_State*) -> void; } // namespace lua diff --git a/src/tangara/lua/property.cpp b/src/tangara/lua/property.cpp index 1be1fd2d..847bbe15 100644 --- a/src/tangara/lua/property.cpp +++ b/src/tangara/lua/property.cpp @@ -19,6 +19,7 @@ #include "lauxlib.h" #include "lua.h" #include "lua.hpp" +#include "lua/lua_database.hpp" #include "lua/lua_thread.hpp" #include "lvgl.h" #include "memory_resource.hpp" @@ -240,29 +241,6 @@ auto Property::set(const LuaValue& val) -> bool { return true; } -static auto pushTagValue(lua_State* L, const database::TagValue& val) -> void { - std::visit( - [&](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - lua_pushlstring(L, arg.data(), arg.size()); - } else if constexpr (std::is_same_v< - T, std::span>) { - lua_createtable(L, 0, arg.size()); - for (const auto& i : arg) { - lua_pushlstring(L, i.data(), i.size()); - lua_pushboolean(L, true); - lua_rawset(L, -3); - } - } else if constexpr (std::is_same_v) { - lua_pushinteger(L, arg); - } else { - lua_pushnil(L); - } - }, - val); -} - static void pushTrack(lua_State* L, const audio::TrackInfo& track) { lua_newtable(L); From c479d699d059bc58e6850d43b14f2e91c2076e12 Mon Sep 17 00:00:00 2001 From: ailurux Date: Tue, 17 Sep 2024 14:13:05 +1000 Subject: [PATCH 5/8] Implements seeking to saved position for tracks --- lua/browser.lua | 4 +++- src/tangara/audio/audio_events.hpp | 2 ++ src/tangara/audio/audio_fsm.cpp | 2 +- src/tangara/audio/track_queue.cpp | 23 ++++++++++++++++++++++- src/tangara/audio/track_queue.hpp | 1 + src/tangara/lua/lua_queue.cpp | 14 ++++++++++++++ 6 files changed, 43 insertions(+), 3 deletions(-) diff --git a/lua/browser.lua b/lua/browser.lua index 731c1dc6..3d7e3e9d 100644 --- a/lua/browser.lua +++ b/lua/browser.lua @@ -105,8 +105,10 @@ return screen:new{ local track = database.track_by_id(contents) if (track) then print("Track saved position: ", track.saved_position) + queue.play_from(track.filepath, track.saved_position) + else + queue.add(contents) end - queue.add(contents) playback.playing:set(true) backstack.push(playing:new()) end diff --git a/src/tangara/audio/audio_events.hpp b/src/tangara/audio/audio_events.hpp index 56d150b2..89dc28ff 100644 --- a/src/tangara/audio/audio_events.hpp +++ b/src/tangara/audio/audio_events.hpp @@ -106,6 +106,8 @@ struct QueueUpdate : tinyfsm::Event { kBulkLoadingUpdate, }; Reason reason; + + std::optional seek_to_second; }; struct StepUpVolume : tinyfsm::Event {}; diff --git a/src/tangara/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp index 71decd48..dd9f2fde 100644 --- a/src/tangara/audio/audio_fsm.cpp +++ b/src/tangara/audio/audio_fsm.cpp @@ -113,7 +113,7 @@ auto AudioState::emitPlaybackUpdate(bool paused) -> void { void AudioState::react(const QueueUpdate& ev) { SetTrack cmd{ .new_track = std::monostate{}, - .seek_to_second = {}, + .seek_to_second = ev.seek_to_second, }; auto current = sServices->track_queue().current(); diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 2c1faf96..ff24637b 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -85,6 +85,16 @@ auto notifyChanged(bool current_changed, Reason reason) -> void { events::Audio().Dispatch(ev); } +auto notifyPlayFrom(uint32_t start_from_position) -> void { + QueueUpdate ev{ + .current_changed = true, + .reason = Reason::kExplicitUpdate, + .seek_to_second = start_from_position, + }; + events::Ui().Dispatch(ev); + events::Audio().Dispatch(ev); +} + TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker, database::Handle db) : mutex_(), bg_worker_(bg_worker), @@ -109,6 +119,17 @@ auto TrackQueue::current() const -> TrackItem { return val; } +auto TrackQueue::playFromPosition(const std::string& filepath, + uint32_t position) -> void { + clear(); + { + const std::unique_lock lock(mutex_); + playlist_.append(filepath); + updateShuffler(true); + } + notifyPlayFrom(position); +} + auto TrackQueue::currentPosition() const -> size_t { const std::shared_lock lock(mutex_); return position_; @@ -245,7 +266,7 @@ auto TrackQueue::currentPosition(size_t position) -> bool { goTo(position); } - // If we're explicitly setting the position, we want to treat it as though + // If we're explicitly setting the position, we want to treat it as though // the current track has changed, even if the position was the same notifyChanged(true, Reason::kExplicitUpdate); return true; diff --git a/src/tangara/audio/track_queue.hpp b/src/tangara/audio/track_queue.hpp index a8d1dc3a..727b4be0 100644 --- a/src/tangara/audio/track_queue.hpp +++ b/src/tangara/audio/track_queue.hpp @@ -78,6 +78,7 @@ class TrackQueue { auto open() -> bool; auto openPlaylist(const std::string& playlist_file, bool notify = true) -> bool; + auto playFromPosition(const std::string& filepath, uint32_t position) -> void; using Item = std::variant; diff --git a/src/tangara/lua/lua_queue.cpp b/src/tangara/lua/lua_queue.cpp index 7eb32c62..07093390 100644 --- a/src/tangara/lua/lua_queue.cpp +++ b/src/tangara/lua/lua_queue.cpp @@ -79,10 +79,24 @@ static auto queue_open_playlist(lua_State* state) -> int { return 0; } +static auto queue_play_from(lua_State* state) -> int { + Bridge* instance = Bridge::Get(state); + audio::TrackQueue& queue = instance->services().track_queue(); + size_t len = 0; + const char* str = luaL_checklstring(state, 1, &len); + if (!str) { + return 0; + } + auto pos = luaL_checkinteger(state, 2); + queue.playFromPosition(str, pos); + return 0; +} + static const struct luaL_Reg kQueueFuncs[] = { {"add", queue_add}, {"clear", queue_clear}, {"open_playlist", queue_open_playlist}, + {"play_from", queue_play_from}, {NULL, NULL}}; static auto lua_queue(lua_State* state) -> int { From 3be8ae33497c65353dc4e6991745ffbc016d0798 Mon Sep 17 00:00:00 2001 From: ailurux Date: Tue, 17 Sep 2024 14:18:05 +1000 Subject: [PATCH 6/8] Remove logging --- lua/browser.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/browser.lua b/lua/browser.lua index 3d7e3e9d..48c3895f 100644 --- a/lua/browser.lua +++ b/lua/browser.lua @@ -104,7 +104,6 @@ return screen:new{ queue.clear() local track = database.track_by_id(contents) if (track) then - print("Track saved position: ", track.saved_position) queue.play_from(track.filepath, track.saved_position) else queue.add(contents) From e96dcde0852526b33ee522dc0b1df8cdd0bc1253 Mon Sep 17 00:00:00 2001 From: ailurux Date: Thu, 19 Sep 2024 13:26:04 +1000 Subject: [PATCH 7/8] Fix commented issues --- src/tangara/audio/audio_fsm.cpp | 2 +- src/tangara/database/track.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tangara/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp index dd9f2fde..f9823fb3 100644 --- a/src/tangara/audio/audio_fsm.cpp +++ b/src/tangara/audio/audio_fsm.cpp @@ -94,7 +94,7 @@ auto AudioState::emitPlaybackUpdate(bool paused) -> void { // increment a counter. Every 60 counts (ie, every minute) save the current elapsed position if (position && *position > (5 * 60)) { sUpdateCounter++; - if (sUpdateCounter > 60) { + if (sUpdateCounter >= 60) { sUpdateCounter = 0; updateSavedPosition(current.first->uri, *position); } diff --git a/src/tangara/database/track.hpp b/src/tangara/database/track.hpp index 6e2bacce..03fc47b9 100644 --- a/src/tangara/database/track.hpp +++ b/src/tangara/database/track.hpp @@ -174,7 +174,7 @@ struct TrackData { TrackData& operator=(TrackData& other) = delete; auto clone() const -> std::shared_ptr; - bool operator==(const TrackData&) const = delete; + bool operator==(const TrackData&) const = default; }; /* From 7f43d4d1265ce7f456b36f51987c812d35bcd616 Mon Sep 17 00:00:00 2001 From: ailurux Date: Thu, 19 Sep 2024 14:04:13 +1000 Subject: [PATCH 8/8] Add luals stubs for new methods --- luals-stubs/database.lua | 14 ++++++++++++++ luals-stubs/queue.lua | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/luals-stubs/database.lua b/luals-stubs/database.lua index 753961fe..92c2fb8d 100644 --- a/luals-stubs/database.lua +++ b/luals-stubs/database.lua @@ -10,6 +10,19 @@ local database = {} --- @return Index[] function database.indexes() end +--- Returns the track in the database with the id given +--- @param id TrackId +--- @return Track +function database.track_by_id(id) end + + +--- @class Track +--- @field id TrackId The track id of this track +--- @field filepath string The filepath of this track +--- @field saved_position integer The last saved position of this track +--- @field tags table A mapping of any available tags to that tag's value +local Track = {} + --- An iterator is a userdata type that behaves like an ordinary Lua iterator. --- @class Iterator local Iterator = {} @@ -19,6 +32,7 @@ local Iterator = {} --- @class TrackId local TrackId = {} + --- Gets the human-readable text representing this record. The `__tostring` --- metatable function is an alias of this function. --- @class Record diff --git a/luals-stubs/queue.lua b/luals-stubs/queue.lua index 97583587..a0473407 100644 --- a/luals-stubs/queue.lua +++ b/luals-stubs/queue.lua @@ -33,4 +33,10 @@ function queue.next() end --- Moves backward in the play queue, looping back around to the end if repeat is on. function queue.previous() end +--- Play a track starting from a number of seconds in +--- This will replace the existing queue +--- @param filepath string +--- @param seconds_offset integer +function queue.play_from(filepath, seconds_offset) end + return queue