@treeviz/gedcom-parser 2.1.9 → 2.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/classes/common.d.ts.map +1 -1
- package/dist/classes/gedcom.d.ts +5 -0
- package/dist/classes/gedcom.d.ts.map +1 -1
- package/dist/classes/index.js +146 -74
- package/dist/classes/indi.d.ts.map +1 -1
- package/dist/classes/obje.d.ts.map +1 -1
- package/dist/cli/index.js +146 -74
- package/dist/constants/index.js +115 -69
- package/dist/factories/index.js +115 -69
- package/dist/index.js +151 -84
- package/dist/interfaces/indi.d.ts +1 -0
- package/dist/interfaces/indi.d.ts.map +1 -1
- package/dist/kinship-translator/index.js +115 -69
- package/dist/utils/cache.d.ts.map +1 -1
- package/dist/utils/gedzip.d.ts.map +1 -1
- package/dist/utils/index.js +151 -84
- package/dist/utils/local-media.d.ts +7 -3
- package/dist/utils/local-media.d.ts.map +1 -1
- package/dist/utils/media-utils.d.ts +20 -0
- package/dist/utils/media-utils.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -41,6 +41,82 @@ var appendGedcomTrailer = (serialized) => {
|
|
|
41
41
|
}
|
|
42
42
|
return `${trimmed}${newline}0 TRLR`;
|
|
43
43
|
};
|
|
44
|
+
|
|
45
|
+
// src/utils/media-utils.ts
|
|
46
|
+
var getFileExtension = (filename) => {
|
|
47
|
+
if (!filename) {
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
if (filename.startsWith("data:")) {
|
|
51
|
+
const mime = filename.slice(5).split(";")[0] || "";
|
|
52
|
+
const subtype = (mime.split("/")[1] || "").toLowerCase();
|
|
53
|
+
if (subtype === "jpeg") {
|
|
54
|
+
return "jpg";
|
|
55
|
+
}
|
|
56
|
+
return subtype.split("+")[0] || "";
|
|
57
|
+
}
|
|
58
|
+
const withoutQuery = filename.split(/[?#]/)[0] || filename;
|
|
59
|
+
const match = withoutQuery.match(/\.([^.]+)$/);
|
|
60
|
+
return match ? match[1].toLowerCase() : "";
|
|
61
|
+
};
|
|
62
|
+
var isImageFormat = (format2) => {
|
|
63
|
+
if (!format2) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
let normalized = format2.toLowerCase().trim();
|
|
67
|
+
if (normalized.startsWith("data:")) {
|
|
68
|
+
normalized = getFileExtension(normalized);
|
|
69
|
+
} else if (normalized.includes("/")) {
|
|
70
|
+
normalized = normalized.split("/")[1]?.split("+")[0] || "";
|
|
71
|
+
if (normalized === "jpeg") {
|
|
72
|
+
normalized = "jpg";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const imageFormats = [
|
|
76
|
+
"jpg",
|
|
77
|
+
"jpeg",
|
|
78
|
+
"png",
|
|
79
|
+
"gif",
|
|
80
|
+
"bmp",
|
|
81
|
+
"webp",
|
|
82
|
+
"svg",
|
|
83
|
+
"tiff",
|
|
84
|
+
"tif"
|
|
85
|
+
];
|
|
86
|
+
return imageFormats.includes(normalized);
|
|
87
|
+
};
|
|
88
|
+
var resolveObjeForm = (obje) => {
|
|
89
|
+
const value = obje?.get?.("FILE.FORM")?.toValue?.() ?? obje?.get?.("FORM")?.toValue?.();
|
|
90
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
91
|
+
};
|
|
92
|
+
var mediaIdValue = (obje, path) => {
|
|
93
|
+
const value = obje?.get?.(path)?.toValue?.();
|
|
94
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
95
|
+
};
|
|
96
|
+
var resolveObjeMediaId = (obje) => mediaIdValue(obje, "RIN") || mediaIdValue(obje, "_CLON._OID") || mediaIdValue(obje, "_MSER._LKID") || mediaIdValue(obje, "_OID") || mediaIdValue(obje, "_LKID");
|
|
97
|
+
var ANCESTRY_MEDIA_RETRIEVAL_PREFIX = "https://www.ancestry.com/api/media/retrieval/v2/image";
|
|
98
|
+
var ANCESTRY_MEDIA_QUERY = "client=trees-mediaservice&imageQuality=hq";
|
|
99
|
+
var ancestryMediaPath = (namespace, imgId) => `/namespaces/${namespace}/media/${imgId}?${ANCESTRY_MEDIA_QUERY}`;
|
|
100
|
+
var ancestryMediaFileUrl = (namespace, imgId) => {
|
|
101
|
+
if (!namespace || !imgId) {
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
return `${ANCESTRY_MEDIA_RETRIEVAL_PREFIX}${ancestryMediaPath(namespace, imgId)}`;
|
|
105
|
+
};
|
|
106
|
+
var objeXrefKey = (obje, fallback = 0) => {
|
|
107
|
+
if (typeof obje?.id === "string" && obje.id) {
|
|
108
|
+
return obje.id;
|
|
109
|
+
}
|
|
110
|
+
const value = obje?.toValue?.();
|
|
111
|
+
if (typeof value === "string" && value.trim()) {
|
|
112
|
+
return value.trim();
|
|
113
|
+
}
|
|
114
|
+
if (typeof fallback === "string" && fallback.trim()) {
|
|
115
|
+
return fallback.trim();
|
|
116
|
+
}
|
|
117
|
+
return `@O${fallback}@`;
|
|
118
|
+
};
|
|
119
|
+
var objeNoteValue = (obje) => mediaIdValue(obje, "FILE.NOTE") || mediaIdValue(obje, "NOTE") || "";
|
|
44
120
|
var List = class _List {
|
|
45
121
|
// length = 0;
|
|
46
122
|
constructor(items) {
|
|
@@ -690,7 +766,7 @@ var Common = class _Common {
|
|
|
690
766
|
this,
|
|
691
767
|
options.obje.namespace,
|
|
692
768
|
options.obje.override,
|
|
693
|
-
void 0,
|
|
769
|
+
this.isAncestry() ? ancestryMediaFileUrl : void 0,
|
|
694
770
|
options.gedcomVersion
|
|
695
771
|
);
|
|
696
772
|
}
|
|
@@ -1209,11 +1285,8 @@ var storeCache = {
|
|
|
1209
1285
|
getCacheDbs().relativesOnDegreeCache.setItem(value);
|
|
1210
1286
|
}
|
|
1211
1287
|
}, 50),
|
|
1212
|
-
//
|
|
1288
|
+
// Image bytes are stored as one IndexedDB record per photo.
|
|
1213
1289
|
profilePictureCache: debounce((value) => {
|
|
1214
|
-
if (value) {
|
|
1215
|
-
getCacheDbs().profilePictureCache.setItem(value);
|
|
1216
|
-
}
|
|
1217
1290
|
}, 100)
|
|
1218
1291
|
};
|
|
1219
1292
|
var resetRelativesCache = () => {
|
|
@@ -2269,65 +2342,23 @@ var isRemoteOrEmbeddedMediaUrl = (path) => {
|
|
|
2269
2342
|
}
|
|
2270
2343
|
return path.startsWith("data:") || path.startsWith("blob:") || /^https?:\/\//i.test(path);
|
|
2271
2344
|
};
|
|
2272
|
-
var resolveLocalMediaUrl = async (path) => {
|
|
2345
|
+
var resolveLocalMediaUrl = async (path, context) => {
|
|
2273
2346
|
if (!path) {
|
|
2274
2347
|
return void 0;
|
|
2275
2348
|
}
|
|
2276
|
-
if (
|
|
2349
|
+
if (path.startsWith("data:") || path.startsWith("blob:")) {
|
|
2277
2350
|
return path;
|
|
2278
2351
|
}
|
|
2279
|
-
const resolved = await localMediaResolver?.(path);
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
var implemented = (type, ...args) => {
|
|
2283
|
-
};
|
|
2284
|
-
|
|
2285
|
-
// src/utils/media-utils.ts
|
|
2286
|
-
var getFileExtension = (filename) => {
|
|
2287
|
-
if (!filename) {
|
|
2288
|
-
return "";
|
|
2289
|
-
}
|
|
2290
|
-
if (filename.startsWith("data:")) {
|
|
2291
|
-
const mime = filename.slice(5).split(";")[0] || "";
|
|
2292
|
-
const subtype = (mime.split("/")[1] || "").toLowerCase();
|
|
2293
|
-
if (subtype === "jpeg") {
|
|
2294
|
-
return "jpg";
|
|
2295
|
-
}
|
|
2296
|
-
return subtype.split("+")[0] || "";
|
|
2352
|
+
const resolved = await localMediaResolver?.(path, context);
|
|
2353
|
+
if (resolved) {
|
|
2354
|
+
return resolved;
|
|
2297
2355
|
}
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
return match ? match[1].toLowerCase() : "";
|
|
2301
|
-
};
|
|
2302
|
-
var isImageFormat = (format2) => {
|
|
2303
|
-
if (!format2) {
|
|
2304
|
-
return false;
|
|
2305
|
-
}
|
|
2306
|
-
let normalized = format2.toLowerCase().trim();
|
|
2307
|
-
if (normalized.startsWith("data:")) {
|
|
2308
|
-
normalized = getFileExtension(normalized);
|
|
2309
|
-
} else if (normalized.includes("/")) {
|
|
2310
|
-
normalized = normalized.split("/")[1]?.split("+")[0] || "";
|
|
2311
|
-
if (normalized === "jpeg") {
|
|
2312
|
-
normalized = "jpg";
|
|
2313
|
-
}
|
|
2356
|
+
if (/^https?:\/\//i.test(path)) {
|
|
2357
|
+
return path;
|
|
2314
2358
|
}
|
|
2315
|
-
|
|
2316
|
-
"jpg",
|
|
2317
|
-
"jpeg",
|
|
2318
|
-
"png",
|
|
2319
|
-
"gif",
|
|
2320
|
-
"bmp",
|
|
2321
|
-
"webp",
|
|
2322
|
-
"svg",
|
|
2323
|
-
"tiff",
|
|
2324
|
-
"tif"
|
|
2325
|
-
];
|
|
2326
|
-
return imageFormats.includes(normalized);
|
|
2359
|
+
return void 0;
|
|
2327
2360
|
};
|
|
2328
|
-
var
|
|
2329
|
-
const value = obje?.get?.("FILE.FORM")?.toValue?.() ?? obje?.get?.("FORM")?.toValue?.();
|
|
2330
|
-
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2361
|
+
var implemented = (type, ...args) => {
|
|
2331
2362
|
};
|
|
2332
2363
|
var uniqueItemsCache = /* @__PURE__ */ new WeakMap();
|
|
2333
2364
|
var setNestedGroup = (obj, key, value, uniqueCounting = true) => {
|
|
@@ -3504,22 +3535,19 @@ var Indi = class extends Common {
|
|
|
3504
3535
|
if (objeList) {
|
|
3505
3536
|
await Promise.all(
|
|
3506
3537
|
objeList.map(async (objeRef) => {
|
|
3507
|
-
const key = objeRef
|
|
3538
|
+
const key = objeXrefKey(objeRef, 0);
|
|
3508
3539
|
const obje = objeRef?.standardizeMedia(
|
|
3509
3540
|
namespace,
|
|
3510
3541
|
true,
|
|
3511
|
-
|
|
3512
|
-
return ns && iId ? `https://mediasvc.ancestry.com/v2/image/namespaces/${ns}/media/${iId}?client=trees-mediaservice&imageQuality=hq` : void 0;
|
|
3513
|
-
}
|
|
3542
|
+
ancestryMediaFileUrl
|
|
3514
3543
|
);
|
|
3515
3544
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3516
|
-
const media =
|
|
3517
|
-
const clone = obje?.get("_CLON._OID")?.toValue();
|
|
3518
|
-
const mser = obje?.get("_MSER._LKID")?.toValue();
|
|
3545
|
+
const media = resolveObjeMediaId(obje);
|
|
3519
3546
|
let url = obje?.get("FILE")?.toValue();
|
|
3520
3547
|
const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
|
|
3548
|
+
const note = objeNoteValue(obje);
|
|
3521
3549
|
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
3522
|
-
let imgId =
|
|
3550
|
+
let imgId = media;
|
|
3523
3551
|
const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
|
|
3524
3552
|
if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
|
|
3525
3553
|
return;
|
|
@@ -3555,6 +3583,7 @@ var Indi = class extends Common {
|
|
|
3555
3583
|
imgId,
|
|
3556
3584
|
person: this.id,
|
|
3557
3585
|
title,
|
|
3586
|
+
note,
|
|
3558
3587
|
url,
|
|
3559
3588
|
contentType: type,
|
|
3560
3589
|
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
|
|
@@ -3593,7 +3622,7 @@ var Indi = class extends Common {
|
|
|
3593
3622
|
return;
|
|
3594
3623
|
}
|
|
3595
3624
|
const obje = o;
|
|
3596
|
-
const key =
|
|
3625
|
+
const key = objeXrefKey(obje, index);
|
|
3597
3626
|
obje.standardizeMedia();
|
|
3598
3627
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3599
3628
|
const url = obje?.get("FILE")?.toValue();
|
|
@@ -3612,6 +3641,7 @@ var Indi = class extends Common {
|
|
|
3612
3641
|
imgId,
|
|
3613
3642
|
person: this.id,
|
|
3614
3643
|
title,
|
|
3644
|
+
note: objeNoteValue(obje),
|
|
3615
3645
|
url,
|
|
3616
3646
|
contentType: type,
|
|
3617
3647
|
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
|
|
@@ -3720,7 +3750,7 @@ var Indi = class extends Common {
|
|
|
3720
3750
|
if (!obje) {
|
|
3721
3751
|
return;
|
|
3722
3752
|
}
|
|
3723
|
-
const key =
|
|
3753
|
+
const key = objeXrefKey(obje, index);
|
|
3724
3754
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3725
3755
|
const url = obje?.get("FILE")?.toValue();
|
|
3726
3756
|
const title = obje?.get("TITL")?.toValue() ?? "";
|
|
@@ -3737,6 +3767,7 @@ var Indi = class extends Common {
|
|
|
3737
3767
|
imgId,
|
|
3738
3768
|
person: this.id,
|
|
3739
3769
|
title,
|
|
3770
|
+
note: objeNoteValue(obje),
|
|
3740
3771
|
url,
|
|
3741
3772
|
contentType: type,
|
|
3742
3773
|
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
|
|
@@ -3760,7 +3791,7 @@ var Indi = class extends Common {
|
|
|
3760
3791
|
if (!obje) {
|
|
3761
3792
|
return;
|
|
3762
3793
|
}
|
|
3763
|
-
const key =
|
|
3794
|
+
const key = objeXrefKey(obje, index);
|
|
3764
3795
|
obje.standardizeMedia();
|
|
3765
3796
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3766
3797
|
const url = obje?.get("FILE")?.toValue();
|
|
@@ -3777,6 +3808,7 @@ var Indi = class extends Common {
|
|
|
3777
3808
|
imgId,
|
|
3778
3809
|
person: this.id,
|
|
3779
3810
|
title,
|
|
3811
|
+
note: objeNoteValue(obje),
|
|
3780
3812
|
url,
|
|
3781
3813
|
contentType: type,
|
|
3782
3814
|
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
|
|
@@ -3808,7 +3840,12 @@ var Indi = class extends Common {
|
|
|
3808
3840
|
);
|
|
3809
3841
|
if (cached !== void 0) {
|
|
3810
3842
|
if (cached?.file && !isRemoteOrEmbeddedMediaUrl(cached.file)) {
|
|
3811
|
-
const resolvedCached = await resolveLocalMediaUrl(cached.file
|
|
3843
|
+
const resolvedCached = await resolveLocalMediaUrl(cached.file, {
|
|
3844
|
+
url: cached.file,
|
|
3845
|
+
person: this.id,
|
|
3846
|
+
tree: this.getTreeId?.(),
|
|
3847
|
+
treeName: this.getTreeName?.()
|
|
3848
|
+
});
|
|
3812
3849
|
if (resolvedCached && isRemoteOrEmbeddedMediaUrl(resolvedCached)) {
|
|
3813
3850
|
const refreshed = { ...cached, file: resolvedCached };
|
|
3814
3851
|
profilePictureCache(
|
|
@@ -3833,7 +3870,16 @@ var Indi = class extends Common {
|
|
|
3833
3870
|
}
|
|
3834
3871
|
const mediaArray = Object.values(mediaList);
|
|
3835
3872
|
const toDisplayableProfile = async (media, isPrimary) => {
|
|
3836
|
-
const resolvedFile = await resolveLocalMediaUrl(media.url
|
|
3873
|
+
const resolvedFile = await resolveLocalMediaUrl(media.url, {
|
|
3874
|
+
url: media.url,
|
|
3875
|
+
id: media.id,
|
|
3876
|
+
imgId: media.imgId,
|
|
3877
|
+
key: media.key,
|
|
3878
|
+
contentType: media.contentType,
|
|
3879
|
+
person: media.person || this.id,
|
|
3880
|
+
tree: media.tree || this.getTreeId?.(),
|
|
3881
|
+
treeName: this.getTreeName?.()
|
|
3882
|
+
});
|
|
3837
3883
|
if (!resolvedFile || !isRemoteOrEmbeddedMediaUrl(resolvedFile)) {
|
|
3838
3884
|
return void 0;
|
|
3839
3885
|
}
|
|
@@ -8611,7 +8657,7 @@ var ensureExtensionSchema = (gedcom, extraTags) => {
|
|
|
8611
8657
|
|
|
8612
8658
|
// package.json
|
|
8613
8659
|
var package_default = {
|
|
8614
|
-
version: "2.1.
|
|
8660
|
+
version: "2.1.11"};
|
|
8615
8661
|
|
|
8616
8662
|
// src/utils/get-product-details.ts
|
|
8617
8663
|
var isDevelopment = () => {
|
|
@@ -8694,16 +8740,26 @@ var Obje = class extends Common {
|
|
|
8694
8740
|
if (!this._gedcom) {
|
|
8695
8741
|
return this;
|
|
8696
8742
|
}
|
|
8743
|
+
if (typeof this.value === "string" && isId(this.value) && this.refType === "OBJE") {
|
|
8744
|
+
const resolved = this.ref;
|
|
8745
|
+
if (resolved && resolved !== this && typeof resolved.standardizeMedia === "function") {
|
|
8746
|
+
resolved.standardizeMedia(
|
|
8747
|
+
namespace,
|
|
8748
|
+
override,
|
|
8749
|
+
urlGetter,
|
|
8750
|
+
gedcomVersion
|
|
8751
|
+
);
|
|
8752
|
+
return this;
|
|
8753
|
+
}
|
|
8754
|
+
}
|
|
8697
8755
|
const rin = this?.get("RIN")?.toValue();
|
|
8698
|
-
const clone = this?.get("_CLON._OID")?.toValue();
|
|
8699
|
-
const mser = this?.get("_MSER._LKID")?.toValue();
|
|
8700
8756
|
const title = this?.get("FILE.TITL")?.toValue() ?? this?.get("TITL")?.toValue() ?? "";
|
|
8701
8757
|
const note = this?.get("FILE.NOTE")?.toValue() ?? this?.get("NOTE")?.toValue() ?? "";
|
|
8702
8758
|
const formRaw = this?.get("FILE.FORM")?.toValue() ?? this?.get("FORM")?.toValue();
|
|
8703
8759
|
const mediType = this?.get("FILE.FORM.TYPE")?.toValue() ?? this?.get("FORM.TYPE")?.toValue() ?? this?.get("MEDI")?.toValue();
|
|
8704
8760
|
const file = this?.get("FILE")?.toValue();
|
|
8705
|
-
const imgId =
|
|
8706
|
-
const url = file || namespace && urlGetter?.(namespace, imgId);
|
|
8761
|
+
const imgId = resolveObjeMediaId(this);
|
|
8762
|
+
const url = file || this.isAncestry() && namespace && urlGetter?.(namespace, imgId);
|
|
8707
8763
|
if (!url) {
|
|
8708
8764
|
return this;
|
|
8709
8765
|
}
|
|
@@ -9216,6 +9272,22 @@ var GedCom = class extends Common {
|
|
|
9216
9272
|
obje(index) {
|
|
9217
9273
|
return this.getMain(this.objes(), index);
|
|
9218
9274
|
}
|
|
9275
|
+
/**
|
|
9276
|
+
* People who link a shared multimedia record (`1 OBJE @On@`), i.e. Ancestry
|
|
9277
|
+
* face tags / everyone the photo is attached to.
|
|
9278
|
+
*/
|
|
9279
|
+
indisLinkingObje(objeKey) {
|
|
9280
|
+
const people = [];
|
|
9281
|
+
this.indis()?.forEach((indi) => {
|
|
9282
|
+
const linked = indi?.get("OBJE")?.toList()?.values()?.some(
|
|
9283
|
+
(item) => item?.toValue?.() === objeKey || item?.id === objeKey
|
|
9284
|
+
);
|
|
9285
|
+
if (linked && indi) {
|
|
9286
|
+
people.push(indi);
|
|
9287
|
+
}
|
|
9288
|
+
});
|
|
9289
|
+
return people;
|
|
9290
|
+
}
|
|
9219
9291
|
sour(index) {
|
|
9220
9292
|
return this.getMain(this.sours(), index);
|
|
9221
9293
|
}
|
package/dist/constants/index.js
CHANGED
|
@@ -171,11 +171,8 @@ var storeCache = {
|
|
|
171
171
|
getCacheDbs().relativesOnDegreeCache.setItem(value);
|
|
172
172
|
}
|
|
173
173
|
}, 50),
|
|
174
|
-
//
|
|
174
|
+
// Image bytes are stored as one IndexedDB record per photo.
|
|
175
175
|
profilePictureCache: debounce((value) => {
|
|
176
|
-
if (value) {
|
|
177
|
-
getCacheDbs().profilePictureCache.setItem(value);
|
|
178
|
-
}
|
|
179
176
|
}, 100)
|
|
180
177
|
};
|
|
181
178
|
var resetRelativesCache = () => {
|
|
@@ -555,6 +552,82 @@ var dateFormatter = (indi, showMarriages = false, showDays = false, showPlaces =
|
|
|
555
552
|
// src/utils/gedcom-trailer.ts
|
|
556
553
|
var GEDCOM_TRAILER_TAG = "TRLR";
|
|
557
554
|
var isGedcomTrailerTag = (tag) => tag === GEDCOM_TRAILER_TAG;
|
|
555
|
+
|
|
556
|
+
// src/utils/media-utils.ts
|
|
557
|
+
var getFileExtension = (filename) => {
|
|
558
|
+
if (!filename) {
|
|
559
|
+
return "";
|
|
560
|
+
}
|
|
561
|
+
if (filename.startsWith("data:")) {
|
|
562
|
+
const mime = filename.slice(5).split(";")[0] || "";
|
|
563
|
+
const subtype = (mime.split("/")[1] || "").toLowerCase();
|
|
564
|
+
if (subtype === "jpeg") {
|
|
565
|
+
return "jpg";
|
|
566
|
+
}
|
|
567
|
+
return subtype.split("+")[0] || "";
|
|
568
|
+
}
|
|
569
|
+
const withoutQuery = filename.split(/[?#]/)[0] || filename;
|
|
570
|
+
const match = withoutQuery.match(/\.([^.]+)$/);
|
|
571
|
+
return match ? match[1].toLowerCase() : "";
|
|
572
|
+
};
|
|
573
|
+
var isImageFormat = (format2) => {
|
|
574
|
+
if (!format2) {
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
577
|
+
let normalized = format2.toLowerCase().trim();
|
|
578
|
+
if (normalized.startsWith("data:")) {
|
|
579
|
+
normalized = getFileExtension(normalized);
|
|
580
|
+
} else if (normalized.includes("/")) {
|
|
581
|
+
normalized = normalized.split("/")[1]?.split("+")[0] || "";
|
|
582
|
+
if (normalized === "jpeg") {
|
|
583
|
+
normalized = "jpg";
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
const imageFormats = [
|
|
587
|
+
"jpg",
|
|
588
|
+
"jpeg",
|
|
589
|
+
"png",
|
|
590
|
+
"gif",
|
|
591
|
+
"bmp",
|
|
592
|
+
"webp",
|
|
593
|
+
"svg",
|
|
594
|
+
"tiff",
|
|
595
|
+
"tif"
|
|
596
|
+
];
|
|
597
|
+
return imageFormats.includes(normalized);
|
|
598
|
+
};
|
|
599
|
+
var resolveObjeForm = (obje) => {
|
|
600
|
+
const value = obje?.get?.("FILE.FORM")?.toValue?.() ?? obje?.get?.("FORM")?.toValue?.();
|
|
601
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
602
|
+
};
|
|
603
|
+
var mediaIdValue = (obje, path) => {
|
|
604
|
+
const value = obje?.get?.(path)?.toValue?.();
|
|
605
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
606
|
+
};
|
|
607
|
+
var resolveObjeMediaId = (obje) => mediaIdValue(obje, "RIN") || mediaIdValue(obje, "_CLON._OID") || mediaIdValue(obje, "_MSER._LKID") || mediaIdValue(obje, "_OID") || mediaIdValue(obje, "_LKID");
|
|
608
|
+
var ANCESTRY_MEDIA_RETRIEVAL_PREFIX = "https://www.ancestry.com/api/media/retrieval/v2/image";
|
|
609
|
+
var ANCESTRY_MEDIA_QUERY = "client=trees-mediaservice&imageQuality=hq";
|
|
610
|
+
var ancestryMediaPath = (namespace, imgId) => `/namespaces/${namespace}/media/${imgId}?${ANCESTRY_MEDIA_QUERY}`;
|
|
611
|
+
var ancestryMediaFileUrl = (namespace, imgId) => {
|
|
612
|
+
if (!namespace || !imgId) {
|
|
613
|
+
return void 0;
|
|
614
|
+
}
|
|
615
|
+
return `${ANCESTRY_MEDIA_RETRIEVAL_PREFIX}${ancestryMediaPath(namespace, imgId)}`;
|
|
616
|
+
};
|
|
617
|
+
var objeXrefKey = (obje, fallback = 0) => {
|
|
618
|
+
if (typeof obje?.id === "string" && obje.id) {
|
|
619
|
+
return obje.id;
|
|
620
|
+
}
|
|
621
|
+
const value = obje?.toValue?.();
|
|
622
|
+
if (typeof value === "string" && value.trim()) {
|
|
623
|
+
return value.trim();
|
|
624
|
+
}
|
|
625
|
+
if (typeof fallback === "string" && fallback.trim()) {
|
|
626
|
+
return fallback.trim();
|
|
627
|
+
}
|
|
628
|
+
return `@O${fallback}@`;
|
|
629
|
+
};
|
|
630
|
+
var objeNoteValue = (obje) => mediaIdValue(obje, "FILE.NOTE") || mediaIdValue(obje, "NOTE") || "";
|
|
558
631
|
var List = class _List {
|
|
559
632
|
// length = 0;
|
|
560
633
|
constructor(items) {
|
|
@@ -1204,7 +1277,7 @@ var Common = class _Common {
|
|
|
1204
1277
|
this,
|
|
1205
1278
|
options.obje.namespace,
|
|
1206
1279
|
options.obje.override,
|
|
1207
|
-
void 0,
|
|
1280
|
+
this.isAncestry() ? ancestryMediaFileUrl : void 0,
|
|
1208
1281
|
options.gedcomVersion
|
|
1209
1282
|
);
|
|
1210
1283
|
}
|
|
@@ -2152,65 +2225,23 @@ var isRemoteOrEmbeddedMediaUrl = (path) => {
|
|
|
2152
2225
|
}
|
|
2153
2226
|
return path.startsWith("data:") || path.startsWith("blob:") || /^https?:\/\//i.test(path);
|
|
2154
2227
|
};
|
|
2155
|
-
var resolveLocalMediaUrl = async (path) => {
|
|
2228
|
+
var resolveLocalMediaUrl = async (path, context) => {
|
|
2156
2229
|
if (!path) {
|
|
2157
2230
|
return void 0;
|
|
2158
2231
|
}
|
|
2159
|
-
if (
|
|
2232
|
+
if (path.startsWith("data:") || path.startsWith("blob:")) {
|
|
2160
2233
|
return path;
|
|
2161
2234
|
}
|
|
2162
|
-
const resolved = await localMediaResolver?.(path);
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
var implemented = (type, ...args) => {
|
|
2166
|
-
};
|
|
2167
|
-
|
|
2168
|
-
// src/utils/media-utils.ts
|
|
2169
|
-
var getFileExtension = (filename) => {
|
|
2170
|
-
if (!filename) {
|
|
2171
|
-
return "";
|
|
2172
|
-
}
|
|
2173
|
-
if (filename.startsWith("data:")) {
|
|
2174
|
-
const mime = filename.slice(5).split(";")[0] || "";
|
|
2175
|
-
const subtype = (mime.split("/")[1] || "").toLowerCase();
|
|
2176
|
-
if (subtype === "jpeg") {
|
|
2177
|
-
return "jpg";
|
|
2178
|
-
}
|
|
2179
|
-
return subtype.split("+")[0] || "";
|
|
2180
|
-
}
|
|
2181
|
-
const withoutQuery = filename.split(/[?#]/)[0] || filename;
|
|
2182
|
-
const match = withoutQuery.match(/\.([^.]+)$/);
|
|
2183
|
-
return match ? match[1].toLowerCase() : "";
|
|
2184
|
-
};
|
|
2185
|
-
var isImageFormat = (format2) => {
|
|
2186
|
-
if (!format2) {
|
|
2187
|
-
return false;
|
|
2235
|
+
const resolved = await localMediaResolver?.(path, context);
|
|
2236
|
+
if (resolved) {
|
|
2237
|
+
return resolved;
|
|
2188
2238
|
}
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
normalized = getFileExtension(normalized);
|
|
2192
|
-
} else if (normalized.includes("/")) {
|
|
2193
|
-
normalized = normalized.split("/")[1]?.split("+")[0] || "";
|
|
2194
|
-
if (normalized === "jpeg") {
|
|
2195
|
-
normalized = "jpg";
|
|
2196
|
-
}
|
|
2239
|
+
if (/^https?:\/\//i.test(path)) {
|
|
2240
|
+
return path;
|
|
2197
2241
|
}
|
|
2198
|
-
|
|
2199
|
-
"jpg",
|
|
2200
|
-
"jpeg",
|
|
2201
|
-
"png",
|
|
2202
|
-
"gif",
|
|
2203
|
-
"bmp",
|
|
2204
|
-
"webp",
|
|
2205
|
-
"svg",
|
|
2206
|
-
"tiff",
|
|
2207
|
-
"tif"
|
|
2208
|
-
];
|
|
2209
|
-
return imageFormats.includes(normalized);
|
|
2242
|
+
return void 0;
|
|
2210
2243
|
};
|
|
2211
|
-
var
|
|
2212
|
-
const value = obje?.get?.("FILE.FORM")?.toValue?.() ?? obje?.get?.("FORM")?.toValue?.();
|
|
2213
|
-
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2244
|
+
var implemented = (type, ...args) => {
|
|
2214
2245
|
};
|
|
2215
2246
|
var uniqueItemsCache = /* @__PURE__ */ new WeakMap();
|
|
2216
2247
|
var setNestedGroup = (obj, key, value, uniqueCounting = true) => {
|
|
@@ -3488,22 +3519,19 @@ var Indi = class extends Common {
|
|
|
3488
3519
|
if (objeList) {
|
|
3489
3520
|
await Promise.all(
|
|
3490
3521
|
objeList.map(async (objeRef) => {
|
|
3491
|
-
const key = objeRef
|
|
3522
|
+
const key = objeXrefKey(objeRef, 0);
|
|
3492
3523
|
const obje = objeRef?.standardizeMedia(
|
|
3493
3524
|
namespace,
|
|
3494
3525
|
true,
|
|
3495
|
-
|
|
3496
|
-
return ns && iId ? `https://mediasvc.ancestry.com/v2/image/namespaces/${ns}/media/${iId}?client=trees-mediaservice&imageQuality=hq` : void 0;
|
|
3497
|
-
}
|
|
3526
|
+
ancestryMediaFileUrl
|
|
3498
3527
|
);
|
|
3499
3528
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3500
|
-
const media =
|
|
3501
|
-
const clone = obje?.get("_CLON._OID")?.toValue();
|
|
3502
|
-
const mser = obje?.get("_MSER._LKID")?.toValue();
|
|
3529
|
+
const media = resolveObjeMediaId(obje);
|
|
3503
3530
|
let url = obje?.get("FILE")?.toValue();
|
|
3504
3531
|
const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
|
|
3532
|
+
const note = objeNoteValue(obje);
|
|
3505
3533
|
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
3506
|
-
let imgId =
|
|
3534
|
+
let imgId = media;
|
|
3507
3535
|
const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
|
|
3508
3536
|
if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
|
|
3509
3537
|
return;
|
|
@@ -3539,6 +3567,7 @@ var Indi = class extends Common {
|
|
|
3539
3567
|
imgId,
|
|
3540
3568
|
person: this.id,
|
|
3541
3569
|
title,
|
|
3570
|
+
note,
|
|
3542
3571
|
url,
|
|
3543
3572
|
contentType: type,
|
|
3544
3573
|
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
|
|
@@ -3577,7 +3606,7 @@ var Indi = class extends Common {
|
|
|
3577
3606
|
return;
|
|
3578
3607
|
}
|
|
3579
3608
|
const obje = o;
|
|
3580
|
-
const key =
|
|
3609
|
+
const key = objeXrefKey(obje, index);
|
|
3581
3610
|
obje.standardizeMedia();
|
|
3582
3611
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3583
3612
|
const url = obje?.get("FILE")?.toValue();
|
|
@@ -3596,6 +3625,7 @@ var Indi = class extends Common {
|
|
|
3596
3625
|
imgId,
|
|
3597
3626
|
person: this.id,
|
|
3598
3627
|
title,
|
|
3628
|
+
note: objeNoteValue(obje),
|
|
3599
3629
|
url,
|
|
3600
3630
|
contentType: type,
|
|
3601
3631
|
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
|
|
@@ -3704,7 +3734,7 @@ var Indi = class extends Common {
|
|
|
3704
3734
|
if (!obje) {
|
|
3705
3735
|
return;
|
|
3706
3736
|
}
|
|
3707
|
-
const key =
|
|
3737
|
+
const key = objeXrefKey(obje, index);
|
|
3708
3738
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3709
3739
|
const url = obje?.get("FILE")?.toValue();
|
|
3710
3740
|
const title = obje?.get("TITL")?.toValue() ?? "";
|
|
@@ -3721,6 +3751,7 @@ var Indi = class extends Common {
|
|
|
3721
3751
|
imgId,
|
|
3722
3752
|
person: this.id,
|
|
3723
3753
|
title,
|
|
3754
|
+
note: objeNoteValue(obje),
|
|
3724
3755
|
url,
|
|
3725
3756
|
contentType: type,
|
|
3726
3757
|
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
|
|
@@ -3744,7 +3775,7 @@ var Indi = class extends Common {
|
|
|
3744
3775
|
if (!obje) {
|
|
3745
3776
|
return;
|
|
3746
3777
|
}
|
|
3747
|
-
const key =
|
|
3778
|
+
const key = objeXrefKey(obje, index);
|
|
3748
3779
|
obje.standardizeMedia();
|
|
3749
3780
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3750
3781
|
const url = obje?.get("FILE")?.toValue();
|
|
@@ -3761,6 +3792,7 @@ var Indi = class extends Common {
|
|
|
3761
3792
|
imgId,
|
|
3762
3793
|
person: this.id,
|
|
3763
3794
|
title,
|
|
3795
|
+
note: objeNoteValue(obje),
|
|
3764
3796
|
url,
|
|
3765
3797
|
contentType: type,
|
|
3766
3798
|
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
|
|
@@ -3792,7 +3824,12 @@ var Indi = class extends Common {
|
|
|
3792
3824
|
);
|
|
3793
3825
|
if (cached !== void 0) {
|
|
3794
3826
|
if (cached?.file && !isRemoteOrEmbeddedMediaUrl(cached.file)) {
|
|
3795
|
-
const resolvedCached = await resolveLocalMediaUrl(cached.file
|
|
3827
|
+
const resolvedCached = await resolveLocalMediaUrl(cached.file, {
|
|
3828
|
+
url: cached.file,
|
|
3829
|
+
person: this.id,
|
|
3830
|
+
tree: this.getTreeId?.(),
|
|
3831
|
+
treeName: this.getTreeName?.()
|
|
3832
|
+
});
|
|
3796
3833
|
if (resolvedCached && isRemoteOrEmbeddedMediaUrl(resolvedCached)) {
|
|
3797
3834
|
const refreshed = { ...cached, file: resolvedCached };
|
|
3798
3835
|
profilePictureCache(
|
|
@@ -3817,7 +3854,16 @@ var Indi = class extends Common {
|
|
|
3817
3854
|
}
|
|
3818
3855
|
const mediaArray = Object.values(mediaList);
|
|
3819
3856
|
const toDisplayableProfile = async (media, isPrimary) => {
|
|
3820
|
-
const resolvedFile = await resolveLocalMediaUrl(media.url
|
|
3857
|
+
const resolvedFile = await resolveLocalMediaUrl(media.url, {
|
|
3858
|
+
url: media.url,
|
|
3859
|
+
id: media.id,
|
|
3860
|
+
imgId: media.imgId,
|
|
3861
|
+
key: media.key,
|
|
3862
|
+
contentType: media.contentType,
|
|
3863
|
+
person: media.person || this.id,
|
|
3864
|
+
tree: media.tree || this.getTreeId?.(),
|
|
3865
|
+
treeName: this.getTreeName?.()
|
|
3866
|
+
});
|
|
3821
3867
|
if (!resolvedFile || !isRemoteOrEmbeddedMediaUrl(resolvedFile)) {
|
|
3822
3868
|
return void 0;
|
|
3823
3869
|
}
|