Skip to content

Commit

Permalink
Expanded import/export to cover playlists and deleted media
Browse files Browse the repository at this point in the history
  • Loading branch information
SimplyBoo6 committed Jan 11, 2024
1 parent 0b5f5ba commit 08e7155
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 10 deletions.
5 changes: 5 additions & 0 deletions common/src/media.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,8 @@ export interface MediaResolution {
export interface Media extends BaseMedia {
absolutePath: string;
}

export interface DeletedMedia {
hash: string;
path: string;
}
30 changes: 27 additions & 3 deletions server/src/database/mongodb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Path from 'path';
import {
BaseMedia,
Configuration,
DeletedMedia,
Media,
MediaPlaylist,
Playlist,
Expand Down Expand Up @@ -54,11 +55,15 @@ export class MongoConnector extends Database {
if (!config) {
throw new Error('database config missing');
}
if (config.provider !== 'mongodb') {
throw new Error('Missing mongo config');
}
const mongoConfig = config;

// eslint-disable-next-line no-constant-condition
while (true) {
try {
return await MongoClient.connect(config.uri, {
return await MongoClient.connect(mongoConfig.uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
Expand All @@ -74,7 +79,16 @@ export class MongoConnector extends Database {
private constructor(server: MongoClient) {
super();
this.server = server;
const dbName = Config.get().database?.db;

const config = Config.get().database;
if (!config) {
throw new Error('database config missing');
}
if (config.provider !== 'mongodb') {
throw new Error('Missing mongo config');
}
const mongoConfig = config;
const dbName = mongoConfig.db;
if (!dbName) {
throw new Error('missing database config');
}
Expand Down Expand Up @@ -603,17 +617,27 @@ export class MongoConnector extends Database {
}

if (media && ignoreInImport) {
await this.db.collection<BaseMedia>('media.deleted').update({ hash: media.hash }, media, { upsert: true });
await this.addDeleted(media);
}
await mediaCollection.deleteOne({ hash });
}

public async addDeleted(deleted: DeletedMedia): Promise<void> {
await this.db.collection<BaseMedia>('media.deleted').update({ hash: deleted.hash }, deleted, { upsert: true });
}

public async isDeletedPath(path: string): Promise<boolean> {
const media = this.db.collection<BaseMedia>('media.deleted');
const result = await media.findOne({ path });
return Boolean(result);
}

public async getDeletedMedia(): Promise<DeletedMedia[]> {
const media = this.db.collection<BaseMedia>('media.deleted');
const result = await media.find({}).toArray();
return result.map((res) => ({ hash: res.hash, path: res.path }));
}

public async addMediaTag(hash: string, tag: string): Promise<void> {
await this.db.collection<BaseMedia>('media').updateOne({ hash }, { $addToSet: { tags: tag } });
}
Expand Down
3 changes: 3 additions & 0 deletions server/src/types/database.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {
BaseMedia,
Configuration,
DeletedMedia,
Media,
MediaPlaylist,
Playlist,
Expand All @@ -19,6 +20,8 @@ export abstract class Database {
public abstract saveBulkMedia(constraints: SubsetConstraints, media: UpdateMedia): Promise<number>;
public abstract removeMedia(hash: string, ignoreInImport: boolean): Promise<void>;
public abstract isDeletedPath(path: string): Promise<boolean>;
public abstract getDeletedMedia(): Promise<DeletedMedia[]>;
public abstract addDeleted(deleted: DeletedMedia): Promise<void>;
// Media - tags
public abstract addMediaTag(hash: string, tag: string): Promise<void>;
public abstract removeMediaTag(hash: string, tag: string): Promise<void>;
Expand Down
8 changes: 7 additions & 1 deletion server/src/types/dump.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { BaseMedia, Configuration } from '@vimtur/common';
import { BaseMedia, Configuration, DeletedMedia, Playlist } from '@vimtur/common';

export interface DumpPlaylist extends Playlist {
hashes: string[];
}

export interface DumpFile {
tags: string[];
actors: string[];
media: BaseMedia[];
config?: Configuration.Partial;
deleted?: DeletedMedia[];
version?: number;
playlists?: DumpPlaylist[];
}
2 changes: 1 addition & 1 deletion server/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { Database } from './database';
export type { DumpFile } from './dump';
export type { DumpFile, DumpPlaylist } from './dump';
export type { TaskRunnerCallback, TaskRunner, Task, RouterTask } from './task';
export type { DownloaderCallback, DownloaderRunner, Downloader } from './downloader';
14 changes: 13 additions & 1 deletion server/src/utils/export-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Util from 'util';

import Config from '../config';
import { setup as setupDb } from '../database';
import type { DumpFile } from '../types';
import type { DumpFile, DumpPlaylist } from '../types';

async function main(): Promise<void> {
const file = process.argv[2];
Expand All @@ -20,13 +20,25 @@ async function main(): Promise<void> {
const userConfigOverlay = await db.getUserConfig();
Config.setUserOverlay(userConfigOverlay);

const outputPlaylists: DumpPlaylist[] = [];
const output: DumpFile = {
tags: await db.getTags(),
media: [],
actors: await db.getActors(),
config: userConfigOverlay,
playlists: outputPlaylists,
deleted: await db.getDeletedMedia(),
version: 4,
};

const playlists = await db.getPlaylists();
for (const playlist of playlists) {
outputPlaylists.push({
...playlist,
hashes: await db.subset({ playlist: playlist.id, sortBy: 'order' }),
});
}

// Save tags
const map = await db.subset({});
for (const hash of map) {
Expand Down
21 changes: 17 additions & 4 deletions server/src/utils/import-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Config from '../config';
import { setup as setupDb } from '../database';
import type { Database, DumpFile } from '../types';

// TODO This must also cover playlists and deleted media.
async function importMedia(db: Database, media: BaseMedia, version?: number): Promise<void> {
if (!media.hash) {
throw new Error('Missing hash');
Expand Down Expand Up @@ -142,6 +143,10 @@ async function main(): Promise<void> {

console.log('Adding all to database. This can take some time.');
const start = new Date();
console.log('Adding config...');
if (imported.config && Object.keys(imported.config).length) {
await db.saveUserConfig(imported.config);
}
console.log('Adding tags...');
for (const tag of imported.tags) {
await db.addTag(tag);
Expand All @@ -150,10 +155,6 @@ async function main(): Promise<void> {
for (const actor of imported.actors) {
await db.addActor(actor);
}
console.log('Adding config...');
if (imported.config && Object.keys(imported.config).length) {
await db.saveUserConfig(imported.config);
}
console.log('Adding media...');
let progress = 0;
for (let i = 0; i < imported.media.length; i++) {
Expand All @@ -175,6 +176,18 @@ async function main(): Promise<void> {
);
}
}

console.log('Adding deleted media...');
for (const deleted of imported.deleted || []) {
await db.addDeleted(deleted);
}

console.log('Adding playlists...');
for (const playlist of imported.playlists || []) {
// Note this discards the ID.
await db.addPlaylist(playlist);
}

console.log('Import complete');

await db.close();
Expand Down

0 comments on commit 08e7155

Please sign in to comment.