Skip to content

Commit

Permalink
Merge branch 'dev' into feature/profile_editing
Browse files Browse the repository at this point in the history
  • Loading branch information
undyingwraith committed Jun 26, 2024
2 parents 36bab75 + 2bdc70c commit 72873e2
Show file tree
Hide file tree
Showing 43 changed files with 1,309 additions and 1,269 deletions.
894 changes: 0 additions & 894 deletions .yarn/releases/yarn-4.2.1.cjs

This file was deleted.

894 changes: 894 additions & 0 deletions .yarn/releases/yarn-4.3.1.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ packageExtensions:
dependencies:
undici: "*"

yarnPath: .yarn/releases/yarn-4.2.1.cjs
yarnPath: .yarn/releases/yarn-4.3.1.cjs
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"license": "MIT",
"private": true,
"type": "module",
"packageManager": "yarn@4.2.1",
"packageManager": "yarn@4.3.1",
"scripts": {
"watch": "yarn workspaces foreach -Api run watch",
"build": "yarn workspaces foreach -At run build",
Expand Down
7 changes: 6 additions & 1 deletion packages/core/src/Modules/CoreModule.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { IKeyValueStoreSymbol, IObjectStoreSymbol } from 'ipmc-interfaces';
import { IIndexManagerSymbol, IKeyValueStoreSymbol, IObjectStoreSymbol } from 'ipmc-interfaces';
import { MemoryKeyValueStore } from '../Services/MemoryKeyValueStore';
import { ObjectStore } from '../Services/ObjectStore';
import { IModule } from './IModule';
import { IndexManager } from '../Services/IndexManager';
import { TaskManager } from '../Services/TaskManager';
import { ITaskManagerSymbol } from 'ipmc-interfaces';

export const CoreModule: IModule = (app) => {
app.register(MemoryKeyValueStore, IKeyValueStoreSymbol);
app.register(ObjectStore, IObjectStoreSymbol);
app.register(IndexManager, IIndexManagerSymbol);
app.register(TaskManager, ITaskManagerSymbol);
};
93 changes: 93 additions & 0 deletions packages/core/src/Services/IndexManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Signal } from '@preact/signals-core';
import { inject, injectable, postConstruct, preDestroy } from 'inversify';
import { IIndexManager, IIpfsService, IIpfsServiceSymbol, ILibrary, ILibraryIndex, IObjectStore, IObjectStoreSymbol, IProfile, IProfileSymbol, ITask, isMovieLibrary, isSeriesLibrary } from 'ipmc-interfaces';
import { MovieIndexFetcher, SeriesIndexFetcher } from './Indexer';
import { ITaskManager, ITaskManagerSymbol } from 'ipmc-interfaces';

@injectable()
export class IndexManager implements IIndexManager {
public constructor(
@inject(IProfileSymbol) private readonly profile: IProfile,
@inject(IIpfsServiceSymbol) private readonly ipfs: IIpfsService,
@inject(IObjectStoreSymbol) private readonly objectStore: IObjectStore,
@inject(ITaskManagerSymbol) private readonly taskManager: ITaskManager
) {
for (const lib of this.profile.libraries) {
this.libraries.set(lib.name, new Signal<ILibrary>(lib));
const indexSignal = new Signal<ILibraryIndex<any> | undefined>(this.objectStore.get(this.getIndexStorageKey(lib.name)));
this.indexes.set(lib.name, indexSignal);
indexSignal.subscribe((newState) => {
if (newState !== undefined) {
this.objectStore.set(this.getIndexStorageKey(lib.name), newState);
}
});
}
}

@postConstruct()
public start(): void {
this.triggerUpdate();
this.timer = setInterval(() => {
this.triggerUpdate();
}, 15 * 60 * 1000);
}

@preDestroy()
public stop(): void {
clearInterval(this.timer);
}

public indexes = new Map<string, Signal<ILibraryIndex<any> | undefined>>();

public tasks = new Signal<ITask[]>([]);

private getIndexStorageKey(name: string) {
return `${this.profile.id}_index_${name}`;
}

private triggerUpdate(): void {
for (const library of this.libraries.values()) {
const lib = library.value;
if (!this.updates.has(lib.name)) {
this.taskManager.runTask({
task: () => this.updateLibrary(lib),
title: '',
onEnd: () => {
this.updates.delete(lib.name);
},
});
}
}
}

private async updateLibrary(library: ILibrary): Promise<void> {
const index = this.indexes.get(library.name);
if (library.upstream != undefined && index != undefined) {
try {
const cid = await this.ipfs.resolve(library.upstream);
const indexer = isMovieLibrary(library) ? new MovieIndexFetcher(this.ipfs) : isSeriesLibrary(library) ? new SeriesIndexFetcher(this.ipfs) : undefined;
if (index.value?.cid != cid || indexer?.version !== index.value.indexer) {
if (indexer == undefined) {
throw new Error(`Unknown library type [${library.type}]`);
}

const newIndex = await indexer.fetchIndex(cid);

index.value = {
cid: cid,
indexer: indexer.version,
index: newIndex,
};
}
} catch (ex) {
console.error(ex);
}
}
}

private libraries = new Map<string, Signal<ILibrary>>();

private updates = new Map<string, Promise<void>>();

private timer: any;
}
3 changes: 2 additions & 1 deletion packages/core/src/Services/Indexer/IIndexFetcher.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export interface IIndexFetcher<TIndex> {
fetchIndex(): Promise<TIndex>;
fetchIndex(cid: string): Promise<TIndex>;
version: string;
}
12 changes: 7 additions & 5 deletions packages/core/src/Services/Indexer/MovieIndexFetcher.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { IIpfsService, IGenericLibrary, IMovieMetaData, IFileInfo } from 'ipmc-interfaces';
import { IIndexFetcher } from './IIndexFetcher';
import { IFileInfo, IIpfsService, IMovieMetaData } from 'ipmc-interfaces';
import { Regexes } from '../../Regexes';
import { IIndexFetcher } from './IIndexFetcher';

