Skip to content

Add missing models in Shared #149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions shared/src/publication/AltIdentifier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* Copyright 2025 Readium Foundation. All rights reserved.
* Use of this source code is governed by a BSD-style license,
* available in the LICENSE file present in the Github repository of the project.
*/

/**
* Represents an alternate identifier for a publication.
* https://readium.org/webpub-manifest/schema/altIdentifier.schema.json
*/
export class AltIdentifier {
/** The value of the alternate identifier. */
public readonly value: string;

/** The scheme of the alternate identifier (URI format). */
public readonly scheme?: string;

/** Creates an AltIdentifier object */
constructor(values: {
value: string;
scheme?: string;
}) {
this.value = values.value;
this.scheme = values.scheme;
}

/**
* Parses an AltIdentifier from its RWPM JSON representation.
*/
public static deserialize(json: string | any): AltIdentifier | undefined {
if (!json) return;

if (typeof json === 'string') {
return new AltIdentifier({ value: json });
}

if (typeof json === 'object' && json.value) {
return new AltIdentifier({
value: json.value,
scheme: json.scheme
});
}

return undefined;
}

/**
* Serializes an AltIdentifier to its RWPM JSON representation.
*/
public serialize(): string | any {
if (this.scheme) {
return {
value: this.value,
scheme: this.scheme
};
}
return this.value;
}
}
15 changes: 15 additions & 0 deletions shared/src/publication/Contributor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
setToArray,
} from '../util/JSONParse';
import { LocalizedString } from './LocalizedString';
import { AltIdentifier } from './AltIdentifier';

/**
* Contributor Object for the Readium Web Publication Manifest.
Expand All @@ -25,6 +26,9 @@ export class Contributor {
/** An unambiguous reference to this contributor. */
public readonly identifier?: string;

/** Alternate identifiers for this contributor. */
public readonly altIdentifiers?: Set<AltIdentifier>;

/** The role of the contributor in the publication making. */
public readonly roles?: Set<string>;

