• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bpatrik / pigallery2 / 19246693835

10 Nov 2025 09:28PM UTC coverage: 68.916% (+0.2%) from 68.683%
19246693835

push

github

bpatrik
Fix contentwrapper packing and unpacking issue

1449 of 2351 branches covered (61.63%)

Branch coverage included in aggregate %.

4 of 5 new or added lines in 2 files covered. (80.0%)

11 existing lines in 1 file now uncovered.

5240 of 7355 relevant lines covered (71.24%)

4194.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.52
/src/common/entities/ContentWrapper.ts
1
/* eslint-disable @typescript-eslint/ban-ts-comment */
2
import {DirectoryBaseDTO, DirectoryPathDTO, ParentDirectoryDTO} from './DirectoryDTO';
3
import {SearchResultDTO} from './SearchResultDTO';
4
import {Utils} from '../Utils';
1✔
5
import {MediaDTO, MediaDTOUtils} from './MediaDTO';
1✔
6
import {FileDTO} from './FileDTO';
7
import {VideoDTO} from './VideoDTO';
8
import {PhotoDTO} from './PhotoDTO';
9

10

11
export interface ContentWrapper {
12
  directory: ParentDirectoryDTO;
13
  searchResult: SearchResultDTO;
14
  notModified?: boolean;
15
}
16

17
export interface PackedContentWrapper {
18
  directory: ParentDirectoryDTO;
19
  searchResult: SearchResultDTO;
20
  notModified?: boolean;
21
  map: {
22
    faces: string[],
23
    keywords: string[],
24
    lens: string[],
25
    camera: string[],
26
    directories: DirectoryPathDTO[]
27
  };
28
  // temporal field
29
  reverseMap?: {
30
    faces: Map<string, number>,
31
    keywords: Map<string, number>,
32
    lens: Map<string, number>,
33
    camera: Map<string, number>,
34
    directories: Map<string, number>
35
  };
36
}
37

38

39
export interface ContentWrapperWithError extends ContentWrapper {
40
  error?: string;
41
}
42

43
export interface PackedContentWrapperWithError extends PackedContentWrapper {
44
  error?: string;
45
}
46

