@readium/shared 1.2.0
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/LICENSE +28 -0
- package/README.MD +27 -0
- package/dist/index.js +2536 -0
- package/dist/index.umd.cjs +2 -0
- package/package.json +73 -0
- package/src/fetcher/Fetcher.ts +37 -0
- package/src/fetcher/HttpFetcher.ts +122 -0
- package/src/fetcher/Resource.ts +37 -0
- package/src/fetcher/index.ts +2 -0
- package/src/index.ts +4 -0
- package/src/opds/Acquisition.ts +54 -0
- package/src/opds/Availability.ts +61 -0
- package/src/opds/Copies.ts +43 -0
- package/src/opds/Holds.ts +43 -0
- package/src/opds/Price.ts +51 -0
- package/src/opds/index.ts +5 -0
- package/src/publication/BelongsTo.ts +51 -0
- package/src/publication/Contributor.ts +129 -0
- package/src/publication/GuidedNavigation.ts +176 -0
- package/src/publication/Link.ts +332 -0
- package/src/publication/LocalizedString.ts +74 -0
- package/src/publication/Locator.ts +225 -0
- package/src/publication/LocatorCollection.ts +133 -0
- package/src/publication/Manifest.ts +256 -0
- package/src/publication/Metadata.ts +329 -0
- package/src/publication/Properties.ts +44 -0
- package/src/publication/Publication.ts +148 -0
- package/src/publication/PublicationCollection.ts +144 -0
- package/src/publication/ReadingProgression.ts +28 -0
- package/src/publication/Subject.ts +115 -0
- package/src/publication/encryption/Encryption.ts +68 -0
- package/src/publication/encryption/Properties.ts +20 -0
- package/src/publication/encryption/index.ts +2 -0
- package/src/publication/epub/EPUBLayout.ts +10 -0
- package/src/publication/epub/Presentation.ts +16 -0
- package/src/publication/epub/Properties.ts +28 -0
- package/src/publication/epub/Publication.ts +51 -0
- package/src/publication/epub/index.ts +4 -0
- package/src/publication/html/DomRange.ts +63 -0
- package/src/publication/html/DomRangePoint.ts +64 -0
- package/src/publication/html/Locations.ts +129 -0
- package/src/publication/html/index.ts +3 -0
- package/src/publication/index.ts +19 -0
- package/src/publication/opds/Properties.ts +84 -0
- package/src/publication/opds/Publication.ts +14 -0
- package/src/publication/opds/index.ts +2 -0
- package/src/publication/presentation/Metadata.ts +19 -0
- package/src/publication/presentation/Presentation.ts +155 -0
- package/src/publication/presentation/Properties.ts +70 -0
- package/src/publication/presentation/index.ts +3 -0
- package/src/publication/services/content/Content.ts +36 -0
- package/src/publication/services/content/ContentTokenizer.ts +62 -0
- package/src/publication/services/content/Iterator.ts +46 -0
- package/src/publication/services/content/element/attributes.ts +44 -0
- package/src/publication/services/content/element/element.ts +118 -0
- package/src/publication/services/content/element/index.ts +3 -0
- package/src/publication/services/content/element/text_role.ts +60 -0
- package/src/publication/services/content/index.ts +5 -0
- package/src/publication/services/content/iterators/HTMLResourceContentIterator.ts +571 -0
- package/src/publication/services/content/iterators/PDFTextContentIterator.ts +184 -0
- package/src/publication/services/content/iterators/PublicationContentIterator.ts +144 -0
- package/src/publication/services/content/iterators/helpers.ts +146 -0
- package/src/publication/services/content/iterators/index.ts +3 -0
- package/src/publication/services/index.ts +1 -0
- package/src/util/JSONParse.ts +31 -0
- package/src/util/Language.ts +5 -0
- package/src/util/URITemplate.ts +83 -0
- package/src/util/index.ts +5 -0
- package/src/util/mediatype/MediaType.ts +563 -0
- package/src/util/mediatype/index.ts +1 -0
- package/src/util/tokenizer/TextTokenizer.ts +126 -0
- package/src/util/tokenizer/Tokenizer.ts +8 -0
- package/src/util/tokenizer/index.ts +2 -0
- package/src/util/tokenizer/tokenize-english/README.md +7 -0
- package/src/util/tokenizer/tokenize-english/abbreviations.js +52 -0
- package/src/util/tokenizer/tokenize-english/index.d.ts +3 -0
- package/src/util/tokenizer/tokenize-english/index.js +243 -0
- package/src/util/tokenizer/tokenize-english/utils.js +16 -0
- package/src/util/tokenizer/tokenize-text/README.MD +6 -0
- package/src/util/tokenizer/tokenize-text/index.d.ts +52 -0
- package/src/util/tokenizer/tokenize-text/index.js +256 -0
- package/src/util/tokenizer/tokenize-text/tokens.js +100 -0
- package/types/src/fetcher/Fetcher.d.ts +27 -0
- package/types/src/fetcher/HttpFetcher.d.ts +28 -0
- package/types/src/fetcher/Resource.d.ts +15 -0
- package/types/src/fetcher/index.d.ts +2 -0
- package/types/src/index.d.ts +4 -0
- package/types/src/opds/Acquisition.d.ts +26 -0
- package/types/src/opds/Availability.d.ts +32 -0
- package/types/src/opds/Copies.d.ts +22 -0
- package/types/src/opds/Holds.d.ts +22 -0
- package/types/src/opds/Price.d.ts +29 -0
- package/types/src/opds/index.d.ts +5 -0
- package/types/src/publication/BelongsTo.d.ts +23 -0
- package/types/src/publication/Contributor.d.ts +60 -0
- package/types/src/publication/GuidedNavigation.d.ts +70 -0
- package/types/src/publication/Link.d.ts +128 -0
- package/types/src/publication/LocalizedString.d.ts +48 -0
- package/types/src/publication/Locator.d.ts +101 -0
- package/types/src/publication/LocatorCollection.d.ts +54 -0
- package/types/src/publication/Manifest.d.ts +59 -0
- package/types/src/publication/Metadata.d.ts +101 -0
- package/types/src/publication/Properties.d.ts +28 -0
- package/types/src/publication/Publication.d.ts +53 -0
- package/types/src/publication/PublicationCollection.d.ts +34 -0
- package/types/src/publication/ReadingProgression.d.ts +9 -0
- package/types/src/publication/Subject.d.ts +56 -0
- package/types/src/publication/encryption/Encryption.d.ts +33 -0
- package/types/src/publication/encryption/Properties.d.ts +10 -0
- package/types/src/publication/encryption/index.d.ts +2 -0
- package/types/src/publication/epub/EPUBLayout.d.ts +5 -0
- package/types/src/publication/epub/Presentation.d.ts +7 -0
- package/types/src/publication/epub/Properties.d.ts +14 -0
- package/types/src/publication/epub/Publication.d.ts +19 -0
- package/types/src/publication/epub/index.d.ts +4 -0
- package/types/src/publication/html/DomRange.d.ts +40 -0
- package/types/src/publication/html/DomRangePoint.d.ts +36 -0
- package/types/src/publication/html/Locations.d.ts +45 -0
- package/types/src/publication/html/index.d.ts +3 -0
- package/types/src/publication/index.d.ts +19 -0
- package/types/src/publication/opds/Properties.d.ts +38 -0
- package/types/src/publication/opds/Publication.d.ts +6 -0
- package/types/src/publication/opds/index.d.ts +2 -0
- package/types/src/publication/presentation/Metadata.d.ts +6 -0
- package/types/src/publication/presentation/Presentation.d.ts +95 -0
- package/types/src/publication/presentation/Properties.d.ts +32 -0
- package/types/src/publication/presentation/index.d.ts +3 -0
- package/types/src/publication/services/content/Content.d.ts +20 -0
- package/types/src/publication/services/content/ContentTokenizer.d.ts +19 -0
- package/types/src/publication/services/content/Iterator.d.ts +38 -0
- package/types/src/publication/services/content/element/attributes.d.ts +31 -0
- package/types/src/publication/services/content/element/element.d.ts +107 -0
- package/types/src/publication/services/content/element/index.d.ts +3 -0
- package/types/src/publication/services/content/element/text_role.d.ts +53 -0
- package/types/src/publication/services/content/index.d.ts +5 -0
- package/types/src/publication/services/content/iterators/HTMLResourceContentIterator.d.ts +30 -0
- package/types/src/publication/services/content/iterators/PDFTextContentIterator.d.ts +60 -0
- package/types/src/publication/services/content/iterators/PublicationContentIterator.d.ts +59 -0
- package/types/src/publication/services/content/iterators/helpers.d.ts +10 -0
- package/types/src/publication/services/content/iterators/index.d.ts +3 -0
- package/types/src/publication/services/index.d.ts +1 -0
- package/types/src/util/JSONParse.d.ts +11 -0
- package/types/src/util/Language.d.ts +1 -0
- package/types/src/util/URITemplate.d.ts +24 -0
- package/types/src/util/index.d.ts +5 -0
- package/types/src/util/mediatype/MediaType.d.ts +148 -0
- package/types/src/util/mediatype/index.d.ts +1 -0
- package/types/src/util/tokenizer/TextTokenizer.d.ts +39 -0
- package/types/src/util/tokenizer/Tokenizer.d.ts +6 -0
- package/types/src/util/tokenizer/index.d.ts +2 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* Copyright 2021 Readium Foundation. All rights reserved.
|
|
2
|
+
* Use of this source code is governed by a BSD-style license,
|
|
3
|
+
* available in the LICENSE file present in the Github repository of the project.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Contributors as Collection } from './Contributor';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* BelongsTo Object for the Readium Web Publication Manifest.
|
|
10
|
+
* https://readium.org/webpub-manifest/schema/contributor-object.schema.json
|
|
11
|
+
*/
|
|
12
|
+
export class BelongsTo {
|
|
13
|
+
/**
|
|
14
|
+
* Map of [BelongsTo] items.
|
|
15
|
+
*/
|
|
16
|
+
public readonly items: Map<string, Collection>;
|
|
17
|
+
|
|
18
|
+
/** Creates an Array of [Subject]. */
|
|
19
|
+
constructor(values?: { items?: Map<string, Collection> }) {
|
|
20
|
+
this.items =
|
|
21
|
+
values && values.items ? values.items : new Map<string, Collection>();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parses a [BelongsTo] from its RWPM JSON representation.
|
|
26
|
+
*/
|
|
27
|
+
public static deserialize(json: any): BelongsTo | undefined {
|
|
28
|
+
if (!(json && json instanceof Object)) return;
|
|
29
|
+
|
|
30
|
+
const items = new Map<string, Collection>();
|
|
31
|
+
Object.entries(json).forEach(([key, value]) => {
|
|
32
|
+
const obj = Collection.deserialize(value);
|
|
33
|
+
if (obj && obj.items.length > 0) {
|
|
34
|
+
items.set(key, obj);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return new BelongsTo({ items });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Serializes a [BelongsTo] to its RWPM JSON representation.
|
|
43
|
+
*/
|
|
44
|
+
public serialize(): any {
|
|
45
|
+
const json: any = {};
|
|
46
|
+
this.items.forEach(
|
|
47
|
+
(value: Collection, key: string) => (json[key] = value.serialize())
|
|
48
|
+
);
|
|
49
|
+
return json;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* Copyright 2021 Readium Foundation. All rights reserved.
|
|
2
|
+
* Use of this source code is governed by a BSD-style license,
|
|
3
|
+
* available in the LICENSE file present in the Github repository of the project.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Links } from './Link';
|
|
7
|
+
import {
|
|
8
|
+
arrayfromJSONorString,
|
|
9
|
+
numberfromJSON,
|
|
10
|
+
setToArray,
|
|
11
|
+
} from '../util/JSONParse';
|
|
12
|
+
import { LocalizedString } from './LocalizedString';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Contributor Object for the Readium Web Publication Manifest.
|
|
16
|
+
* https://readium.org/webpub-manifest/schema/contributor-object.schema.json
|
|
17
|
+
*/
|
|
18
|
+
export class Contributor {
|
|
19
|
+
/** The name of the contributor. */
|
|
20
|
+
public readonly name: LocalizedString;
|
|
21
|
+
|
|
22
|
+
/** The string used to sort the name of the contributor. */
|
|
23
|
+
public readonly sortAs?: string;
|
|
24
|
+
|
|
25
|
+
/** An unambiguous reference to this contributor. */
|
|
26
|
+
public readonly identifier?: string;
|
|
27
|
+
|
|
28
|
+
/** The role of the contributor in the publication making. */
|
|
29
|
+
public readonly roles?: Set<string>;
|
|
30
|
+
|
|
31
|
+
/** Used to retrieve similar publications for the given contributor. */
|
|
32
|
+
public readonly links?: Links;
|
|
33
|
+
|
|
34
|
+
/** The position of the publication in this collection/series, when the contributor represents a collection. */
|
|
35
|
+
public readonly position?: number;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates a [Contributor] object.
|
|
39
|
+
*/
|
|
40
|
+
constructor(values: {
|
|
41
|
+
name: LocalizedString;
|
|
42
|
+
sortAs?: string;
|
|
43
|
+
identifier?: string;
|
|
44
|
+
roles?: Set<string>;
|
|
45
|
+
links?: Links;
|
|
46
|
+
position?: number;
|
|
47
|
+
}) {
|
|
48
|
+
this.name = values.name;
|
|
49
|
+
this.sortAs = values.sortAs;
|
|
50
|
+
this.identifier = values.identifier;
|
|
51
|
+
this.roles = values.roles;
|
|
52
|
+
this.links = values.links;
|
|
53
|
+
this.position = values.position;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Parses a [Contributor] from its RWPM JSON representation.
|
|
58
|
+
*
|
|
59
|
+
* A contributor can be parsed from a single string, or a full-fledged object.
|
|
60
|
+
*/
|
|
61
|
+
public static deserialize(json: any): Contributor | undefined {
|
|
62
|
+
if (!json) return;
|
|
63
|
+
if (typeof json === 'string') {
|
|
64
|
+
return new Contributor({
|
|
65
|
+
name: LocalizedString.deserialize(json) as LocalizedString,
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
if (!json.name) return;
|
|
69
|
+
return new Contributor({
|
|
70
|
+
name: LocalizedString.deserialize(json.name) as LocalizedString,
|
|
71
|
+
sortAs: json.sortAs,
|
|
72
|
+
identifier: json.identifier,
|
|
73
|
+
roles: json.role
|
|
74
|
+
? new Set<string>(arrayfromJSONorString(json.role))
|
|
75
|
+
: undefined,
|
|
76
|
+
links: Links.deserialize(json.links),
|
|
77
|
+
position: numberfromJSON(json.position),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Serializes a [Contributor] to its RWPM JSON representation.
|
|
84
|
+
*/
|
|
85
|
+
public serialize(): any {
|
|
86
|
+
const json: any = { name: this.name.serialize() };
|
|
87
|
+
if (this.sortAs !== undefined) json.sortAs = this.sortAs;
|
|
88
|
+
if (this.identifier !== undefined) json.identifier = this.identifier;
|
|
89
|
+
if (this.roles) json.role = setToArray(this.roles);
|
|
90
|
+
if (this.links) json.links = this.links.serialize();
|
|
91
|
+
if (this.position !== undefined) json.position = this.position;
|
|
92
|
+
return json;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export class Contributors {
|
|
97
|
+
/**
|
|
98
|
+
* Array of [Contributor] .
|
|
99
|
+
*/
|
|
100
|
+
public readonly items: Array<Contributor>;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Creates a [Contributors] object.
|
|
104
|
+
*/
|
|
105
|
+
constructor(items: Array<Contributor>) {
|
|
106
|
+
this.items = items;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Parses a [Contributors] from its RWPM JSON representation.
|
|
111
|
+
*
|
|
112
|
+
*/
|
|
113
|
+
public static deserialize(json: any): Contributors | undefined {
|
|
114
|
+
if (!json) return;
|
|
115
|
+
const items = json instanceof Array ? json : [json];
|
|
116
|
+
return new Contributors(
|
|
117
|
+
items
|
|
118
|
+
.map<Contributor>(item => Contributor.deserialize(item) as Contributor)
|
|
119
|
+
.filter(x => x !== undefined)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Serializes a [Contributors] to its RWPM JSON representation.
|
|
125
|
+
*/
|
|
126
|
+
public serialize(): any {
|
|
127
|
+
return this.items.map(x => x.serialize());
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import {
|
|
2
|
+
arrayfromJSONorString,
|
|
3
|
+
setToArray,
|
|
4
|
+
} from '../util/JSONParse';
|
|
5
|
+
import { Links } from "./Link";
|
|
6
|
+
|
|
7
|
+
export interface Clip {
|
|
8
|
+
audioResource: string;
|
|
9
|
+
fragmentId?: string;
|
|
10
|
+
start?: number;
|
|
11
|
+
end?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Guided Navigation Document
|
|
16
|
+
* https://readium.org/guided-navigation/schema/document.schema.json
|
|
17
|
+
*/
|
|
18
|
+
export class GuidedNavigationDocument {
|
|
19
|
+
public readonly links?: Links;
|
|
20
|
+
public readonly guided?: GuidedNavigationObject[];
|
|
21
|
+
|
|
22
|
+
constructor(values: {
|
|
23
|
+
links?: Links;
|
|
24
|
+
guided?: GuidedNavigationObject[];
|
|
25
|
+
}) {
|
|
26
|
+
this.links = values.links;
|
|
27
|
+
this.guided = values.guided;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static deserialize(json: any): GuidedNavigationDocument | undefined {
|
|
31
|
+
if (!json) return;
|
|
32
|
+
return new GuidedNavigationDocument({
|
|
33
|
+
links: Links.deserialize(json.links),
|
|
34
|
+
guided: GuidedNavigationObject.deserializeArray(json.guided),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public serialize(): any {
|
|
39
|
+
const json: any = {};
|
|
40
|
+
if (this.links !== undefined) json.links = this.links.serialize();
|
|
41
|
+
if (this.guided !== undefined) json.guided = this.guided.map(x => x.serialize());
|
|
42
|
+
return json;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Guided Navigation Object
|
|
48
|
+
* https://github.com/readium/guided-navigation/blob/main/schema/object.schema.json
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
export class GuidedNavigationObject {
|
|
52
|
+
/** References an audio resource or a fragment of it. */
|
|
53
|
+
public readonly audioref?: string;
|
|
54
|
+
|
|
55
|
+
/** Items that are children of the containing Guided Navigation Object. */
|
|
56
|
+
public readonly children?: GuidedNavigationObject[];
|
|
57
|
+
|
|
58
|
+
/** References an image or a fragment of it. */
|
|
59
|
+
public readonly imgref?: string;
|
|
60
|
+
|
|
61
|
+
/** Convey the structural semantics of a publication. */
|
|
62
|
+
public readonly role?: Set<string>;
|
|
63
|
+
|
|
64
|
+
/** Textual equivalent of the resources or fragment of the resources referenced by the current Guided Navigation Object. */
|
|
65
|
+
public readonly text?: string;
|
|
66
|
+
|
|
67
|
+
/** References a textual resource or a fragment of it. */
|
|
68
|
+
public readonly textref?: string;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Creates a [GuidedNavigation] object.
|
|
72
|
+
*/
|
|
73
|
+
constructor(values: {
|
|
74
|
+
audioref?: string;
|
|
75
|
+
children?: GuidedNavigationObject[];
|
|
76
|
+
imgref?: string;
|
|
77
|
+
role?: Set<string>;
|
|
78
|
+
text?: string;
|
|
79
|
+
textref?: string;
|
|
80
|
+
}) {
|
|
81
|
+
this.audioref = values.audioref;
|
|
82
|
+
this.children = values.children;
|
|
83
|
+
this.imgref = values.imgref;
|
|
84
|
+
this.role = values.role;
|
|
85
|
+
this.text = values.text;
|
|
86
|
+
this.textref = values.textref;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Parses a [GuidedNavigationObject] from its RWPM JSON representation.
|
|
91
|
+
*
|
|
92
|
+
* A GuidedNavigationObject can be parsed from a single string, or a full-fledged object.
|
|
93
|
+
*/
|
|
94
|
+
public static deserialize(json: any): GuidedNavigationObject | undefined {
|
|
95
|
+
if (!json) return;
|
|
96
|
+
return new GuidedNavigationObject({
|
|
97
|
+
audioref: json.audioref,
|
|
98
|
+
children: GuidedNavigationObject.deserializeArray(json.children),
|
|
99
|
+
imgref: json.imgref,
|
|
100
|
+
role: json.role
|
|
101
|
+
? new Set<string>(arrayfromJSONorString(json.role))
|
|
102
|
+
: undefined,
|
|
103
|
+
text: json.text,
|
|
104
|
+
textref: json.textref,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Parses a [GuidedNavigationObject] array from its RWPM JSON representation.
|
|
110
|
+
*/
|
|
111
|
+
public static deserializeArray(json: any): GuidedNavigationObject[] | undefined {
|
|
112
|
+
if (!(json instanceof Array)) return;
|
|
113
|
+
return json
|
|
114
|
+
.map<GuidedNavigationObject>((item) => GuidedNavigationObject.deserialize(item) as GuidedNavigationObject)
|
|
115
|
+
.filter((x) => x !== undefined);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Serializes a [GuidedNavigationObject] to its RWPM JSON representation.
|
|
120
|
+
*/
|
|
121
|
+
public serialize(): any {
|
|
122
|
+
const json: any = {};
|
|
123
|
+
if (this.audioref !== undefined) json.audioref = this.audioref;
|
|
124
|
+
if (this.children !== undefined) json.children = this.children.map(x => x.serialize());
|
|
125
|
+
if (this.imgref !== undefined) json.imgref = this.imgref;
|
|
126
|
+
if (this.role !== undefined) json.role = setToArray(this.role);
|
|
127
|
+
if (this.text !== undefined) json.text = this.text;
|
|
128
|
+
if (this.textref !== undefined) json.textref = this.textref;
|
|
129
|
+
return json;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public get audioFile(): string | undefined {
|
|
133
|
+
return this.audioref?.split('#')[0];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public get audioTime(): string | undefined {
|
|
137
|
+
if(this.audioref?.includes('#')) {
|
|
138
|
+
return this.audioref.split('#', 2)[1];
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public get textFile(): string | undefined {
|
|
144
|
+
return this.textref?.split('#')[0];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public get fragmentId(): string | undefined {
|
|
148
|
+
if(this.textref?.includes('#')) {
|
|
149
|
+
return this.textref.split('#', 2)[1];
|
|
150
|
+
}
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public get clip(): Clip | undefined {
|
|
155
|
+
const audio = this.audioFile;
|
|
156
|
+
if(!audio) return undefined;
|
|
157
|
+
const time = this.audioTime;
|
|
158
|
+
const result = {
|
|
159
|
+
audioResource: audio,
|
|
160
|
+
fragmentId: this.fragmentId,
|
|
161
|
+
} as Clip;
|
|
162
|
+
if(!time) return result;
|
|
163
|
+
const times = this.parseTimer(time);
|
|
164
|
+
result.start = times[0];
|
|
165
|
+
result.end = times[1];
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private parseTimer(times: string): [number?, number?] {
|
|
170
|
+
if(!times || !times.startsWith("t=")) return [undefined, undefined];
|
|
171
|
+
const ts = times.substring(2).split(',').map(t => parseFloat(t));
|
|
172
|
+
if(ts.length === 1) return [isNaN(ts[0]) ? undefined : ts[0], undefined];
|
|
173
|
+
if(ts.length > 2) return [undefined, undefined];
|
|
174
|
+
return [isNaN(ts[0]) ? undefined : ts[0], isNaN(ts[1]) ? undefined : ts[1]];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/* Copyright 2021 Readium Foundation. All rights reserved.
|
|
2
|
+
* Use of this source code is governed by a BSD-style license,
|
|
3
|
+
* available in the LICENSE file present in the Github repository of the project.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { MediaType } from '../util/mediatype/MediaType';
|
|
7
|
+
import { Properties } from './Properties';
|
|
8
|
+
import { URITemplate } from '../util/URITemplate';
|
|
9
|
+
import {
|
|
10
|
+
arrayfromJSONorString,
|
|
11
|
+
positiveNumberfromJSON,
|
|
12
|
+
setToArray,
|
|
13
|
+
} from '../util/JSONParse';
|
|
14
|
+
import { LocatorLocations, Locator } from './Locator';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Link Object for the Readium Web Publication Manifest.
|
|
18
|
+
* https://readium.org/webpub-manifest/schema/link.schema.json
|
|
19
|
+
*/
|
|
20
|
+
export class Link {
|
|
21
|
+
/** URI or URI template of the linked resource. */
|
|
22
|
+
public readonly href: string;
|
|
23
|
+
|
|
24
|
+
/** Indicates that a URI template is used in href. */
|
|
25
|
+
public readonly templated?: boolean;
|
|
26
|
+
|
|
27
|
+
/** MIME type of the linked resource. */
|
|
28
|
+
public readonly type?: string;
|
|
29
|
+
|
|
30
|
+
/** Title of the linked resource. */
|
|
31
|
+
public readonly title?: string;
|
|
32
|
+
|
|
33
|
+
/** Relation between the linked resource and its containing collection. */
|
|
34
|
+
public readonly rels?: Set<string>;
|
|
35
|
+
|
|
36
|
+
/** Properties associated to the linked resource. */
|
|
37
|
+
public properties?: Properties;
|
|
38
|
+
|
|
39
|
+
/** Height of the linked resource in pixels. */
|
|
40
|
+
public readonly height?: number;
|
|
41
|
+
|
|
42
|
+
/** Width of the linked resource in pixels. */
|
|
43
|
+
public readonly width?: number;
|
|
44
|
+
|
|
45
|
+
/** Length of the linked resource in seconds. */
|
|
46
|
+
public readonly duration?: number;
|
|
47
|
+
|
|
48
|
+
/** Bitrate of the linked resource in kbps. */
|
|
49
|
+
public readonly bitrate?: number;
|
|
50
|
+
|
|
51
|
+
/** Expected language of the linked resource. */
|
|
52
|
+
public readonly languages?: Array<string>;
|
|
53
|
+
|
|
54
|
+
/** Alternate resources for the linked resource. */
|
|
55
|
+
public readonly alternates?: Links;
|
|
56
|
+
|
|
57
|
+
/** Resources that are children of the linked resource, in the context of a given collection role. */
|
|
58
|
+
public readonly children?: Links;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Creates a [Link].
|
|
62
|
+
*/
|
|
63
|
+
constructor(values: {
|
|
64
|
+
href: string;
|
|
65
|
+
templated?: boolean;
|
|
66
|
+
type?: string;
|
|
67
|
+
title?: string;
|
|
68
|
+
rels?: Set<string>;
|
|
69
|
+
properties?: Properties;
|
|
70
|
+
height?: number;
|
|
71
|
+
width?: number;
|
|
72
|
+
duration?: number;
|
|
73
|
+
bitrate?: number;
|
|
74
|
+
languages?: Array<string>;
|
|
75
|
+
alternates?: Links;
|
|
76
|
+
children?: Links;
|
|
77
|
+
}) {
|
|
78
|
+
this.href = values.href;
|
|
79
|
+
this.templated = values.templated;
|
|
80
|
+
this.type = values.type;
|
|
81
|
+
this.title = values.title;
|
|
82
|
+
this.rels = values.rels;
|
|
83
|
+
this.properties = values.properties;
|
|
84
|
+
this.height = values.height;
|
|
85
|
+
this.width = values.width;
|
|
86
|
+
this.duration = values.duration;
|
|
87
|
+
this.bitrate = values.bitrate;
|
|
88
|
+
this.languages = values.languages;
|
|
89
|
+
this.alternates = values.alternates;
|
|
90
|
+
this.children = values.children;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Parses a [Link] from its RWPM JSON representation.
|
|
95
|
+
*/
|
|
96
|
+
public static deserialize(json: any): Link | undefined {
|
|
97
|
+
if (!(json && json.href && typeof json.href === 'string')) return;
|
|
98
|
+
return new Link({
|
|
99
|
+
href: json.href,
|
|
100
|
+
templated: json.templated,
|
|
101
|
+
type: json.type,
|
|
102
|
+
title: json.title,
|
|
103
|
+
rels: json.rel
|
|
104
|
+
? json.rel instanceof Array
|
|
105
|
+
? new Set<string>(json.rel as Array<string>)
|
|
106
|
+
: new Set<string>([json.rel as string])
|
|
107
|
+
: undefined,
|
|
108
|
+
properties: Properties.deserialize(json.properties),
|
|
109
|
+
height: positiveNumberfromJSON(json.height),
|
|
110
|
+
width: positiveNumberfromJSON(json.width),
|
|
111
|
+
duration: positiveNumberfromJSON(json.duration),
|
|
112
|
+
bitrate: positiveNumberfromJSON(json.bitrate),
|
|
113
|
+
languages: arrayfromJSONorString(json.language),
|
|
114
|
+
alternates: Links.deserialize(json.alternate),
|
|
115
|
+
children: Links.deserialize(json.children),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Serializes a [Link] to its RWPM JSON representation.
|
|
121
|
+
*/
|
|
122
|
+
public serialize(): any {
|
|
123
|
+
const json: any = { href: this.href };
|
|
124
|
+
if (this.templated !== undefined) json.templated = this.templated;
|
|
125
|
+
if (this.type !== undefined) json.type = this.type;
|
|
126
|
+
if (this.title !== undefined) json.title = this.title;
|
|
127
|
+
if (this.rels) json.rel = setToArray(this.rels);
|
|
128
|
+
if (this.properties) json.properties = this.properties.serialize();
|
|
129
|
+
if (this.height !== undefined) json.height = this.height;
|
|
130
|
+
if (this.width !== undefined) json.width = this.width;
|
|
131
|
+
if (this.duration !== undefined) json.duration = this.duration;
|
|
132
|
+
if (this.bitrate !== undefined) json.bitrate = this.bitrate;
|
|
133
|
+
if (this.languages) json.language = this.languages;
|
|
134
|
+
if (this.alternates) json.alternate = this.alternates.serialize();
|
|
135
|
+
if (this.children) json.children = this.children.serialize();
|
|
136
|
+
return json;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** MediaType of the linked resource. */
|
|
140
|
+
public get mediaType(): MediaType {
|
|
141
|
+
return this.type !== undefined
|
|
142
|
+
? MediaType.parse({ mediaType: this.type })
|
|
143
|
+
: MediaType.BINARY;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Computes an absolute URL to the link, relative to the given `baseURL`.
|
|
147
|
+
* If the link's `href` is already absolute, the `baseURL` is ignored.
|
|
148
|
+
*/
|
|
149
|
+
public toURL(baseUrl?: string): string | undefined {
|
|
150
|
+
const href = this.href.replace(/^(\/)/, '');
|
|
151
|
+
if (href.length === 0) return;
|
|
152
|
+
let _baseUrl = baseUrl ? baseUrl : '/';
|
|
153
|
+
|
|
154
|
+
if (_baseUrl.startsWith('/')) {
|
|
155
|
+
_baseUrl = 'file://' + _baseUrl;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return new URL(href, _baseUrl).href.replace(/^(file:\/\/)/, '');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** List of URI template parameter keys, if the `Link` is templated. */
|
|
162
|
+
public get templateParameters(): Set<string> {
|
|
163
|
+
return this.templated ? new URITemplate(this.href).parameters : new Set();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Expands the `Link`'s HREF by replacing URI template variables by the given parameters.
|
|
167
|
+
* See RFC 6570 on URI template: https://tools.ietf.org/html/rfc6570
|
|
168
|
+
*/
|
|
169
|
+
public expandTemplate(parameters: { [param: string]: string }): Link {
|
|
170
|
+
// Probably make copy instead of a new one
|
|
171
|
+
return new Link({
|
|
172
|
+
href: new URITemplate(this.href).expand(parameters),
|
|
173
|
+
templated: false,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Makes a copy of this [Link] after merging in the given additional other [properties].
|
|
179
|
+
*/
|
|
180
|
+
public addProperties(properties: { [key: string]: any }): Link {
|
|
181
|
+
const link = Link.deserialize(this.serialize()) as Link;
|
|
182
|
+
link.properties = link.properties
|
|
183
|
+
? link.properties?.add(properties)
|
|
184
|
+
: new Properties(properties);
|
|
185
|
+
return link;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Creates a [Locator] from a reading order [Link].
|
|
190
|
+
*/
|
|
191
|
+
public get locator(): Locator {
|
|
192
|
+
let parts = this.href.split('#');
|
|
193
|
+
return new Locator({
|
|
194
|
+
href: parts.length > 0 && parts[0] !== undefined ? parts[0] : this.href,
|
|
195
|
+
type: this.type ?? '',
|
|
196
|
+
title: this.title,
|
|
197
|
+
locations: new LocatorLocations({
|
|
198
|
+
fragments: parts.length > 1 && parts[1] !== undefined ? [parts[1]] : [],
|
|
199
|
+
}),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Parses multiple JSON links into an array of Link.
|
|
206
|
+
*/
|
|
207
|
+
export class Links {
|
|
208
|
+
public items: Array<Link>;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Creates a [Links].
|
|
212
|
+
*/
|
|
213
|
+
constructor(items: Array<Link>) {
|
|
214
|
+
this.items = items;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Creates a list of [Link] from its RWPM JSON representation.
|
|
219
|
+
*/
|
|
220
|
+
public static deserialize(json: any): Links | undefined {
|
|
221
|
+
if (!(json && json instanceof Array)) return;
|
|
222
|
+
return new Links(
|
|
223
|
+
json
|
|
224
|
+
.map<Link>(item => Link.deserialize(item) as Link)
|
|
225
|
+
.filter(x => x !== undefined)
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Serializes an array of [Link] to its RWPM JSON representation.
|
|
231
|
+
*/
|
|
232
|
+
public serialize(): any {
|
|
233
|
+
return this.items.map(x => x.serialize());
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Finds the first link with the given relation. */
|
|
237
|
+
public findWithRel(rel: string): Link | undefined {
|
|
238
|
+
const predicate = (el: Link) => el.rels && el.rels.has(rel);
|
|
239
|
+
return this.items.find(predicate);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Finds all the links with the given relation. */
|
|
243
|
+
public filterByRel(rel: string): Array<Link> {
|
|
244
|
+
const predicate = (el: Link) => el.rels && el.rels.has(rel);
|
|
245
|
+
return this.items.filter(predicate);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Finds the first link matching the given HREF. */
|
|
249
|
+
public findWithHref(href: string): Link | undefined {
|
|
250
|
+
const predicate = (el: Link) => el.href === href;
|
|
251
|
+
return this.items.find(predicate);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Finds the index of the first link matching the given HREF. */
|
|
255
|
+
public findIndexWithHref(href: string): number {
|
|
256
|
+
const predicate = (el: Link) => el.href === href;
|
|
257
|
+
return this.items.findIndex(predicate);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Finds the first link matching the given media type. */
|
|
261
|
+
public findWithMediaType(mediaType: string): Link | undefined {
|
|
262
|
+
const predicate = (el: Link) => el.mediaType.matches(mediaType);
|
|
263
|
+
return this.items.find(predicate);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Finds all the links matching the given media type. */
|
|
267
|
+
public filterByMediaType(mediaType: string): Array<Link> {
|
|
268
|
+
const predicate = (el: Link) => el.mediaType.matches(mediaType);
|
|
269
|
+
return this.items.filter(predicate);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Finds all the links matching any of the given media types. */
|
|
273
|
+
public filterByMediaTypes(mediaTypes: Array<string>): Array<Link> {
|
|
274
|
+
const predicate = (el: Link) => {
|
|
275
|
+
for (const mediaType of mediaTypes) {
|
|
276
|
+
if (el.mediaType.matches(mediaType)) {
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return false;
|
|
281
|
+
};
|
|
282
|
+
return this.items.filter(predicate);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Returns whether all the resources in the collection are audio clips. */
|
|
286
|
+
public everyIsAudio(): boolean {
|
|
287
|
+
const predicate = (el: Link) => el.mediaType.isAudio;
|
|
288
|
+
return this.items.length > 0 && this.items.every(predicate);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Returns whether all the resources in the collection are bitmaps. */
|
|
292
|
+
public everyIsBitmap(): boolean {
|
|
293
|
+
const predicate = (el: Link) => el.mediaType.isBitmap;
|
|
294
|
+
return this.items.length > 0 && this.items.every(predicate);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** Returns whether all the resources in the collection are HTML documents. */
|
|
298
|
+
public everyIsHTML(): boolean {
|
|
299
|
+
const predicate = (el: Link) => el.mediaType.isHTML;
|
|
300
|
+
return this.items.length > 0 && this.items.every(predicate);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Returns whether all the resources in the collection are video clips. */
|
|
304
|
+
public everyIsVideo(): boolean {
|
|
305
|
+
const predicate = (el: Link) => el.mediaType.isVideo;
|
|
306
|
+
return this.items.length > 0 && this.items.every(predicate);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Returns whether all the resources in the collection are matching any of the given media types. */
|
|
310
|
+
public everyMatchesMediaType(mediaTypes: string | Array<string>): boolean {
|
|
311
|
+
if (Array.isArray(mediaTypes)) {
|
|
312
|
+
return (
|
|
313
|
+
this.items.length > 0 &&
|
|
314
|
+
this.items.every((el: Link) => {
|
|
315
|
+
for (const mediaType of mediaTypes) {
|
|
316
|
+
return el.mediaType.matches(mediaType);
|
|
317
|
+
}
|
|
318
|
+
return false;
|
|
319
|
+
})
|
|
320
|
+
);
|
|
321
|
+
} else {
|
|
322
|
+
return (
|
|
323
|
+
this.items.length > 0 &&
|
|
324
|
+
this.items.every((el: Link) => el.mediaType.matches(mediaTypes))
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
public filterLinksHasType(): Array<Link> {
|
|
330
|
+
return this.items.filter(x => x.type);
|
|
331
|
+
}
|
|
332
|
+
}
|