const { coreDataDateToJSDate } = require('./helpers');
/**
* The Folder class contains Albums and sub-Folders.
* It's basically what you see in the sidebar of your Photos app: a folder structure of albums.
*
* Read from the database `RKFolder`.
*/
class Folder {
/**
* Create a new Folder class.
* @param {PhotosLibrary} library An instance of PhotosLibrary used for album fetching.
* @param {Object} row A database row from RKFolder.
* @return {Folder} The generated Folder instance.
*/
constructor(library, row) {
/**
* The library used for media fetching.
* @type {PhotosLibrary}
*/
this.library = library;
/**
* The ID of the Folder in the database (database field: modelId).
* @type {int}
*/
this.id = row.modelId;
/**
* The uuid of the Folder in the database (database field: uuid).
* @type {string}
*/
this.uuid = row.uuid;
/**
* The name of the Folder. (database field: name).
* @type {string}
*/
this.name = row.name;
/**
* The cloud ID of the Folder. (database field: cloudIdentifier).
* @type {string}
*/
this.cloudId = row.cloudIdentifier;
/**
* Wether or not the folder has been synced to iCloud. (database field: hasBeenSynced).
* @type {Bool}
*/
this.synced = row.hasBeenSynced;
/**
* The date the Folder was created. (database field: createDate).
*
* The database value is converted from a Apple Core Data date to a Javascript Date object.
* @type {Date}
*/
this.created = coreDataDateToJSDate(row.createDate);
/**
* A Folder is magic if it is generated by Apple Photos and not by the user (e.g. Favorites).
* @type {Bool}
*/
this.magic = Boolean(row.isMagic);
/**
* The uuid of the parent Folder the Folder is in. (database field: folderUuid).
* @type {string}
*/
this.parentFolderUuid = row.parentFolderUuid;
/**
* The Albums located in this Folder.
*
* **Will only be initialized after initFolder() is called!**
*
* @type {Array.<Album>}
*/
this.albums = []; // will be initialized in `initFolder()` method
/**
* The sub-Folders located in this Folder.
*
* **Will only be initialized after `initFolder()` is called!**
*
* @type {Array.<Folder>}
*/
this.folders = [];
if (row.children) {
row.children.forEach(child => {
if (child.isInTrash) return;
const folder = new Folder(this.library, child);
this.folders.push(folder);
});
}
}
/**
* Initialize this folder and load Albums and sub-Folders.
*
* This method needs to be called in order for the albums and folders properties to be populated.
*/
async initFolder() {
this.albums = await this.library.getAlbumsInFolder(this.uuid);
for (const folder of Object.values(this.folders)) {
await folder.initFolder();
}
}
/**
* Count all the albums in this folder.
*
* This will recursively call the same function on all subfolders to get a true total.
*
* @return {int} Total amount of Albums in the Folder (including subfolders).
*/
countAlbums() {
let count = this.albums.length;
return this.folders.reduce((total, folder) => {
return total + folder.countAlbums();
}, count);
}
/**
* Prepare the Folder for JSON serialization.
*
* This function is needed to exclude the library property from JSON serialization.
* @return {Object} The filtered object.
*/
toJSON() {
return {
...this,
library: undefined
}
}
}
module.exports = Folder;