Skip to content

Commit 1f35c56

Browse files
authored
Merge pull request #27 from matt-thurling/support-for-multiple-albums
Added support for pulling images from multiple albums
2 parents e54ed44 + 63cfc61 commit 1f35c56

4 files changed

Lines changed: 65 additions & 29 deletions

File tree

MMM-ImmichSlideShow.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ Module.register('MMM-ImmichSlideShow', {
664664
}
665665
break;
666666
case 'count': // show image count
667+
case 'album':
667668
break;
668669
default:
669670
Log.warn(
@@ -675,7 +676,14 @@ Module.register('MMM-ImmichSlideShow', {
675676

676677
// Log.debug('config.imageInfo[count]', config.imageInfo.includes('count'));
677678
// Log.dir('config.imageInfo', config.imageInfo);
678-
let innerHTML = config.imageInfo.includes('count') ? `<header class="infoDivHeader">${imageinfo.index} of ${imageinfo.total}</header>`: '';
679+
let headerString = '';
680+
if (config.imageInfo.includes('count')) {
681+
headerString = `${imageinfo.index} of ${imageinfo.total}`;
682+
}
683+
if (config.imageInfo.includes('album')) {
684+
headerString = headerString.length == 0 ? imageinfo.albumName : headerString + '<br>' + imageinfo.albumName;
685+
}
686+
let innerHTML = headerString.length > 0 ? `<header class="infoDivHeader">${headerString}</header>`: '';
679687
imageProps.forEach((val, idx) => {
680688
innerHTML += val + '<br/>';
681689
});

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -353,15 +353,17 @@ The following properties can be configured:
353353
</tr>
354354
<tr>
355355
<td><code>albumId</code></td>
356-
<td>The id of the album to show pictures from. Note that if <i>albumId</i> and <i>albumName</i> are provided, <i>albumId</i> will take precedence.<br>
357-
<br><b>Example:</b> <code>1b57d1dc-57d6-4cd4-bc1d-f8ebf759ba16</code>
356+
<td>Either a single id, or an array of ids of the albums to show pictures from. Note that if <i>albumId</i> and <i>albumName</i> are provided, <i>albumId</i> will take precedence.<br>
357+
<br><b>Example 1:</b> <code>1b57d1dc-57d6-4cd4-bc1d-f8ebf759ba16</code>
358+
<br><b>Example 2:</b> <code>['1b57d1dc-57d6-4cd4-bc1d-f8ebf759ba16', '4aff9b7b-ae55-404f-81d5-27ccd93d1f9b']</code>
358359
<br>This value is <b>REQUIRED</b> if <i>mode</i> is set to <i>album</i> and <i>albumName</i> is not provided.
359360
</td>
360361
</tr>
361362
<tr>
362363
<td><code>albumName</code></td>
363-
<td>The id of the album to show pictures from. This name is case sensitive and should match the album name in Immich exactly. Note that if <i>albumId</i> and <i>albumName</i> are provided, <i>albumId</i> will take precedence.<br>
364-
<br><b>Example:</b> <code>Family Trip 2023</code>
364+
<td>Either a single name, or an array of names of the albums to show pictures from. These names are case sensitive and should match the album name in Immich exactly. Note that if <i>albumId</i> and <i>albumName</i> are provided, <i>albumId</i> will take precedence.<br>
365+
<br><b>Example 1:</b> <code>Family Trip 2023</code>
366+
<br><b>Example 2:</b> <code>['Family Trip 2023', 'Christmas 2024']</code>
365367
<br>This value is <b>REQUIRED</b> if <i>mode</i> is set to <i>album</i> and <i>albumId</i> is not provided.
366368
</td>
367369
</tr>
@@ -398,8 +400,8 @@ The following properties can be configured:
398400
</tr>
399401
<tr>
400402
<td><code>imageInfo</code></td>
401-
<td>A list of image properties to display in the image info div. Possible values are : <code>date</code> (EXIF date from image), <code>name</code> (image name), <code>since</code> (how long ago the picture was taken), <code>geo</code> (the city and country where the picture was taken if available), <code>people</code> (the name of the people in the picture. Use <code>people_skip</code> instead to not show extra separators for recognized faces with no name), <code>age</code> (The age of the people at the time the photo was taken. Only works if <code>people</code> is also added), and <code>desc</code> (The description of the image if one is available), <code>count</code> (The current image number and total image count. Not displayed by default after 1.4.0+).
402-
The values can be provided as an array of strings or as a space separated list string and the order that you provide this info is how it will display (top to bottom).<br/>
403+
<td>A list of image properties to display in the image info div. Possible values are : <code>date</code> (EXIF date from image), <code>name</code> (image name), <code>since</code> (how long ago the picture was taken), <code>geo</code> (the city and country where the picture was taken if available), <code>people</code> (the name of the people in the picture. Use <code>people_skip</code> instead to not show extra separators for recognized faces with no name), <code>age</code> (The age of the people at the time the photo was taken. Only works if <code>people</code> is also added), and <code>desc</code> (The description of the image if one is available), <code>album</code> (the name of the album the photo belongs to, useful if you have multiple albums configured), <code>count</code> (The current image number and total image count. Not displayed by default after 1.4.0+).
404+
The values can be provided as an array of strings or as a space separated list string and the order that you provide this info is how it will display (top to bottom), except for album and count which will always display at the top.<br/>
403405
<b>Note</b>: providing too many options here may take up a large portion of the screen.<br/>
404406
<br><b>Example:</b> <code>'date name people age'</code> or <code>[ 'date', 'name', 'people', 'age']</code>
405407
<br><b>Default value:</b> <code>['date', 'since', 'count']</code>

immichApi.js

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,33 +142,37 @@ const immichApi = {
142142
}
143143
},
144144

145-
findAlbumId: async function (albumName) {
146-
let albumId = null;
145+
getAlbumNameToIdMap: async function () {
146+
let albumNameToIdMap = new Map();
147147
try {
148148
const response = await this.http.get(this.apiUrls[this.apiLevel]['albums'], {responseType: 'json'});
149149
if (response.status === 200) {
150-
// Loop through the albums to find the right now
151150
for (let i=0; i < response.data.length; i++) {
152151
const album = response.data[i];
153-
Log.debug(LOG_PREFIX + `comparing ${album.albumName} to ${albumName}`);
154-
if (album.albumName === albumName) {
155-
Log.debug(LOG_PREFIX + 'match found');
156-
albumId = album.id;
157-
break;
158-
}
159-
}
160-
161-
if (!albumId) {
162-
Log.error(LOG_PREFIX + `could not find an album with the provided name (${albumName}). Note that album name is case sensitive`);
152+
albumNameToIdMap.set(album.albumName, album.id);
153+
Log.debug(LOG_PREFIX + 'album name: ' + album.albumName + ', album id: ' + album.id);
163154
}
164155
} else {
165156
Log.error(LOG_PREFIX + 'unexpected response from Immich', response.status, response.statusText);
166157
}
167158
} catch (e) {
168159
Log.error(LOG_PREFIX + 'Oops! Exception while fetching albums from Immich', e.message);
169160
}
161+
return albumNameToIdMap;
162+
},
170163

171-
return albumId;
164+
findAlbumIds: async function (albumNames) {
165+
let albumNameToAlbumIdMap = await this.getAlbumNameToIdMap();
166+
let albumIds = [];
167+
for (const albumName of albumNames) {
168+
if (albumNameToAlbumIdMap.has(albumName)) {
169+
albumIds = albumIds.concat(albumNameToAlbumIdMap.get(albumName));
170+
} else {
171+
Log.error(LOG_PREFIX + `could not find an album with the provided name (${albumName}). Note that album name is case sensitive`);
172+
}
173+
}
174+
Log.debug(LOG_PREFIX + `Found (${albumIds.length}/${albumNames.length}) matching albumIds`);
175+
return albumIds;
172176
},
173177

174178
getAlbumAssets: async function (albumId) {
@@ -177,6 +181,12 @@ const immichApi = {
177181
const response = await this.http.get(this.apiUrls[this.apiLevel]['albumInfo'].replace('{id}',albumId), {responseType: 'json'});
178182
if (response.status === 200) {
179183
imageList = [...response.data.assets];
184+
if (response.data.albumName) {
185+
Log.debug(LOG_PREFIX + `Retrieved ${imageList.length} images for album ${response.data.albumName}`);
186+
imageList.forEach(image =>
187+
image.albumName = response.data.albumName
188+
);
189+
}
180190
} else {
181191
Log.error(LOG_PREFIX + 'unexpected response from Immich', response.status, response.statusText);
182192
}
@@ -187,6 +197,18 @@ const immichApi = {
187197
return imageList;
188198
},
189199

200+
getAlbumAssetsForAlbumIds: async function (albumIds) {
201+
let imageList = [];
202+
for (const albumId of albumIds) {
203+
let currentAlbumImages = await this.getAlbumAssets(albumId);
204+
if (currentAlbumImages && currentAlbumImages.length > 0) {
205+
imageList = imageList.concat(currentAlbumImages);
206+
}
207+
}
208+
Log.debug(LOG_PREFIX + `retrieved ${imageList.length} images.`);
209+
return imageList;
210+
},
211+
190212
getMemoryLaneAssets: async function (numDays) {
191213
let imageList = [];
192214

node_helper.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ module.exports = NodeHelper.create({
8181
},
8282

8383
sortImageList: function (imageList, sortBy, sortDescending) {
84-
Log.log(LOG_PREFIX + 'sortImageList :: imageList is Array?', Array.isArray(imageList), sortBy, sortDescending);
84+
Log.debug(LOG_PREFIX + 'sortImageList :: imageList is Array?', Array.isArray(imageList), sortBy, sortDescending);
8585
let sortedList = imageList;
8686
switch (sortBy) {
8787
case 'created':
@@ -144,7 +144,7 @@ module.exports = NodeHelper.create({
144144
this.imageList = [];
145145

146146
// we default albumId to the config value and override below if albumName is provided
147-
let albumId = config.activeImmichConfig.albumId;
147+
let albumIds = config.activeImmichConfig.albumId;
148148

149149
// Get today's date at midnight
150150
let today = (new Date());
@@ -154,15 +154,18 @@ module.exports = NodeHelper.create({
154154
if (config.activeImmichConfig.mode === 'album') {
155155
// If we have albumName but no albumId, then get the albumId
156156
if (config.activeImmichConfig.albumName && !config.activeImmichConfig.albumId) {
157-
albumId = await immichApi.findAlbumId(config.activeImmichConfig.albumName);
157+
let albumNames = config.activeImmichConfig.albumName;
158+
albumNames = Array.isArray(albumNames) ? albumNames : [].concat(albumNames);
159+
albumIds = await immichApi.findAlbumIds(albumNames);
158160
}
159161
// Only proceed if we have an albumId
160-
if (albumId) {
161-
Log.debug(LOG_PREFIX + 'fetching pictures from album', albumId);
162+
if (albumIds) {
163+
albumIds = Array.isArray(albumIds) ? albumIds : [].concat(albumIds);
164+
Log.debug(LOG_PREFIX + 'fetching pictures from albums', albumIds);
162165
// Get the pictures from the album
163-
this.imageList = await immichApi.getAlbumAssets(albumId);
166+
this.imageList = await immichApi.getAlbumAssetsForAlbumIds(albumIds);
164167
} else {
165-
Log.error(LOG_PREFIX + 'could not find the specified album in Immich. Please check your configuration again');
168+
Log.error(LOG_PREFIX + 'could not find any of the specified album(s) in Immich. Please check your configuration again');
166169
}
167170
} else if (config.activeImmichConfig.mode === 'search') {
168171
// Search mode
@@ -249,7 +252,8 @@ module.exports = NodeHelper.create({
249252
data: null,
250253
imageId: image.id,
251254
index: this.index+1, // Index is zero based
252-
total: this.imageList.length
255+
total: this.imageList.length,
256+
albumName: image.albumName
253257
};
254258

255259
// If there is no exif info available, or if we need people but no people are listed

0 commit comments

Comments
 (0)