Expand All @@ -41,13 +45,15 @@ export class Contributor {
name: LocalizedString;
sortAs?: string;
identifier?: string;
altIdentifiers?: Set<AltIdentifier>;
roles?: Set<string>;
links?: Links;
position?: number;
}) {
this.name = values.name;
this.sortAs = values.sortAs;
this.identifier = values.identifier;
this.altIdentifiers = values.altIdentifiers;
this.roles = values.roles;
this.links = values.links;
this.position = values.position;
Expand All @@ -70,6 +76,14 @@ export class Contributor {
name: LocalizedString.deserialize(json.name) as LocalizedString,
sortAs: json.sortAs,
identifier: json.identifier,
altIdentifiers: json.altIdentifier
? (json.altIdentifier instanceof Array
? new Set<AltIdentifier>(json.altIdentifier
.map((x: string | { value: string; scheme?: string }) => AltIdentifier.deserialize(x))
.filter((x: AltIdentifier | undefined): x is AltIdentifier => x !== undefined))
: new Set<AltIdentifier>([AltIdentifier.deserialize(json.altIdentifier as string | { value: string; scheme?: string })]
.filter((x: AltIdentifier | undefined): x is AltIdentifier => x !== undefined)))
: undefined,
roles: json.role
? new Set<string>(arrayfromJSONorString(json.role))
: undefined,
Expand All @@ -86,6 +100,7 @@ export class Contributor {
const json: any = { name: this.name.serialize() };
if (this.sortAs !== undefined) json.sortAs = this.sortAs;
if (this.identifier !== undefined) json.identifier = this.identifier;
if (this.altIdentifiers) json.altIdentifier = setToArray(this.altIdentifiers).map(altId => altId.serialize());
if (this.roles) json.role = setToArray(this.roles);
if (this.links) json.links = this.links.serialize();
if (this.position !== undefined) json.position = this.position;
Expand Down
7 changes: 7 additions & 0 deletions shared/src/publication/Link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export class Link {
/** Width of the linked resource in pixels. */
public readonly width?: number;

/** Size of the linked resource in bytes. */
public readonly size?: number;

/** Length of the linked resource in seconds. */
public readonly duration?: number;

Expand Down Expand Up @@ -69,6 +72,7 @@ export class Link {
properties?: Properties;
height?: number;
width?: number;
size?: number;
duration?: number;
bitrate?: number;
languages?: Array<string>;
Expand All @@ -83,6 +87,7 @@ export class Link {
this.properties = values.properties;
this.height = values.height;
this.width = values.width;
this.size = values.size;
this.duration = values.duration;
this.bitrate = values.bitrate;
this.languages = values.languages;
Expand All @@ -109,6 +114,7 @@ export class Link {
properties: Properties.deserialize(json.properties),
height: positiveNumberfromJSON(json.height),
width: positiveNumberfromJSON(json.width),
size: positiveNumberfromJSON(json.size),
duration: positiveNumberfromJSON(json.duration),
bitrate: positiveNumberfromJSON(json.bitrate),
languages: arrayfromJSONorString(json.language),
Expand All @@ -129,6 +135,7 @@ export class Link {
if (this.properties) json.properties = this.properties.serialize();
if (this.height !== undefined) json.height = this.height;
if (this.width !== undefined) json.width = this.width;
if (this.size !== undefined) json.size = this.size;
if (this.duration !== undefined) json.duration = this.duration;
if (this.bitrate !== undefined) json.bitrate = this.bitrate;
if (this.languages) json.language = this.languages;
Expand Down
18 changes: 17 additions & 1 deletion shared/src/publication/Metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import {
datefromJSON,
positiveNumberfromJSON,
} from '../util/JSONParse';
import { AltIdentifier } from './AltIdentifier';
import { BelongsTo } from './BelongsTo';
import { Contributors } from './Contributor';
import { LocalizedString } from './LocalizedString';
import { ReadingProgression } from './ReadingProgression';
import { Subjects } from './Subject';
import { TDM } from './TDM';

/**
* https://readium.org/webpub-manifest/schema/metadata.schema.json
Expand All @@ -26,6 +28,7 @@ export class Metadata {
public title: LocalizedString;
public typeUri?: string;
public identifier?: string;
public altIdentifier?: AltIdentifier;
public subtitle?: LocalizedString;
public sortAs?: LocalizedString;
public artists?: Contributors;
Expand All @@ -52,13 +55,15 @@ export class Metadata {
public readingProgression?: ReadingProgression;
public duration?: number;
public numberOfPages?: number;
public tdm?: TDM;
public otherMetadata?: { [key: string]: any };

/**All metadata not in otherMetadata */
private static readonly mappedProperties = [
'title',
'@type',
'identifier',
'altIdentifier',
'subtitle',
'sortAs',
'artist',
Expand All @@ -83,13 +88,15 @@ export class Metadata {
'readingProgression',
'duration',
'numberOfPages',
'tdm'
];

/** Creates [Metadata] object */
constructor(values: {
title: LocalizedString;
typeUri?: string;
identifier?: string;
altIdentifier?: AltIdentifier;
subtitle?: LocalizedString;
sortAs?: LocalizedString;
artists?: Contributors;
Expand All @@ -116,12 +123,14 @@ export class Metadata {
readingProgression?: ReadingProgression;
duration?: number;
numberOfPages?: number;
tdm?: TDM;
otherMetadata?: { [key: string]: any };
}) {
//title always required
this.title = values.title as LocalizedString;
this.typeUri = values.typeUri;
this.identifier = values.identifier;
this.altIdentifier = values.altIdentifier;
this.subtitle = values.subtitle;
this.sortAs = values.sortAs;
this.artists = values.artists;
Expand Down Expand Up @@ -166,6 +175,7 @@ export class Metadata {
this.readingProgression = values.readingProgression;
this.duration = values.duration;
this.numberOfPages = values.numberOfPages;
this.tdm = values.tdm;
this.otherMetadata = values.otherMetadata;
}

Expand All @@ -180,6 +190,7 @@ export class Metadata {
const title = LocalizedString.deserialize(json.title) as LocalizedString;
const typeUri = json['@type'];
const identifier = json.identifier;
const altIdentifier = AltIdentifier.deserialize(json.altIdentifier);
const subtitle = LocalizedString.deserialize(json.subtitle);
const sortAs = LocalizedString.deserialize(json.sortAs);
const artists = Contributors.deserialize(json.artist);
Expand All @@ -204,6 +215,7 @@ export class Metadata {
const readingProgression = json.readingProgression;
const duration = positiveNumberfromJSON(json.duration);
const numberOfPages = positiveNumberfromJSON(json.numberOfPages);
const tdm = TDM.deserialize(json.tdm);

let otherMetadata = Object.assign({}, json);
Metadata.mappedProperties.forEach(x => delete otherMetadata[x]);
Expand All @@ -215,6 +227,7 @@ export class Metadata {
title,
typeUri,
identifier,
altIdentifier,
subtitle,
sortAs,
artists,
Expand All @@ -239,7 +252,8 @@ export class Metadata {
readingProgression,
duration,
numberOfPages,
otherMetadata,
tdm,
otherMetadata
});
}

Expand All @@ -250,6 +264,7 @@ export class Metadata {
const json: any = { title: this.title.serialize() };
if (this.typeUri !== undefined) json['@type'] = this.typeUri;
if (this.identifier !== undefined) json.identifier = this.identifier;
if (this.altIdentifier) json.altIdentifier = this.altIdentifier.serialize();
if (this.subtitle) json.subtitle = this.subtitle.serialize();
if (this.sortAs) json.sortAs = this.sortAs.serialize();
if (this.editors) json.editor = this.editors.serialize();
Expand Down Expand Up @@ -278,6 +293,7 @@ export class Metadata {
if (this.duration !== undefined) json.duration = this.duration;
if (this.numberOfPages !== undefined)
json.numberOfPages = this.numberOfPages;
if (this.tdm) json.tdm = this.tdm.serialize();

if (this.otherMetadata) {
const metadata = this.otherMetadata;
Expand Down
56 changes: 56 additions & 0 deletions shared/src/publication/TDM.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* Copyright 2025 Readium Foundation. All rights reserved.
* Use of this source code is governed by a BSD-style license,
* available in the LICENSE file present in the Github repository of the project.
*/

/**
* https://readium.org/webpub-manifest/contexts/default/#text-and-data-mining
*/

export enum TDMReservation {
all = 'all',
none = 'none'
}

export class TDM {
/**
* Indicates whether the publication allows text and data mining.
*/
public readonly reservation?: TDMReservation;

/**
* Additional policy information about text and data mining usage.
*/
public readonly policy?: string;

/** Creates a [TDM] object */
constructor(values: {
reservation?: TDMReservation;
policy?: string;
}) {
this.reservation = values.reservation;
this.policy = values.policy;
}

/**
* Parses a [TDM] from its RWPM JSON representation.
*/
public static deserialize(json: any): TDM | undefined {
if (!json) return;

return new TDM({
reservation: json.reservation as TDMReservation,
policy: json.policy,
});
}

/**
* Serializes a [TDM] to its RWPM JSON representation.
*/
public serialize(): any {
const json: any = {};
if (this.reservation !== undefined) json.reservation = this.reservation;
if (this.policy !== undefined) json.policy = this.policy;
return json;
}
}
18 changes: 18 additions & 0 deletions shared/src/publication/divina/Properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Properties } from "../Properties";

// Divina extensions for link [Properties].
// https://github.com/readium/webpub-manifest/blob/master/schema/extensions/divina/properties.schema.json

declare module '../Properties' {
export interface Properties {
/**
* Specifies that an item in the reading order should break the current continuous scroll
* and start a new one.
*/
getBreakScrollBefore(): boolean;
}
}

Properties.prototype.getBreakScrollBefore = function(): boolean {
return this.otherProperties['break-scroll-before'] ?? false;
};
1 change: 1 addition & 0 deletions shared/src/publication/divina/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Properties';
Loading
Loading