@treeviz/gedcom-parser 2.1.17 → 2.1.18
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 +19 -1
- package/dist/classes/common.d.ts.map +1 -1
- package/dist/classes/index.js +178 -56
- package/dist/classes/indi.d.ts.map +1 -1
- package/dist/classes/obje.d.ts +1 -1
- package/dist/classes/obje.d.ts.map +1 -1
- package/dist/cli/index.js +178 -56
- package/dist/constants/index.js +157 -37
- package/dist/factories/index.js +157 -37
- package/dist/index.js +180 -58
- package/dist/kinship-translator/index.js +157 -37
- package/dist/utils/index.js +180 -58
- package/dist/utils/media-utils.d.ts +10 -0
- package/dist/utils/media-utils.d.ts.map +1 -1
- package/dist/utils/multimedia.d.ts +5 -0
- package/dist/utils/multimedia.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -94,6 +94,30 @@ var mediaIdValue = (obje, path) => {
|
|
|
94
94
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
95
95
|
};
|
|
96
96
|
var resolveObjeMediaId = (obje) => mediaIdValue(obje, "RIN") || mediaIdValue(obje, "_CLON._OID") || mediaIdValue(obje, "_MSER._LKID") || mediaIdValue(obje, "_OID") || mediaIdValue(obje, "_LKID");
|
|
97
|
+
var ANCESTRY_TREE_MEDIA_NAMESPACE = 1093;
|
|
98
|
+
var ANCESTRY_NAMESPACE_IN_URL = /\/namespaces\/(\d+)\/media\//i;
|
|
99
|
+
var parseAncestryNamespaceFromUrl = (url) => {
|
|
100
|
+
if (!url) {
|
|
101
|
+
return void 0;
|
|
102
|
+
}
|
|
103
|
+
const match = url.match(ANCESTRY_NAMESPACE_IN_URL);
|
|
104
|
+
const namespace = match?.[1] ? Number(match[1]) : NaN;
|
|
105
|
+
return Number.isFinite(namespace) ? namespace : void 0;
|
|
106
|
+
};
|
|
107
|
+
var isAncestryOriginObje = (obje) => {
|
|
108
|
+
if (!obje) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const orig = mediaIdValue(obje, "_ORIG");
|
|
112
|
+
if (orig?.toLowerCase() === "acom") {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
const file = mediaIdValue(obje, "FILE") ?? "";
|
|
116
|
+
if (parseAncestryNamespaceFromUrl(file)) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return Boolean(resolveObjeMediaId(obje) && !file.trim());
|
|
120
|
+
};
|
|
97
121
|
var ANCESTRY_MEDIA_RETRIEVAL_PREFIX = "https://www.ancestry.com/api/media/retrieval/v2/image";
|
|
98
122
|
var ANCESTRY_MEDIA_QUERY = "client=trees-mediaservice&imageQuality=hq";
|
|
99
123
|
var ancestryMediaPath = (namespace, imgId) => `/namespaces/${namespace}/media/${imgId}?${ANCESTRY_MEDIA_QUERY}`;
|
|
@@ -887,8 +911,25 @@ var Common = class _Common {
|
|
|
887
911
|
getHeadRecord() {
|
|
888
912
|
return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
|
|
889
913
|
}
|
|
914
|
+
unwrapHeadRecord(node) {
|
|
915
|
+
if (!node) {
|
|
916
|
+
return void 0;
|
|
917
|
+
}
|
|
918
|
+
const common = node instanceof List ? node.index(0) : node;
|
|
919
|
+
if (!common || typeof common.get !== "function") {
|
|
920
|
+
return void 0;
|
|
921
|
+
}
|
|
922
|
+
const nested = common.get("HEAD");
|
|
923
|
+
if (nested instanceof List) {
|
|
924
|
+
return nested.index(0) ?? common;
|
|
925
|
+
}
|
|
926
|
+
if (nested instanceof _Common) {
|
|
927
|
+
return nested;
|
|
928
|
+
}
|
|
929
|
+
return common;
|
|
930
|
+
}
|
|
890
931
|
getOriginalHeadRecord() {
|
|
891
|
-
return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
|
|
932
|
+
return this.unwrapHeadRecord(get(this, ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getGedcom(), ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getHeadRecord(), ORIG_HEAD_TAG));
|
|
892
933
|
}
|
|
893
934
|
getSourceHeads() {
|
|
894
935
|
const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
|
|
@@ -896,9 +937,23 @@ var Common = class _Common {
|
|
|
896
937
|
return Boolean(head && heads.indexOf(head) === index);
|
|
897
938
|
});
|
|
898
939
|
}
|
|
940
|
+
sourceHeadField(head, path) {
|
|
941
|
+
const normalized = path.endsWith(".value") ? path.slice(0, -".value".length) : path;
|
|
942
|
+
const node = head.get(normalized);
|
|
943
|
+
if (!node) {
|
|
944
|
+
return void 0;
|
|
945
|
+
}
|
|
946
|
+
if (node instanceof List) {
|
|
947
|
+
return node.index(0)?.toValue();
|
|
948
|
+
}
|
|
949
|
+
if (typeof node.toValue === "function") {
|
|
950
|
+
return node.toValue();
|
|
951
|
+
}
|
|
952
|
+
return void 0;
|
|
953
|
+
}
|
|
899
954
|
getFromSourceHeads(path) {
|
|
900
955
|
for (const head of this.getSourceHeads()) {
|
|
901
|
-
const value =
|
|
956
|
+
const value = this.sourceHeadField(head, path);
|
|
902
957
|
if (value !== void 0 && value !== null && value !== "") {
|
|
903
958
|
return value;
|
|
904
959
|
}
|
|
@@ -907,8 +962,8 @@ var Common = class _Common {
|
|
|
907
962
|
}
|
|
908
963
|
sourStartsWith(prefix) {
|
|
909
964
|
return this.getSourceHeads().some((head) => {
|
|
910
|
-
const sour =
|
|
911
|
-
return
|
|
965
|
+
const sour = this.sourceHeadField(head, "SOUR");
|
|
966
|
+
return typeof sour === "string" && sour.toLowerCase().startsWith(prefix);
|
|
912
967
|
});
|
|
913
968
|
}
|
|
914
969
|
isGenoPro() {
|
|
@@ -926,6 +981,51 @@ var Common = class _Common {
|
|
|
926
981
|
isMyHeritage() {
|
|
927
982
|
return this.sourStartsWith("myheritage");
|
|
928
983
|
}
|
|
984
|
+
/**
|
|
985
|
+
* GEDCOM root for Ancestry media helpers.
|
|
986
|
+
* `this._gedcom` when called on a child record; `this` when called on the file root.
|
|
987
|
+
*
|
|
988
|
+
* Cannot use `instanceof GedCom`: `GedComType` is a type alias (erased at runtime),
|
|
989
|
+
* and importing the `GedCom` class here would cycle (`GedCom extends Common`).
|
|
990
|
+
* The root is the only Common with an `objes()` method.
|
|
991
|
+
*/
|
|
992
|
+
hostGedcom() {
|
|
993
|
+
const linked = this.getGedcom();
|
|
994
|
+
if (linked) {
|
|
995
|
+
return linked;
|
|
996
|
+
}
|
|
997
|
+
if ("objes" in this && typeof this.objes === "function") {
|
|
998
|
+
return this;
|
|
999
|
+
}
|
|
1000
|
+
return void 0;
|
|
1001
|
+
}
|
|
1002
|
+
/** True when the file still has Ancestry tree media (`_ORIG acom`, `_OID`, retrieval URL). */
|
|
1003
|
+
hasAncestryOriginMedia() {
|
|
1004
|
+
const objes = this.hostGedcom()?.objes?.();
|
|
1005
|
+
return objes?.values().some((obje) => isAncestryOriginObje(obje)) ?? false;
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* Namespace for Ancestry tree photos. Prefer a `namespaces/{id}` FILE URL
|
|
1009
|
+
* (TreeViz GEDCOM 7 / GEDZIP export), otherwise 1093 for member-tree media.
|
|
1010
|
+
*/
|
|
1011
|
+
getAncestryMediaNamespace() {
|
|
1012
|
+
const objes = this.hostGedcom()?.objes?.();
|
|
1013
|
+
if (objes) {
|
|
1014
|
+
for (const obje of objes.values()) {
|
|
1015
|
+
const file = obje?.get("FILE")?.toValue();
|
|
1016
|
+
const fromUrl = parseAncestryNamespaceFromUrl(
|
|
1017
|
+
typeof file === "string" ? file : void 0
|
|
1018
|
+
);
|
|
1019
|
+
if (fromUrl) {
|
|
1020
|
+
return fromUrl;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
if (this.isAncestry() || this.hasAncestryOriginMedia()) {
|
|
1025
|
+
return ANCESTRY_TREE_MEDIA_NAMESPACE;
|
|
1026
|
+
}
|
|
1027
|
+
return void 0;
|
|
1028
|
+
}
|
|
929
1029
|
/**
|
|
930
1030
|
* Get the source type as a string (for prefixing tree IDs and names)
|
|
931
1031
|
* Returns the detected source type or undefined if unknown
|
|
@@ -942,13 +1042,13 @@ var Common = class _Common {
|
|
|
942
1042
|
}
|
|
943
1043
|
isFamilySearch() {
|
|
944
1044
|
return this.getSourceHeads().some((head) => {
|
|
945
|
-
const sourName =
|
|
1045
|
+
const sourName = this.sourceHeadField(head, "SOUR.NAME");
|
|
946
1046
|
return sourName === "FamilySearch API";
|
|
947
1047
|
});
|
|
948
1048
|
}
|
|
949
1049
|
isGNO2GED() {
|
|
950
1050
|
return this.getSourceHeads().some((head) => {
|
|
951
|
-
const sour =
|
|
1051
|
+
const sour = this.sourceHeadField(head, "SOUR");
|
|
952
1052
|
return sour === "GNO2GED";
|
|
953
1053
|
});
|
|
954
1054
|
}
|
|
@@ -993,8 +1093,7 @@ var Common = class _Common {
|
|
|
993
1093
|
return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
|
|
994
1094
|
}
|
|
995
1095
|
getMyHeritageTreeName() {
|
|
996
|
-
const
|
|
997
|
-
const treeDetails = get(this, path) || get(this.getGedcom(), path);
|
|
1096
|
+
const treeDetails = this.getFromSourceHeads("FILE.value") || (get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value"));
|
|
998
1097
|
return treeDetails?.match(
|
|
999
1098
|
/Exported by MyHeritage.com from (?<tree>.+) in.+$/
|
|
1000
1099
|
)?.groups?.tree;
|
|
@@ -1011,7 +1110,7 @@ var Common = class _Common {
|
|
|
1011
1110
|
if (treeName) {
|
|
1012
1111
|
return treeName;
|
|
1013
1112
|
}
|
|
1014
|
-
const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
|
|
1113
|
+
const fileName = this.getFromSourceHeads("FILE.value") || get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
|
|
1015
1114
|
return fileName || "FamilySearch Import";
|
|
1016
1115
|
}
|
|
1017
1116
|
getAhnenblattTreeId() {
|
|
@@ -2388,6 +2487,44 @@ var resolveLocalMediaUrl = async (path, context) => {
|
|
|
2388
2487
|
};
|
|
2389
2488
|
var implemented = (type, ...args) => {
|
|
2390
2489
|
};
|
|
2490
|
+
|
|
2491
|
+
// src/utils/multimedia.ts
|
|
2492
|
+
var inferMediaForm = (file, fallback = "bin") => {
|
|
2493
|
+
const withoutQuery = file.split("?")[0] || file;
|
|
2494
|
+
const ext = getFileExtension(withoutQuery);
|
|
2495
|
+
if (ext) {
|
|
2496
|
+
return ext.toLowerCase() === "jpeg" ? "jpg" : ext.toLowerCase();
|
|
2497
|
+
}
|
|
2498
|
+
return fallback;
|
|
2499
|
+
};
|
|
2500
|
+
var mergeMediaLists = (...lists) => {
|
|
2501
|
+
const merged = {};
|
|
2502
|
+
for (const list of lists) {
|
|
2503
|
+
if (!list) continue;
|
|
2504
|
+
Object.assign(merged, list);
|
|
2505
|
+
}
|
|
2506
|
+
return merged;
|
|
2507
|
+
};
|
|
2508
|
+
var mergeMediaListsByObjeKey = (...lists) => {
|
|
2509
|
+
const merged = {};
|
|
2510
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2511
|
+
for (const list of lists) {
|
|
2512
|
+
if (!list) {
|
|
2513
|
+
continue;
|
|
2514
|
+
}
|
|
2515
|
+
for (const [id, item] of Object.entries(list)) {
|
|
2516
|
+
const objeKey = item.key ? String(item.key) : "";
|
|
2517
|
+
if (objeKey && seen.has(objeKey)) {
|
|
2518
|
+
continue;
|
|
2519
|
+
}
|
|
2520
|
+
merged[id] = item;
|
|
2521
|
+
if (objeKey) {
|
|
2522
|
+
seen.add(objeKey);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
return merged;
|
|
2527
|
+
};
|
|
2391
2528
|
var uniqueItemsCache = /* @__PURE__ */ new WeakMap();
|
|
2392
2529
|
var setNestedGroup = (obj, key, value, uniqueCounting = true) => {
|
|
2393
2530
|
const parts = Array.isArray(key) ? key : key.split(/,\s*/);
|
|
@@ -3546,7 +3683,10 @@ var Indi = class extends Common {
|
|
|
3546
3683
|
return result;
|
|
3547
3684
|
}
|
|
3548
3685
|
ancestryLink() {
|
|
3549
|
-
|
|
3686
|
+
let www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
3687
|
+
if (!www || /treeviz/i.test(String(www))) {
|
|
3688
|
+
www = "www.ancestry.com";
|
|
3689
|
+
}
|
|
3550
3690
|
const tree = this.getAncestryTreeId();
|
|
3551
3691
|
if (this.id) {
|
|
3552
3692
|
return `https://${www}/family-tree/person/tree/${tree}/person/${this.id.replace(
|
|
@@ -3558,14 +3698,15 @@ var Indi = class extends Common {
|
|
|
3558
3698
|
async ancestryMedia(namespace) {
|
|
3559
3699
|
const list = {};
|
|
3560
3700
|
const objeList = this.get("OBJE")?.toList().copy();
|
|
3561
|
-
|
|
3701
|
+
this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
3562
3702
|
const tree = this.getAncestryTreeId();
|
|
3703
|
+
const usedNamespace = namespace || this.getAncestryMediaNamespace() || ANCESTRY_TREE_MEDIA_NAMESPACE;
|
|
3563
3704
|
if (objeList) {
|
|
3564
3705
|
await Promise.all(
|
|
3565
3706
|
objeList.map(async (objeRef) => {
|
|
3566
3707
|
const key = objeXrefKey(objeRef, 0);
|
|
3567
3708
|
const obje = objeRef?.standardizeMedia(
|
|
3568
|
-
|
|
3709
|
+
usedNamespace,
|
|
3569
3710
|
true,
|
|
3570
3711
|
ancestryMediaFileUrl
|
|
3571
3712
|
);
|
|
@@ -3577,27 +3718,9 @@ var Indi = class extends Common {
|
|
|
3577
3718
|
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
3578
3719
|
let imgId = media;
|
|
3579
3720
|
const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
|
|
3580
|
-
if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
|
|
3581
|
-
return;
|
|
3582
|
-
}
|
|
3583
3721
|
if (!this.id) {
|
|
3584
3722
|
return;
|
|
3585
3723
|
}
|
|
3586
|
-
if (!namespace && !url) {
|
|
3587
|
-
try {
|
|
3588
|
-
if (media) {
|
|
3589
|
-
const mediaDetailsResponse = await fetch(
|
|
3590
|
-
`https://www.ancestry.com/api/media/viewer/v2/trees/${tree}/media?id=${media}`
|
|
3591
|
-
);
|
|
3592
|
-
const mediaDetails = await mediaDetailsResponse.json();
|
|
3593
|
-
if (mediaDetails.url) {
|
|
3594
|
-
url = `${mediaDetails.url}&imageQuality=hq`;
|
|
3595
|
-
}
|
|
3596
|
-
}
|
|
3597
|
-
} catch (_e) {
|
|
3598
|
-
}
|
|
3599
|
-
url = url || `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
|
|
3600
|
-
}
|
|
3601
3724
|
if (!imgId && hasEmbeddedOrLocalFile && url) {
|
|
3602
3725
|
imgId = typeof media === "string" && media || `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}`;
|
|
3603
3726
|
}
|
|
@@ -3623,9 +3746,12 @@ var Indi = class extends Common {
|
|
|
3623
3746
|
return list;
|
|
3624
3747
|
}
|
|
3625
3748
|
myheritageLink(poolId = 0) {
|
|
3626
|
-
|
|
3749
|
+
let www = (this.getFromSourceHeads("SOUR.CORP.value") || this._gedcom?.HEAD?.SOUR?.CORP?.value)?.toLowerCase().replace(/^www\./gi, "");
|
|
3750
|
+
if (!www || /treeviz/i.test(www)) {
|
|
3751
|
+
www = "myheritage.com";
|
|
3752
|
+
}
|
|
3627
3753
|
const site = this.getMyHeritageTreeId();
|
|
3628
|
-
const file = this._gedcom?.HEAD?.get("FILE")?.toValue()?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
|
|
3754
|
+
const file = (this.getFromSourceHeads("FILE.value") || this._gedcom?.HEAD?.get("FILE")?.toValue())?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
|
|
3629
3755
|
const normalizedFile = file?.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
3630
3756
|
if (normalizedFile && this.id) {
|
|
3631
3757
|
const id = Number(this.id.replace(/@|I/g, "")) + poolId;
|
|
@@ -3846,16 +3972,26 @@ var Indi = class extends Common {
|
|
|
3846
3972
|
return list;
|
|
3847
3973
|
}
|
|
3848
3974
|
async multimedia(namespace) {
|
|
3849
|
-
|
|
3850
|
-
|
|
3975
|
+
const lists = [];
|
|
3976
|
+
const ownObjes = this.get("OBJE")?.toList()?.values() ?? [];
|
|
3977
|
+
const ownAncestryMedia = ownObjes.some(
|
|
3978
|
+
(obje) => !!obje && (isAncestryOriginObje(obje) || isAncestryOriginObje(obje.ref))
|
|
3979
|
+
);
|
|
3980
|
+
if (this.isAncestry() || ownAncestryMedia) {
|
|
3981
|
+
lists.push(
|
|
3982
|
+
await this.ancestryMedia(
|
|
3983
|
+
namespace || this.getAncestryMediaNamespace()
|
|
3984
|
+
)
|
|
3985
|
+
);
|
|
3851
3986
|
}
|
|
3852
3987
|
if (this?.isMyHeritage()) {
|
|
3853
|
-
|
|
3988
|
+
lists.push(this.myheritageMedia());
|
|
3854
3989
|
}
|
|
3855
3990
|
if (this?.isGeni()) {
|
|
3856
|
-
|
|
3991
|
+
lists.push(this.geniMedia());
|
|
3857
3992
|
}
|
|
3858
|
-
|
|
3993
|
+
lists.push(this.universalMedia());
|
|
3994
|
+
return mergeMediaListsByObjeKey(...lists);
|
|
3859
3995
|
}
|
|
3860
3996
|
async getProfilePicture(namespace, onlyPrimary = true) {
|
|
3861
3997
|
if (!this.id) {
|
|
@@ -9024,7 +9160,7 @@ var ensureExtensionSchema = (gedcom, extraTags) => {
|
|
|
9024
9160
|
|
|
9025
9161
|
// package.json
|
|
9026
9162
|
var package_default = {
|
|
9027
|
-
version: "2.1.
|
|
9163
|
+
version: "2.1.18"};
|
|
9028
9164
|
|
|
9029
9165
|
// src/utils/get-product-details.ts
|
|
9030
9166
|
var isDevelopment = () => {
|
|
@@ -9032,24 +9168,6 @@ var isDevelopment = () => {
|
|
|
9032
9168
|
};
|
|
9033
9169
|
var getVersion = () => package_default.version;
|
|
9034
9170
|
|
|
9035
|
-
// src/utils/multimedia.ts
|
|
9036
|
-
var inferMediaForm = (file, fallback = "bin") => {
|
|
9037
|
-
const withoutQuery = file.split("?")[0] || file;
|
|
9038
|
-
const ext = getFileExtension(withoutQuery);
|
|
9039
|
-
if (ext) {
|
|
9040
|
-
return ext.toLowerCase() === "jpeg" ? "jpg" : ext.toLowerCase();
|
|
9041
|
-
}
|
|
9042
|
-
return fallback;
|
|
9043
|
-
};
|
|
9044
|
-
var mergeMediaLists = (...lists) => {
|
|
9045
|
-
const merged = {};
|
|
9046
|
-
for (const list of lists) {
|
|
9047
|
-
if (!list) continue;
|
|
9048
|
-
Object.assign(merged, list);
|
|
9049
|
-
}
|
|
9050
|
-
return merged;
|
|
9051
|
-
};
|
|
9052
|
-
|
|
9053
9171
|
// src/classes/note.ts
|
|
9054
9172
|
var CommonNote = class extends Common {
|
|
9055
9173
|
constructor(gedcom, id, main, parent) {
|
|
@@ -9200,6 +9318,10 @@ var Obje = class extends Common {
|
|
|
9200
9318
|
if (lkidNode && !newObject.get("_LKID")) {
|
|
9201
9319
|
newObject.set("_LKID", lkidNode);
|
|
9202
9320
|
}
|
|
9321
|
+
const origNode = this.get("_ORIG");
|
|
9322
|
+
if (origNode && !newObject.get("_ORIG")) {
|
|
9323
|
+
newObject.set("_ORIG", origNode);
|
|
9324
|
+
}
|
|
9203
9325
|
if (override) {
|
|
9204
9326
|
this.remove("FILE");
|
|
9205
9327
|
this.remove("FORM");
|
package/dist/constants/index.js
CHANGED
|
@@ -409,6 +409,30 @@ var mediaIdValue = (obje, path) => {
|
|
|
409
409
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
410
410
|
};
|
|
411
411
|
var resolveObjeMediaId = (obje) => mediaIdValue(obje, "RIN") || mediaIdValue(obje, "_CLON._OID") || mediaIdValue(obje, "_MSER._LKID") || mediaIdValue(obje, "_OID") || mediaIdValue(obje, "_LKID");
|
|
412
|
+
var ANCESTRY_TREE_MEDIA_NAMESPACE = 1093;
|
|
413
|
+
var ANCESTRY_NAMESPACE_IN_URL = /\/namespaces\/(\d+)\/media\//i;
|
|
414
|
+
var parseAncestryNamespaceFromUrl = (url) => {
|
|
415
|
+
if (!url) {
|
|
416
|
+
return void 0;
|
|
417
|
+
}
|
|
418
|
+
const match = url.match(ANCESTRY_NAMESPACE_IN_URL);
|
|
419
|
+
const namespace = match?.[1] ? Number(match[1]) : NaN;
|
|
420
|
+
return Number.isFinite(namespace) ? namespace : void 0;
|
|
421
|
+
};
|
|
422
|
+
var isAncestryOriginObje = (obje) => {
|
|
423
|
+
if (!obje) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
const orig = mediaIdValue(obje, "_ORIG");
|
|
427
|
+
if (orig?.toLowerCase() === "acom") {
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
const file = mediaIdValue(obje, "FILE") ?? "";
|
|
431
|
+
if (parseAncestryNamespaceFromUrl(file)) {
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
return Boolean(resolveObjeMediaId(obje) && !file.trim());
|
|
435
|
+
};
|
|
412
436
|
var ANCESTRY_MEDIA_RETRIEVAL_PREFIX = "https://www.ancestry.com/api/media/retrieval/v2/image";
|
|
413
437
|
var ANCESTRY_MEDIA_QUERY = "client=trees-mediaservice&imageQuality=hq";
|
|
414
438
|
var ancestryMediaPath = (namespace, imgId) => `/namespaces/${namespace}/media/${imgId}?${ANCESTRY_MEDIA_QUERY}`;
|
|
@@ -784,8 +808,25 @@ var Common = class _Common {
|
|
|
784
808
|
getHeadRecord() {
|
|
785
809
|
return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
|
|
786
810
|
}
|
|
811
|
+
unwrapHeadRecord(node) {
|
|
812
|
+
if (!node) {
|
|
813
|
+
return void 0;
|
|
814
|
+
}
|
|
815
|
+
const common = node instanceof List ? node.index(0) : node;
|
|
816
|
+
if (!common || typeof common.get !== "function") {
|
|
817
|
+
return void 0;
|
|
818
|
+
}
|
|
819
|
+
const nested = common.get("HEAD");
|
|
820
|
+
if (nested instanceof List) {
|
|
821
|
+
return nested.index(0) ?? common;
|
|
822
|
+
}
|
|
823
|
+
if (nested instanceof _Common) {
|
|
824
|
+
return nested;
|
|
825
|
+
}
|
|
826
|
+
return common;
|
|
827
|
+
}
|
|
787
828
|
getOriginalHeadRecord() {
|
|
788
|
-
return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
|
|
829
|
+
return this.unwrapHeadRecord(get(this, ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getGedcom(), ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getHeadRecord(), ORIG_HEAD_TAG));
|
|
789
830
|
}
|
|
790
831
|
getSourceHeads() {
|
|
791
832
|
const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
|
|
@@ -793,9 +834,23 @@ var Common = class _Common {
|
|
|
793
834
|
return Boolean(head && heads.indexOf(head) === index);
|
|
794
835
|
});
|
|
795
836
|
}
|
|
837
|
+
sourceHeadField(head, path) {
|
|
838
|
+
const normalized = path.endsWith(".value") ? path.slice(0, -".value".length) : path;
|
|
839
|
+
const node = head.get(normalized);
|
|
840
|
+
if (!node) {
|
|
841
|
+
return void 0;
|
|
842
|
+
}
|
|
843
|
+
if (node instanceof List) {
|
|
844
|
+
return node.index(0)?.toValue();
|
|
845
|
+
}
|
|
846
|
+
if (typeof node.toValue === "function") {
|
|
847
|
+
return node.toValue();
|
|
848
|
+
}
|
|
849
|
+
return void 0;
|
|
850
|
+
}
|
|
796
851
|
getFromSourceHeads(path) {
|
|
797
852
|
for (const head of this.getSourceHeads()) {
|
|
798
|
-
const value =
|
|
853
|
+
const value = this.sourceHeadField(head, path);
|
|
799
854
|
if (value !== void 0 && value !== null && value !== "") {
|
|
800
855
|
return value;
|
|
801
856
|
}
|
|
@@ -804,8 +859,8 @@ var Common = class _Common {
|
|
|
804
859
|
}
|
|
805
860
|
sourStartsWith(prefix) {
|
|
806
861
|
return this.getSourceHeads().some((head) => {
|
|
807
|
-
const sour =
|
|
808
|
-
return
|
|
862
|
+
const sour = this.sourceHeadField(head, "SOUR");
|
|
863
|
+
return typeof sour === "string" && sour.toLowerCase().startsWith(prefix);
|
|
809
864
|
});
|
|
810
865
|
}
|
|
811
866
|
isGenoPro() {
|
|
@@ -823,6 +878,51 @@ var Common = class _Common {
|
|
|
823
878
|
isMyHeritage() {
|
|
824
879
|
return this.sourStartsWith("myheritage");
|
|
825
880
|
}
|
|
881
|
+
/**
|
|
882
|
+
* GEDCOM root for Ancestry media helpers.
|
|
883
|
+
* `this._gedcom` when called on a child record; `this` when called on the file root.
|
|
884
|
+
*
|
|
885
|
+
* Cannot use `instanceof GedCom`: `GedComType` is a type alias (erased at runtime),
|
|
886
|
+
* and importing the `GedCom` class here would cycle (`GedCom extends Common`).
|
|
887
|
+
* The root is the only Common with an `objes()` method.
|
|
888
|
+
*/
|
|
889
|
+
hostGedcom() {
|
|
890
|
+
const linked = this.getGedcom();
|
|
891
|
+
if (linked) {
|
|
892
|
+
return linked;
|
|
893
|
+
}
|
|
894
|
+
if ("objes" in this && typeof this.objes === "function") {
|
|
895
|
+
return this;
|
|
896
|
+
}
|
|
897
|
+
return void 0;
|
|
898
|
+
}
|
|
899
|
+
/** True when the file still has Ancestry tree media (`_ORIG acom`, `_OID`, retrieval URL). */
|
|
900
|
+
hasAncestryOriginMedia() {
|
|
901
|
+
const objes = this.hostGedcom()?.objes?.();
|
|
902
|
+
return objes?.values().some((obje) => isAncestryOriginObje(obje)) ?? false;
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Namespace for Ancestry tree photos. Prefer a `namespaces/{id}` FILE URL
|
|
906
|
+
* (TreeViz GEDCOM 7 / GEDZIP export), otherwise 1093 for member-tree media.
|
|
907
|
+
*/
|
|
908
|
+
getAncestryMediaNamespace() {
|
|
909
|
+
const objes = this.hostGedcom()?.objes?.();
|
|
910
|
+
if (objes) {
|
|
911
|
+
for (const obje of objes.values()) {
|
|
912
|
+
const file = obje?.get("FILE")?.toValue();
|
|
913
|
+
const fromUrl = parseAncestryNamespaceFromUrl(
|
|
914
|
+
typeof file === "string" ? file : void 0
|
|
915
|
+
);
|
|
916
|
+
if (fromUrl) {
|
|
917
|
+
return fromUrl;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
if (this.isAncestry() || this.hasAncestryOriginMedia()) {
|
|
922
|
+
return ANCESTRY_TREE_MEDIA_NAMESPACE;
|
|
923
|
+
}
|
|
924
|
+
return void 0;
|
|
925
|
+
}
|
|
826
926
|
/**
|
|
827
927
|
* Get the source type as a string (for prefixing tree IDs and names)
|
|
828
928
|
* Returns the detected source type or undefined if unknown
|
|
@@ -839,13 +939,13 @@ var Common = class _Common {
|
|
|
839
939
|
}
|
|
840
940
|
isFamilySearch() {
|
|
841
941
|
return this.getSourceHeads().some((head) => {
|
|
842
|
-
const sourName =
|
|
942
|
+
const sourName = this.sourceHeadField(head, "SOUR.NAME");
|
|
843
943
|
return sourName === "FamilySearch API";
|
|
844
944
|
});
|
|
845
945
|
}
|
|
846
946
|
isGNO2GED() {
|
|
847
947
|
return this.getSourceHeads().some((head) => {
|
|
848
|
-
const sour =
|
|
948
|
+
const sour = this.sourceHeadField(head, "SOUR");
|
|
849
949
|
return sour === "GNO2GED";
|
|
850
950
|
});
|
|
851
951
|
}
|
|
@@ -890,8 +990,7 @@ var Common = class _Common {
|
|
|
890
990
|
return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
|
|
891
991
|
}
|
|
892
992
|
getMyHeritageTreeName() {
|
|
893
|
-
const
|
|
894
|
-
const treeDetails = get(this, path) || get(this.getGedcom(), path);
|
|
993
|
+
const treeDetails = this.getFromSourceHeads("FILE.value") || (get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value"));
|
|
895
994
|
return treeDetails?.match(
|
|
896
995
|
/Exported by MyHeritage.com from (?<tree>.+) in.+$/
|
|
897
996
|
)?.groups?.tree;
|
|
@@ -908,7 +1007,7 @@ var Common = class _Common {
|
|
|
908
1007
|
if (treeName) {
|
|
909
1008
|
return treeName;
|
|
910
1009
|
}
|
|
911
|
-
const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
|
|
1010
|
+
const fileName = this.getFromSourceHeads("FILE.value") || get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
|
|
912
1011
|
return fileName || "FamilySearch Import";
|
|
913
1012
|
}
|
|
914
1013
|
getAhnenblattTreeId() {
|
|
@@ -2273,6 +2372,28 @@ var resolveLocalMediaUrl = async (path, context) => {
|
|
|
2273
2372
|
};
|
|
2274
2373
|
var implemented = (type, ...args) => {
|
|
2275
2374
|
};
|
|
2375
|
+
|
|
2376
|
+
// src/utils/multimedia.ts
|
|
2377
|
+
var mergeMediaListsByObjeKey = (...lists) => {
|
|
2378
|
+
const merged = {};
|
|
2379
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2380
|
+
for (const list of lists) {
|
|
2381
|
+
if (!list) {
|
|
2382
|
+
continue;
|
|
2383
|
+
}
|
|
2384
|
+
for (const [id, item] of Object.entries(list)) {
|
|
2385
|
+
const objeKey = item.key ? String(item.key) : "";
|
|
2386
|
+
if (objeKey && seen.has(objeKey)) {
|
|
2387
|
+
continue;
|
|
2388
|
+
}
|
|
2389
|
+
merged[id] = item;
|
|
2390
|
+
if (objeKey) {
|
|
2391
|
+
seen.add(objeKey);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
return merged;
|
|
2396
|
+
};
|
|
2276
2397
|
var uniqueItemsCache = /* @__PURE__ */ new WeakMap();
|
|
2277
2398
|
var setNestedGroup = (obj, key, value, uniqueCounting = true) => {
|
|
2278
2399
|
const parts = Array.isArray(key) ? key : key.split(/,\s*/);
|
|
@@ -3532,7 +3653,10 @@ var Indi = class extends Common {
|
|
|
3532
3653
|
return result;
|
|
3533
3654
|
}
|
|
3534
3655
|
ancestryLink() {
|
|
3535
|
-
|
|
3656
|
+
let www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
3657
|
+
if (!www || /treeviz/i.test(String(www))) {
|
|
3658
|
+
www = "www.ancestry.com";
|
|
3659
|
+
}
|
|
3536
3660
|
const tree = this.getAncestryTreeId();
|
|
3537
3661
|
if (this.id) {
|
|
3538
3662
|
return `https://${www}/family-tree/person/tree/${tree}/person/${this.id.replace(
|
|
@@ -3544,14 +3668,15 @@ var Indi = class extends Common {
|
|
|
3544
3668
|
async ancestryMedia(namespace) {
|
|
3545
3669
|
const list = {};
|
|
3546
3670
|
const objeList = this.get("OBJE")?.toList().copy();
|
|
3547
|
-
|
|
3671
|
+
this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
3548
3672
|
const tree = this.getAncestryTreeId();
|
|
3673
|
+
const usedNamespace = namespace || this.getAncestryMediaNamespace() || ANCESTRY_TREE_MEDIA_NAMESPACE;
|
|
3549
3674
|
if (objeList) {
|
|
3550
3675
|
await Promise.all(
|
|
3551
3676
|
objeList.map(async (objeRef) => {
|
|
3552
3677
|
const key = objeXrefKey(objeRef, 0);
|
|
3553
3678
|
const obje = objeRef?.standardizeMedia(
|
|
3554
|
-
|
|
3679
|
+
usedNamespace,
|
|
3555
3680
|
true,
|
|
3556
3681
|
ancestryMediaFileUrl
|
|
3557
3682
|
);
|
|
@@ -3563,27 +3688,9 @@ var Indi = class extends Common {
|
|
|
3563
3688
|
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
3564
3689
|
let imgId = media;
|
|
3565
3690
|
const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
|
|
3566
|
-
if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
|
|
3567
|
-
return;
|
|
3568
|
-
}
|
|
3569
3691
|
if (!this.id) {
|
|
3570
3692
|
return;
|
|
3571
3693
|
}
|
|
3572
|
-
if (!namespace && !url) {
|
|
3573
|
-
try {
|
|
3574
|
-
if (media) {
|
|
3575
|
-
const mediaDetailsResponse = await fetch(
|
|
3576
|
-
`https://www.ancestry.com/api/media/viewer/v2/trees/${tree}/media?id=${media}`
|
|
3577
|
-
);
|
|
3578
|
-
const mediaDetails = await mediaDetailsResponse.json();
|
|
3579
|
-
if (mediaDetails.url) {
|
|
3580
|
-
url = `${mediaDetails.url}&imageQuality=hq`;
|
|
3581
|
-
}
|
|
3582
|
-
}
|
|
3583
|
-
} catch (_e) {
|
|
3584
|
-
}
|
|
3585
|
-
url = url || `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
|
|
3586
|
-
}
|
|
3587
3694
|
if (!imgId && hasEmbeddedOrLocalFile && url) {
|
|
3588
3695
|
imgId = typeof media === "string" && media || `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}`;
|
|
3589
3696
|
}
|
|
@@ -3609,9 +3716,12 @@ var Indi = class extends Common {
|
|
|
3609
3716
|
return list;
|
|
3610
3717
|
}
|
|
3611
3718
|
myheritageLink(poolId = 0) {
|
|
3612
|
-
|
|
3719
|
+
let www = (this.getFromSourceHeads("SOUR.CORP.value") || this._gedcom?.HEAD?.SOUR?.CORP?.value)?.toLowerCase().replace(/^www\./gi, "");
|
|
3720
|
+
if (!www || /treeviz/i.test(www)) {
|
|
3721
|
+
www = "myheritage.com";
|
|
3722
|
+
}
|
|
3613
3723
|
const site = this.getMyHeritageTreeId();
|
|
3614
|
-
const file = this._gedcom?.HEAD?.get("FILE")?.toValue()?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
|
|
3724
|
+
const file = (this.getFromSourceHeads("FILE.value") || this._gedcom?.HEAD?.get("FILE")?.toValue())?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
|
|
3615
3725
|
const normalizedFile = file?.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
3616
3726
|
if (normalizedFile && this.id) {
|
|
3617
3727
|
const id = Number(this.id.replace(/@|I/g, "")) + poolId;
|
|
@@ -3832,16 +3942,26 @@ var Indi = class extends Common {
|
|
|
3832
3942
|
return list;
|
|
3833
3943
|
}
|
|
3834
3944
|
async multimedia(namespace) {
|
|
3835
|
-
|
|
3836
|
-
|
|
3945
|
+
const lists = [];
|
|
3946
|
+
const ownObjes = this.get("OBJE")?.toList()?.values() ?? [];
|
|
3947
|
+
const ownAncestryMedia = ownObjes.some(
|
|
3948
|
+
(obje) => !!obje && (isAncestryOriginObje(obje) || isAncestryOriginObje(obje.ref))
|
|
3949
|
+
);
|
|
3950
|
+
if (this.isAncestry() || ownAncestryMedia) {
|
|
3951
|
+
lists.push(
|
|
3952
|
+
await this.ancestryMedia(
|
|
3953
|
+
namespace || this.getAncestryMediaNamespace()
|
|
3954
|
+
)
|
|
3955
|
+
);
|
|
3837
3956
|
}
|
|
3838
3957
|
if (this?.isMyHeritage()) {
|
|
3839
|
-
|
|
3958
|
+
lists.push(this.myheritageMedia());
|
|
3840
3959
|
}
|
|
3841
3960
|
if (this?.isGeni()) {
|
|
3842
|
-
|
|
3961
|
+
lists.push(this.geniMedia());
|
|
3843
3962
|
}
|
|
3844
|
-
|
|
3963
|
+
lists.push(this.universalMedia());
|
|
3964
|
+
return mergeMediaListsByObjeKey(...lists);
|
|
3845
3965
|
}
|
|
3846
3966
|
async getProfilePicture(namespace, onlyPrimary = true) {
|
|
3847
3967
|
if (!this.id) {
|