diff --git a/src/lib/server/oauthPlaylistAdder.ts b/src/lib/server/playlist/oauthPlaylistAdder.ts similarity index 100% rename from src/lib/server/oauthPlaylistAdder.ts rename to src/lib/server/playlist/oauthPlaylistAdder.ts diff --git a/src/lib/server/playlist/playlistAdder.ts b/src/lib/server/playlist/playlistAdder.ts new file mode 100644 index 0000000..a52693c --- /dev/null +++ b/src/lib/server/playlist/playlistAdder.ts @@ -0,0 +1,5 @@ +import type { SongInfo } from '$lib/odesliResponse'; + +export interface PlaylistAdder { + addToPlaylist(song: SongInfo): Promise; +} diff --git a/src/lib/server/spotifyPlaylistAdder.ts b/src/lib/server/playlist/spotifyPlaylistAdder.ts similarity index 96% rename from src/lib/server/spotifyPlaylistAdder.ts rename to src/lib/server/playlist/spotifyPlaylistAdder.ts index f423864..1b2a4dc 100644 --- a/src/lib/server/spotifyPlaylistAdder.ts +++ b/src/lib/server/playlist/spotifyPlaylistAdder.ts @@ -3,8 +3,9 @@ import { Logger } from '$lib/log'; import type { OauthResponse } from '$lib/mastodon/response'; import type { SongInfo } from '$lib/odesliResponse'; import { OauthPlaylistAdder } from './oauthPlaylistAdder'; +import type { PlaylistAdder } from './playlistAdder'; -export class SpotifyPlaylistAdder extends OauthPlaylistAdder { +export class SpotifyPlaylistAdder extends OauthPlaylistAdder implements PlaylistAdder { public constructor() { super('https://api.spotify.com/v1', 'spotify_auth_token'); this.logger = new Logger('SpotifyPlaylistAdder'); diff --git a/src/lib/server/ytPlaylistAdder.ts b/src/lib/server/playlist/ytPlaylistAdder.ts similarity index 96% rename from src/lib/server/ytPlaylistAdder.ts rename to src/lib/server/playlist/ytPlaylistAdder.ts index c18f3b3..ecded66 100644 --- a/src/lib/server/ytPlaylistAdder.ts +++ b/src/lib/server/playlist/ytPlaylistAdder.ts @@ -8,8 +8,9 @@ import { log } from '$lib/log'; import type { OauthResponse } from '$lib/mastodon/response'; import type { SongInfo } from '$lib/odesliResponse'; import { OauthPlaylistAdder } from './oauthPlaylistAdder'; +import type { PlaylistAdder } from './playlistAdder'; -export class YoutubePlaylistAdder extends OauthPlaylistAdder { +export class YoutubePlaylistAdder extends OauthPlaylistAdder implements PlaylistAdder { public constructor() { super('https://www.googleapis.com/youtube/v3', 'yt_auth_token'); } diff --git a/src/lib/server/timeline.ts b/src/lib/server/timeline.ts index 097f29c..25b62bb 100644 --- a/src/lib/server/timeline.ts +++ b/src/lib/server/timeline.ts @@ -25,8 +25,9 @@ import { savePost, saveSongThumbnail } from '$lib/server/db'; +import { SpotifyPlaylistAdder } from '$lib/server/playlist/spotifyPlaylistAdder'; +import { YoutubePlaylistAdder } from '$lib/server/playlist/ytPlaylistAdder'; import { createFeed, saveAtomFeed } from '$lib/server/rss'; -import { YoutubePlaylistAdder } from '$lib/server/ytPlaylistAdder'; import { sleep } from '$lib/sleep'; import crypto from 'crypto'; import fs from 'fs/promises'; @@ -34,7 +35,7 @@ import { console } from 'inspector/promises'; import sharp from 'sharp'; import { URL, URLSearchParams } from 'url'; import { WebSocket } from 'ws'; -import { SpotifyPlaylistAdder } from './spotifyPlaylistAdder'; +import type { PlaylistAdder } from './playlist/playlistAdder'; const URL_REGEX = new RegExp(/href="(?[^>]+?)" target="_blank"/gm); const INVIDIOUS_REGEX = new RegExp(/invidious.*?watch.*?v=(?[a-zA-Z_0-9-]+)/gm); @@ -45,8 +46,7 @@ const YOUTUBE_REGEX = new RegExp( export class TimelineReader { private static _instance: TimelineReader; private lastPosts: string[] = []; - private youtubePlaylistAdder: YoutubePlaylistAdder; - private spotifyPlaylistAdder: SpotifyPlaylistAdder; + private playlistAdders: PlaylistAdder[]; private static async isMusicVideo(videoId: string) { if (!YOUTUBE_API_KEY || YOUTUBE_API_KEY === 'CHANGE_ME') { @@ -190,86 +190,10 @@ export class TimelineReader { } } - /* - private async addToYoutubePlaylist(song: SongInfo) { - log.debug('addToYoutubePlaylist'); - let token: OauthResponse; - try { - const youtube_token_file = await fs.readFile('yt_auth_token', { encoding: 'utf8' }); - token = JSON.parse(youtube_token_file); - log.debug('read youtube access token', token); - } catch (e) { - log.error('Could not read youtube access token', e); - return; - } - - if (!YOUTUBE_PLAYLIST_ID || YOUTUBE_PLAYLIST_ID === 'CHANGE_ME') { - log.debug('no playlist ID configured'); - return; - } - if (!song.youtubeUrl) { - log.debug('Skip adding song to YT playlist, no youtube Url', song); - return; - } - - const songUrl = new URL(song.youtubeUrl); - const youtubeId = songUrl.searchParams.get('v'); - if (!youtubeId) { - log.debug( - 'Skip adding song to YT playlist, could not extract YT id from URL', - song.youtubeUrl - ); - return; - } - log.debug('Found YT id from URL', song.youtubeUrl, youtubeId); - - const playlistItemsUrl = new URL('https://www.googleapis.com/youtube/v3/playlistItems'); - playlistItemsUrl.searchParams.append('videoId', youtubeId); - playlistItemsUrl.searchParams.append('playlistId', YOUTUBE_PLAYLIST_ID); - playlistItemsUrl.searchParams.append('part', 'id'); - const existingPlaylistItem = await fetch( - 'https://www.googleapis.com/youtube/v3/playlistItems', - { - headers: { Authorization: `${token.token_type} ${token.access_token}` } - } - ).then((r) => r.json()); - log.debug('existingPlaylistItem', existingPlaylistItem); - if (existingPlaylistItem.pageInfo && existingPlaylistItem.pageInfo.totalResults > 0) { - log.info('Item already in playlist'); - return; - } - - const searchParams = new URLSearchParams([ - ['part', 'snippet'] - //['key', token.access_token] - ]); - const options: RequestInit = { - method: 'POST', - headers: { Authorization: `${token.token_type} ${token.access_token}` }, - body: JSON.stringify({ - snippet: { - playlistId: YOUTUBE_PLAYLIST_ID, - resourceId: { - videoId: youtubeId, - kind: 'youtube#video' - } - } - }) - }; - const youtubeApiUrl = new URL( - `https://www.googleapis.com/youtube/v3/playlistItems?${searchParams}` - ); - const resp = await fetch(youtubeApiUrl, options); - const respObj = await resp.json(); - log.debug('Added to playlist', options, respObj); - if (respObj.error) { - log.debug('Add to playlist failed', respObj.error.errors); - } - } - */ private async addToPlaylist(song: SongInfo) { - await this.youtubePlaylistAdder.addToPlaylist(song); - await this.spotifyPlaylistAdder.addToPlaylist(song); + for (let adder of this.playlistAdders) { + await adder.addToPlaylist(song); + } } private static async resizeAvatar( @@ -554,8 +478,7 @@ export class TimelineReader { private constructor() { log.log('Constructing timeline object'); - this.youtubePlaylistAdder = new YoutubePlaylistAdder(); - this.spotifyPlaylistAdder = new SpotifyPlaylistAdder(); + this.playlistAdders = [new YoutubePlaylistAdder(), new SpotifyPlaylistAdder()]; this.startWebsocket(); this.loadPostsSinceLastRun() diff --git a/src/routes/spotifyAuth/+page.server.ts b/src/routes/spotifyAuth/+page.server.ts index 3aa2a53..033ed95 100644 --- a/src/routes/spotifyAuth/+page.server.ts +++ b/src/routes/spotifyAuth/+page.server.ts @@ -1,5 +1,5 @@ import { log } from '$lib/log'; -import { SpotifyPlaylistAdder } from '$lib/server/spotifyPlaylistAdder'; +import { SpotifyPlaylistAdder } from '$lib/server/playlist/spotifyPlaylistAdder'; import { redirect } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; diff --git a/src/routes/ytauth/+page.server.ts b/src/routes/ytauth/+page.server.ts index 026869d..5280e67 100644 --- a/src/routes/ytauth/+page.server.ts +++ b/src/routes/ytauth/+page.server.ts @@ -1,5 +1,5 @@ import { log } from '$lib/log'; -import { YoutubePlaylistAdder } from '$lib/server/ytPlaylistAdder'; +import { YoutubePlaylistAdder } from '$lib/server/playlist/ytPlaylistAdder'; import { redirect } from '@sveltejs/kit'; import type { PageServerLoad } from './$types';