GCC Code Coverage Report


Directory: ./
File: commands/PlaylistCommands.cpp
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 251 283 88.7%
Functions: 31 31 100.0%
Branches: 365 792 46.1%

Line Branch Exec Source
1 /*
2 * This file is part of the Falcon Player (FPP) and is Copyright (C)
3 * 2013-2022 by the Falcon Player Developers.
4 *
5 * The Falcon Player (FPP) is free software, and is covered under
6 * multiple Open Source licenses. Please see the included 'LICENSES'
7 * file for descriptions of what files are covered by each license.
8 *
9 * This source file is covered under the LGPL v2.1 as described in the
10 * included LICENSE.LGPL file.
11 */
12
13 #include "fpp-pch.h"
14
15 #include "../common.h"
16 #include "../log.h"
17 #include <thread> // std::this_thread::sleep_for -- needed directly for NOPCH builds
18
19 #include "Player.h"
20 #include "PlaylistCommands.h"
21 #include "Scheduler.h"
22
23 // A playlist name is the one argument every command in this file needs, and an
24 // empty one is never a playlist: it is a UI that posted with nothing selected,
25 // or a %VAR:name% that resolved to nothing. CommandManager's missing-argument
26 // check (invokeCommand(), Commands.cpp) only catches an argument that is not
27 // there at all - an explicit "" still reaches run() and gets treated as a name.
28 // That is how "Start Playlist At Item" with an empty name matched the (equally
29 // empty) name of the playlist the scheduler thought should be running, deferred
30 // to the scheduler, started nothing, and still returned success, leaving the web
31 // UI to report "Playlist Started" with the player sitting idle (issue #2944).
32 1609 static std::unique_ptr<Command::Result> MissingPlaylistName(const std::vector<std::string>& args,
33 const std::string& command) {
34
5/6
✓ Branch 0 taken 1609 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 1602 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 1602 times.
1609 if (args.empty() || args[0].empty()) {
35 7 LogWarn(VB_COMMAND, "Ignoring \"%s\" - no playlist name was given\n", command.c_str());
36
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 return std::make_unique<Command::ErrorResult>("\"" + command + "\" requires a playlist name");
37 }
38 1602 return nullptr;
39 }
40
41 1888 StopPlaylistCommand::StopPlaylistCommand() :
42
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Stop Now") {
43 1888 }
44 580 std::unique_ptr<Command::Result> StopPlaylistCommand::run(const std::vector<std::string>& args) {
45 580 Player::INSTANCE.StopNow(1);
46 580 return std::make_unique<Command::Result>("Stopped");
47 }
48
49 1888 StopGracefullyPlaylistCommand::StopGracefullyPlaylistCommand() :
50
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Stop Gracefully") {
51 // Optional: run() has always treated a missing argument as "false", and
52 // "Stop Gracefully" with no arguments at all is a normal way to call it.
53 // Saying so here is what keeps CommandManager's missing-argument check
54 // (invokeCommand(), Commands.cpp) from refusing that call.
55
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("loop", "bool", "After Loop", true).setDefaultValue("false"));
56 1888 }
57 6 std::unique_ptr<Command::Result> StopGracefullyPlaylistCommand::run(const std::vector<std::string>& args) {
58 6 bool loop = false;
59
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (args.size()) {
60
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
3 loop = args[0] == "true" || args[0] == "1";
61 }
62 6 Player::INSTANCE.StopGracefully(1, loop);
63 6 return std::make_unique<Command::Result>("Stopping");
64 }
65
66 1888 RestartPlaylistCommand::RestartPlaylistCommand() :
67
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Restart Playlist Item") {
68 1888 }
69 9050 std::unique_ptr<Command::Result> RestartPlaylistCommand::run(const std::vector<std::string>& args) {
70 9050 Player::INSTANCE.RestartItem();
71 9050 return std::make_unique<Command::Result>("Restarting");
72 }
73
74 1888 NextPlaylistCommand::NextPlaylistCommand() :
75
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Next Playlist Item") {
76 1888 }
77 9112 std::unique_ptr<Command::Result> NextPlaylistCommand::run(const std::vector<std::string>& args) {
78 9112 Player::INSTANCE.NextItem();
79 9112 return std::make_unique<Command::Result>("Next Item Playing");
80 }
81
82 1888 PrevPlaylistCommand::PrevPlaylistCommand() :
83
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Prev Playlist Item") {
84 1888 }
85 9080 std::unique_ptr<Command::Result> PrevPlaylistCommand::run(const std::vector<std::string>& args) {
86 9080 Player::INSTANCE.PrevItem();
87 9080 return std::make_unique<Command::Result>("Prev Item Playing");
88 }
89
90 1888 StartPlaylistCommand::StartPlaylistCommand() :
91
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Start Playlist") {
92
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("name", "string", "Playlist Name")
93
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setContentListUrl("api/playlists/playable"));
94
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("repeat", "bool", "Repeat", true).setDefaultValue("false"));
95
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("ifNotRunning", "bool", "If Not Running", true)
96
1/2
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
1888 .setDefaultValue("false")
97
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setHelp("Checks to see if this exact item is already running and "
98 "prevents it from running again."));
99
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("scheduleProtected", "bool", "Protected from Schedule Override", true).setDefaultValue("false"));
100 1888 }
101 993 std::unique_ptr<Command::Result> StartPlaylistCommand::run(const std::vector<std::string>& args) {
102
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 992 times.
993 if (auto missing = MissingPlaylistName(args, name)) {
103 1 return missing;
104 992 }
105 992 bool r = false;
106 992 bool iNR = false;
107 992 bool scheduleProtected = false;
108
1/2
✓ Branch 0 taken 992 times.
✗ Branch 1 not taken.
992 if (args.size() > 1) {
109
3/4
✓ Branch 0 taken 745 times.
✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 745 times.
992 r = args[1] == "true" || args[1] == "1";
110 }
111
1/2
✓ Branch 0 taken 992 times.
✗ Branch 1 not taken.
992 if (args.size() > 2) {
112
2/4
✓ Branch 0 taken 992 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 992 times.
992 iNR = args[2] == "true" || args[2] == "1";
113 }
114
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 989 times.
992 if (args.size() > 3) {
115
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 scheduleProtected = args[3] == "true" || args[3] == "1";
116 }
117
3/12
✗ Branch 0 not taken.
✓ Branch 1 taken 992 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 992 times.
✓ Branch 8 taken 992 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
992 if (!iNR || args[0] != Player::INSTANCE.GetPlaylistName()) {
118 // The stop and the wait below are part of the start: the scheduler
119 // must not act on the player being idle in between.
120
1/2
✓ Branch 0 taken 992 times.
✗ Branch 1 not taken.
992 Player::SwitchScope switching;
121
3/6
✓ Branch 0 taken 992 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 992 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 992 times.
✗ Branch 5 not taken.
992 LogInfo(VB_COMMAND, "StartPlaylistCommand: Requesting playlist '%s', current='%s', status=%d\n",
122 args[0].c_str(), Player::INSTANCE.GetPlaylistName().c_str(), Player::INSTANCE.GetStatus());
123
124 // Always stop if not idle to avoid deferred start mechanism
125
3/4
✓ Branch 0 taken 992 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 875 times.
992 if (Player::INSTANCE.GetStatus() != FPP_STATUS_IDLE) {
126
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 LogInfo(VB_COMMAND, "StartPlaylistCommand: Stopping current playlist\n");
127 // Clear force-stopped flag to allow scheduler to work if needed
128
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 Player::INSTANCE.ClearForceStopped();
129
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 Player::INSTANCE.StopNow(1);
130 // Brief wait to let stop complete - don't wait too long to avoid scheduler interference
131
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 std::this_thread::sleep_for(std::chrono::milliseconds(150));
132
2/4
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
117 LogInfo(VB_COMMAND, "StartPlaylistCommand: After stop wait, status=%d\n", Player::INSTANCE.GetStatus());
133 }
134
1/2
✓ Branch 0 taken 992 times.
✗ Branch 1 not taken.
992 Player::INSTANCE.StartPlaylist(args[0], r, -1, -1, -1, !scheduleProtected);
135 992 }
136 992 return std::make_unique<Command::Result>("Playlist Starting");
137 }
138
139 1888 TogglePlaylistCommand::TogglePlaylistCommand() :
140
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Toggle Playlist") {
141
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("name", "string", "Playlist Name")
142
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setContentListUrl("api/playlists/playable"));
143
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("repeat", "bool", "Repeat", true).setDefaultValue("false"));
144
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("stop", "string", "Stop Type")
145
1/2
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
5664 .setContentList({ "Gracefully", "After Loop", "Now" })
146
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
1888 .setDefaultValue("Gracefully"));
147 1888 }
148 3 std::unique_ptr<Command::Result> TogglePlaylistCommand::run(const std::vector<std::string>& args) {
149
3/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
3 if (auto missing = MissingPlaylistName(args, name)) {
150 1 return missing;
151 2 }
152 2 bool r = false;
153
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 std::string stopType = "Gracefully";
154
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (args.size() > 1) {
155
4/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
2 r = args[1] == "true" || args[1] == "1";
156 }
157
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (args.size() > 2) {
158
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 stopType = args[2];
159 }
160
9/14
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
2 if (Player::INSTANCE.IsPlaying() && Player::INSTANCE.GetPlaylistName() == args[0]) {
161
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (stopType == "Now") {
162
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Player::INSTANCE.StopNow(1);
163 ✗ } else if (stopType == "After Loop") {
164 ✗ Player::INSTANCE.StopGracefully(true, true);
165 } else {
166 ✗ Player::INSTANCE.StopGracefully(true, false);
167 }
168
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 return std::make_unique<Command::Result>("Playlist Stopping");
169 }
170
171
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 LogInfo(VB_COMMAND, "TogglePlaylistCommand: Requesting playlist '%s', current='%s', status=%d\n",
172 args[0].c_str(), Player::INSTANCE.GetPlaylistName().c_str(), Player::INSTANCE.GetStatus());
173
174
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Player::SwitchScope switching; // see StartPlaylistCommand
175 // If a different playlist is playing, stop it first to avoid race conditions
176
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (Player::INSTANCE.GetStatus() != FPP_STATUS_IDLE) {
177 ✗ LogInfo(VB_COMMAND, "TogglePlaylistCommand: Stopping current playlist\n");
178 ✗ Player::INSTANCE.ClearForceStopped();
179 ✗ Player::INSTANCE.StopNow(1);
180 ✗ std::this_thread::sleep_for(std::chrono::milliseconds(150));
181 ✗ LogInfo(VB_COMMAND, "TogglePlaylistCommand: After stop wait, status=%d\n", Player::INSTANCE.GetStatus());
182 }
183
184
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Player::INSTANCE.StartPlaylist(args[0], r);
185
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 return std::make_unique<Command::Result>("Playlist Starting");
186 2 }
187
188 1888 StartPlaylistAtCommand::StartPlaylistAtCommand() :
189
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Start Playlist At Item") {
190
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("name", "string", "Playlist Name")
191
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setContentListUrl("api/playlists"));
192
5/10
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
11328 args.push_back(CommandArg("item", "int", "Item Index").setRange(1, 100));
193
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("repeat", "bool", "Repeat", true).setDefaultValue("false"));
194
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("ifNotRunning", "bool", "If Not Running", true)
195
1/2
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
1888 .setDefaultValue("false")
196
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setHelp("Checks to see if this exact item is already running and "
197 "prevents it from running again."));
198
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("scheduleProtected", "bool", "Protected from Schedule Override", true).setDefaultValue("false"));
199 1888 }
200 18 std::unique_ptr<Command::Result> StartPlaylistAtCommand::run(const std::vector<std::string>& args) {
201
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 if (auto missing = MissingPlaylistName(args, name)) {
202 1 return missing;
203 17 }
204 17 bool r = false;
205 17 bool scheduleProtected = false;
206
207 17 int idx = 1;
208
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (args.size() > 1) {
209 17 idx = std::atoi(args[1].c_str());
210 }
211 17 bool iNR = false;
212
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (args.size() > 2) {
213
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
17 r = args[2] == "true" || args[2] == "1";
214 }
215
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (args.size() > 3) {
216
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
17 iNR = args[3] == "true" || args[3] == "1";
217 }
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (args.size() > 4) {
219 ✗ scheduleProtected = args[4] == "true" || args[4] == "1";
220 }
221
3/12
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 17 times.
✓ Branch 8 taken 17 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
17 if (!iNR || args[0] != Player::INSTANCE.GetPlaylistName()) {
222 17 int scheduledRepeat = 0;
223
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 std::string playlistName = scheduler->GetPlaylistThatShouldBePlaying(scheduledRepeat);
224 17 bool repeat = scheduledRepeat;
225
226
3/6
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
17 LogInfo(VB_COMMAND, "StartPlaylistAtCommand: args[0]='%s', status=%d, currentPlaylist='%s', scheduledPlaylist='%s'\n",
227 args[0].c_str(), Player::INSTANCE.GetStatus(),
228 Player::INSTANCE.GetPlaylistName().c_str(), playlistName.c_str());
229
230 // Only defer to scheduler if we're idle AND the requested playlist matches what should be scheduled
231 // AND it's not currently being played. This prevents the race condition where we're playing a
232 // scheduled background playlist and want to start a different playlist via API.
233
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
24 if ((Player::INSTANCE.GetStatus() == FPP_STATUS_IDLE) &&
234
3/6
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17 times.
24 (args[0] == playlistName) &&
235 (r == repeat)) {
236 ✗ LogInfo(VB_COMMAND, "StartPlaylistAtCommand: Deferring to scheduler\n");
237 // Allow the scheduler to restart even if force stopped
238 ✗ Player::INSTANCE.ClearForceStopped();
239 ✗ scheduler->CheckIfShouldBePlayingNow(1);
240 } else {
241
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 Player::SwitchScope switching; // see StartPlaylistCommand
242 // Always directly start the playlist if:
243 // 1. Something is already playing (even if it's the scheduled playlist)
244 // 2. The requested playlist doesn't match what's scheduled
245 // 3. The repeat mode doesn't match
246
247 // If playing a different playlist, stop the current one first
248
3/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 7 times.
27 if ((Player::INSTANCE.GetStatus() != FPP_STATUS_IDLE) &&
249
7/10
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
27 (Player::INSTANCE.GetPlaylistName() != args[0])) {
250
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 LogInfo(VB_COMMAND, "StartPlaylistAtCommand: Stopping current playlist '%s' before starting '%s'\n",
251 Player::INSTANCE.GetPlaylistName().c_str(), args[0].c_str());
252
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Player::INSTANCE.StopNow(1);
253 }
254
255
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 LogInfo(VB_COMMAND, "StartPlaylistAtCommand: Starting playlist '%s'\n", args[0].c_str());
256
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 Player::INSTANCE.StartPlaylist(args[0], r, idx - 1, -1, -1, !scheduleProtected);
257 17 }
258 17 }
259 17 return std::make_unique<Command::Result>("Playlist Starting");
260 }
261
262 1888 StartPlaylistAtRandomCommand::StartPlaylistAtRandomCommand() :
263
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Start Playlist At Random Item") {
264
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("name", "string", "Playlist Name")
265
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setContentListUrl("api/playlists"));
266
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("repeat", "bool", "Repeat", true).setDefaultValue("false"));
267
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("ifNotRunning", "bool", "If Not Running", true)
268
1/2
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
1888 .setDefaultValue("false")
269
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setHelp("Checks to see if this exact item is already running and "
270 "prevents it from running again."));
271 1888 }
272 1 std::unique_ptr<Command::Result> StartPlaylistAtRandomCommand::run(const std::vector<std::string>& args) {
273
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (auto missing = MissingPlaylistName(args, name)) {
274 1 return missing;
275 ✗ }
276 ✗ bool r = false;
277 ✗ bool iNR = false;
278 ✗ if (args.size() > 1) {
279 ✗ r = args[1] == "true" || args[1] == "1";
280 }
281 ✗ if (args.size() > 2) {
282 ✗ iNR = args[2] == "true" || args[2] == "1";
283 }
284 ✗ if (!iNR || args[0] != Player::INSTANCE.GetPlaylistName()) {
285 ✗ Player::SwitchScope switching; // see StartPlaylistCommand
286 ✗ LogInfo(VB_COMMAND, "StartPlaylistAtRandomCommand: Requesting playlist '%s', current='%s', status=%d\n",
287 args[0].c_str(), Player::INSTANCE.GetPlaylistName().c_str(), Player::INSTANCE.GetStatus());
288
289 // Always stop if not idle to avoid deferred start mechanism
290 ✗ if (Player::INSTANCE.GetStatus() != FPP_STATUS_IDLE) {
291 ✗ LogInfo(VB_COMMAND, "StartPlaylistAtRandomCommand: Stopping current playlist\n");
292 // Clear force-stopped flag to allow scheduler to work if needed
293 ✗ Player::INSTANCE.ClearForceStopped();
294 ✗ Player::INSTANCE.StopNow(1);
295 // Brief wait to let stop complete - don't wait too long to avoid scheduler interference
296 ✗ std::this_thread::sleep_for(std::chrono::milliseconds(150));
297 ✗ LogInfo(VB_COMMAND, "StartPlaylistAtRandomCommand: After stop wait, status=%d\n", Player::INSTANCE.GetStatus());
298 }
299 ✗ Player::INSTANCE.StartPlaylist(args[0], r, -2);
300 ✗ }
301 ✗ return std::make_unique<Command::Result>("Playlist Starting");
302 }
303
304 1888 InsertPlaylistCommand::InsertPlaylistCommand() :
305
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
7552 Command("Insert Playlist After Current", "After the current item of the currently running playlist is complete, run the new playlist. When complete, resumes the original playlist at the next position.") {
306
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("name", "string", "Playlist Name")
307
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setContentListUrl("api/playlists/playable"));
308
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("startItem", "int", "Start Item Index", true).setRange(-1, 100).setDefaultValue("-1"));
309
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("endItem", "int", "End Item Index", true).setRange(-1, 100).setDefaultValue("-1"));
310
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("ifNotRunning", "bool", "If Not Running", true)
311
1/2
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
1888 .setDefaultValue("false")
312
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setHelp("Checks to see if this exact item is already running and "
313 "prevents it from running again."));
314 1888 }
315 10 std::unique_ptr<Command::Result> InsertPlaylistCommand::run(const std::vector<std::string>& args) {
316
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (auto missing = MissingPlaylistName(args, name)) {
317 1 return missing;
318 9 }
319 9 int start = -1;
320 9 int end = -1;
321 9 bool iNR = false;
322
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (args.size() > 1) {
323 9 start = std::atoi(args[1].c_str());
324 }
325
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (args.size() > 2) {
326 9 end = std::atoi(args[2].c_str());
327 }
328
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (args.size() > 3) {
329
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 iNR = args[3] == "true" || args[3] == "1";
330 }
331
3/12
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
9 if (!iNR || args[0] != Player::INSTANCE.GetPlaylistName()) {
332 9 Player::INSTANCE.InsertPlaylistAsNext(args[0], start > 0 ? start - 1 : -1, end > 0 ? end - 1 : -1);
333 }
334 9 return std::make_unique<Command::Result>("Playlist Inserted");
335 }
336
337 1888 InsertPlaylistImmediate::InsertPlaylistImmediate() :
338
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
7552 Command("Insert Playlist Immediate", "If possible, pauses the currently running playlist and then runs the new playlist. When complete, resumes the original playlist where it was paused.") {
339
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("name", "string", "Playlist Name")
340
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setContentListUrl("api/playlists/playable"));
341
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("startItem", "int", "Start Item Index", true).setRange(0, 100).setDefaultValue("0"));
342
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("endItem", "int", "End Item Index", true).setRange(0, 100).setDefaultValue("0"));
343
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("ifNotRunning", "bool", "If Not Running", true)
344
1/2
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
1888 .setDefaultValue("false")
345
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setHelp("Checks to see if this exact item is already running and "
346 "prevents it from running again."));
347 1888 }
348 577 std::unique_ptr<Command::Result> InsertPlaylistImmediate::run(const std::vector<std::string>& args) {
349
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 576 times.
577 if (auto missing = MissingPlaylistName(args, name)) {
350 1 return missing;
351 576 }
352 576 int start = -1;
353 576 int end = -1;
354 576 bool iNR = false;
355
1/2
✓ Branch 0 taken 576 times.
✗ Branch 1 not taken.
576 if (args.size() > 1) {
356 576 start = std::atoi(args[1].c_str());
357 }
358
1/2
✓ Branch 0 taken 576 times.
✗ Branch 1 not taken.
576 if (args.size() > 2) {
359 576 end = std::atoi(args[2].c_str());
360 }
361
1/2
✓ Branch 0 taken 576 times.
✗ Branch 1 not taken.
576 if (args.size() > 3) {
362
2/4
✓ Branch 0 taken 576 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 576 times.
576 iNR = args[3] == "true" || args[3] == "1";
363 }
364
3/12
✗ Branch 0 not taken.
✓ Branch 1 taken 576 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 576 times.
✓ Branch 8 taken 576 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
576 if (!iNR || args[0] != Player::INSTANCE.GetPlaylistName()) {
365 576 Player::INSTANCE.InsertPlaylistImmediate(args[0], start > 0 ? start - 1 : -1, end > 0 ? end - 1 : -1);
366 }
367 576 return std::make_unique<Command::Result>("Playlist Inserted");
368 }
369
370 1888 InsertRandomItemFromPlaylistCommand::InsertRandomItemFromPlaylistCommand() :
371
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
7552 Command("Insert Random Item From Playlist", "Run a random item from the given playlist. When complete, resumes the original playlist.") {
372
4/8
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
13216 args.push_back(CommandArg("name", "string", "Playlist Name")
373
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
3776 .setContentListUrl("api/playlists/playable"));
374
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("immediate", "bool", "Immediate", true).setDefaultValue("false"));
375 1888 }
376 7 std::unique_ptr<Command::Result> InsertRandomItemFromPlaylistCommand::run(const std::vector<std::string>& args) {
377
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (auto missing = MissingPlaylistName(args, name)) {
378 1 return missing;
379 6 }
380 6 bool immediate = false;
381
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (args.size() > 1) {
382
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
6 immediate = args[1] == "true" || args[1] == "1";
383 }
384
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (immediate) {
385 6 Player::INSTANCE.InsertPlaylistImmediate(args[0], -2, 0);
386 } else {
387 ✗ Player::INSTANCE.InsertPlaylistAsNext(args[0], -2, 0);
388 }
389 6 return std::make_unique<Command::Result>("Playlist Inserted");
390 }
391
392 1888 PlaylistPauseCommand::PlaylistPauseCommand() :
393
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
7552 Command("Pause Playlist", "If possible, pauses the currently running playlist. This command can not be run from inside a playlist") {
394 1888 }
395 15 std::unique_ptr<Command::Result> PlaylistPauseCommand::run(const std::vector<std::string>& args) {
396 15 Player::INSTANCE.Pause();
397 15 return std::make_unique<Command::Result>("Playlist Paused");
398 }
399
400 1888 PlaylistResumeCommand::PlaylistResumeCommand() :
401
2/4
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
3776 Command("Resume Playlist") {
402 1888 }
403 13 std::unique_ptr<Command::Result> PlaylistResumeCommand::run(const std::vector<std::string>& args) {
404 13 Player::INSTANCE.Resume();
405 13 return std::make_unique<Command::Result>("Playlist Restarted");
406 }
407
408 1888 SetPlaylistRepeatCommand::SetPlaylistRepeatCommand() :
409
3/6
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
7552 Command("Set Playlist Repeat", "Turns repeat on or off for the running playlist. Nothing is started, stopped or restarted; the new setting is read when the playlist reaches the end of its current loop.") {
410
6/12
✓ Branch 0 taken 1888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1888 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1888 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1888 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1888 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1888 times.
✗ Branch 11 not taken.
11328 args.push_back(CommandArg("repeat", "bool", "Repeat").setDefaultValue("true"));
411 1888 }
412 4 std::unique_ptr<Command::Result> SetPlaylistRepeatCommand::run(const std::vector<std::string>& args) {
413 4 bool repeat = true;
414
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (args.size()) {
415
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
4 repeat = args[0] == "true" || args[0] == "1";
416 }
417
418 // Repeat is a property of a *running* playlist, and only there. The idle
419 // playlist has been Cleanup()ed back to repeat=0, Play() reloads the value
420 // from the playlist file and then overwrites it with whatever the start
421 // command passed, and GetCurrentStatus() reports a hard-coded "0" while
422 // idle. Setting it now would therefore report success, never show up in
423 // /api/fppd/status, and be thrown away by the next start - so refuse
424 // instead of lying about it (issue #2971).
425
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (Player::INSTANCE.GetStatus() == FPP_STATUS_IDLE) {
426 1 LogWarn(VB_COMMAND, "Ignoring \"Set Playlist Repeat\" - no playlist is running\n");
427
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 return std::make_unique<Command::ErrorResult>("No playlist is running; pass the repeat flag to \"Start Playlist\" instead");
428 }
429
430
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 Player::INSTANCE.SetRepeat(repeat ? 1 : 0);
431
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 return std::make_unique<Command::Result>(repeat ? "Repeat Enabled" : "Repeat Disabled");
432 }
433