Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 85ef89fa4b | |||
| e5f5934eb6 | |||
| 80286da166 | |||
| 6f2b8fe90c |
8
CHANGELOG.md
Normal file
8
CHANGELOG.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
# [Unreleased]
|
||||
|
||||
- Nothing yet.
|
||||
|
||||
# [0.0.9] - 2026-02-01
|
||||
- Fix sidecar handling
|
||||
@@ -148,7 +148,7 @@ QVector<ImmichAsset> ImmichClient::fetchAssets()
|
||||
}
|
||||
|
||||
if (!config.userId.empty() && config.albumIds.empty() && config.personIds.empty())
|
||||
return fetchAssetsByUser();
|
||||
return fetchAssetsBySearch();
|
||||
|
||||
if (!config.userId.empty() && (!config.albumIds.empty() || !config.personIds.empty()))
|
||||
{
|
||||
@@ -166,20 +166,24 @@ QVector<ImmichAsset> ImmichClient::fetchAssetsBySearch()
|
||||
int maxAssets = config.maxAssets;
|
||||
bool triedZero = false;
|
||||
int page = 1;
|
||||
QString userFilterKey;
|
||||
QByteArray firstResponse;
|
||||
QJsonArray items;
|
||||
int total = 0;
|
||||
|
||||
if (ShouldLog())
|
||||
{
|
||||
Log("Immich search: size=", config.size, ", order=", config.order,
|
||||
", pageSize=", pageSize, ", maxAssets=", maxAssets,
|
||||
", userId=", config.userId,
|
||||
", albumIds=", config.albumIds.size(),
|
||||
", personIds=", config.personIds.size(),
|
||||
", allowedExtensions=", config.allowedExtensions.size());
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto fetchPage = [&](int pageIndex, const QString &userKey) -> QByteArray {
|
||||
QJsonObject body;
|
||||
body["page"] = page;
|
||||
body["page"] = pageIndex;
|
||||
body["size"] = pageSize;
|
||||
body["type"] = "IMAGE";
|
||||
body["order"] = QString::fromStdString(config.order);
|
||||
@@ -199,19 +203,69 @@ QVector<ImmichAsset> ImmichClient::fetchAssetsBySearch()
|
||||
ids.append(QString::fromStdString(id));
|
||||
body["personIds"] = ids;
|
||||
}
|
||||
if (!config.userId.empty() && !userKey.isEmpty())
|
||||
{
|
||||
body[userKey] = QString::fromStdString(config.userId);
|
||||
}
|
||||
return postJson(apiUrl("/search/metadata"), body, nullptr, kMetadataTimeoutMs);
|
||||
};
|
||||
|
||||
QByteArray response = postJson(apiUrl("/search/metadata"), body, nullptr, kMetadataTimeoutMs);
|
||||
if (response.isEmpty())
|
||||
break;
|
||||
|
||||
auto parseSearch = [&](const QByteArray &response, QJsonArray &outItems, int &outTotal) -> bool {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response);
|
||||
if (!doc.isObject())
|
||||
break;
|
||||
|
||||
return false;
|
||||
QJsonObject root = doc.object();
|
||||
if (root.contains("error") || root.contains("statusCode"))
|
||||
return false;
|
||||
if (!root.contains("assets"))
|
||||
return false;
|
||||
QJsonObject assetsObj = root["assets"].toObject();
|
||||
QJsonArray items = assetsObj["items"].toArray();
|
||||
int total = assetsObj["total"].toInt();
|
||||
outItems = assetsObj["items"].toArray();
|
||||
outTotal = assetsObj["total"].toInt();
|
||||
return true;
|
||||
};
|
||||
|
||||
QStringList userKeyCandidates;
|
||||
if (!config.userId.empty())
|
||||
userKeyCandidates << "ownerId" << "userId";
|
||||
userKeyCandidates << "";
|
||||
|
||||
bool firstResponseReady = false;
|
||||
for (const auto &candidate : userKeyCandidates)
|
||||
{
|
||||
QByteArray response = fetchPage(page, candidate);
|
||||
if (response.isEmpty())
|
||||
continue;
|
||||
if (!parseSearch(response, items, total))
|
||||
continue;
|
||||
userFilterKey = candidate;
|
||||
firstResponse = response;
|
||||
firstResponseReady = true;
|
||||
if (!config.userId.empty() && userFilterKey.isEmpty())
|
||||
{
|
||||
Log("Immich search user filter not accepted by server; falling back to search without userId.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!firstResponseReady)
|
||||
return assets;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (firstResponseReady)
|
||||
{
|
||||
firstResponseReady = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
QByteArray response = fetchPage(page, userFilterKey);
|
||||
if (response.isEmpty())
|
||||
break;
|
||||
if (!parseSearch(response, items, total))
|
||||
break;
|
||||
}
|
||||
|
||||
Log("Immich page ", page, ": ", items.size(), " assets (total ", total, ")");
|
||||
if (items.isEmpty())
|
||||
{
|
||||
@@ -259,6 +313,9 @@ QVector<ImmichAsset> ImmichClient::fetchAssetsByUser()
|
||||
int pageSize = config.pageSize > 0 ? config.pageSize : 200;
|
||||
int maxAssets = config.maxAssets;
|
||||
int skip = 0;
|
||||
QString endpointPath = "/assets";
|
||||
QByteArray initialResponse;
|
||||
bool endpointResolved = false;
|
||||
|
||||
if (ShouldLog())
|
||||
{
|
||||
@@ -268,24 +325,52 @@ QVector<ImmichAsset> ImmichClient::fetchAssetsByUser()
|
||||
", includeArchived=", config.includeArchived);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
QUrl url = apiUrl("/assets");
|
||||
auto fetchPage = [&](const QString &path, int offset) -> QByteArray {
|
||||
QUrl url = apiUrl(path);
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("take", QString::number(pageSize));
|
||||
query.addQueryItem("skip", QString::number(skip));
|
||||
query.addQueryItem("skip", QString::number(offset));
|
||||
query.addQueryItem("userId", QString::fromStdString(config.userId));
|
||||
if (!config.includeArchived)
|
||||
query.addQueryItem("isArchived", "false");
|
||||
url.setQuery(query);
|
||||
return getBytes(url, nullptr, kMetadataTimeoutMs);
|
||||
};
|
||||
|
||||
QByteArray response = getBytes(url, nullptr, kMetadataTimeoutMs);
|
||||
initialResponse = fetchPage(endpointPath, skip);
|
||||
if (initialResponse.isEmpty())
|
||||
{
|
||||
endpointPath = "/asset";
|
||||
initialResponse = fetchPage(endpointPath, skip);
|
||||
}
|
||||
if (initialResponse.isEmpty())
|
||||
{
|
||||
Log("Immich user assets endpoint not available; falling back to metadata search (userId filter may be ignored).");
|
||||
return fetchAssetsBySearch();
|
||||
}
|
||||
endpointResolved = true;
|
||||
|
||||
while (true)
|
||||
{
|
||||
QByteArray response;
|
||||
if (endpointResolved)
|
||||
{
|
||||
response = initialResponse;
|
||||
endpointResolved = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
response = fetchPage(endpointPath, skip);
|
||||
}
|
||||
if (response.isEmpty())
|
||||
break;
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response);
|
||||
if (!doc.isArray())
|
||||
break;
|
||||
{
|
||||
Log("Immich user assets response was not an array; falling back to metadata search.");
|
||||
return fetchAssetsBySearch();
|
||||
}
|
||||
|
||||
QJsonArray items = doc.array();
|
||||
Log("Immich user assets skip ", skip, ": ", items.size(), " assets");
|
||||
|
||||
Reference in New Issue
Block a user