47
export class ContentWrapperUtils {
1✔
48

49
  static equals(cw1: ContentWrapper, cw2: ContentWrapper): boolean {
50
    if (cw1 === cw2) {
45✔
51
      return true;
2✔
52
    }
53

54
    if (!cw1 || !cw2) {
43✔
55
      return false;
2✔
56
    }
57

58
    if (cw1.notModified !== cw2.notModified) {
41✔
59
      return false;
2✔
60
    }
61

62
    if (cw1.directory && !ContentWrapperUtils.equalsPartialDirectory(cw1.directory, cw2.directory)) {
39✔
63
      return false;
2✔
64
    }
65
    const c1 = cw1.directory || cw1.searchResult;
37✔
66
    const c2 = cw2.directory || cw2.searchResult;
37✔
67
    if (c1 === c2) {
37✔
68
      return true;
1✔
69
    }
70

71
    if (!c1 || !c2) {
36!
NEW
72
      return false;
×
73
    }
74
    if (!this.equalsDirectories(c1.directories, c2.directories)) {
36✔
75
      return false;
2✔
76
    }
77
    if (!this.equalsFiles(c1.media, c2.media)) {
34✔
78
      return false;
12✔
79
    }
80
    if (!this.equalsFiles(c1.metaFile, c2.metaFile)) {
22✔
81
      return false;
5✔
82
    }
83

84
    return true;
17✔
85
  }
86

87
  static equalsMedia(d1: FileDTO, d2: FileDTO): boolean {
88
    if (d1 === d2) {
139✔
89
      return true;
39✔
90
    }
91
    if (!d1 || !d2) {
100!
UNCOV
92
      return false;
×
93
    }
94
    const {directory: m1dir, ...pm1} = d1;
100✔
95
    const {directory: m2dir, ...pm2} = d2;
100✔
96

97
    if (m1dir.name !== m2dir.name || m1dir.path !== m2dir.path) {
100!
UNCOV
98
      return false;
×
99
    }
100

101
    if (!Utils.equalsFilter(pm1, pm2)) {
100✔
102
      return false;
8✔
103
    }
104

105
    return true;
92✔
106

107

108
  }
109

110
  static equalsPartialDirectory(d1: DirectoryBaseDTO, d2: DirectoryBaseDTO): boolean {
111
    if (d1 === d2) {
41✔
112
      return true;
1✔
113
    }
114
    if (!d1 || !d2) {
40✔
115
      return false;
1✔
116
    }
117

118
    if (!ContentWrapperUtils.equalsMedia(d1.cache?.cover, d2.cache?.cover)) {
39!
UNCOV
119
      return false;
×
120
    }
121

122
    const {cover: d1cover, ...d1c} = d1.cache;
39✔
123
    const {cover: d2cover, ...d2c} = d2.cache;
39✔
124

125
    if (!Utils.equalsFilter(d1c, d2c)) {
39!
UNCOV
126
      return false;
×
127
    }
128

129
    const {parent: d1parent, directories: d1directories, media: d1media, metaFile: d1metaFile, cache: d1cache, ...pd1} = d1;
39✔
130
    const {parent: d2parent, directories: d2directories, media: d2media, metaFile: d2metaFile, cache: d2cache, ...pd2} = d2;
39✔
131

132
    if (!Utils.equalsFilter(pd1, pd2)) {
39✔
133
      return false;
2✔
134
    }
135

136
    return true;
37✔
137

138
  }
139

140
  static equalsDirectories(d1: DirectoryBaseDTO[], d2: DirectoryBaseDTO[]): boolean {
141
    if (d1 === d2) {
36!
UNCOV
142
      return true;
×
143
    }
144
    if (!d1 || !d2) {
36!
UNCOV
145
      return false;
×
146
    }
147
    if (d1.length !== d2.length) {
36✔
148
      return false;
1✔
149
    }
150

151
    const fullPath = (d: DirectoryBaseDTO) => d.path + '/' + d.name;
35✔
152

153
    const d1c = d1.slice().sort((a, b) => fullPath(a).localeCompare(fullPath(b)));
35✔
154
    const d2c = d2.slice().sort((a, b) => fullPath(a).localeCompare(fullPath(b)));
35✔
155
    for (let i = 0; i < d1.length; ++i) {
35✔
156
      if (ContentWrapperUtils.equalsPartialDirectory(d1c[i], d2c[i]) === false) {
7✔
157
        return false;
1✔
158
      }
159
    }
160
    return true;
34✔
161
  }
162

163
  static equalsFiles(m1: FileDTO[], m2: FileDTO[]): boolean {
164
    if (m1 === m2) {
56!
UNCOV
165
      return true;
×
166
    }
167
    if (!m1 || !m2) {
56✔
168
      return false;
2✔
169
    }
170

171
    if (m1.length !== m2.length) {
54✔
172
      return false;
7✔
173
    }
174

175
    const fullPath = (m: FileDTO) => m.directory.path + '/' + m.directory.name + '/' + m.name;
508✔
176
    const m1c = m1.slice().sort((a, b) => fullPath(a).localeCompare(fullPath(b)));
127✔
177
    const m2c = m2.slice().sort((a, b) => fullPath(a).localeCompare(fullPath(b)));
127✔
178

179
    for (let i = 0; i < m1.length; ++i) {
47✔
180
      if (ContentWrapperUtils.equalsMedia(m1c[i], m2c[i]) === false) {
100✔
181
        return false;
8✔
182
      }
183
    }
184
    return true;
39✔
185
  }
186

187

188
  static pack(cwIn: ContentWrapper): PackedContentWrapper {
189
    const cw: PackedContentWrapper = {
12✔
190
      map: {
191
        faces: [], keywords: [], lens: [],
192
        camera: [], directories: []
193
      },
194
      reverseMap: {
195
        faces: new Map(), keywords: new Map(),
196
        lens: new Map(), camera: new Map(), directories: new Map()
197
      },
198
      ...cwIn
199
    };
200

201
    if (cw?.directory) {
12✔
202
      ContentWrapperUtils.packDirectory(cw, cw.directory);
11✔
203
    } else if (cw.searchResult) {
1✔
204
      ContentWrapperUtils.packDirectory(cw, cw.searchResult, true);
1✔
205
    }
206

207
    // remove empty maps
208
    for (const k in cw.map) {
12✔
209
      // @ts-ignore
210
      if (cw.map[k].length === 0) {
60✔
211
        // @ts-ignore
212
        delete cw.map[k];
20✔
213
      }
214
    }
215

216
    delete cw.reverseMap;
12✔
217
    return cw;
12✔
218

219
  }
220

221
  static unpack(cwIn: PackedContentWrapper): ContentWrapper {
222
    const cw = {...cwIn};
2✔
223
    if (!cw || cw.notModified) {
2!
UNCOV
224
      return cw;
×
225
    }
226
    if (cw?.directory) {
2✔
227
      ContentWrapperUtils.unPackDirectory(cw, cw.directory);
1✔
228
    } else if (cw.searchResult) {
1✔
229
      ContentWrapperUtils.unPackDirectory(cw, cw.searchResult, true);
1✔
230
    }
231
    delete cw.map;
2✔
232
    return cw;
2✔
233
  }
234

235
  public static build(
236
    directory: ParentDirectoryDTO = null,
×
237
    searchResult: SearchResultDTO = null,
×
238
    notModified?: boolean
239
  ) {
240
    const cw: ContentWrapper = {
48✔
241
      ...(directory && {directory}),
82✔
242
      ...(searchResult && {searchResult}),
62✔
243
      ...(notModified && {notModified}),
51✔
244
    };
245
    return cw;
48✔
246
  }
247

248
  private static mapify(cw: PackedContentWrapper, media: FileDTO, isSearchResult: boolean): void {
249
    if (isSearchResult) {
215✔
250
      const k = JSON.stringify(media.directory);
5✔
251
      if (!cw.reverseMap.directories.has(k)) {
5✔
252
        cw.reverseMap.directories.set(k, cw.map.directories.length);
3✔
253
        cw.map.directories.push(media.directory);
3✔
254
      }
255
      // @ts-ignore
256
      media.d = cw.reverseMap.directories.get(k);
5✔
257
      delete media.directory;
5✔
258
    }
259

260

261
    // @ts-ignore
262
    (media as MediaDTO)['n'] = (media as MediaDTO).name;
215✔
263
    delete (media as MediaDTO).name;
215✔
264

265
    if (typeof (media as MediaDTO).missingThumbnails !== 'undefined') {
215✔
266
      // @ts-ignore
267
      (media as MediaDTO)['t'] = (media as MediaDTO).missingThumbnails;
173✔
268
      delete (media as MediaDTO).missingThumbnails;
173✔
269
    }
270

271
    if ((media as MediaDTO).metadata) {
215✔
272
      // @ts-ignore
273
      (media as MediaDTO).metadata['d'] = [(media as MediaDTO).metadata.size.width, (media as MediaDTO).metadata.size.height];
209✔
274
      delete (media as MediaDTO).metadata.size;
209✔
275
      // @ts-ignore
276
      (media as MediaDTO).metadata['s'] = (media as MediaDTO).metadata.fileSize;
209✔
277
      delete (media as MediaDTO).metadata.fileSize;
209✔
278

279
      // @ts-ignore
280
      (media as MediaDTO).metadata['t'] = (media as MediaDTO).metadata.creationDate / 1000; // skip millies
209✔
281
      delete (media as MediaDTO).metadata.creationDate;
209✔
282

283
      if ((media as MediaDTO).metadata.creationDateOffset) {
209✔
284
        // @ts-ignore
285
        (media as MediaDTO).metadata['o'] = Utils.getOffsetMinutes((media as MediaDTO).metadata.creationDateOffset); // offset in minutes
119✔
286
        delete (media as MediaDTO).metadata.creationDateOffset;
119✔
287
      }
288

289
      if ((media as PhotoDTO).metadata.rating) {
209✔
290
        // @ts-ignore
291
        (media as PhotoDTO).metadata['r'] = (media as PhotoDTO).metadata.rating;
20✔
292
        delete (media as PhotoDTO).metadata.rating;
20✔
293
      }
294
      if ((media as PhotoDTO).metadata.caption) {
209✔
295
        // @ts-ignore
296
        (media as PhotoDTO).metadata['a'] = (media as PhotoDTO).metadata.caption;
16✔
297
        delete (media as PhotoDTO).metadata.caption;
16✔
298
      }
299

300
      if ((media as PhotoDTO).metadata.faces) {
209✔
301
        for (let i = 0; i < (media as PhotoDTO).metadata.faces.length; ++i) {
81✔
302
          const name = (media as PhotoDTO).metadata.faces[i].name;
129✔
303
          if (!cw.reverseMap.faces.has(name)) {
129✔
304
            cw.reverseMap.faces.set(name, cw.map.faces.length);
61✔
305
            cw.map.faces.push(name);
61✔
306
          }
307
          // @ts-ignore
308
          (media as PhotoDTO).metadata.faces[i] = [...(media as PhotoDTO).metadata.faces[i].b, cw.reverseMap.faces.get(name)];
129✔
309
        }
310

311
        // @ts-ignore
312
        (media as PhotoDTO).metadata['f'] = (media as PhotoDTO).metadata.faces;
81✔
313
        delete (media as PhotoDTO).metadata.faces;
81✔
314
      }
315

316
      if ((media as PhotoDTO).metadata.keywords) {
209✔
317
        for (let i = 0; i < (media as PhotoDTO).metadata.keywords.length; ++i) {
103✔
318
          const k = (media as PhotoDTO).metadata.keywords[i];
126✔
319
          if (!cw.reverseMap.keywords.has(k)) {
126✔
320
            cw.reverseMap.keywords.set(k, cw.map.keywords.length);
78✔
321
            cw.map.keywords.push(k);
78✔
322
          }
323
          // @ts-ignore
324
          (media as PhotoDTO).metadata.keywords[i] = cw.reverseMap.keywords.get(k);
126✔
325
        }
326
        // @ts-ignore
327
        (media as PhotoDTO).metadata['k'] = (media as PhotoDTO).metadata.keywords;
103✔
328
        delete (media as PhotoDTO).metadata.keywords;
103✔
329
      }
330
      const mapifyOne = <T>(map: string[], reverseMap: Map<string, number>,
209✔
331
                            obj: T, key: keyof T, mappedKey: string) => {
332

333
        // @ts-ignore
334
        const k: string = obj[key];
299✔
335

336
        if (!reverseMap.has(k)) {
299✔
337
          reverseMap.set(k, map.length);
183✔
338
          map.push(k);
183✔
339
        }
340
        // @ts-ignore
341
        obj[mappedKey] = reverseMap.get(k);
299✔
342
        delete obj[key];
299✔
343
      };
344
      if ((media as PhotoDTO).metadata.cameraData) {
209✔
345
        if ((media as PhotoDTO).metadata.cameraData.lens) {
95✔
346
          mapifyOne(cw.map.lens, cw.reverseMap.lens,
35✔
347
            (media as PhotoDTO).metadata.cameraData, 'lens', 'l');
348
        }
349
        if ((media as PhotoDTO).metadata.cameraData.make) {
95✔
350
          mapifyOne(cw.map.camera, cw.reverseMap.camera,
77✔
351
            (media as PhotoDTO).metadata.cameraData, 'make', 'm');
352
        }
353
        if ((media as PhotoDTO).metadata.cameraData.model) {
95✔
354
          mapifyOne(cw.map.camera, cw.reverseMap.camera,
77✔
355
            (media as PhotoDTO).metadata.cameraData, 'model', 'o');
356
        }
357

358
        if ((media as PhotoDTO).metadata.cameraData.ISO) {
95✔
359
          // @ts-ignore
360
          (media as PhotoDTO).metadata.cameraData['i'] = (media as PhotoDTO).metadata.cameraData.ISO;
52✔
361
          delete (media as PhotoDTO).metadata.cameraData.ISO;
52✔
362
        }
363
        if ((media as PhotoDTO).metadata.cameraData.fStop) {
95✔
364
          // @ts-ignore
365
          (media as PhotoDTO).metadata.cameraData['s'] = (media as PhotoDTO).metadata.cameraData.fStop;
61✔
366
          delete (media as PhotoDTO).metadata.cameraData.fStop;
61✔
367
        }
368
        if ((media as PhotoDTO).metadata.cameraData.exposure) {
95✔
369
          // @ts-ignore
370
          (media as PhotoDTO).metadata.cameraData['e'] = (media as PhotoDTO).metadata.cameraData.exposure;
61✔
371
          delete (media as PhotoDTO).metadata.cameraData.exposure;
61✔
372
        }
373
        if ((media as PhotoDTO).metadata.cameraData.focalLength) {
95✔
374
          // @ts-ignore
375
          (media as PhotoDTO).metadata.cameraData['a'] = (media as PhotoDTO).metadata.cameraData.focalLength;
61✔
376
          delete (media as PhotoDTO).metadata.cameraData.focalLength;
61✔
377
        }
378

379
        // @ts-ignore
380
        (media as PhotoDTO).metadata['c'] = (media as PhotoDTO).metadata.cameraData;
95✔
381
        delete (media as PhotoDTO).metadata.cameraData;
95✔
382
      }
383
      if ((media as PhotoDTO).metadata.positionData) {
209✔
384
        if ((media as PhotoDTO).metadata.positionData.country) {
79✔
385
          mapifyOne(cw.map.keywords, cw.reverseMap.keywords,
38✔
386
            (media as PhotoDTO).metadata.positionData, 'country', 'c');
387
        }
388
        if ((media as PhotoDTO).metadata.positionData.city) {
79✔
389
          mapifyOne(cw.map.keywords, cw.reverseMap.keywords,
34✔
390
            (media as PhotoDTO).metadata.positionData, 'city', 'cy');
391
        }
392
        if ((media as PhotoDTO).metadata.positionData.state) {
79✔
393
          mapifyOne(cw.map.keywords, cw.reverseMap.keywords,
38✔
394
            (media as PhotoDTO).metadata.positionData, 'state', 's');
395
        }
396

397
        if ((media as PhotoDTO).metadata.positionData.GPSData) {
79✔
398
          // @ts-ignore
399
          (media as PhotoDTO).metadata.positionData['g'] = [(media as PhotoDTO).metadata.positionData.GPSData.latitude, (media as PhotoDTO).metadata.positionData.GPSData.longitude];
71✔
400
          delete (media as PhotoDTO).metadata.positionData.GPSData;
71✔
401
        }
402
        // @ts-ignore
403
        (media as PhotoDTO).metadata['p'] = (media as PhotoDTO).metadata.positionData;
79✔
404
        delete (media as PhotoDTO).metadata.positionData;
79✔
405
      }
406

407
      // @ts-ignore
408
      (media as PhotoDTO)['m'] = (media as PhotoDTO).metadata;
209✔
409
      delete (media as PhotoDTO).metadata;
209✔
410
    }
411

412
  }
413

414
  private static packMedia(cw: PackedContentWrapper, media: MediaDTO[], isSearchResult: boolean): void {
415

416
    // clean up media
417
    for (let i = 0; i < media.length; ++i) {
40✔
418
      const m = media[i];
209✔
419
      delete m.id;
209✔
420

421
      if (m.directory) {
209✔
422
        if (isSearchResult) {
188✔
423
          // keep the directory for search result
424
          m.directory = {
4✔
425
            path: (m.directory as DirectoryBaseDTO).path,
426
            name: (m.directory as DirectoryBaseDTO).name,
427
          } as DirectoryPathDTO;
428
        } else {
429
          // for gallery listing, photos belong to one directory,
430
          // this can be deleted as the directory know its child
431
          delete m.directory;
184✔
432
        }
433
      }
434

435
      if (MediaDTOUtils.isPhoto(m)) {
209✔
436
        delete (m as VideoDTO).metadata.bitRate;
195✔
437
        delete (m as VideoDTO).metadata.duration;
195✔
438

439
        // compress faces
440
        if ((m as PhotoDTO).metadata.faces) {
195✔
441
          for (let j = 0; j < (m as PhotoDTO).metadata.faces.length; ++j) {
81✔
442
            const f = (m as PhotoDTO).metadata.faces[j];
129✔
443
            // @ts-ignore
444
            f['b'] = [f.box.top, f.box.left, f.box.height, f.box.width];
129✔
445
            delete f.box;
129✔
446
          }
447
        }
448
        ContentWrapperUtils.mapify(cw, m, isSearchResult);
195✔
449
      } else if (MediaDTOUtils.isVideo(m)) {
14✔
450
        delete (m as PhotoDTO).metadata.caption;
14✔
451
        delete (m as PhotoDTO).metadata.cameraData;
14✔
452
        delete (m as PhotoDTO).metadata.faces;
14✔
453
        delete (m as PhotoDTO).metadata.positionData;
14✔
454
        ContentWrapperUtils.mapify(cw, m, isSearchResult);
14✔
455
      }
456
      Utils.removeNullOrEmptyObj(m);
209✔
457
    }
458
  }
459

460
  private static packDirectory(cw: PackedContentWrapper, dir: DirectoryBaseDTO | SearchResultDTO, isSearchResult = false): void {
40✔
461
    if ((dir as DirectoryBaseDTO).cache?.cover) {
41✔
462
      (dir as DirectoryBaseDTO).cache.cover.directory = {
37✔
463
        path: (dir as DirectoryBaseDTO).cache.cover.directory.path,
464
        name: (dir as DirectoryBaseDTO).cache.cover.directory.name,
465
      } as DirectoryPathDTO;
466

467
      // make sure that it is a different object as one of the photo in the media[]
468
      // as the next foreach would remove the directory
469
      (dir as DirectoryBaseDTO).cache.cover = Utils.clone((dir as DirectoryBaseDTO).cache.cover);
37✔
470
    }
471

472
    if (dir.media) {
41✔
473
      ContentWrapperUtils.packMedia(cw, dir.media, isSearchResult);
40✔
474
    }
475

476
    if (dir.metaFile) {
41✔
477
      for (let i = 0; i < dir.metaFile.length; ++i) {
40✔
478
        if (isSearchResult) {
6✔
479
          delete (dir.metaFile[i].directory as DirectoryBaseDTO).id;
1✔
480
        } else {
481
          delete dir.metaFile[i].directory;
5✔
482
        }
483
        delete dir.metaFile[i].id;
6✔
484
        ContentWrapperUtils.mapify(cw, dir.metaFile[i], isSearchResult);
6✔
485
      }
486
    }
487
    if (dir.directories) {
41✔
488
      for (let i = 0; i < dir.directories.length; ++i) {
40✔
489
        // first remove the parent otherwise it will be a infinite recursion
490
        delete dir.directories[i].parent;
29✔
491
        ContentWrapperUtils.packDirectory(cw, dir.directories[i]);
29✔
492
      }
493
    }
494

495
    // should not go to the client side
496
    delete (dir as DirectoryBaseDTO).cache?.directory; // client know its directory
41✔
497
    delete (dir as DirectoryBaseDTO).cache?.cover?.id;
41✔
498
    delete (dir as DirectoryBaseDTO).cache?.id;
41✔
499
    delete (dir as DirectoryBaseDTO).cache?.projectionKey; // client already knows its projectionKey
41✔
500
    delete (dir as DirectoryBaseDTO).cache?.valid;
41✔
501

502
    Utils.removeNullOrEmptyObj(dir);
41✔
503
  }
504

505
  private static deMapify(cw: PackedContentWrapper, media: FileDTO, isSearchResult: boolean): void {
506

507
    const deMapifyOne = <T>(map: any[],
10✔
508
                            obj: T, key: keyof T, mappedKey: string) => {
509
      // @ts-ignore
510
      obj[key] = map[obj[mappedKey]];
41✔
511
      // @ts-ignore
512
      delete obj[mappedKey];
41✔
513
    };
514
    if (isSearchResult) {
10✔
515
      deMapifyOne(cw.map.directories, media, 'directory', 'd');
5✔
516
    }
517

518
    // @ts-ignore
519
    if ((media as MediaDTO)['n']) {
10✔
520
      // @ts-ignore
521
      (media as PhotoDTO).name = (media as PhotoDTO)['n'];
10✔
522
      // @ts-ignore
523
      delete (media as PhotoDTO)['n'];
10✔
524
    }
525
    // @ts-ignore
526
    if ((media as MediaDTO)['t']) {
10!
527
      // @ts-ignore
UNCOV
528
      (media as PhotoDTO).missingThumbnails = (media as PhotoDTO)['t'];
×
529
      // @ts-ignore
UNCOV
530
      delete (media as PhotoDTO)['t'];
×
531
    }
532

533
    // @ts-ignore
534
    if ((media as MediaDTO)['m']) {
10✔
535
      // @ts-ignore
536
      (media as PhotoDTO).metadata = (media as PhotoDTO)['m'];
8✔
537
      // @ts-ignore
538
      delete (media as PhotoDTO)['m'];
8✔
539

540
      (media as MediaDTO).metadata.size = {
8✔
541
        // @ts-ignore
542
        width: (media as MediaDTO).metadata['d'][0],
543
        // @ts-ignore
544
        height: (media as MediaDTO).metadata['d'][1],
545
      };
546
      // @ts-ignore
547
      delete (media as MediaDTO).metadata['d'];
8✔
548

549

550
      // @ts-ignore
551
      if (typeof (media as PhotoDTO).metadata['t'] !== 'undefined') {
8✔
552
        // @ts-ignore
553
        (media as PhotoDTO).metadata.creationDate = (media as PhotoDTO).metadata['t'] * 1000;
8✔
554
        // @ts-ignore
555
        delete (media as PhotoDTO).metadata['t'];
8✔
556
      }
557

558
      // @ts-ignore
559
      if (typeof (media as PhotoDTO).metadata['o'] !== 'undefined') {
8✔
560
        // @ts-ignore
561
        (media as PhotoDTO).metadata.creationDateOffset = Utils.getOffsetString((media as PhotoDTO).metadata['o']);//convert offset from minutes to String
6✔
562
        // @ts-ignore
563
        delete (media as PhotoDTO).metadata['o'];
6✔
564
      }
565

566
      // @ts-ignore
567
      if (typeof (media as PhotoDTO).metadata['r'] !== 'undefined') {
8✔
568
        // @ts-ignore
569
        (media as PhotoDTO).metadata.rating = (media as PhotoDTO).metadata['r'];
4✔
570
        // @ts-ignore
571
        delete (media as PhotoDTO).metadata['r'];
4✔
572
      }
573

574
      // @ts-ignore
575
      if (typeof (media as PhotoDTO).metadata['a'] !== 'undefined') {
8✔
576
        // @ts-ignore
577
        (media as PhotoDTO).metadata.caption = (media as PhotoDTO).metadata['a'];
4✔
578
        // @ts-ignore
579
        delete (media as PhotoDTO).metadata['a'];
4✔
580
      }
581

582
      // @ts-ignore
583
      (media as PhotoDTO).metadata.fileSize = (media as PhotoDTO).metadata['s'];
8✔
584
      // @ts-ignore
585
      delete (media as PhotoDTO).metadata['s'];
8✔
586

587

588
      // @ts-ignore
589
      if ((media as PhotoDTO).metadata['f']) {
8✔
590
        // @ts-ignore
591
        (media as PhotoDTO).metadata.faces = (media as PhotoDTO).metadata['f'];
4✔
592
        // @ts-ignore
593
        delete (media as PhotoDTO).metadata['f'];
4✔
594
        for (let j = 0; j < (media as PhotoDTO).metadata.faces.length; ++j) {
4✔
595
          // @ts-ignore
596
          const boxArr: number[] = (media as PhotoDTO).metadata.faces[j];
20✔
597
          (media as PhotoDTO).metadata.faces[j] = {
20✔
598
            box: {
599
              top: boxArr[0],
600
              left: boxArr[1],
601
              height: boxArr[2],
602
              width: boxArr[3],
603
            },
604
            // @ts-ignore
605
            name: boxArr[4]
606
          };
607
        }
608

609
        for (let i = 0; i < (media as PhotoDTO).metadata.faces.length; ++i) {
4✔
610
          // @ts-ignore
611
          (media as PhotoDTO).metadata.faces[i].name = cw.map.faces[(media as PhotoDTO).metadata.faces[i].name];
20✔
612

613
        }
614

615
      }
616
      // @ts-ignore
617
      if ((media as PhotoDTO).metadata['k']) {
8✔
618

619
        // @ts-ignore
620
        (media as PhotoDTO).metadata.keywords = (media as PhotoDTO).metadata['k'];
6✔
621
        // @ts-ignore
622
        delete (media as PhotoDTO).metadata['k'];
6✔
623
        for (let i = 0; i < (media as PhotoDTO).metadata.keywords.length; ++i) {
6✔
624
          // @ts-ignore
625
          (media as PhotoDTO).metadata.keywords[i] = cw.map.keywords[(media as PhotoDTO).metadata.keywords[i]];
22✔
626
        }
627
      }
628
      // @ts-ignore
629
      if ((media as PhotoDTO).metadata['c']) {
8✔
630
        // @ts-ignore
631
        (media as PhotoDTO).metadata.cameraData = (media as PhotoDTO).metadata.c;
6✔
632
        // @ts-ignore
633
        delete (media as PhotoDTO).metadata.c;
6✔
634

635
        // @ts-ignore
636
        if (typeof (media as PhotoDTO).metadata.cameraData.l !== 'undefined') {
6✔
637
          deMapifyOne(cw.map.lens,
6✔
638
            (media as PhotoDTO).metadata.cameraData, 'lens', 'l');
639
        }
640
        // @ts-ignore
641
        if (typeof (media as PhotoDTO).metadata.cameraData.m !== 'undefined') {
6✔
642
          deMapifyOne(cw.map.camera,
6✔
643
            (media as PhotoDTO).metadata.cameraData, 'make', 'm');
644
        }
645
        // @ts-ignore
646
        if (typeof (media as PhotoDTO).metadata.cameraData['o'] !== 'undefined') {
6✔
647
          deMapifyOne(cw.map.camera,
6✔
648
            (media as PhotoDTO).metadata.cameraData, 'model', 'o');
649
        }
650

651
        // @ts-ignore
652
        if (typeof (media as PhotoDTO).metadata.cameraData['i'] !== 'undefined') {
6✔
653
          // @ts-ignore
654
          (media as PhotoDTO).metadata.cameraData.ISO = (media as PhotoDTO).metadata.cameraData['i'];
6✔
655
          // @ts-ignore
656
          delete (media as PhotoDTO).metadata.cameraData['i'];
6✔
657
        }
658
        // @ts-ignore
659
        if (typeof (media as PhotoDTO).metadata.cameraData['a'] !== 'undefined') {
6✔
660
          // @ts-ignore
661
          (media as PhotoDTO).metadata.cameraData.focalLength = (media as PhotoDTO).metadata.cameraData['a'];
6✔
662
          // @ts-ignore
663
          delete (media as PhotoDTO).metadata.cameraData['a'];
6✔
664
        }
665
        // @ts-ignore
666
        if (typeof (media as PhotoDTO).metadata.cameraData['e'] !== 'undefined') {
6✔
667
          // @ts-ignore
668
          (media as PhotoDTO).metadata.cameraData.exposure = (media as PhotoDTO).metadata.cameraData['e'];
6✔
669
          // @ts-ignore
670
          delete (media as PhotoDTO).metadata.cameraData['e'];
6✔
671
        }
672
        // @ts-ignore
673
        if (typeof (media as PhotoDTO).metadata.cameraData['s'] !== 'undefined') {
6✔
674
          // @ts-ignore
675
          (media as PhotoDTO).metadata.cameraData.fStop = (media as PhotoDTO).metadata.cameraData['s'];
6✔
676
          // @ts-ignore
677
          delete (media as PhotoDTO).metadata.cameraData['s'];
6✔
678
        }
679

680
      }
681
      // @ts-ignore
682
      if ((media as PhotoDTO).metadata['p']) {
8✔
683
        // @ts-ignore
684
        (media as PhotoDTO).metadata.positionData = (media as PhotoDTO).metadata.p;
6✔
685
        // @ts-ignore
686
        delete (media as PhotoDTO).metadata.p;
6✔
687
        // @ts-ignore
688
        if (typeof (media as PhotoDTO).metadata.positionData.c !== 'undefined') {
6✔
689
          deMapifyOne(cw.map.keywords,
6✔
690
            (media as PhotoDTO).metadata.positionData, 'country', 'c');
691
        }
692
        // @ts-ignore
693
        if (typeof (media as PhotoDTO).metadata.positionData.cy !== 'undefined') {
6✔
694
          deMapifyOne(cw.map.keywords,
6✔
695
            (media as PhotoDTO).metadata.positionData, 'city', 'cy');
696
        }
697
        // @ts-ignore
698
        if (typeof (media as PhotoDTO).metadata.positionData.s !== 'undefined') {
6✔
699
          deMapifyOne(cw.map.keywords,
6✔
700
            (media as PhotoDTO).metadata.positionData, 'state', 's');
701
        }
702

703
        // @ts-ignore
704
        if ((media as PhotoDTO).metadata.positionData['g']) {
6✔
705
          (media as PhotoDTO).metadata.positionData.GPSData =
6✔
706
            {
707
              // @ts-ignore
708
              latitude: (media as PhotoDTO).metadata.positionData['g'][0],
709
              // @ts-ignore
710
              longitude: (media as PhotoDTO).metadata.positionData['g'][1]
711
            };
712
          // @ts-ignore
713
          delete (media as PhotoDTO).metadata.positionData['g'];
6✔
714
        }
715
      }
716
    }
717

718
  }
719

720
  private static unPackMedia(cw: PackedContentWrapper, dir: DirectoryBaseDTO, media: MediaDTO[], isSearchResult: boolean): void {
721
// clean up media
722
    for (let i = 0; i < media.length; ++i) {
2✔
723
      const m = media[i];
8✔
724

725
      ContentWrapperUtils.deMapify(cw, m, isSearchResult);
8✔
726

727
      if (!isSearchResult) {
8✔
728
        m.directory = dir;
4✔
729
      }
730
    }
731
  }
732

733
  private static unPackDirectory(cw: PackedContentWrapper, dir: DirectoryBaseDTO | SearchResultDTO, isSearchResult = false): void {
2✔
734
    if (dir.media) {
3✔
735
      ContentWrapperUtils.unPackMedia(cw, dir as DirectoryBaseDTO, dir.media, isSearchResult);
2✔
736
    }
737

738
    if (dir.metaFile) {
3✔
739
      for (let i = 0; i < dir.metaFile.length; ++i) {
2✔
740
        if (!isSearchResult) {
2✔
741
          dir.metaFile[i].directory = dir as DirectoryBaseDTO;
1✔
742
        }
743
        ContentWrapperUtils.deMapify(cw, dir.metaFile[i], isSearchResult);
2✔
744
      }
745
    }
746
    if (dir.directories) {
3✔
747
      for (let i = 0; i < dir.directories.length; ++i) {
1✔
748
        ContentWrapperUtils.unPackDirectory(cw, dir.directories[i]);
1✔
749
        if (!isSearchResult) {
1!
UNCOV
750
          dir.directories[i].parent = dir as DirectoryBaseDTO;
×
751
        }
752
      }
753
    }
754

755
  }
756
}
757

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc