prepare for being available on multiple domain names
This commit is contained in:
@ -3,16 +3,32 @@ import { TimelineReader } from '$lib/server/timeline';
|
||||
import type { Handle, HandleServerError } from '@sveltejs/kit';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import fs from 'fs/promises';
|
||||
import { close } from '$lib/server/db';
|
||||
|
||||
const logger = new Logger('App');
|
||||
|
||||
logger.log('App startup');
|
||||
if (process?.pid) {
|
||||
try {
|
||||
await fs.writeFile('moshing-mammut.pid', process.pid.toString());
|
||||
} catch (e) {
|
||||
logger.error('Could not write PID to file', e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.log('App startup, PID', process?.pid);
|
||||
|
||||
logger.log('Debug log enabled', Logger.isDebugEnabled());
|
||||
TimelineReader.init();
|
||||
|
||||
export const handleError = (({ error }) => {
|
||||
if (error instanceof Error) {
|
||||
logger.error('Something went wrong: ', error.name, error.message);
|
||||
process.on('sveltekit:shutdown', (reason) => {
|
||||
close();
|
||||
logger.log('Shutting down', reason);
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
export const handleError = (({ error, status }) => {
|
||||
if (error instanceof Error && status !== 404) {
|
||||
logger.error('Something went wrong:', error.name, error.message);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -48,25 +48,25 @@ export class Logger {
|
||||
if (!enableVerboseLog) {
|
||||
return;
|
||||
}
|
||||
console.debug(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.debug(new Date().toISOString(), `- ${this.name} -`, '- [VRBSE] -', ...params);
|
||||
}
|
||||
public debug(...params: any[]) {
|
||||
if (!Logger.isDebugEnabled()) {
|
||||
return;
|
||||
}
|
||||
console.debug(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.debug(new Date().toISOString(), `- ${this.name} -`, '- [DEBUG] -', ...params);
|
||||
}
|
||||
public log(...params: any[]) {
|
||||
console.log(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.log(new Date().toISOString(), `- ${this.name} -`, '- [ LOG ] -', ...params);
|
||||
}
|
||||
public info(...params: any[]) {
|
||||
console.info(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.info(new Date().toISOString(), `- ${this.name} -`, '- [INFO ] -', ...params);
|
||||
}
|
||||
public warn(...params: any[]) {
|
||||
console.warn(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.warn(new Date().toISOString(), `- ${this.name} -`, '- [WARN ] -', ...params);
|
||||
}
|
||||
public error(...params: any[]) {
|
||||
console.error(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.error(new Date().toISOString(), `- ${this.name} -`, '- [ERROR] -', ...params);
|
||||
}
|
||||
|
||||
public static error(...params: any[]) {
|
||||
|
@ -68,6 +68,15 @@ type Migration = {
|
||||
};
|
||||
|
||||
const db: sqlite3.Database = new sqlite3.Database('moshingmammut.db');
|
||||
|
||||
export function close() {
|
||||
try {
|
||||
db.close();
|
||||
} catch (e) {
|
||||
logger.error('Could not close DB');
|
||||
}
|
||||
}
|
||||
|
||||
// for the local masto instance, the instance name is *not* saved
|
||||
// as part of the username or acct, so it needs to be stripped
|
||||
const ignoredUsers: string[] =
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { BASE_URL } from '$env/static/private';
|
||||
import { Logger } from '$lib/log';
|
||||
import type { OauthResponse } from '$lib/mastodon/response';
|
||||
import fs from 'fs/promises';
|
||||
@ -6,6 +7,7 @@ export abstract class OauthPlaylistAdder {
|
||||
/// How many minutes before expiry the token will be refreshed
|
||||
protected refresh_time: number = 15;
|
||||
protected logger: Logger = new Logger('OauthPlaylistAdder');
|
||||
protected redirectUri?: URL;
|
||||
|
||||
protected constructor(
|
||||
protected apiBase: string,
|
||||
@ -22,6 +24,12 @@ export abstract class OauthPlaylistAdder {
|
||||
}
|
||||
}
|
||||
|
||||
protected getRedirectUri(suffix: string): URL {
|
||||
const uri = this.redirectUri ?? new URL(`${BASE_URL}/${suffix}`);
|
||||
this.logger.debug('getRedirectUri', uri);
|
||||
return uri;
|
||||
}
|
||||
|
||||
protected constructAuthUrlInternal(
|
||||
endpointUrl: string,
|
||||
clientId: string,
|
||||
|
@ -1,9 +1,4 @@
|
||||
import {
|
||||
BASE_URL,
|
||||
YOUTUBE_CLIENT_ID,
|
||||
YOUTUBE_CLIENT_SECRET,
|
||||
YOUTUBE_PLAYLIST_ID
|
||||
} from '$env/static/private';
|
||||
import { YOUTUBE_CLIENT_ID, YOUTUBE_CLIENT_SECRET, YOUTUBE_PLAYLIST_ID } from '$env/static/private';
|
||||
import { Logger } from '$lib/log';
|
||||
import type { OauthResponse } from '$lib/mastodon/response';
|
||||
import type { SongInfo } from '$lib/odesliResponse';
|
||||
@ -17,6 +12,7 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
}
|
||||
|
||||
public constructAuthUrl(redirectUri: URL): URL {
|
||||
this.redirectUri = redirectUri;
|
||||
let additionalParameters = new Map([
|
||||
['access_type', 'offline'],
|
||||
['include_granted_scopes', 'false']
|
||||
@ -33,6 +29,7 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
|
||||
public async receivedAuthCode(code: string, url: URL) {
|
||||
this.logger.debug('received code');
|
||||
this.redirectUri = url;
|
||||
const tokenUrl = new URL('https://oauth2.googleapis.com/token');
|
||||
await this.receivedAuthCodeInternal(
|
||||
tokenUrl,
|
||||
@ -57,13 +54,13 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
}
|
||||
}
|
||||
|
||||
private async refreshToken(): Promise<OauthResponse | null> {
|
||||
private async refreshToken(force: boolean = false): Promise<OauthResponse | null> {
|
||||
const tokenInfo = await this.shouldRefreshToken();
|
||||
if (tokenInfo == null) {
|
||||
return null;
|
||||
}
|
||||
let token = tokenInfo.token;
|
||||
if (!tokenInfo.refresh) {
|
||||
if (!tokenInfo.refresh && !force) {
|
||||
return token;
|
||||
}
|
||||
if (!token.refresh_token) {
|
||||
@ -76,12 +73,17 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
tokenUrl,
|
||||
YOUTUBE_CLIENT_ID,
|
||||
token.refresh_token,
|
||||
`${BASE_URL}/ytauth`,
|
||||
this.getRedirectUri('ytauth').toString(),
|
||||
YOUTUBE_CLIENT_SECRET
|
||||
);
|
||||
}
|
||||
|
||||
public async addToPlaylist(song: SongInfo) {
|
||||
public async addToPlaylist(song: SongInfo) {}
|
||||
|
||||
private async addToPlaylistRetry(song: SongInfo, remaning: number = 3) {
|
||||
if (remaning < 0) {
|
||||
this.logger.error('max retries reached, song will not be added to spotify playlist');
|
||||
}
|
||||
this.logger.debug('addToYoutubePlaylist');
|
||||
const token = await this.refreshToken();
|
||||
if (token == null) {
|
||||
@ -139,7 +141,15 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
const respObj = await resp.json();
|
||||
this.logger.info('Added to playlist', youtubeId, song.title);
|
||||
if (respObj.error) {
|
||||
this.logger.debug('Add to playlist failed', respObj.error.errors);
|
||||
this.logger.error('Add to playlist failed', respObj.error.errors);
|
||||
if (respObj.error.errors && respObj.error.errors[0].reason === 'authError') {
|
||||
this.logger.info('Refreshing auth token');
|
||||
const token = await this.refreshToken(true);
|
||||
if (token == null) {
|
||||
return;
|
||||
}
|
||||
this.addToPlaylistRetry(song, remaning--);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import {
|
||||
HASHTAG_FILTER,
|
||||
MASTODON_ACCESS_TOKEN,
|
||||
MASTODON_INSTANCE,
|
||||
IGNORE_USERS,
|
||||
ODESLI_API_KEY,
|
||||
YOUTUBE_API_KEY
|
||||
} from '$env/static/private';
|
||||
@ -48,6 +49,7 @@ export class TimelineReader {
|
||||
private lastPosts: string[] = [];
|
||||
private playlistAdders: PlaylistAdder[];
|
||||
private logger: Logger;
|
||||
private ignoredUsers: string[];
|
||||
|
||||
private async isMusicVideo(videoId: string) {
|
||||
if (!YOUTUBE_API_KEY || YOUTUBE_API_KEY === 'CHANGE_ME') {
|
||||
@ -372,6 +374,20 @@ export class TimelineReader {
|
||||
}
|
||||
|
||||
private async checkAndSavePost(post: Post) {
|
||||
if (IGNORE_USERS !== undefined && IGNORE_USERS !== '' && IGNORE_USERS !== 'CHANGE_ME') {
|
||||
const ignorelist = IGNORE_USERS.split(',');
|
||||
const isIgnored = ignorelist.includes(post.account.username);
|
||||
const isIgnoredDb = this.ignoredUsers.includes(post.account.username);
|
||||
this.logger.debug(
|
||||
'Check if user',
|
||||
post.account.username,
|
||||
'is ignored',
|
||||
this.ignoredUsers,
|
||||
isIgnored,
|
||||
isIgnoredDb
|
||||
);
|
||||
}
|
||||
|
||||
const hashttags: string[] = HASHTAG_FILTER.split(',');
|
||||
const found_tags: Tag[] = post.tags.filter((t: Tag) => hashttags.includes(t.name));
|
||||
|
||||
@ -480,6 +496,16 @@ export class TimelineReader {
|
||||
this.logger = new Logger('Timeline');
|
||||
this.logger.log('Constructing timeline object');
|
||||
this.playlistAdders = [new YoutubePlaylistAdder(), new SpotifyPlaylistAdder()];
|
||||
this.ignoredUsers =
|
||||
IGNORE_USERS === undefined
|
||||
? []
|
||||
: IGNORE_USERS.split(',')
|
||||
.map((u) => (u.startsWith('@') ? u.substring(1) : u))
|
||||
.map((u) =>
|
||||
u.endsWith('@' + MASTODON_INSTANCE)
|
||||
? u.substring(0, u.length - ('@' + MASTODON_INSTANCE).length)
|
||||
: u
|
||||
);
|
||||
this.startWebsocket();
|
||||
|
||||
this.loadPostsSinceLastRun()
|
||||
|
@ -7,9 +7,10 @@ const { DEV } = import.meta.env;
|
||||
|
||||
const logger = new Logger('SpotifyAuth');
|
||||
|
||||
export const load: PageServerLoad = async ({ url }) => {
|
||||
export const load: PageServerLoad = async ({ url, request }) => {
|
||||
const baseUrl = request.headers.get('X-Forwarded-Host') ?? BASE_URL;
|
||||
const adder = new SpotifyPlaylistAdder();
|
||||
let redirect_uri = new URL(`${BASE_URL}/spotifyAuth`);
|
||||
let redirect_uri = new URL(`${new URL(BASE_URL).protocol}//${baseUrl}/spotifyAuth`);
|
||||
if (url.hostname === 'localhost' && DEV) {
|
||||
redirect_uri.hostname = '127.0.0.1';
|
||||
}
|
||||
|
@ -6,9 +6,11 @@ import type { PageServerLoad } from './$types';
|
||||
|
||||
const logger = new Logger('YT Auth');
|
||||
|
||||
export const load: PageServerLoad = async ({ url }) => {
|
||||
export const load: PageServerLoad = async ({ url, request }) => {
|
||||
const baseUrl = request.headers.get('X-Forwarded-Host') ?? BASE_URL;
|
||||
const adder = new YoutubePlaylistAdder();
|
||||
const redirect_uri = new URL(`${BASE_URL}/ytauth`);
|
||||
logger.debug('redirect URL', `${new URL(BASE_URL).protocol}//${baseUrl}/ytauth`);
|
||||
const redirect_uri = new URL(`${new URL(BASE_URL).protocol}//${baseUrl}/ytauth`);
|
||||
if (url.searchParams.has('code')) {
|
||||
logger.debug(url.searchParams);
|
||||
await adder.receivedAuthCode(url.searchParams.get('code') || '', redirect_uri);
|
||||
|
Reference in New Issue
Block a user