diff --git a/.eslint.cjs b/.eslint.cjs new file mode 100644 index 0000000..db46b2e --- /dev/null +++ b/.eslint.cjs @@ -0,0 +1,73 @@ +const { defineConfig, globalIgnores } = require('eslint/config'); + +const tsParser = require('@typescript-eslint/parser'); +const typescriptEslint = require('@typescript-eslint/eslint-plugin'); +const parser = require('svelte-eslint-parser'); +const globals = require('globals'); +const js = require('@eslint/js'); + +const { FlatCompat } = require('@eslint/eslintrc'); + +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +module.exports = defineConfig([ + { + languageOptions: { + parser: tsParser, + sourceType: 'module', + ecmaVersion: 2020, + + parserOptions: { + extraFileExtensions: ['.svelte'] + }, + + globals: { + ...globals.browser, + ...globals.node + } + }, + + extends: compat.extends( + 'plugin:svelte/recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier' + ), + + plugins: { + '@typescript-eslint': typescriptEslint + }, + + settings: { + 'svelte3/typescript': () => require('typescript') + } + }, + globalIgnores(['**/*.cjs']), + { + files: ['**/*.svelte'], + + languageOptions: { + parser: parser, + + parserOptions: { + parser: '@typescript-eslint/parser' + } + } + }, + globalIgnores([ + '**/.DS_Store', + '**/node_modules', + 'build', + '.svelte-kit', + 'package', + '**/.env', + '**/.env.*', + '!**/.env.example', + '**/pnpm-lock.yaml', + '**/package-lock.json', + '**/yarn.lock' + ]) +]); diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 914e81c..0000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = { - root: true, - parser: '@typescript-eslint/parser', - extends: ['plugin:svelte/recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], - plugins: ['@typescript-eslint'], - ignorePatterns: ['*.cjs'], - overrides: [ - { - files: ['*.svelte'], - parser: 'svelte-eslint-parser', - parserOptions: { - parser: '@typescript-eslint/parser' - } - } - ], - settings: { - 'svelte3/typescript': () => require('typescript') - }, - parserOptions: { - sourceType: 'module', - ecmaVersion: 2020, - extraFileExtensions: ['.svelte'] - }, - env: { - browser: true, - es2017: true, - node: true - } -}; diff --git a/.prettierrc b/.prettierrc index 4146a05..1b2ae3a 100644 --- a/.prettierrc +++ b/.prettierrc @@ -5,6 +5,5 @@ "trailingComma": "none", "printWidth": 100, "plugins": ["prettier-plugin-svelte"], - "pluginSearchDirs": ["."], "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] } diff --git a/package-lock.json b/package-lock.json index a03f42c..d66b12e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "moshing-mammut", - "version": "1.4.0", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "moshing-mammut", - "version": "1.4.0", + "version": "2.0.0", "license": "LGPL-3.0-or-later", "dependencies": { "dotenv": "^17.0.0", @@ -16,6 +16,8 @@ "ws": "^8.18.0" }, "devDependencies": { + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.30.1", "@sveltejs/adapter-node": "^5.2.12", "@sveltejs/kit": "^2.22.2", "@sveltejs/vite-plugin-svelte": "^5.1.0", @@ -28,6 +30,7 @@ "eslint": "^9.11.1", "eslint-config-prettier": "^10.0.0", "eslint-plugin-svelte": "^3.0.0", + "globals": "^16.3.0", "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.2.6", "svelte": "^5", @@ -615,6 +618,19 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -639,9 +655,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.30.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.0.tgz", - "integrity": "sha512-Wzw3wQwPvc9sHM+NjakWTcPx11mbZyiYHuwWa/QfZ7cIRX7WK54PSk7bdyXDaoaopUcMatv1zaQvOAAO8hCdww==", + "version": "9.30.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz", + "integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==", "dev": true, "license": "MIT", "engines": { @@ -2824,19 +2840,6 @@ } } }, - "node_modules/eslint-plugin-svelte/node_modules/globals": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", - "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -2867,6 +2870,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "9.30.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.0.tgz", + "integrity": "sha512-Wzw3wQwPvc9sHM+NjakWTcPx11mbZyiYHuwWa/QfZ7cIRX7WK54PSk7bdyXDaoaopUcMatv1zaQvOAAO8hCdww==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -3320,9 +3336,9 @@ } }, "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", + "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 1d446c0..0f8e49f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "moshing-mammut", - "version": "2.0.0", + "version": "2.0.1", "private": true, "license": "LGPL-3.0-or-later", "scripts": { @@ -14,6 +14,8 @@ "format": "prettier --plugin-search-dir . --write ." }, "devDependencies": { + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.30.1", "@sveltejs/adapter-node": "^5.2.12", "@sveltejs/kit": "^2.22.2", "@sveltejs/vite-plugin-svelte": "^5.1.0", @@ -26,6 +28,7 @@ "eslint": "^9.11.1", "eslint-config-prettier": "^10.0.0", "eslint-plugin-svelte": "^3.0.0", + "globals": "^16.3.0", "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.2.6", "svelte": "^5", diff --git a/src/lib/log.ts b/src/lib/log.ts index db34ee7..d552d5e 100644 --- a/src/lib/log.ts +++ b/src/lib/log.ts @@ -41,7 +41,7 @@ export class Logger { public constructor(private name: string) {} public static isDebugEnabled(): boolean { - return DEV; + return DEV || enableVerboseLog; } public verbose(...params: any[]) { if (!enableVerboseLog) { @@ -50,7 +50,7 @@ export class Logger { console.debug(new Date().toISOString(), `- ${this.name} -`, ...params); } public debug(...params: any[]) { - if (!Logger.isDebugEnabled()) { + if (false && !Logger.isDebugEnabled()) { return; } console.debug(new Date().toISOString(), `- ${this.name} -`, ...params); diff --git a/src/lib/server/db.ts b/src/lib/server/db.ts index 430837c..7dc7108 100644 --- a/src/lib/server/db.ts +++ b/src/lib/server/db.ts @@ -126,7 +126,7 @@ async function applyMigration(migration: Migration) { `Fetching songs for existing post ${current.toString().padStart(4, '0')} of ${total}`, post.url ); - const songs = await TimelineReader.getSongInfoInPost(post); + const songs = await TimelineReader.instance.getSongInfoInPost(post); await saveSongInfoData(post.url, songs); logger.debug(`Fetched ${songs.length} songs for existing post`, post.url); } diff --git a/src/lib/server/playlist/oauthPlaylistAdder.ts b/src/lib/server/playlist/oauthPlaylistAdder.ts index 3e1bbfe..ffc9b1f 100644 --- a/src/lib/server/playlist/oauthPlaylistAdder.ts +++ b/src/lib/server/playlist/oauthPlaylistAdder.ts @@ -14,9 +14,8 @@ export abstract class OauthPlaylistAdder { public async authCodeExists(): Promise { try { - const fileHandle = await fs.open(this.token_file_name); - await fileHandle.close(); - return true; + const token = await this.auth(); + return token !== null && !token.error; } catch { this.logger.info('No auth token yet, authorizing...'); return false; @@ -45,7 +44,7 @@ export abstract class OauthPlaylistAdder { tokenUrl: URL, clientId: string, code: string, - url: URL, + redirectUri: URL, client_secret?: string, customHeader?: HeadersInit ) { @@ -54,7 +53,7 @@ export abstract class OauthPlaylistAdder { params.append('client_id', clientId); params.append('code', code); params.append('grant_type', 'authorization_code'); - params.append('redirect_uri', `${url.origin}${url.pathname}`); + params.append('redirect_uri', redirectUri.toString()); if (client_secret) { params.append('client_secret', client_secret); } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index effb47a..1ca468a 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -100,7 +100,7 @@ }); } - onMount(async () => { + onMount(() => { posts = data.posts; if (posts.length > 0) { oldestBeforeLastFetch = new Date(posts[posts.length - 1].created_at).getTime(); diff --git a/src/routes/spotifyAuth/+page.server.ts b/src/routes/spotifyAuth/+page.server.ts index fafe286..db5630f 100644 --- a/src/routes/spotifyAuth/+page.server.ts +++ b/src/routes/spotifyAuth/+page.server.ts @@ -1,19 +1,21 @@ +import { BASE_URL } from '$env/static/private'; import { Logger } from '$lib/log'; import { SpotifyPlaylistAdder } from '$lib/server/playlist/spotifyPlaylistAdder'; import { redirect } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; +const { DEV } = import.meta.env; const logger = new Logger('SpotifyAuth'); export const load: PageServerLoad = async ({ url }) => { const adder = new SpotifyPlaylistAdder(); - let redirectUri = url; - if (url.hostname === 'localhost') { - redirectUri.hostname = '127.0.0.1'; + let redirect_uri = new URL(`${BASE_URL}/spotifyAuth`); + if (url.hostname === 'localhost' && DEV) { + redirect_uri.hostname = '127.0.0.1'; } logger.debug(url.searchParams, url.hostname); if (url.searchParams.has('code')) { - await adder.receivedAuthCode(url.searchParams.get('code') || '', url); + await adder.receivedAuthCode(url.searchParams.get('code') || '', redirect_uri); redirect(307, '/'); } else if (url.searchParams.has('error')) { logger.error('received error', url.searchParams.get('error')); @@ -24,7 +26,7 @@ export const load: PageServerLoad = async ({ url }) => { redirect(307, '/'); } - const authUrl = adder.constructAuthUrl(url); + const authUrl = adder.constructAuthUrl(redirect_uri); logger.debug('+page.server.ts', authUrl.toString()); redirect(307, authUrl); }; diff --git a/src/routes/ytauth/+page.server.ts b/src/routes/ytauth/+page.server.ts index e8167bf..db72690 100644 --- a/src/routes/ytauth/+page.server.ts +++ b/src/routes/ytauth/+page.server.ts @@ -1,3 +1,4 @@ +import { BASE_URL } from '$env/static/private'; import { Logger } from '$lib/log'; import { YoutubePlaylistAdder } from '$lib/server/playlist/ytPlaylistAdder'; import { redirect } from '@sveltejs/kit'; @@ -7,9 +8,10 @@ const logger = new Logger('YT Auth'); export const load: PageServerLoad = async ({ url }) => { const adder = new YoutubePlaylistAdder(); + const redirect_uri = new URL(`${BASE_URL}/ytauth`); if (url.searchParams.has('code')) { logger.debug(url.searchParams); - await adder.receivedAuthCode(url.searchParams.get('code') || '', url); + await adder.receivedAuthCode(url.searchParams.get('code') || '', redirect_uri); redirect(307, '/'); } else if (url.searchParams.has('error')) { logger.error('received error', url.searchParams.get('error')); @@ -19,8 +21,7 @@ export const load: PageServerLoad = async ({ url }) => { if (await adder.authCodeExists()) { redirect(307, '/'); } - - const authUrl = adder.constructAuthUrl(url); + const authUrl = adder.constructAuthUrl(redirect_uri); logger.debug('+page.server.ts', authUrl.toString()); redirect(307, authUrl); };