Added & configured typeorm for storing settings

This commit is contained in:
Aleksi Lassila
2023-08-17 02:57:10 +03:00
parent 4d84337f7d
commit dfa8228d9d
15 changed files with 1563 additions and 102 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@ node_modules
.output
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
/config/*.sqlite

0
config/.gitkeep Normal file
View File

1411
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -53,6 +53,9 @@
"hls.js": "^1.4.6",
"openapi-fetch": "^0.2.1",
"radix-icons-svelte": "^1.2.1",
"tailwind-scrollbar-hide": "^1.1.7"
"reflect-metadata": "^0.1.13",
"sqlite3": "^5.1.6",
"tailwind-scrollbar-hide": "^1.1.7",
"typeorm": "^0.3.17"
}
}

4
src/hooks.server.ts Normal file
View File

@@ -0,0 +1,4 @@
import TypeOrm from '$lib/db';
import 'reflect-metadata';
await TypeOrm.getDb();

View File

@@ -52,13 +52,15 @@
trailerVisible = false;
UIVisible = true;
timeout = setTimeout(() => {
trailerMounted = true;
if ($settings.autoplayTrailers) {
timeout = setTimeout(() => {
trailerVisible = true;
}, TRAILER_LOAD_TIME);
}, TRAILER_TIMEOUT - TRAILER_LOAD_TIME);
trailerMounted = true; // Mount the trailer
timeout = setTimeout(() => {
trailerVisible = true;
}, TRAILER_LOAD_TIME);
}, TRAILER_TIMEOUT - TRAILER_LOAD_TIME);
}
}
onMount(() => {

35
src/lib/db.ts Normal file
View File

@@ -0,0 +1,35 @@
import 'reflect-metadata';
import { DataSource } from 'typeorm';
import { Settings } from './entities/Settings';
class TypeOrm {
private static instance: Promise<DataSource | null> | null = null;
private constructor() {
// Private constructor to prevent external instantiation
}
public static getDb(): Promise<DataSource | null> {
if (!TypeOrm.instance) {
TypeOrm.instance = new DataSource({
type: 'sqlite',
database: 'config/reiverr.sqlite',
synchronize: true,
entities: [Settings],
logging: true
})
.initialize()
.then((fulfilled) => {
console.info('Data Source has been initialized!');
return fulfilled;
})
.catch((err) => {
console.error('Error during Data Source initialization', err);
return null;
});
}
return TypeOrm.instance;
}
}
export default TypeOrm;

View File

@@ -0,0 +1,78 @@
import { BaseEntity, Column, Entity, PrimaryColumn } from 'typeorm';
@Entity({ name: 'settings' })
export class Settings extends BaseEntity {
@PrimaryColumn('text')
name: string;
@Column('boolean', { default: false })
isSetupDone: boolean;
// General
@Column('boolean', { default: true })
autoplayTrailers: boolean;
@Column('boolean', { default: true })
excludeLibraryItemsFromDiscovery: boolean;
@Column('text', { default: 'en' })
language: string;
@Column('text', { default: 'US' })
region: string;
@Column('integer', { default: 150 })
animationDuration: number;
// Discover
// @Column()
// discoverIncludedLanguages: string[];
@Column('boolean', { default: true })
discoverFilterBasedOnLanguage: boolean;
// Sonarr
@Column('integer', { default: 0 })
sonarrQualityProfileId: number;
@Column('integer', { default: 0 })
sonarrLanguageProfileId: number;
@Column('text', { default: '/tv' })
sonarrRootFolderPath: string;
// Radarr
@Column('integer', { default: 0 })
radarrQualityProfileId: number;
@Column('integer', { default: 0 })
radarrProfileId: number;
@Column('text', { default: '/movies' })
radarrRootFolderPath: string;
// Jellyfin
@Column('text', { default: '' })
jellyfinUserId: string;
// Playback
@Column('text', { default: 'reiverr' })
preferredPlaybackSource: 'reiverr' | 'jellyfin';
public static async get(name = 'default'): Promise<Settings> {
const settings = await this.findOne({ where: { name } });
if (!settings) {
const defaultSettings = new Settings();
defaultSettings.name = 'default';
await defaultSettings.save();
return defaultSettings;
}
return settings;
}
}

View File

@@ -1,15 +1,15 @@
import { get, writable } from 'svelte/store';
interface Settings {
export interface SettingsValues {
autoplayTrailers: boolean;
excludeLibraryItemsFromDiscovery: boolean;
language: string;
region: string;
animationDuration: number;
discover: {
includedLanguages: string[];
filterBasedOnLanguage: boolean;
};
animationDuration: number;
sonarr: {
qualityProfileId: number;
rootFolderPath: string;
@@ -28,16 +28,16 @@ interface Settings {
};
}
const defaultSettings: Settings = {
export const defaultSettings: SettingsValues = {
autoplayTrailers: true,
excludeLibraryItemsFromDiscovery: true,
language: 'en',
region: 'US',
animationDuration: 150,
discover: {
filterBasedOnLanguage: true,
includedLanguages: ['en']
},
animationDuration: 150,
sonarr: {
qualityProfileId: 4,
rootFolderPath: '/tv',
@@ -56,7 +56,7 @@ const defaultSettings: Settings = {
}
};
export const settings = writable<Settings>(defaultSettings);
export const settings = writable<SettingsValues>();
export const getIncludedLanguagesQuery = () => {
const settingsValue = get(settings);

View File

@@ -0,0 +1,44 @@
import {
JELLYFIN_API_KEY,
JELLYFIN_BASE_URL,
RADARR_API_KEY,
RADARR_BASE_URL,
SONARR_API_KEY,
SONARR_BASE_URL
} from '$lib/constants';
import { Settings } from '$lib/entities/Settings';
import type { LayoutServerLoad } from './$types';
export type MissingEnvironmentVariables = {
PUBLIC_RADARR_API_KEY: boolean;
PUBLIC_RADARR_BASE_URL: boolean;
PUBLIC_SONARR_API_KEY: boolean;
PUBLIC_SONARR_BASE_URL: boolean;
PUBLIC_JELLYFIN_API_KEY: boolean;
PUBLIC_JELLYFIN_URL: boolean;
};
export const load: LayoutServerLoad = async () => {
const settings = await Settings.get();
const isApplicationSetUp =
!!RADARR_API_KEY &&
!!RADARR_BASE_URL &&
!!SONARR_API_KEY &&
!!SONARR_BASE_URL &&
!!JELLYFIN_API_KEY &&
!!JELLYFIN_BASE_URL;
return {
settings: JSON.parse(JSON.stringify(settings)),
isApplicationSetUp,
missingEnvironmentVariables: {
PUBLIC_RADARR_API_KEY: !RADARR_API_KEY,
PUBLIC_RADARR_BASE_URL: !RADARR_BASE_URL,
PUBLIC_SONARR_API_KEY: !SONARR_API_KEY,
PUBLIC_SONARR_BASE_URL: !SONARR_BASE_URL,
PUBLIC_JELLYFIN_API_KEY: !JELLYFIN_API_KEY,
PUBLIC_JELLYFIN_URL: !JELLYFIN_BASE_URL
}
};
};

View File

@@ -1,12 +1,3 @@
import {
JELLYFIN_API_KEY,
JELLYFIN_BASE_URL,
RADARR_API_KEY,
RADARR_BASE_URL,
SONARR_API_KEY,
SONARR_BASE_URL
} from '$lib/constants';
import type { LayoutLoad } from './$types';
// import { dev } from '$app/environment';
// Disable SSR when running the dev server
@@ -14,34 +5,3 @@ import type { LayoutLoad } from './$types';
// https://github.com/vitejs/vite/issues/11468
// export const ssr = !dev;
export const ssr = false;
export type MissingEnvironmentVariables = {
PUBLIC_RADARR_API_KEY: boolean;
PUBLIC_RADARR_BASE_URL: boolean;
PUBLIC_SONARR_API_KEY: boolean;
PUBLIC_SONARR_BASE_URL: boolean;
PUBLIC_JELLYFIN_API_KEY: boolean;
PUBLIC_JELLYFIN_URL: boolean;
};
export const load = (async () => {
const isApplicationSetUp =
!!RADARR_API_KEY &&
!!RADARR_BASE_URL &&
!!SONARR_API_KEY &&
!!SONARR_BASE_URL &&
!!JELLYFIN_API_KEY &&
!!JELLYFIN_BASE_URL;
return {
isApplicationSetUp,
missingEnvironmentVariables: {
PUBLIC_RADARR_API_KEY: !RADARR_API_KEY,
PUBLIC_RADARR_BASE_URL: !RADARR_BASE_URL,
PUBLIC_SONARR_API_KEY: !SONARR_API_KEY,
PUBLIC_SONARR_BASE_URL: !SONARR_BASE_URL,
PUBLIC_JELLYFIN_API_KEY: !JELLYFIN_API_KEY,
PUBLIC_JELLYFIN_URL: !JELLYFIN_BASE_URL
}
};
}) satisfies LayoutLoad;

View File

@@ -5,7 +5,17 @@
import Poster from '$lib/components/Poster/Poster.svelte';
import TitleShowcase from '$lib/components/TitleShowcase/TitleShowcase.svelte';
import { library } from '$lib/stores/library.store';
import { defaultSettings, settings } from '$lib/stores/settings.store';
import type { ComponentProps } from 'svelte';
import type { LayoutServerData } from './$types';
export let data: LayoutServerData;
const settingsData = data.settings;
settings.set({
...defaultSettings,
autoplayTrailers: settingsData.autoplayTrailers
});
let continueWatchingVisible = true;

View File

@@ -0,0 +1,6 @@
import { Settings } from '$lib/entities/Settings';
import { json, type RequestHandler } from '@sveltejs/kit';
export const GET: RequestHandler = async ({ url }) => {
return json(await Settings.get());
};

View File

@@ -11,6 +11,10 @@
"strict": true,
"target": "ES2022",
"module": "ES2022",
"lib": ["es6"],
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//

View File

@@ -9,5 +9,8 @@ export default defineConfig({
// },
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
},
ssr: {
external: ['reflect-metadata']
}
});