diff options
| author | Carl Hetherington <cth@carlh.net> | 2026-01-31 00:59:50 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2026-02-16 01:20:39 +0100 |
| commit | 0e057a0fc38586ea55746173ca11446eef6d5865 (patch) | |
| tree | 93cb177c37436ae5dbab075c05ee9fa7da939006 | |
| parent | 651722fb46269ff06e5ff41227fd874ed5fd9854 (diff) | |
Support playlist load from the web interface.
| -rw-r--r-- | src/lib/http_server.cc | 18 | ||||
| -rw-r--r-- | src/lib/http_server.h | 1 | ||||
| -rw-r--r-- | src/wx/player_frame.cc | 29 | ||||
| -rw-r--r-- | src/wx/player_frame.h | 8 | ||||
| -rw-r--r-- | src/wx/playlist_controls.cc | 4 | ||||
| -rw-r--r-- | web/index.html | 10 | ||||
| -rw-r--r-- | web/playlists.html | 4 |
7 files changed, 66 insertions, 8 deletions
diff --git a/src/lib/http_server.cc b/src/lib/http_server.cc index 088a4c2bc..43b4cbb84 100644 --- a/src/lib/http_server.cc +++ b/src/lib/http_server.cc @@ -28,12 +28,14 @@ #include "show_playlist_list.h" #include "util.h" #include "variant.h" +#include <dcp/raw_convert.h> #include <nlohmann/json.hpp> #include <boost/algorithm/string.hpp> #include <stdexcept> using std::make_pair; +using std::pair; using std::runtime_error; using std::shared_ptr; using std::string; @@ -207,6 +209,22 @@ HTTPServer::post_request(string const& url, string const& body) auto response = Response(303); response.add_header("Location", "/"); return response; + } else if (url == "/api/v1/load-playlist") { + nlohmann::json details = nlohmann::json::parse(body); + vector<pair<string, boost::optional<float>>> entries; + for (auto const& entry: details["entries"]) { + if (!entry.contains("uuid")) { + continue; + } + boost::optional<float> crop; + if (entry.contains("crop_to_ratio")) { + crop = entry["crop_to_ratio"]; + } + entries.push_back({entry["uuid"], crop}); + } + emit(boost::bind(boost::ref(LoadPlaylist), entries)); + /* XXX: return a failure if LoadPlaylist fails */ + return Response(200); } else if (url == "/api/v1/playlists") { ShowPlaylist playlist("New Playlist"); ShowPlaylistList list; diff --git a/src/lib/http_server.h b/src/lib/http_server.h index 56f75047c..7ca5fa534 100644 --- a/src/lib/http_server.h +++ b/src/lib/http_server.h @@ -65,6 +65,7 @@ public: boost::signals2::signal<void ()> Play; boost::signals2::signal<void ()> Stop; + boost::signals2::signal<void (std::vector<std::pair<std::string, boost::optional<float>>>)> LoadPlaylist; void set_playing(bool playing) { boost::mutex::scoped_lock lm(_mutex); diff --git a/src/wx/player_frame.cc b/src/wx/player_frame.cc index afc43b807..5097c5e00 100644 --- a/src/wx/player_frame.cc +++ b/src/wx/player_frame.cc @@ -71,6 +71,7 @@ LIBDCP_ENABLE_WARNINGS using std::dynamic_pointer_cast; using std::exception; using std::make_shared; +using std::pair; using std::shared_ptr; using std::string; using std::weak_ptr; @@ -1168,6 +1169,7 @@ PlayerFrame::setup_http_server() _http_server.reset(new HTTPServer(config->player_http_server_port())); _http_server->Play.connect(boost::bind(&FilmViewer::start, &_viewer)); _http_server->Stop.connect(boost::bind(&FilmViewer::stop, &_viewer)); + _http_server->LoadPlaylist.connect(boost::bind(&PlayerFrame::load_pair_playlist, this, _1)); _http_server_thread = boost::thread(boost::bind(&HTTPServer::run, _http_server.get())); } } catch (std::exception& e) { @@ -1330,7 +1332,18 @@ get_kdm_from_directory(shared_ptr<DCPContent> dcp) bool -PlayerFrame::set_playlist(vector<ShowPlaylistEntry> playlist) +PlayerFrame::load_playlist(vector<ShowPlaylistEntry> const& playlist) +{ + vector<pair<string, optional<float>>> details; + for (auto const& entry: playlist) { + details.push_back({entry.uuid(), entry.crop_to_ratio()}); + } + return load_pair_playlist(details); +} + + +bool +PlayerFrame::load_pair_playlist(vector<pair<string, optional<float>>> const& playlist) { bool was_playing = false; if (_viewer.playing()) { @@ -1346,7 +1359,7 @@ PlayerFrame::set_playlist(vector<ShowPlaylistEntry> playlist) auto const store = ShowPlaylistContentStore::instance(); for (auto const& entry: playlist) { dialog.Pulse(); - auto content = store->get(entry); + auto content = store->get(entry.first); if (!content) { error_dialog(this, _("This playlist cannot be loaded as some content is missing.")); _playlist.clear(); @@ -1374,7 +1387,7 @@ PlayerFrame::set_playlist(vector<ShowPlaylistEntry> playlist) return false; } } - _playlist.push_back({content, entry.crop_to_ratio()}); + _playlist.push_back({content, entry.second}); } take_playlist_entry(); @@ -1389,6 +1402,16 @@ PlayerFrame::set_playlist(vector<ShowPlaylistEntry> playlist) } +void +PlayerFrame::clear_playlist() +{ + _playlist.clear(); + _playlist_position = 0; + take_playlist_entry(); + _controls->playlist_changed(); +} + + /** Stop the viewer, take the thing at _playlist_position and prepare to play it. * Set up to play nothing if the playlist is empty, or we're off the * end of it. diff --git a/src/wx/player_frame.h b/src/wx/player_frame.h index e50bc7995..7663aa110 100644 --- a/src/wx/player_frame.h +++ b/src/wx/player_frame.h @@ -71,10 +71,14 @@ public: void load_stress_script(boost::filesystem::path path); void idle(); - /** Set the playlist. If we're currently playing, this will stop whatever is + /** Load some ShowPlaylistEntrys and set our playlist to them + * If we're currently playing, this will stop whatever is * happening now and start playing this playlist. + * @return true on success, false on failure */ - bool set_playlist(std::vector<ShowPlaylistEntry> playlist); + bool load_playlist(std::vector<ShowPlaylistEntry> const& playlist); + bool load_pair_playlist(std::vector<std::pair<std::string, boost::optional<float>>> const& playlist); + void clear_playlist(); std::vector<std::shared_ptr<Content>> playlist() const; diff --git a/src/wx/playlist_controls.cc b/src/wx/playlist_controls.cc index a0f91b00f..8618f7921 100644 --- a/src/wx/playlist_controls.cc +++ b/src/wx/playlist_controls.cc @@ -202,7 +202,7 @@ PlaylistControls::stopped() void PlaylistControls::play_clicked() { - if (_player->set_playlist(_next_playlist)) { + if (_player->load_playlist(_next_playlist)) { _viewer.start(); } } @@ -240,7 +240,7 @@ PlaylistControls::stop_clicked() _paused = false; _viewer.stop(); _viewer.seek(DCPTime(), true); - _player->set_playlist({}); + _player->clear_playlist(); } diff --git a/web/index.html b/web/index.html index b0b5b4505..91e3e0bf1 100644 --- a/web/index.html +++ b/web/index.html @@ -18,6 +18,13 @@ setInterval(function() { }); }, 250); function play() { + entries = []; + var nextPlaylist = document.getElementById('next-playlist').children[0].children; + for (var i = 0; i < nextPlaylist.length; i++) { + entries.push({"uuid": nextPlaylist[i].uuid, "crop_to_ratio": nextPlaylist[i].crop_to_ratio}); + } + console.log(JSON.stringify({"entries": entries})); + fetch("/api/v1/load-playlist", { method: "POST", body: JSON.stringify({"entries": entries}) }); fetch("/api/v1/play", { method: "POST" }); } function stop() { @@ -49,9 +56,10 @@ function showPlaylists() data.content.forEach(content => { var li = document.createElement("li"); li.appendChild(document.createTextNode(content.name)); + li.uuid = content.uuid; + li.crop_to_ratio = content.crop_to_ratio; ul.appendChild(li); }); - console.log(data); }) }); }; diff --git a/web/playlists.html b/web/playlists.html index 3d2e37f41..723b2ec6c 100644 --- a/web/playlists.html +++ b/web/playlists.html @@ -306,6 +306,8 @@ ul#content { SIDEBAR +<div style="margin-left: 15%;"> + <div style="width: 45%; display: inline-block; margin-right: 3em;"> <p>Playlists: <button onclick="newPlaylist();">Add</button> <button id="remove-playlist" onclick="removeSelectedPlaylist();">Remove</button> <ul id="playlists"> @@ -324,6 +326,8 @@ SIDEBAR </ul> </div> +</div> + </body> </html> |
