-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathphotoSorter.gs
222 lines (183 loc) · 8.03 KB
/
photoSorter.gs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/**
* Upon opening the spreadsheet, a menu tab for the program is created. It contains three buttons: one
to check the user's library for media items in more than one album, one to check the user's library
for media items that are not in an album, and one containing text about the program.
* @param {event} e Event object containing context on the program's opening.
*/
function onOpen(e){
UIObj.intializeMenu();
};
/**
* Writes an array of strings on a row-per-row basis in Google Sheets.
* @param {Array<string>} itemArray 2D Array of strings to write to the active sheet. First level represents
rows, second level represents columns.
* @param {boolean=} boldFirstLine Optional boolean for whether or not the first line should be bolded. Default
is true.
* @param {integer=} startingColumnNo Optional integer representing the column to begin with
(i.e. column E would be 5). Default value is 1.
* @param {Sheet=} sheetToWriteTo Optional Sheet object from Google Sheet's API. Represents the
sheet that will be written to. If blank, writes to the active sheet.
*/
function write2DArrayToSheet(itemArray, boldFirstLine = true, startingColumnNo = 1,
sheetToWriteTo = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()){
for (let item in itemArray){
let rowToWrite = sheetToWriteTo.getLastRow() + 1;
let columnIterable = startingColumnNo;
let arrayLvl1 = itemArray[item];
for (let arrayLvl2 of arrayLvl1){
sheetToWriteTo.getRange(rowToWrite, columnIterable).setValue(arrayLvl2);
if ((item == 0) && (boldFirstLine)){
sheetToWriteTo.getRange(rowToWrite, columnIterable).setFontWeight("bold");
};
columnIterable += 1;
};
rowToWrite += 1;
};
};
/**
* For a user's Google Photos library, compares a list of all media items (retrieved with the
API's mediaItems.list function) to all media items with at least one album. Returns a list
of all media items that are isolated, meaning they are without any associated album.
* @return {Array<mediaItem>} Array of mediaItems that are isolated.
*/
function checkForNotInAlbum(){
let mediaNotInAlbum = [];
try{
const allMediaItems = Array.from(PhotoApp.getMediaItemList());
} catch(e){
return [e];
};
const allMediaItems = Array.from(PhotoApp.getMediaItemList());
const albumList = Array.from(PhotoApp.getAlbumList({excludeNonAppCreatedData: false}));
const allItems = albumList.map(album => Array.from(PhotoApp.searchMediaItems({"albumId": album.id})));
let mediaItemsInAlbums = allItems.flat();
if (mediaItemsInAlbums.length === 0){
return [];
};
// Pulling mediaItems not in any albums by finding unique values between both lists
const allMediaItemsIds = allMediaItems.map(mediaItem => mediaItem.id);
const mediaItemsInAlbumsIds = mediaItemsInAlbums.map(mediaItemInAlbum => mediaItemInAlbum.id);
const uniqueToAllMediaItemsIDs = allMediaItemsIds.filter((id) => mediaItemsInAlbumsIds.indexOf(id) === -1);
// Running in batches according to BATCH_CALL_CAP const. Default value of 50 almost always results in errors
// due to overly-long URLs in API call.
const batchRunCap = 15;
const timesToRun = Math.ceil(uniqueToAllMediaItemsIDs.length/batchRunCap);
const lastRoundNumber = uniqueToAllMediaItemsIDs.length % batchRunCap;
let innerIteration = 0;
let innerIterCap = batchRunCap;
for (let i = 0; i < timesToRun; i++){
let arrayForBatchCall = [];
if ((timesToRun - 1) === i){
innerIterCap = innerIteration + lastRoundNumber;
for (let j = innerIteration; j < innerIterCap; j++ ){
arrayForBatchCall.push(uniqueToAllMediaItemsIDs[j]);
};
mediaNotInAlbum.push(PhotoApp.getMediaItems({mediaItemIds: arrayForBatchCall}));
} else {
for (let j = innerIteration; j < innerIterCap; j++){
arrayForBatchCall.push(uniqueToAllMediaItemsIDs[j]);
}
let setFromBatchArray = [...new Set(arrayForBatchCall)];
mediaNotInAlbum.push(PhotoApp.getMediaItems({mediaItemIds: setFromBatchArray}));
innerIteration += batchRunCap;
innerIterCap += batchRunCap;
};
};
// unpacking batchGets into a standard array of mediaItems
let isolatedMediaItems = [];
for (let i in mediaNotInAlbum){
for (let j in mediaNotInAlbum[i].mediaItemResults){
isolatedMediaItems.push(mediaNotInAlbum[i].mediaItemResults[j].mediaItem);
};
};
return isolatedMediaItems;
};
/**
* Retrieves all mediaItems that are in at least 1 album, including its related album.
* @return {Array<Object>} Object with 2 properties: a mediaItem, and the album it was found in.
*/
function getAllMediaInAlbumsIncAlbumInfo(){
const albumList = Array.from(PhotoApp.getAlbumList({excludeNonAppCreatedData: false}));
let mediaItemsInAlbumsRaw = [];
for (let i in albumList){
let albumId = albumList[i].id;
let mediaItem = Array.from(PhotoApp.searchMediaItems({"albumId": albumId}));
for (let j in mediaItem){
let mediaItemAlbumPair = {};
mediaItemAlbumPair.album = albumList[i];
mediaItemAlbumPair.mediaItem = mediaItem[j];
mediaItemsInAlbumsRaw.push(mediaItemAlbumPair);
};
};
const allMediaInAlbumsIncAlbumInfo = mediaItemsInAlbumsRaw.filter(mediaItem => mediaItem.album.id !==undefined)
return allMediaInAlbumsIncAlbumInfo;
};
/**
* Executes a series of functions to find all media (photos, videos) in a user's Google Photos library
* that is not in an album. Then writes the file name and product URL to a new sheet titled
* "All Isolated Media".
*/
function writeIsolatedMediaToSheet(){
const isolatedMedia = checkForNotInAlbum();
const SHEET_HEADER = ["File Name", "Product URL"];
if (isolatedMedia.length === 0){
UIObj.displayAlert("No items returned. Please verify that there are isolated items in your library.");
return;
} else if ((isolatedMedia.length === 1) && (isolatedMedia[0] instanceof TypeError)){
UIObj.displayAlert("Error in API iteration. Please check that your library contains items.");
return;
};
let arrayToWrite = [];
for (let media of isolatedMedia){
let innerVar = [];
innerVar.push(media.productUrl);
innerVar.push(media.filename);
arrayToWrite.push(innerVar);
};
arrayToWrite.splice(0, 0, SHEET_HEADER);
write2DArrayToSheet(arrayToWrite);
};
/**
* Executes a series of functions to find all media (photos, videos) in a user's Google Photos library
* that is in more than 1 album. Then writes the product Url, album title, and filename to the active sheet.
*/
function checkLibraryForDuplicates(){
const SHEET_HEADER = ["Product URL", "Album Title", "File Name"];
const libraryItems = getAllMediaInAlbumsIncAlbumInfo();
let dupeIDCheck = [];
let dupeIDCheckCorrespondingItem = [];
let confirmedDupes = [];
for (let i in libraryItems){
let mediaItemId = libraryItems[i].mediaItem.id;
if (dupeIDCheck.includes(mediaItemId)){
let matchingID = dupeIDCheck.indexOf(mediaItemId)
let correspondingItem = dupeIDCheckCorrespondingItem[matchingID];
if (!confirmedDupes.some(e => e.mediaItem.productUrl === correspondingItem.mediaItem.productUrl)){
confirmedDupes.push(correspondingItem);
};
let ToPush = libraryItems[i]
// checking productUrl to ensure the same item isn't written twice
if (!confirmedDupes.some(e => e.mediaItem.productUrl === ToPush.mediaItem.productUrl)){
confirmedDupes.push(ToPush);
};
};
dupeIDCheck.push(mediaItemId);
dupeIDCheckCorrespondingItem.push(libraryItems[i]);
};
if (confirmedDupes.length === 0){
UIObj.displayAlert("No duplicates found.");
return;
};
let arrayToWrite = [];
for (let dupe of confirmedDupes){
let tempArray = [];
tempArray.push(dupe.mediaItem.productUrl);
tempArray.push(dupe.album.title);
tempArray.push(dupe.mediaItem.filename);
arrayToWrite.push(tempArray);
};
if (arrayToWrite){
arrayToWrite.splice(0, 0, SHEET_HEADER);
};
write2DArrayToSheet(arrayToWrite);
};