prepare for being available on multiple domain names
This commit is contained in:
@ -3,15 +3,31 @@ import { TimelineReader } from '$lib/server/timeline';
|
|||||||
import type { Handle, HandleServerError } from '@sveltejs/kit';
|
import type { Handle, HandleServerError } from '@sveltejs/kit';
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
|
import { close } from '$lib/server/db';
|
||||||
|
|
||||||
const logger = new Logger('App');
|
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());
|
logger.log('Debug log enabled', Logger.isDebugEnabled());
|
||||||
TimelineReader.init();
|
TimelineReader.init();
|
||||||
|
|
||||||
export const handleError = (({ error }) => {
|
process.on('sveltekit:shutdown', (reason) => {
|
||||||
if (error instanceof Error) {
|
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);
|
logger.error('Something went wrong:', error.name, error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,25 +48,25 @@ export class Logger {
|
|||||||
if (!enableVerboseLog) {
|
if (!enableVerboseLog) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.debug(new Date().toISOString(), `- ${this.name} -`, ...params);
|
console.debug(new Date().toISOString(), `- ${this.name} -`, '- [VRBSE] -', ...params);
|
||||||
}
|
}
|
||||||
public debug(...params: any[]) {
|
public debug(...params: any[]) {
|
||||||
if (!Logger.isDebugEnabled()) {
|
if (!Logger.isDebugEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.debug(new Date().toISOString(), `- ${this.name} -`, ...params);
|
console.debug(new Date().toISOString(), `- ${this.name} -`, '- [DEBUG] -', ...params);
|
||||||
}
|
}
|
||||||
public log(...params: any[]) {
|
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[]) {
|
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[]) {
|
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[]) {
|
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[]) {
|
public static error(...params: any[]) {
|
||||||
|
@ -68,6 +68,15 @@ type Migration = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const db: sqlite3.Database = new sqlite3.Database('moshingmammut.db');
|
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
|
// for the local masto instance, the instance name is *not* saved
|
||||||
// as part of the username or acct, so it needs to be stripped
|
// as part of the username or acct, so it needs to be stripped
|
||||||
const ignoredUsers: string[] =
|
const ignoredUsers: string[] =
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { BASE_URL } from '$env/static/private';
|
||||||
import { Logger } from '$lib/log';
|
import { Logger } from '$lib/log';
|
||||||
import type { OauthResponse } from '$lib/mastodon/response';
|
import type { OauthResponse } from '$lib/mastodon/response';
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
@ -6,6 +7,7 @@ export abstract class OauthPlaylistAdder {
|
|||||||
/// How many minutes before expiry the token will be refreshed
|
/// How many minutes before expiry the token will be refreshed
|
||||||
protected refresh_time: number = 15;
|
protected refresh_time: number = 15;
|
||||||
protected logger: Logger = new Logger('OauthPlaylistAdder');
|
protected logger: Logger = new Logger('OauthPlaylistAdder');
|
||||||
|
protected redirectUri?: URL;
|
||||||
|
|
||||||
protected constructor(
|
protected constructor(
|
||||||
protected apiBase: string,
|
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(
|
protected constructAuthUrlInternal(
|
||||||
endpointUrl: string,
|
endpointUrl: string,
|
||||||
clientId: string,
|
clientId: string,
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
import {
|
import { YOUTUBE_CLIENT_ID, YOUTUBE_CLIENT_SECRET, YOUTUBE_PLAYLIST_ID } from '$env/static/private';
|
||||||
BASE_URL,
|
|
||||||
YOUTUBE_CLIENT_ID,
|
|
||||||
YOUTUBE_CLIENT_SECRET,
|
|
||||||
YOUTUBE_PLAYLIST_ID
|
|
||||||
} from '$env/static/private';
|
|
||||||
import { Logger } from '$lib/log';
|
import { Logger } from '$lib/log';
|
||||||
import type { OauthResponse } from '$lib/mastodon/response';
|
import type { OauthResponse } from '$lib/mastodon/response';
|
||||||
import type { SongInfo } from '$lib/odesliResponse';
|
import type { SongInfo } from '$lib/odesliResponse';
|
||||||
@ -17,6 +12,7 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
|||||||
}
|
}
|
||||||
|
|
||||||
public constructAuthUrl(redirectUri: URL): URL {
|
public constructAuthUrl(redirectUri: URL): URL {
|
||||||
|
this.redirectUri = redirectUri;
|
||||||
let additionalParameters = new Map([
|
let additionalParameters = new Map([
|
||||||
['access_type', 'offline'],
|
['access_type', 'offline'],
|
||||||
['include_granted_scopes', 'false']
|
['include_granted_scopes', 'false']
|
||||||
@ -33,6 +29,7 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
|||||||
|
|
||||||
public async receivedAuthCode(code: string, url: URL) {
|
public async receivedAuthCode(code: string, url: URL) {
|
||||||
this.logger.debug('received code');
|
this.logger.debug('received code');
|
||||||
|
this.redirectUri = url;
|
||||||
const tokenUrl = new URL('https://oauth2.googleapis.com/token');
|
const tokenUrl = new URL('https://oauth2.googleapis.com/token');
|
||||||
await this.receivedAuthCodeInternal(
|
await this.receivedAuthCodeInternal(
|
||||||
tokenUrl,
|
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();
|
const tokenInfo = await this.shouldRefreshToken();
|
||||||
if (tokenInfo == null) {
|
if (tokenInfo == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let token = tokenInfo.token;
|
let token = tokenInfo.token;
|
||||||
if (!tokenInfo.refresh) {
|
if (!tokenInfo.refresh && !force) {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
if (!token.refresh_token) {
|
if (!token.refresh_token) {
|
||||||
@ -76,12 +73,17 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
|||||||
tokenUrl,
|
tokenUrl,
|
||||||
YOUTUBE_CLIENT_ID,
|
YOUTUBE_CLIENT_ID,
|
||||||
token.refresh_token,
|
token.refresh_token,
|
||||||
`${BASE_URL}/ytauth`,
|
this.getRedirectUri('ytauth').toString(),
|
||||||
YOUTUBE_CLIENT_SECRET
|
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');
|
this.logger.debug('addToYoutubePlaylist');
|
||||||
const token = await this.refreshToken();
|
const token = await this.refreshToken();
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
@ -139,7 +141,15 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
|||||||
const respObj = await resp.json();
|
const respObj = await resp.json();
|
||||||
this.logger.info('Added to playlist', youtubeId, song.title);
|
this.logger.info('Added to playlist', youtubeId, song.title);
|
||||||
if (respObj.error) {
|
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,
|
HASHTAG_FILTER,
|
||||||
MASTODON_ACCESS_TOKEN,
|
MASTODON_ACCESS_TOKEN,
|
||||||
MASTODON_INSTANCE,
|
MASTODON_INSTANCE,
|
||||||
|
IGNORE_USERS,
|
||||||
ODESLI_API_KEY,
|
ODESLI_API_KEY,
|
||||||
YOUTUBE_API_KEY
|
YOUTUBE_API_KEY
|
||||||
} from '$env/static/private';
|
} from '$env/static/private';
|
||||||
@ -48,6 +49,7 @@ export class TimelineReader {
|
|||||||
private lastPosts: string[] = [];
|
private lastPosts: string[] = [];
|
||||||
private playlistAdders: PlaylistAdder[];
|
private playlistAdders: PlaylistAdder[];
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
private ignoredUsers: string[];
|
||||||
|
|
||||||
private async isMusicVideo(videoId: string) {
|
private async isMusicVideo(videoId: string) {
|
||||||
if (!YOUTUBE_API_KEY || YOUTUBE_API_KEY === 'CHANGE_ME') {
|
if (!YOUTUBE_API_KEY || YOUTUBE_API_KEY === 'CHANGE_ME') {
|
||||||
@ -372,6 +374,20 @@ export class TimelineReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async checkAndSavePost(post: Post) {
|
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 hashttags: string[] = HASHTAG_FILTER.split(',');
|
||||||
const found_tags: Tag[] = post.tags.filter((t: Tag) => hashttags.includes(t.name));
|
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 = new Logger('Timeline');
|
||||||
this.logger.log('Constructing timeline object');
|
this.logger.log('Constructing timeline object');
|
||||||
this.playlistAdders = [new YoutubePlaylistAdder(), new SpotifyPlaylistAdder()];
|
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.startWebsocket();
|
||||||
|
|
||||||
this.loadPostsSinceLastRun()
|
this.loadPostsSinceLastRun()
|
||||||
|
@ -7,9 +7,10 @@ const { DEV } = import.meta.env;
|
|||||||
|
|
||||||
const logger = new Logger('SpotifyAuth');
|
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();
|
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) {
|
if (url.hostname === 'localhost' && DEV) {
|
||||||
redirect_uri.hostname = '127.0.0.1';
|
redirect_uri.hostname = '127.0.0.1';
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,11 @@ import type { PageServerLoad } from './$types';
|
|||||||
|
|
||||||
const logger = new Logger('YT Auth');
|
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 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')) {
|
if (url.searchParams.has('code')) {
|
||||||
logger.debug(url.searchParams);
|
logger.debug(url.searchParams);
|
||||||
await adder.receivedAuthCode(url.searchParams.get('code') || '', redirect_uri);
|
await adder.receivedAuthCode(url.searchParams.get('code') || '', redirect_uri);
|
||||||
|
Reference in New Issue
Block a user