#include "Types.h" #include #include #include using namespace Qt::StringLiterals; ShareEndpoint ShareEndpoint::fromUserInput(const QString &input, const QString &password, QString *error) { ShareEndpoint result; const QUrl url = QUrl::fromUserInput(input.trimmed()); if (!url.isValid() || (url.scheme() != u"http" && url.scheme() != u"https") || url.host().isEmpty()) { if (error) { *error = u"Enter a valid HTTP or HTTPS Immich share URL."_s; } return result; } if (!url.userInfo().isEmpty()) { if (error) { *error = u"Credentials in the URL are not supported."_s; } return result; } const QString path = url.path(); const qsizetype marker = path.lastIndexOf(u"/share/"_s); if (marker < 0) { if (error) { *error = u"The URL must contain /share/."_s; } return result; } QString credential = path.sliced(marker + 7); while (credential.endsWith(u'/')) { credential.chop(1); } if (credential.isEmpty() || credential.contains(u'/')) { if (error) { *error = u"The share key or slug is missing or malformed."_s; } return result; } QUrl cleanUrl = url; cleanUrl.setQuery({}); cleanUrl.setFragment({}); QUrl root = cleanUrl; root.setPath(path.first(marker) + u"/api"_s); result.publicUrl = cleanUrl; result.apiRoot = root; result.credential = credential; result.password = password; if (error) { error->clear(); } return result; } QString ShareEndpoint::origin() const { QString value = publicUrl.scheme() + u"://"_s + publicUrl.host(); if (publicUrl.port() > 0) { value += u":"_s + QString::number(publicUrl.port()); } return value; } SyncPlan buildSyncPlan(const ShareInfo &left, const ShareInfo &right) { QSet leftChecksums; QSet rightChecksums; for (const auto &asset : left.assets) { if (!asset.checksum.isEmpty()) { leftChecksums.insert(asset.checksum); } } for (const auto &asset : right.assets) { if (!asset.checksum.isEmpty()) { rightChecksums.insert(asset.checksum); } } SyncPlan plan; for (const auto &asset : left.assets) { if (!asset.checksum.isEmpty() && !rightChecksums.contains(asset.checksum)) { plan.leftToRight.append(asset); } } for (const auto &asset : right.assets) { if (!asset.checksum.isEmpty() && !leftChecksums.contains(asset.checksum)) { plan.rightToLeft.append(asset); } } return plan; } QJsonObject shareInfoJson(const ShareEndpoint &endpoint, const ShareInfo &info) { return { {u"origin"_s, endpoint.origin()}, {u"name"_s, info.name}, {u"description"_s, info.description}, {u"type"_s, info.type}, {u"allowDownload"_s, info.allowDownload}, {u"allowUpload"_s, info.allowUpload}, {u"passwordProtected"_s, info.passwordProtected}, {u"assetCount"_s, static_cast(info.assets.size())}, }; }