export class MovieIndexFetcher implements IIndexFetcher<IMovieMetaData[]> {
constructor(private readonly node: IIpfsService, private readonly lib: IGenericLibrary<IMovieMetaData, 'movie'>) {
constructor(private readonly node: IIpfsService) {
}

public async fetchIndex(): Promise<IMovieMetaData[]> {
const files = (await this.node.ls(this.lib.root.toString())).filter(f => f.type == 'dir');
public version = '0';

public async fetchIndex(cid: string): Promise<IMovieMetaData[]> {
const files = (await this.node.ls(cid)).filter(f => f.type == 'dir');
const index = [];
for (const file of files) {
index.push(await this.extractMovieMetaData(this.node, file));
Expand Down
45 changes: 33 additions & 12 deletions packages/core/src/Services/Indexer/SeriesIndexFetcher.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { IIpfsService, IEpisodeMetaData, IGenericLibrary, ISeasonMetaData, ISeriesMetaData, IFileInfo } from 'ipmc-interfaces';
import { IIndexFetcher } from './IIndexFetcher';
import { IEpisodeMetaData, IFileInfo, IIpfsService, ISeasonMetaData, ISeriesMetaData } from 'ipmc-interfaces';
import { Regexes } from '../../Regexes';
import { IIndexFetcher } from './IIndexFetcher';

export class SeriesIndexFetcher implements IIndexFetcher<ISeriesMetaData[]> {
constructor(private readonly node: IIpfsService, private readonly lib: IGenericLibrary<ISeriesMetaData, 'series'>) {
constructor(private readonly node: IIpfsService) {
}

public async fetchIndex(): Promise<ISeriesMetaData[]> {
const files = (await this.node.ls(this.lib.root.toString())).filter(f => f.type == 'dir');
public version = '0';

public async fetchIndex(cid: string): Promise<ISeriesMetaData[]> {
const files = (await this.node.ls(cid)).filter(f => f.type == 'dir');
const index = [];
for (const file of files) {
index.push(await this.extractSeriesMetaData(this.node, file));
Expand All @@ -21,34 +23,53 @@ export class SeriesIndexFetcher implements IIndexFetcher<ISeriesMetaData[]> {
const files = entries.filter(f => f.type == 'file');
const folders = entries.filter(f => f.type !== 'file');

return {
const serie: Omit<ISeriesMetaData, 'items'> = {
...entry,
title: entry.name,
posters: files.filter(f => Regexes.Poster.exec(f.name) != null),
items: await Promise.all(folders.map(season => this.extractSeasonMetaData(node, season))),
};

return {
...serie,
items: await Promise.all(folders.map(season => this.extractSeasonMetaData(node, season, serie))),
};
}

public async extractSeasonMetaData(node: IIpfsService, entry: IFileInfo, skeleton?: any): Promise<ISeasonMetaData> {
public async extractSeasonMetaData(node: IIpfsService, entry: IFileInfo, parent: Omit<ISeriesMetaData, 'items'>): Promise<ISeasonMetaData> {
const entries = await this.node.ls(entry.cid);
const files = entries.filter(f => f.type == 'file');
const folders = entries.filter(f => f.type !== 'file');

return {
const season: Omit<ISeasonMetaData, 'items'> = {
...entry,
posters: files.filter(f => Regexes.Poster.exec(f.name) != null),
items: await Promise.all(folders.map(episode => this.extractEpisodeMetaData(node, episode))),
};

if (season.posters.length == 0) {
season.posters = parent.posters;
}

return {
...season,
items: await Promise.all(folders.map(episode => this.extractEpisodeMetaData(node, episode, season))),
};
}

public async extractEpisodeMetaData(node: IIpfsService, entry: IFileInfo, skeleton?: any): Promise<IEpisodeMetaData> {
public async extractEpisodeMetaData(node: IIpfsService, entry: IFileInfo, parent: Omit<ISeasonMetaData, 'items'>): Promise<IEpisodeMetaData> {
const files = (await this.node.ls(entry.cid)).filter(f => f.type == 'file');

return {
const episode = {
...entry,
posters: files.filter(f => Regexes.Poster.exec(f.name) != null),
title: entry.name,
video: files.filter(f => f.name.endsWith('.mp4'))[0],
thumbnails: files.filter(f => Regexes.Thumbnail.exec(f.name) != null),
};

if (episode.posters.length == 0) {
episode.posters = parent.posters;
}

return episode;
}
}
1 change: 1 addition & 0 deletions packages/core/src/Services/Indexer/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { type IIndexFetcher } from './IIndexFetcher';
export { MovieIndexFetcher } from './MovieIndexFetcher';
export { SeriesIndexFetcher } from './SeriesIndexFetcher';
103 changes: 0 additions & 103 deletions packages/core/src/Services/ProfileManager/BaseProfileManager.ts

This file was deleted.

Loading

0 comments on commit 72873e2

Please sign in to comment.