I can't believe I figured out how to emulate ytmusic api calls
This commit is contained in:
@@ -6,5 +6,5 @@
|
||||
</script>
|
||||
|
||||
<div id="main">
|
||||
<ScrollableCardMenu header={'Listen Again'} cardDataList={data.recommendations} />
|
||||
<!-- <ScrollableCardMenu header={'Listen Again'} cardDataList={data.recommendations} /> -->
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,7 @@ export const GET: RequestHandler = async ({ url }) => {
|
||||
connection.service = await YouTubeMusic.fetchServiceInfo(connection.service.userId, connection.tokens.accessToken)
|
||||
break
|
||||
}
|
||||
connections.push(connection)
|
||||
}
|
||||
|
||||
return Response.json({ connections })
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit'
|
||||
import { SECRET_INTERNAL_API_KEY } from '$env/static/private'
|
||||
import { Jellyfin } from '$lib/services'
|
||||
import { Jellyfin, YouTubeMusic } from '$lib/services'
|
||||
import { google } from 'googleapis'
|
||||
|
||||
// This is temporary functionally for the sake of developing the app.
|
||||
// In the future will implement more robust algorithm for offering recommendations
|
||||
@@ -33,6 +34,9 @@ export const GET: RequestHandler = async ({ params, fetch }) => {
|
||||
|
||||
for (const song of mostPlayedData.Items) recommendations.push(Jellyfin.songFactory(song, connection))
|
||||
break
|
||||
case 'youtube-music':
|
||||
YouTubeMusic.getHome(tokens.accessToken)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,15 +43,22 @@ export const actions: Actions = {
|
||||
return fail(400, { message: 'Could not reach Jellyfin server' })
|
||||
}
|
||||
|
||||
const newConnection = Connections.addConnection('jellyfin', {
|
||||
const newConnectionId = Connections.addConnection('jellyfin', {
|
||||
userId: locals.user.id,
|
||||
service: { userId: authData.User.Id, urlOrigin: serverUrl.toString() },
|
||||
tokens: { accessToken: authData.AccessToken },
|
||||
})
|
||||
|
||||
return { newConnection }
|
||||
const response = await fetch(`/api/connections?ids=${newConnectionId}`, {
|
||||
method: 'GET',
|
||||
headers: { apikey: SECRET_INTERNAL_API_KEY },
|
||||
})
|
||||
|
||||
const responseData = await response.json()
|
||||
|
||||
return { newConnection: responseData.connections[0] }
|
||||
},
|
||||
youtubeMusicLogin: async ({ request, locals }) => {
|
||||
youtubeMusicLogin: async ({ request, fetch, locals }) => {
|
||||
const formData = await request.formData()
|
||||
const { code } = Object.fromEntries(formData)
|
||||
const client = new google.auth.OAuth2({ clientId: PUBLIC_YOUTUBE_API_CLIENT_ID, clientSecret: YOUTUBE_API_CLIENT_SECRET, redirectUri: 'http://localhost:5173' }) // DO NOT SHIP THIS. THE CLIENT SECRET SHOULD NOT BE MADE AVAILABLE TO USERS. MAKE A REQUEST TO THE LAZULI WEBSITE INSTEAD.
|
||||
@@ -61,13 +68,20 @@ export const actions: Actions = {
|
||||
const userChannelResponse = await youtube.channels.list({ mine: true, part: ['id', 'snippet'], access_token: tokens.access_token! })
|
||||
const userChannel = userChannelResponse.data.items![0]
|
||||
|
||||
const newConnection = Connections.addConnection('youtube-music', {
|
||||
const newConnectionId = Connections.addConnection('youtube-music', {
|
||||
userId: locals.user.id,
|
||||
service: { userId: userChannel.id! },
|
||||
tokens: { accessToken: tokens.access_token!, refreshToken: tokens.refresh_token!, expiry: tokens.expiry_date! },
|
||||
})
|
||||
|
||||
return { newConnection }
|
||||
const response = await fetch(`/api/connections?ids=${newConnectionId}`, {
|
||||
method: 'GET',
|
||||
headers: { apikey: SECRET_INTERNAL_API_KEY },
|
||||
})
|
||||
|
||||
const responseData = await response.json()
|
||||
|
||||
return { newConnection: responseData.connections[0] }
|
||||
},
|
||||
deleteConnection: async ({ request }) => {
|
||||
const formData = await request.formData()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { serviceData } from '$lib/services'
|
||||
import Services from '$lib/services.json'
|
||||
import JellyfinAuthBox from './jellyfinAuthBox.svelte'
|
||||
import { newestAlert } from '$lib/stores.js'
|
||||
import type { PageServerData } from './$types.js'
|
||||
@@ -38,7 +38,7 @@
|
||||
connections = [...connections, newConnection]
|
||||
|
||||
newConnectionModal = null
|
||||
return ($newestAlert = ['success', `Added ${serviceData[newConnection.type].displayName}`])
|
||||
return ($newestAlert = ['success', `Added ${Services[newConnection.type].displayName}`])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,9 +75,6 @@
|
||||
}
|
||||
|
||||
const profileActions: SubmitFunction = ({ action, cancel }) => {
|
||||
console.log(action)
|
||||
cancel()
|
||||
|
||||
return ({ result }) => {
|
||||
if (result.type === 'failure') {
|
||||
return ($newestAlert = ['warning', result.data?.message])
|
||||
@@ -89,7 +86,7 @@
|
||||
connections.splice(indexToDelete, 1)
|
||||
connections = connections
|
||||
|
||||
return ($newestAlert = ['success', `Deleted ${serviceData[serviceType].displayName}`])
|
||||
return ($newestAlert = ['success', `Deleted ${Services[serviceType].displayName}`])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,11 +99,11 @@
|
||||
<h1 class="py-2 text-xl">Add Connection</h1>
|
||||
<div class="flex flex-wrap gap-2 pb-4">
|
||||
<button class="add-connection-button h-14 rounded-md" on:click={() => (newConnectionModal = JellyfinAuthBox)}>
|
||||
<img src={serviceData.jellyfin.icon} alt="{serviceData.jellyfin.displayName} icon" class="aspect-square h-full p-2" />
|
||||
<img src={Services.jellyfin.icon} alt="{Services.jellyfin.displayName} icon" class="aspect-square h-full p-2" />
|
||||
</button>
|
||||
<form method="post" action="?/youtubeMusicLogin" use:enhance={authenticateYouTube}>
|
||||
<button class="add-connection-button h-14 rounded-md">
|
||||
<img src={serviceData['youtube-music'].icon} alt="{serviceData['youtube-music'].displayName} icon" class="aspect-square h-full p-2" />
|
||||
<img src={Services['youtube-music'].icon} alt="{Services['youtube-music'].displayName} icon" class="aspect-square h-full p-2" />
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { serviceData } from '$lib/services'
|
||||
import Services from '$lib/services.json'
|
||||
import IconButton from '$lib/components/util/iconButton.svelte'
|
||||
import Toggle from '$lib/components/util/toggle.svelte'
|
||||
import type { SubmitFunction } from '@sveltejs/kit'
|
||||
@@ -9,26 +9,27 @@
|
||||
export let connection: Connection<serviceType>
|
||||
export let submitFunction: SubmitFunction
|
||||
|
||||
$: reactiveServiceData = serviceData[connection.type]
|
||||
$: serviceData = Services[connection.type]
|
||||
|
||||
let showModal = false
|
||||
|
||||
const subHeaderItems: string[] = []
|
||||
if ('username' in connection.service && connection.service.username) subHeaderItems.push(connection.service.username)
|
||||
if ('serverName' in connection.service && connection.service.serverName) subHeaderItems.push(connection.service.serverName)
|
||||
</script>
|
||||
|
||||
<section class="rounded-lg" style="background-color: rgba(82, 82, 82, 0.25);" transition:fly={{ x: 50 }}>
|
||||
<header class="flex h-20 items-center gap-4 p-4">
|
||||
<div class="relative aspect-square h-full p-1">
|
||||
<img src={reactiveServiceData.icon} alt="{reactiveServiceData.displayName} icon" />
|
||||
{#if 'profilePicture' in connection.service && typeof connection.service.profilePicture === 'string'}
|
||||
<img src={serviceData.icon} alt="{serviceData.displayName} icon" />
|
||||
{#if 'profilePicture' in connection.service && connection.service.profilePicture}
|
||||
<img src={connection.service.profilePicture} alt="" class="absolute bottom-0 right-0 aspect-square h-5 rounded-full" />
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<div>Username</div>
|
||||
<div>{serviceData.displayName}</div>
|
||||
<div class="text-sm text-neutral-500">
|
||||
{reactiveServiceData.displayName}
|
||||
{#if 'serverName' in connection.service}
|
||||
- {connection.service.serverName}
|
||||
{/if}
|
||||
{subHeaderItems.join(' - ')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative ml-auto flex h-8 flex-row-reverse gap-2">
|
||||
|
||||
Reference in New Issue
Block a user