1 /*GRB*
2
3 Gerbera - https://gerbera.io/
4
5 config_load.cc - this file is part of Gerbera.
6
7 Copyright (C) 2020-2021 Gerbera Contributors
8
9 Gerbera is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2
11 as published by the Free Software Foundation.
12
13 Gerbera is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Gerbera. If not, see <http://www.gnu.org/licenses/>.
20
21 $Id$
22 */
23
24 /// \file config_load.cc
25
26 #include "pages.h" // API
27
28 #include <fmt/chrono.h>
29 #include <numeric>
30
31 #include "config/client_config.h"
32 #include "config/config_definition.h"
33 #include "config/config_setup.h"
34 #include "config/directory_tweak.h"
35 #include "config/dynamic_content.h"
36 #include "content/autoscan.h"
37 #include "content/content_manager.h"
38 #include "database/database.h"
39 #include "metadata/metadata_handler.h"
40 #include "transcoding/transcoding.h"
41 #include "upnp_xml.h"
42 #include "util/upnp_clients.h"
43
ConfigLoad(std::shared_ptr<ContentManager> content)44 Web::ConfigLoad::ConfigLoad(std::shared_ptr<ContentManager> content)
45 : WebRequestHandler(std::move(content))
46 {
47 try {
48 if (this->database) {
49 dbEntries = this->database->getConfigValues();
50 } else {
51 log_error("configLoad database missing");
52 }
53 } catch (const std::runtime_error& e) {
54 log_error("configLoad {}", e.what());
55 }
56 }
57
addTypeMeta(pugi::xml_node & meta,const std::shared_ptr<ConfigSetup> & cs)58 void Web::ConfigLoad::addTypeMeta(pugi::xml_node& meta, const std::shared_ptr<ConfigSetup>& cs)
59 {
60 auto info = meta.append_child("item");
61 info.append_attribute("item") = cs->getUniquePath().c_str();
62 info.append_attribute("id") = fmt::format("{:03d}", cs->option).c_str();
63 info.append_attribute("type") = cs->getTypeString().c_str();
64 info.append_attribute("value") = cs->getDefaultValue().c_str();
65 info.append_attribute("help") = cs->getHelp();
66 }
67
createItem(pugi::xml_node & item,const std::string & name,config_option_t id,config_option_t aid,const std::shared_ptr<ConfigSetup> & cs)68 void Web::ConfigLoad::createItem(pugi::xml_node& item, const std::string& name, config_option_t id, config_option_t aid, const std::shared_ptr<ConfigSetup>& cs)
69 {
70 allItems[name] = &item;
71 item.append_attribute("item") = name.c_str();
72 item.append_attribute("id") = fmt::format("{:03d}", id).c_str();
73 item.append_attribute("aid") = fmt::format("{:03d}", aid).c_str();
74 if (std::any_of(dbEntries.begin(), dbEntries.end(), [=](auto&& s) { return s.item == name; })) {
75 item.append_attribute("status") = "unchanged";
76 item.append_attribute("source") = "database";
77 } else {
78 item.append_attribute("status") = !cs || !cs->isDefaultValueUsed() ? "unchanged" : "default";
79 item.append_attribute("source") = !cs || !cs->isDefaultValueUsed() ? "config.xml" : "default";
80 }
81 item.append_attribute("origValue") = config->getOrigValue(name).c_str();
82 item.append_attribute("defaultValue") = cs ? cs->getDefaultValue().c_str() : "";
83 }
84
85 template <typename T>
setValue(pugi::xml_node & item,const T & value)86 void Web::ConfigLoad::setValue(pugi::xml_node& item, const T& value)
87 {
88 static_assert(fmt::has_formatter<T, fmt::format_context>::value, "T must be formattable");
89 item.append_attribute("value") = fmt::to_string(value).c_str();
90 }
91
92 template <>
setValue(pugi::xml_node & item,const std::string & value)93 void Web::ConfigLoad::setValue(pugi::xml_node& item, const std::string& value)
94 {
95 item.append_attribute("value") = value.c_str();
96 }
97
98 template <>
setValue(pugi::xml_node & item,const std::string_view & value)99 void Web::ConfigLoad::setValue(pugi::xml_node& item, const std::string_view& value)
100 {
101 item.append_attribute("value") = value.data();
102 }
103
104 template <>
setValue(pugi::xml_node & item,const fs::path & value)105 void Web::ConfigLoad::setValue(pugi::xml_node& item, const fs::path& value)
106 {
107 item.append_attribute("value") = value.c_str();
108 }
109
110 /// \brief: process config_load request
process()111 void Web::ConfigLoad::process()
112 {
113 check_request();
114 auto root = xmlDoc->document_element();
115 auto values = root.append_child("values");
116
117 // set handling of json properties
118 xml2JsonHints->setArrayName(values, "item");
119 xml2JsonHints->setFieldType("item", "string");
120 xml2JsonHints->setFieldType("id", "string");
121 xml2JsonHints->setFieldType("aid", "string");
122 xml2JsonHints->setFieldType("value", "string");
123 xml2JsonHints->setFieldType("origValue", "string");
124
125 log_debug("Sending Config to web!");
126
127 // generate meta info for ui
128 auto meta = root.append_child("types");
129 xml2JsonHints->setArrayName(meta, "item");
130 for (auto&& cs : ConfigDefinition::getOptionList()) {
131 addTypeMeta(meta, cs);
132 }
133
134 // write database status
135 {
136 auto item = values.append_child("item");
137 createItem(item, "/status/attribute::total", CFG_MAX, CFG_MAX);
138 setValue(item, database->getTotalFiles());
139 item = values.append_child("item");
140 createItem(item, "/status/attribute::virtual", CFG_MAX, CFG_MAX);
141 setValue(item, database->getTotalFiles(true));
142
143 item = values.append_child("item");
144 createItem(item, "/status/attribute::audio", CFG_MAX, CFG_MAX);
145 setValue(item, database->getTotalFiles(false, "audio"));
146 item = values.append_child("item");
147 createItem(item, "/status/attribute::video", CFG_MAX, CFG_MAX);
148 setValue(item, database->getTotalFiles(false, "video"));
149 item = values.append_child("item");
150 createItem(item, "/status/attribute::image", CFG_MAX, CFG_MAX);
151 setValue(item, database->getTotalFiles(false, "image"));
152
153 item = values.append_child("item");
154 createItem(item, "/status/attribute::audioVirtual", CFG_MAX, CFG_MAX);
155 setValue(item, database->getTotalFiles(true, "audio"));
156 item = values.append_child("item");
157 createItem(item, "/status/attribute::videoVirtual", CFG_MAX, CFG_MAX);
158 setValue(item, database->getTotalFiles(true, "video"));
159 item = values.append_child("item");
160 createItem(item, "/status/attribute::imageVirtual", CFG_MAX, CFG_MAX);
161 setValue(item, database->getTotalFiles(true, "image"));
162 }
163
164 // write all values with simple type (string, int, bool)
165 for (auto&& option : ConfigOptionIterator()) {
166 try {
167 auto scs = ConfigDefinition::findConfigSetup(option);
168 auto item = values.append_child("item");
169 createItem(item, scs->getItemPath(ITEM_PATH_ROOT), option, option, scs);
170
171 log_debug(" Option {:03d} {} = {}", option, scs->getItemPath(), scs->getCurrentValue().c_str());
172 setValue(item, scs->getCurrentValue());
173 } catch (const std::runtime_error& e) {
174 log_warning("Option {:03d} {}", option, e.what());
175 }
176 }
177
178 // write client configuration
179 auto cs = ConfigDefinition::findConfigSetup(CFG_CLIENTS_LIST);
180 auto clientConfig = cs->getValue()->getClientConfigListOption();
181 for (std::size_t i = 0; i < clientConfig->size(); i++) {
182 auto client = clientConfig->get(i);
183
184 auto item = values.append_child("item");
185 createItem(item, cs->getItemPath(i, ATTR_CLIENTS_CLIENT_FLAGS), cs->option, ATTR_CLIENTS_CLIENT_FLAGS, cs);
186 setValue(item, ClientConfig::mapFlags(client->getFlags()));
187
188 item = values.append_child("item");
189 createItem(item, cs->getItemPath(i, ATTR_CLIENTS_CLIENT_IP), cs->option, ATTR_CLIENTS_CLIENT_IP, cs);
190 setValue(item, client->getIp());
191
192 item = values.append_child("item");
193 createItem(item, cs->getItemPath(i, ATTR_CLIENTS_CLIENT_USERAGENT), cs->option, ATTR_CLIENTS_CLIENT_USERAGENT, cs);
194 setValue(item, client->getUserAgent());
195 }
196 if (clientConfig->size() == 0) {
197 auto item = values.append_child("item");
198 createItem(item, cs->getItemPath(ITEM_PATH_NEW, ATTR_CLIENTS_CLIENT_FLAGS), cs->option, ATTR_CLIENTS_CLIENT_FLAGS, ConfigDefinition::findConfigSetup(ATTR_CLIENTS_CLIENT_FLAGS));
199
200 item = values.append_child("item");
201 createItem(item, cs->getItemPath(ITEM_PATH_NEW, ATTR_CLIENTS_CLIENT_IP), cs->option, ATTR_CLIENTS_CLIENT_IP, ConfigDefinition::findConfigSetup(ATTR_CLIENTS_CLIENT_IP));
202
203 item = values.append_child("item");
204 createItem(item, cs->getItemPath(ITEM_PATH_NEW, ATTR_CLIENTS_CLIENT_USERAGENT), cs->option, ATTR_CLIENTS_CLIENT_USERAGENT, ConfigDefinition::findConfigSetup(ATTR_CLIENTS_CLIENT_USERAGENT));
205 }
206
207 // write import tweaks
208 cs = ConfigDefinition::findConfigSetup(CFG_IMPORT_DIRECTORIES_LIST);
209 auto directoryConfig = cs->getValue()->getDirectoryTweakOption();
210 for (std::size_t i = 0; i < directoryConfig->size(); i++) {
211 auto dir = directoryConfig->get(i);
212
213 auto item = values.append_child("item");
214 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_LOCATION), cs->option, ATTR_DIRECTORIES_TWEAK_LOCATION);
215 setValue(item, dir->getLocation());
216
217 item = values.append_child("item");
218 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_INHERIT), cs->option, ATTR_DIRECTORIES_TWEAK_INHERIT);
219 setValue(item, dir->getInherit());
220
221 item = values.append_child("item");
222 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_RECURSIVE), cs->option, ATTR_DIRECTORIES_TWEAK_RECURSIVE);
223 setValue(item, dir->getRecursive());
224
225 item = values.append_child("item");
226 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_HIDDEN), cs->option, ATTR_DIRECTORIES_TWEAK_HIDDEN);
227 setValue(item, dir->getHidden());
228
229 item = values.append_child("item");
230 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_CASE_SENSITIVE), cs->option, ATTR_DIRECTORIES_TWEAK_CASE_SENSITIVE);
231 setValue(item, dir->getCaseSensitive());
232
233 item = values.append_child("item");
234 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_FOLLOW_SYMLINKS), cs->option, ATTR_DIRECTORIES_TWEAK_FOLLOW_SYMLINKS);
235 setValue(item, dir->getFollowSymlinks());
236
237 item = values.append_child("item");
238 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_META_CHARSET), cs->option, ATTR_DIRECTORIES_TWEAK_META_CHARSET);
239 setValue(item, dir->hasMetaCharset() ? dir->getMetaCharset() : "");
240
241 item = values.append_child("item");
242 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_FANART_FILE), cs->option, ATTR_DIRECTORIES_TWEAK_FANART_FILE);
243 setValue(item, dir->hasFanArtFile() ? dir->getFanArtFile() : "");
244
245 item = values.append_child("item");
246 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_RESOURCE_FILE), cs->option, ATTR_DIRECTORIES_TWEAK_RESOURCE_FILE);
247 setValue(item, dir->hasResourceFile() ? dir->getResourceFile() : "");
248
249 item = values.append_child("item");
250 createItem(item, cs->getItemPath(i, ATTR_DIRECTORIES_TWEAK_SUBTILTE_FILE), cs->option, ATTR_DIRECTORIES_TWEAK_SUBTILTE_FILE);
251 setValue(item, dir->hasSubTitleFile() ? dir->getSubTitleFile() : "");
252 }
253
254 // write dynamic content
255 cs = ConfigDefinition::findConfigSetup(CFG_SERVER_DYNAMIC_CONTENT_LIST);
256 auto dynContent = cs->getValue()->getDynamicContentListOption();
257 for (std::size_t i = 0; i < dynContent->size(); i++) {
258 auto cont = dynContent->get(i);
259
260 auto item = values.append_child("item");
261 createItem(item, cs->getItemPath(i, ATTR_DYNAMIC_CONTAINER_LOCATION), cs->option, ATTR_DYNAMIC_CONTAINER_LOCATION);
262 setValue(item, cont->getLocation());
263
264 item = values.append_child("item");
265 createItem(item, cs->getItemPath(i, ATTR_DYNAMIC_CONTAINER_IMAGE), cs->option, ATTR_DYNAMIC_CONTAINER_IMAGE);
266 setValue(item, cont->getImage());
267
268 item = values.append_child("item");
269 createItem(item, cs->getItemPath(i, ATTR_DYNAMIC_CONTAINER_TITLE), cs->option, ATTR_DYNAMIC_CONTAINER_TITLE);
270 setValue(item, cont->getTitle());
271
272 item = values.append_child("item");
273 createItem(item, cs->getItemPath(i, ATTR_DYNAMIC_CONTAINER_FILTER), cs->option, ATTR_DYNAMIC_CONTAINER_FILTER);
274 setValue(item, cont->getFilter());
275
276 item = values.append_child("item");
277 createItem(item, cs->getItemPath(i, ATTR_DYNAMIC_CONTAINER_SORT), cs->option, ATTR_DYNAMIC_CONTAINER_SORT);
278 setValue(item, cont->getSort());
279 }
280 if (dynContent->size() == 0) {
281 auto item = values.append_child("item");
282 createItem(item, cs->getItemPath(ITEM_PATH_NEW, ATTR_DYNAMIC_CONTAINER_LOCATION), cs->option, ATTR_DYNAMIC_CONTAINER_LOCATION, ConfigDefinition::findConfigSetup(ATTR_DYNAMIC_CONTAINER_LOCATION));
283
284 item = values.append_child("item");
285 createItem(item, cs->getItemPath(ITEM_PATH_NEW, ATTR_DYNAMIC_CONTAINER_IMAGE), cs->option, ATTR_DYNAMIC_CONTAINER_IMAGE, ConfigDefinition::findConfigSetup(ATTR_DYNAMIC_CONTAINER_IMAGE));
286
287 item = values.append_child("item");
288 createItem(item, cs->getItemPath(ITEM_PATH_NEW, ATTR_DYNAMIC_CONTAINER_TITLE), cs->option, ATTR_DYNAMIC_CONTAINER_TITLE, ConfigDefinition::findConfigSetup(ATTR_DYNAMIC_CONTAINER_TITLE));
289
290 item = values.append_child("item");
291 createItem(item, cs->getItemPath(ITEM_PATH_NEW, ATTR_DYNAMIC_CONTAINER_FILTER), cs->option, ATTR_DYNAMIC_CONTAINER_FILTER, ConfigDefinition::findConfigSetup(ATTR_DYNAMIC_CONTAINER_FILTER));
292
293 item = values.append_child("item");
294 createItem(item, cs->getItemPath(ITEM_PATH_NEW, ATTR_DYNAMIC_CONTAINER_SORT), cs->option, ATTR_DYNAMIC_CONTAINER_SORT, ConfigDefinition::findConfigSetup(ATTR_DYNAMIC_CONTAINER_SORT));
295 }
296
297 // write transconding configuration
298 cs = ConfigDefinition::findConfigSetup(CFG_TRANSCODING_PROFILE_LIST);
299 auto transcoding = cs->getValue()->getTranscodingProfileListOption();
300 int pr = 0;
301 std::map<std::string, int> profiles;
302 for (auto&& [key, val] : transcoding->getList()) {
303 for (auto&& [a, name] : *val) {
304 auto item = values.append_child("item");
305 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_MIMETYPE_PROF_MAP, ATTR_TRANSCODING_MIMETYPE_PROF_MAP_TRANSCODE, ATTR_TRANSCODING_MIMETYPE_PROF_MAP_MIMETYPE), cs->option, ATTR_TRANSCODING_MIMETYPE_PROF_MAP_MIMETYPE, cs);
306 setValue(item, key);
307
308 item = values.append_child("item");
309 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_MIMETYPE_PROF_MAP, ATTR_TRANSCODING_MIMETYPE_PROF_MAP_TRANSCODE, ATTR_TRANSCODING_MIMETYPE_PROF_MAP_USING), cs->option, ATTR_TRANSCODING_MIMETYPE_PROF_MAP_USING, cs);
310 setValue(item, name->getName());
311 profiles.emplace(name->getName(), pr);
312
313 pr++;
314 }
315 }
316
317 pr = 0;
318 for (auto&& [key, val] : profiles) {
319 auto entry = transcoding->getByName(key, true);
320 auto item = values.append_child("item");
321 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_NAME), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_NAME);
322 setValue(item, entry->getName());
323
324 item = values.append_child("item");
325 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_CLIENTFLAGS), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_CLIENTFLAGS);
326 setValue(item, ClientConfig::mapFlags(entry->getClientFlags()));
327
328 item = values.append_child("item");
329 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_ENABLED), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_ENABLED);
330 setValue(item, entry->getEnabled());
331
332 item = values.append_child("item");
333 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_TYPE), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_TYPE);
334 setValue(item, (entry->getType() == TR_External ? "external" : "none"));
335
336 item = values.append_child("item");
337 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_MIMETYPE), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_MIMETYPE);
338 setValue(item, entry->getTargetMimeType());
339
340 item = values.append_child("item");
341 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_RES), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_RES);
342 setValue(item, entry->getAttributes()[MetadataHandler::getResAttrName(R_RESOLUTION)]);
343
344 item = values.append_child("item");
345 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_ACCURL), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_ACCURL);
346 setValue(item, entry->acceptURL());
347
348 item = values.append_child("item");
349 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_SAMPFREQ), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_SAMPFREQ);
350 setValue(item, entry->getSampleFreq());
351
352 item = values.append_child("item");
353 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_NRCHAN), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_NRCHAN);
354 setValue(item, entry->getNumChannels());
355
356 item = values.append_child("item");
357 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_HIDEORIG), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_HIDEORIG);
358 setValue(item, entry->hideOriginalResource());
359
360 item = values.append_child("item");
361 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_THUMB), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_THUMB);
362 setValue(item, entry->isThumbnail());
363
364 item = values.append_child("item");
365 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_FIRST), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_FIRST);
366 setValue(item, entry->firstResource());
367
368 item = values.append_child("item");
369 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_ACCOGG), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_ACCOGG);
370 setValue(item, entry->isTheora());
371
372 item = values.append_child("item");
373 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_AGENT, ATTR_TRANSCODING_PROFILES_PROFLE_AGENT_COMMAND), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_AGENT_COMMAND);
374 setValue(item, entry->getCommand());
375
376 item = values.append_child("item");
377 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_AGENT, ATTR_TRANSCODING_PROFILES_PROFLE_AGENT_ARGS), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_AGENT_ARGS);
378 setValue(item, entry->getArguments());
379
380 item = values.append_child("item");
381 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_BUFFER, ATTR_TRANSCODING_PROFILES_PROFLE_BUFFER_SIZE), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_BUFFER_SIZE);
382 setValue(item, entry->getBufferSize());
383
384 item = values.append_child("item");
385 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_BUFFER, ATTR_TRANSCODING_PROFILES_PROFLE_BUFFER_CHUNK), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_BUFFER_CHUNK);
386 setValue(item, entry->getBufferChunkSize());
387
388 item = values.append_child("item");
389 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_BUFFER, ATTR_TRANSCODING_PROFILES_PROFLE_BUFFER_FILL), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_BUFFER_FILL);
390 setValue(item, entry->getBufferInitialFillSize());
391
392 auto fourCCMode = entry->getAVIFourCCListMode();
393 if (fourCCMode != FCC_None) {
394 item = values.append_child("item");
395 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_AVI4CC, ATTR_TRANSCODING_PROFILES_PROFLE_AVI4CC_MODE), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_AVI4CC_MODE);
396 setValue(item, TranscodingProfile::mapFourCcMode(fourCCMode));
397
398 const auto fourCCList = entry->getAVIFourCCList();
399 if (!fourCCList.empty()) {
400 item = values.append_child("item");
401 createItem(item, cs->getItemPath(pr, ATTR_TRANSCODING_PROFILES_PROFLE, ATTR_TRANSCODING_PROFILES_PROFLE_AVI4CC, ATTR_TRANSCODING_PROFILES_PROFLE_AVI4CC_4CC), cs->option, ATTR_TRANSCODING_PROFILES_PROFLE_AVI4CC_4CC);
402 setValue(item, std::accumulate(next(fourCCList.begin()), fourCCList.end(), fourCCList[0], [](auto&& a, auto&& b) { return fmt::format("{}, {}", a.c_str(), b.c_str()); }));
403 }
404 }
405 pr++;
406 }
407
408 // write autoscan configuration
409 for (auto&& ascs : ConfigDefinition::getConfigSetupList<ConfigAutoscanSetup>()) {
410 auto autoscan = ascs->getValue()->getAutoscanListOption();
411 for (std::size_t i = 0; i < autoscan->size(); i++) {
412 auto&& entry = autoscan->get(i);
413 auto&& adir = content->getAutoscanDirectory(entry->getLocation());
414 auto item = values.append_child("item");
415 createItem(item, ascs->getItemPath(i, ATTR_AUTOSCAN_DIRECTORY_LOCATION), ascs->option, ATTR_AUTOSCAN_DIRECTORY_LOCATION);
416 setValue(item, adir->getLocation());
417
418 item = values.append_child("item");
419 createItem(item, ascs->getItemPath(i, ATTR_AUTOSCAN_DIRECTORY_MODE), ascs->option, ATTR_AUTOSCAN_DIRECTORY_MODE);
420 setValue(item, AutoscanDirectory::mapScanmode(adir->getScanMode()));
421
422 item = values.append_child("item");
423 createItem(item, ascs->getItemPath(i, ATTR_AUTOSCAN_DIRECTORY_INTERVAL), ascs->option, ATTR_AUTOSCAN_DIRECTORY_INTERVAL);
424 setValue(item, adir->getInterval());
425
426 item = values.append_child("item");
427 createItem(item, ascs->getItemPath(i, ATTR_AUTOSCAN_DIRECTORY_RECURSIVE), ascs->option, ATTR_AUTOSCAN_DIRECTORY_RECURSIVE);
428 setValue(item, adir->getRecursive());
429
430 item = values.append_child("item");
431 createItem(item, ascs->getItemPath(i, ATTR_AUTOSCAN_DIRECTORY_HIDDENFILES), ascs->option, ATTR_AUTOSCAN_DIRECTORY_HIDDENFILES);
432 setValue(item, adir->getHidden());
433
434 item = values.append_child("item");
435 createItem(item, ascs->getItemPath(i, ATTR_AUTOSCAN_DIRECTORY_SCANCOUNT), ascs->option, ATTR_AUTOSCAN_DIRECTORY_SCANCOUNT);
436 setValue(item, adir->getActiveScanCount());
437
438 item = values.append_child("item");
439 createItem(item, ascs->getItemPath(i, ATTR_AUTOSCAN_DIRECTORY_TASKCOUNT), ascs->option, ATTR_AUTOSCAN_DIRECTORY_TASKCOUNT);
440 setValue(item, adir->getTaskCount());
441
442 item = values.append_child("item");
443 createItem(item, ascs->getItemPath(i, ATTR_AUTOSCAN_DIRECTORY_LMT), ascs->option, ATTR_AUTOSCAN_DIRECTORY_LMT);
444 setValue(item, fmt::format("{:%Y-%m-%d %H:%M:%S}", fmt::localtime(adir->getPreviousLMT().count())));
445 }
446 if (autoscan->size() == 0) {
447 auto item = values.append_child("item");
448 createItem(item, ascs->getItemPath(ITEM_PATH_NEW, ATTR_AUTOSCAN_DIRECTORY_LOCATION), ascs->option, ATTR_AUTOSCAN_DIRECTORY_LOCATION, ConfigDefinition::findConfigSetup(ATTR_AUTOSCAN_DIRECTORY_LOCATION));
449
450 item = values.append_child("item");
451 createItem(item, ascs->getItemPath(ITEM_PATH_NEW, ATTR_AUTOSCAN_DIRECTORY_MODE), ascs->option, ATTR_AUTOSCAN_DIRECTORY_MODE, ConfigDefinition::findConfigSetup(ATTR_AUTOSCAN_DIRECTORY_MODE));
452
453 item = values.append_child("item");
454 createItem(item, ascs->getItemPath(ITEM_PATH_NEW, ATTR_AUTOSCAN_DIRECTORY_INTERVAL), ascs->option, ATTR_AUTOSCAN_DIRECTORY_INTERVAL, ConfigDefinition::findConfigSetup(ATTR_AUTOSCAN_DIRECTORY_INTERVAL));
455
456 item = values.append_child("item");
457 createItem(item, ascs->getItemPath(ITEM_PATH_NEW, ATTR_AUTOSCAN_DIRECTORY_RECURSIVE), ascs->option, ATTR_AUTOSCAN_DIRECTORY_RECURSIVE, ConfigDefinition::findConfigSetup(ATTR_AUTOSCAN_DIRECTORY_RECURSIVE));
458
459 item = values.append_child("item");
460 createItem(item, ascs->getItemPath(ITEM_PATH_NEW, ATTR_AUTOSCAN_DIRECTORY_HIDDENFILES), ascs->option, ATTR_AUTOSCAN_DIRECTORY_HIDDENFILES, ConfigDefinition::findConfigSetup(ATTR_AUTOSCAN_DIRECTORY_HIDDENFILES));
461
462 item = values.append_child("item");
463 createItem(item, ascs->getItemPath(ITEM_PATH_NEW, ATTR_AUTOSCAN_DIRECTORY_SCANCOUNT), ascs->option, ATTR_AUTOSCAN_DIRECTORY_SCANCOUNT, ConfigDefinition::findConfigSetup(ATTR_AUTOSCAN_DIRECTORY_SCANCOUNT));
464
465 item = values.append_child("item");
466 createItem(item, ascs->getItemPath(ITEM_PATH_NEW, ATTR_AUTOSCAN_DIRECTORY_TASKCOUNT), ascs->option, ATTR_AUTOSCAN_DIRECTORY_TASKCOUNT, ConfigDefinition::findConfigSetup(ATTR_AUTOSCAN_DIRECTORY_TASKCOUNT));
467
468 item = values.append_child("item");
469 createItem(item, ascs->getItemPath(ITEM_PATH_NEW, ATTR_AUTOSCAN_DIRECTORY_LMT), ascs->option, ATTR_AUTOSCAN_DIRECTORY_LMT, ConfigDefinition::findConfigSetup(ATTR_AUTOSCAN_DIRECTORY_LMT));
470 }
471 }
472
473 // write content of all dictionaries
474 for (auto&& dcs : ConfigDefinition::getConfigSetupList<ConfigDictionarySetup>()) {
475 int i = 0;
476 auto dictionary = dcs->getValue()->getDictionaryOption(true);
477 for (auto&& [key, val] : dictionary) {
478 auto item = values.append_child("item");
479 createItem(item, dcs->getItemPath(i, dcs->keyOption), dcs->option, dcs->keyOption, dcs);
480 setValue(item, key.substr(5));
481
482 item = values.append_child("item");
483 createItem(item, dcs->getItemPath(i, dcs->valOption), dcs->option, dcs->valOption, dcs);
484 setValue(item, val);
485 i++;
486 }
487 }
488
489 // write content of all arrays
490 for (auto&& acs : ConfigDefinition::getConfigSetupList<ConfigArraySetup>()) {
491 auto array = acs->getValue()->getArrayOption(true);
492 for (std::size_t i = 0; i < array.size(); i++) {
493 auto entry = array[i];
494 auto item = values.append_child("item");
495 createItem(item, acs->getItemPath(i), acs->option, acs->attrOption != CFG_MAX ? acs->attrOption : acs->nodeOption, acs);
496 setValue(item, entry);
497 }
498 }
499
500 // update entries with datebase values
501 for (auto&& entry : dbEntries) {
502 auto exItem = allItems.find(entry.item);
503 if (exItem != allItems.end()) {
504 auto item = exItem->second;
505 item->attribute("source") = "database";
506 item->attribute("status") = entry.status.c_str();
507 } else {
508 auto cs = ConfigDefinition::findConfigSetupByPath(entry.item, true);
509 auto acs = ConfigDefinition::findConfigSetupByPath(entry.item, true, cs);
510 if (cs) {
511 auto item = values.append_child("item");
512 createItem(item, entry.item, cs->option, acs ? acs->option : CFG_MAX);
513 setValue(item, entry.value);
514 item.attribute("status") = entry.status.c_str();
515 item.attribute("origValue") = config->getOrigValue(entry.item).c_str();
516 item.attribute("source") = "database";
517 }
518 }
519 }
520 }
521