Files
immich-frame/src/photo_queue.cpp

179 lines
4.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "photo_queue.h"
#include "immich_client.h"
#include <ArduinoJson.h>
#include "config.h"
void PhotoQueue::begin(ImmichClient& client, SettingsManager& settings) {
_client = &client;
_settings = &settings;
Settings s = _settings->get();
_cursor = s.queue_cursor;
}
bool PhotoQueue::sync() {
if (_client == nullptr || _settings == nullptr) return false;
Settings s = _settings->get();
std::vector<String> newIds;
// Get selected album IDs
std::vector<String> albumIds = getSelectedAlbumIds();
if (albumIds.empty()) {
// "All photos" mode — fetch from all albums
auto albums = _client->fetchAlbums();
for (auto& album : albums) {
auto ids = _client->fetchAlbumAssetIds(album.id);
for (auto& id : ids) {
newIds.push_back(id);
}
}
} else {
// Fetch from selected albums only
for (auto& albumId : albumIds) {
auto ids = _client->fetchAlbumAssetIds(albumId);
for (auto& id : ids) {
newIds.push_back(id);
}
}
}
// Deduplicate
std::sort(newIds.begin(), newIds.end());
newIds.erase(std::unique(newIds.begin(), newIds.end()), newIds.end());
if (newIds.empty()) {
Serial.println("[queue] No assets found");
return false;
}
_queue = newIds;
// Apply cycling mode
switch (s.cycle_mode) {
case CycleMode::Random:
applyFavoritesWeighting();
shuffle();
break;
case CycleMode::Chronological:
sortChronological(false);
break;
case CycleMode::ReverseChronological:
sortChronological(true);
break;
case CycleMode::FavoritesWeighted:
applyFavoritesWeighting();
shuffle();
break;
}
// Clamp cursor
if (_cursor >= _queue.size()) {
_cursor = 0;
}
_lastSyncTime = millis();
Serial.printf("[queue] Synced: %d assets, cursor at %d\n", _queue.size(), _cursor);
return true;
}
String PhotoQueue::next() {
if (_queue.empty()) return "";
if (_cursor >= _queue.size()) {
_cursor = 0;
shuffle(); // Reshuffle on wrap for random mode
}
String id = _queue[_cursor++];
// Persist cursor
_settings->saveField("queue_cursor", static_cast<uint8_t>(_cursor & 0xFF));
return id;
}
String PhotoQueue::random() {
if (_queue.empty()) return "";
size_t idx = ::random(0, _queue.size());
return _queue[idx];
}
String PhotoQueue::current() {
if (_queue.empty()) return "";
size_t idx = (_cursor > 0) ? _cursor - 1 : 0;
return _queue[idx];
}
size_t PhotoQueue::size() {
return _queue.size();
}
bool PhotoQueue::needsResync() {
if (_lastSyncTime == 0) return true;
unsigned long elapsed = millis() - _lastSyncTime;
return elapsed >= (QUEUE_RESYNC_HOURS * 3600000UL);
}
String PhotoQueue::findPortraitPair(size_t startIndex) {
// Look ahead up to PORTRAIT_LOOKAHEAD items for another portrait
for (size_t i = 1; i <= PORTRAIT_LOOKAHEAD && (startIndex + i) < _queue.size(); i++) {
// We'd need asset info to determine portrait status
// This will be called by the display task which fetches AssetInfo
// Return the ID — caller checks isPortrait from AssetInfo
return _queue[startIndex + i];
}
return "";
}
void PhotoQueue::shuffle() {
for (size_t i = _queue.size() - 1; i > 0; i--) {
size_t j = ::random(0, i + 1);
std::swap(_queue[i], _queue[j]);
}
}
void PhotoQueue::sortChronological(bool reverse) {
// For chronological sort, we'd need timestamps which we don't store in the queue
// The IDs from Immich are UUIDs, not sortable by time
// For now, keep the order returned by Immich (which is chronological within albums)
if (reverse) {
std::reverse(_queue.begin(), _queue.end());
}
}
void PhotoQueue::applyFavoritesWeighting() {
if (_client == nullptr) return;
Settings s = _settings->get();
if (s.cycle_mode != CycleMode::FavoritesWeighted) return;
auto favorites = _client->fetchFavoriteAssetIds();
// Add favorites 2 more times (total 3× appearance)
for (auto& fav : favorites) {
// Only add if already in queue
bool inQueue = false;
for (auto& id : _queue) {
if (id == fav) { inQueue = true; break; }
}
if (inQueue) {
_queue.push_back(fav);
_queue.push_back(fav);
}
}
}
std::vector<String> PhotoQueue::getSelectedAlbumIds() {
std::vector<String> ids;
Settings s = _settings->get();
JsonDocument doc;
DeserializationError err = deserializeJson(doc, s.albums_json);
if (err) return ids;
JsonArray arr = doc.as<JsonArray>();
for (JsonVariant v : arr) {
ids.push_back(v.as<String>());
}
return ids;
}