add more immich control options
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing

This commit is contained in:
2026-02-01 21:24:24 +11:00
parent 3644001dbc
commit 806d701535
9 changed files with 355 additions and 30 deletions

View File

@@ -19,6 +19,9 @@
#include <stdlib.h>
#include <stdio.h>
#include <memory>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
void usage(std::string programName) {
std::cerr << "Usage: " << programName << " [-t rotation_seconds] [-T transition_seconds] [-h/--overlay-color #rrggbb] [-a aspect('l','p','a', 'm')] [-o background_opacity(0..255)] [-b blur_radius] -p image_folder [-r] [-s] [-S] [-v] [--verbose] [--stretch] [-c config_file_path]" << std::endl;
@@ -243,6 +246,216 @@ void ReloadConfigIfNeeded(AppConfig &appConfig, MainWindow &w, ImageSwitcher *sw
}
}
static bool ParseBooleanString(const QString &value, bool &outValue)
{
QString v = value.trimmed().toLower();
if (v == "true" || v == "1" || v == "yes" || v == "on")
{
outValue = true;
return true;
}
if (v == "false" || v == "0" || v == "no" || v == "off")
{
outValue = false;
return true;
}
return false;
}
static std::vector<std::string> SplitCsv(const QString &value)
{
std::vector<std::string> output;
QStringList parts = value.split(',', Qt::SkipEmptyParts);
for (const auto &part : parts)
{
QString trimmed = part.trimmed();
if (!trimmed.isEmpty())
output.push_back(trimmed.toStdString());
}
return output;
}
static bool ApplyImmichPayload(ImmichConfig &config, const QString &payload)
{
bool changed = false;
QString trimmed = payload.trimmed();
if (trimmed.isEmpty())
return false;
if (trimmed.startsWith("{"))
{
QJsonDocument doc = QJsonDocument::fromJson(trimmed.toUtf8());
if (!doc.isObject())
return false;
QJsonObject obj = doc.object();
if (obj.contains("albumId") && obj["albumId"].isString())
{
config.albumIds = { obj["albumId"].toString().toStdString() };
changed = true;
}
if (obj.contains("albumIds") && obj["albumIds"].isArray())
{
config.albumIds.clear();
QJsonArray arr = obj["albumIds"].toArray();
for (const auto &value : arr)
{
if (value.isString())
config.albumIds.push_back(value.toString().toStdString());
}
changed = true;
}
if (obj.contains("personId") && obj["personId"].isString())
{
config.personIds = { obj["personId"].toString().toStdString() };
changed = true;
}
if (obj.contains("personIds") && obj["personIds"].isArray())
{
config.personIds.clear();
QJsonArray arr = obj["personIds"].toArray();
for (const auto &value : arr)
{
if (value.isString())
config.personIds.push_back(value.toString().toStdString());
}
changed = true;
}
if (obj.contains("order") && obj["order"].isString())
{
config.order = obj["order"].toString().toStdString();
changed = true;
}
if (obj.contains("size") && obj["size"].isString())
{
config.size = obj["size"].toString().toStdString();
changed = true;
}
if (obj.contains("pageSize") && obj["pageSize"].isDouble())
{
config.pageSize = (int)obj["pageSize"].toDouble();
changed = true;
}
if (obj.contains("maxAssets") && obj["maxAssets"].isDouble())
{
config.maxAssets = (int)obj["maxAssets"].toDouble();
changed = true;
}
if (obj.contains("includeArchived"))
{
if (obj["includeArchived"].isBool())
{
config.includeArchived = obj["includeArchived"].toBool();
changed = true;
}
else if (obj["includeArchived"].isString())
{
bool parsed = false;
bool boolValue = false;
parsed = ParseBooleanString(obj["includeArchived"].toString(), boolValue);
if (parsed)
{
config.includeArchived = boolValue;
changed = true;
}
}
}
if (obj.contains("reset") && obj["reset"].isBool() && obj["reset"].toBool())
{
config.albumIds.clear();
config.personIds.clear();
changed = true;
}
return changed;
}
QString key;
QString value;
int idx = trimmed.indexOf('=');
if (idx < 0)
idx = trimmed.indexOf(':');
if (idx < 0)
idx = trimmed.indexOf(' ');
if (idx >= 0)
{
key = trimmed.left(idx).trimmed().toLower();
value = trimmed.mid(idx + 1).trimmed();
}
else
{
key = trimmed.toLower();
}
if (key == "reset" || key == "clear" || key == "all")
{
config.albumIds.clear();
config.personIds.clear();
return true;
}
if (key == "album" || key == "albumid")
{
config.albumIds = { value.toStdString() };
return true;
}
if (key == "albums" || key == "albumids")
{
config.albumIds = SplitCsv(value);
return true;
}
if (key == "person" || key == "personid")
{
config.personIds = { value.toStdString() };
return true;
}
if (key == "persons" || key == "personids")
{
config.personIds = SplitCsv(value);
return true;
}
if (key == "order")
{
config.order = value.toStdString();
return true;
}
if (key == "size")
{
config.size = value.toStdString();
return true;
}
if (key == "includearchived")
{
bool boolValue = false;
if (ParseBooleanString(value, boolValue))
{
config.includeArchived = boolValue;
return true;
}
}
if (key == "pagesize")
{
bool ok = false;
int parsed = value.toInt(&ok);
if (ok)
{
config.pageSize = parsed;
return true;
}
}
if (key == "maxassets")
{
bool ok = false;
int parsed = value.toInt(&ok);
if (ok)
{
config.maxAssets = parsed;
return true;
}
}
return false;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
@@ -292,6 +505,32 @@ int main(int argc, char *argv[])
std::unique_ptr<ImageSelector> newSelector = GetSelectorForApp(appConfig);
switcher.restart(newSelector);
});
QObject::connect(mqttController.get(), &MqttController::immichControl, [&appConfig, &switcher](const QString &payload) {
bool updated = false;
for (int i = 0; i < appConfig.paths.count(); ++i)
{
if (!appConfig.paths[i].immich.enabled)
continue;
ImmichConfig newConfig = appConfig.paths[i].immich;
if (ApplyImmichPayload(newConfig, payload))
{
appConfig.paths[i].immich = newConfig;
updated = true;
}
}
if (updated)
{
Log("MQTT immich update applied.");
std::unique_ptr<ImageSelector> newSelector = GetSelectorForApp(appConfig);
switcher.setImageSelector(newSelector);
if (!switcher.isPaused())
switcher.scheduleImageUpdate();
}
else
{
Log("MQTT immich update ignored: ", payload.toStdString());
}
});
mqttController->start();
}
switcher.start();