Skip to content

Commit

Permalink
Add GuidedNavigationDocument, GuidedNavigationObject helper functions
Browse files Browse the repository at this point in the history
  • Loading branch information
chocolatkey committed Sep 3, 2024
1 parent e976a09 commit e76b6ce
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 13 deletions.
115 changes: 105 additions & 10 deletions shared/src/publication/GuidedNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,58 @@ import {
arrayfromJSONorString,
setToArray,
} from '../util/JSONParse';
import { Links } from "./Link";

export interface Clip {
audioResource: string;
fragmentId?: string;
start?: number;
end?: number;
}

/**
* Guided Navigation Document
* https://readium.org/guided-navigation/schema/document.schema.json
*/
export class GuidedNavigationDocument {
public readonly links?: Links;
public readonly guided?: GuidedNavigationObject[];

constructor(values: {
links?: Links;
guided?: GuidedNavigationObject[];
}) {
this.links = values.links;
this.guided = values.guided;
}

public static deserialize(json: any): GuidedNavigationDocument | undefined {
if (!json) return;
return new GuidedNavigationDocument({
links: Links.deserialize(json.links),
guided: GuidedNavigationObject.deserializeArray(json.guided),
});
}

public serialize(): any {
const json: any = {};
if (this.links !== undefined) json.links = this.links.serialize();
if (this.guided !== undefined) json.guided = this.guided.map(x => x.serialize());
return json;
}
}

/**
* Guided Navigation Object for the Readium Web Publication Manifest.
* Guided Navigation Object
* https://github.com/readium/guided-navigation/blob/main/schema/object.schema.json
*/

export class GuidedNavigation {
export class GuidedNavigationObject {
/** References an audio resource or a fragment of it. */
public readonly audioref?: string;

/** Items that are children of the containing Guided Navigation Object. */
public readonly children?: GuidedNavigation[];
public readonly children?: GuidedNavigationObject[];

/** References an image or a fragment of it. */
public readonly imgref?: string;
Expand All @@ -32,7 +72,7 @@ export class GuidedNavigation {
*/
constructor(values: {
audioref?: string;
children?: GuidedNavigation[];
children?: GuidedNavigationObject[];
imgref?: string;
role?: Set<string>;
text?: string;
Expand All @@ -47,15 +87,15 @@ export class GuidedNavigation {
}

/**
* Parses a [GuidedNavigation] from its RWPM JSON representation.
* Parses a [GuidedNavigationObject] from its RWPM JSON representation.
*
* A GuidedNavigation object can be parsed from a single string, or a full-fledged object.
* A GuidedNavigationObject can be parsed from a single string, or a full-fledged object.
*/
public static deserialize(json: any): GuidedNavigation | undefined {
public static deserialize(json: any): GuidedNavigationObject | undefined {
if (!json) return;
return new GuidedNavigation({
return new GuidedNavigationObject({
audioref: json.audioref,
children: GuidedNavigation.deserializeArray(json.children),
children: GuidedNavigationObject.deserializeArray(json.children),
imgref: json.imgref,
role: json.role
? new Set<string>(arrayfromJSONorString(json.role))
Expand All @@ -65,8 +105,18 @@ export class GuidedNavigation {
});
}

/**
* Parses a [GuidedNavigationObject] array from its RWPM JSON representation.
*/
public static deserializeArray(json: any): GuidedNavigationObject[] | undefined {
if (!(json instanceof Array)) return;
return json
.map<GuidedNavigationObject>((item) => GuidedNavigationObject.deserialize(item) as GuidedNavigationObject)
.filter((x) => x !== undefined);
}

/**
* Serializes a [GuidedNavigation] to its RWPM JSON representation.
* Serializes a [GuidedNavigationObject] to its RWPM JSON representation.
*/
public serialize(): any {
const json: any = {};
Expand All @@ -78,4 +128,49 @@ export class GuidedNavigation {
if (this.textref !== undefined) json.textref = this.textref;
return json;
}

public get audioFile(): string | undefined {
return this.audioref?.split('#')[0];
}

public get audioTime(): string | undefined {
if(this.audioref?.includes('#')) {
return this.audioref.split('#', 2)[1];
}
return undefined;
}

public get textFile(): string | undefined {
return this.textref?.split('#')[0];
}

public get fragmentId(): string | undefined {
if(this.textref?.includes('#')) {
return this.textref.split('#', 2)[1];
}
return undefined;
}

public get clip(): Clip | undefined {
const audio = this.audioFile;
if(!audio) return undefined;
const time = this.audioTime;
const result = {
audioResource: audio,
fragmentId: this.fragmentId,
} as Clip;
if(!time) return result;
const times = this.parseTimer(time);
result.start = times[0];
result.end = times[1];
return result;
}

private parseTimer(times: string): [number?, number?] {
if(!times || !times.startsWith("t=")) return [undefined, undefined];
const ts = times.substring(2).split(',').map(t => parseInt(t));
if(ts.length === 1) return [isNaN(ts[0]) ? undefined : ts[0], undefined];
if(ts.length > 2) return [undefined, undefined];
return [isNaN(ts[0]) ? undefined : ts[0], isNaN(ts[1]) ? undefined : ts[1]];
}
}
6 changes: 3 additions & 3 deletions shared/src/publication/Publication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Metadata } from './Metadata';
import { EmptyFetcher, Fetcher } from '../fetcher/Fetcher';
import { PublicationCollection } from './PublicationCollection';
import { Resource } from '../fetcher/Resource';
import { GuidedNavigation } from "./GuidedNavigation";
import { GuidedNavigationDocument } from "./GuidedNavigation";
import { URITemplate } from "../util";

export type ServiceFactory = () => null;
Expand Down Expand Up @@ -93,7 +93,7 @@ export class Publication {
.filter(l => l !== undefined) as Locator[]; // Filter out failures
}

public async guideForLink(link: Link): Promise<GuidedNavigation | undefined> {
public async guideForLink(link: Link): Promise<GuidedNavigationDocument | undefined> {
const findGNLink = (l: Link): Link | undefined => l.alternates?.findWithMediaType(
'application/guided-navigation+json'
);
Expand Down Expand Up @@ -135,7 +135,7 @@ export class Publication {
const guidedNavigationJSON = (await this.get(new Link({
href,
})).readAsJSON());
return GuidedNavigation.deserialize(guidedNavigationJSON);
return GuidedNavigationDocument.deserialize(guidedNavigationJSON);
}

/**
Expand Down
1 change: 1 addition & 0 deletions shared/src/publication/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export * from './Publication';
export * from './PublicationCollection';
export * from './ReadingProgression';
export * from './Subject';
export * from './GuidedNavigation';

0 comments on commit e76b6ce

Please sign in to comment.