first schema ver
This commit is contained in:
parent
38732a4cf6
commit
6ae23f7c07
4 changed files with 297 additions and 4 deletions
|
|
@ -4,6 +4,9 @@ import { db } from "./db";
|
|||
import Elysia, { status, type Context } from "elysia";
|
||||
import * as schema from "./db/auth-schema";
|
||||
|
||||
export const SPOTIFY_CLIENT_ID = process.env.SPOTIFY_CLIENT_ID!;
|
||||
export const SPOTIFY_CLIENT_SECRET = process.env.SPOTIFY_CLIENT_SECRET!;
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: drizzleAdapter(db, {
|
||||
provider: "pg",
|
||||
|
|
@ -11,8 +14,8 @@ export const auth = betterAuth({
|
|||
}),
|
||||
socialProviders: {
|
||||
spotify: {
|
||||
clientId: process.env.SPOTIFY_CLIENT_ID!,
|
||||
clientSecret: process.env.SPOTIFY_CLIENT_SECRET!,
|
||||
clientId: SPOTIFY_CLIENT_ID,
|
||||
clientSecret: SPOTIFY_CLIENT_SECRET,
|
||||
scope: [
|
||||
"user-read-playback-state",
|
||||
"user-read-currently-playing",
|
||||
|
|
|
|||
|
|
@ -1,2 +1,254 @@
|
|||
import { integer, pgTable, varchar } from "drizzle-orm/pg-core";
|
||||
import {
|
||||
boolean,
|
||||
index,
|
||||
integer,
|
||||
pgEnum,
|
||||
pgTable,
|
||||
primaryKey,
|
||||
text,
|
||||
timestamp,
|
||||
uuid,
|
||||
varchar,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { user } from "./auth-schema";
|
||||
export * from "./auth-schema";
|
||||
|
||||
const platform = pgEnum("platform", ["spotify"]);
|
||||
|
||||
export const artist = pgTable("artist", {
|
||||
id: uuid().defaultRandom().primaryKey().notNull(),
|
||||
platform_id: text().notNull(),
|
||||
platform: platform().notNull(),
|
||||
name: text().notNull(),
|
||||
type: text(),
|
||||
popularity: integer(),
|
||||
});
|
||||
|
||||
export const genre = pgTable("genre", {
|
||||
id: uuid().defaultRandom().primaryKey().notNull(),
|
||||
});
|
||||
|
||||
export const artistGenre = pgTable(
|
||||
"artist_genre",
|
||||
{
|
||||
artist: uuid()
|
||||
.references(() => artist.id)
|
||||
.notNull(),
|
||||
genre: uuid()
|
||||
.references(() => genre.id)
|
||||
.notNull(),
|
||||
},
|
||||
(artistGenres) => [
|
||||
primaryKey({
|
||||
columns: [artistGenres.artist, artistGenres.genre],
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
||||
export const platformImage = pgTable("platform_image", {
|
||||
id: uuid().defaultRandom().primaryKey().notNull(),
|
||||
platform: platform().notNull(),
|
||||
url: text(),
|
||||
height: integer(),
|
||||
width: integer(),
|
||||
});
|
||||
|
||||
export const artistImage = pgTable(
|
||||
"artist_image",
|
||||
{
|
||||
artist: uuid()
|
||||
.references(() => artist.id)
|
||||
.notNull(),
|
||||
image: uuid()
|
||||
.references(() => platformImage.id)
|
||||
.notNull(),
|
||||
},
|
||||
(artistImages) => [
|
||||
primaryKey({
|
||||
columns: [artistImages.artist, artistImages.image],
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
||||
export const album = pgTable("album", {
|
||||
id: uuid().defaultRandom().primaryKey().notNull(),
|
||||
type: text(),
|
||||
name: text(),
|
||||
platform: platform(),
|
||||
platform_id: text(),
|
||||
popularity: integer(),
|
||||
release_date: timestamp(),
|
||||
label: text(),
|
||||
});
|
||||
|
||||
export const albumImage = pgTable(
|
||||
"album_image",
|
||||
{
|
||||
album: uuid()
|
||||
.references(() => album.id)
|
||||
.notNull(),
|
||||
image: uuid()
|
||||
.references(() => platformImage.id)
|
||||
.notNull(),
|
||||
},
|
||||
(albumImage) => [
|
||||
primaryKey({
|
||||
columns: [albumImage.album, albumImage.image],
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
||||
export const track = pgTable(
|
||||
"track",
|
||||
{
|
||||
id: uuid().defaultRandom().primaryKey().notNull(),
|
||||
album: uuid()
|
||||
.references(() => album.id)
|
||||
.notNull(),
|
||||
name: text(),
|
||||
platform: platform(),
|
||||
platform_id: text(),
|
||||
popularity: integer(),
|
||||
duration: integer(),
|
||||
explicit: boolean(),
|
||||
disc_number: integer(),
|
||||
track_number: integer(),
|
||||
},
|
||||
(track) => [index().on([track.album])],
|
||||
);
|
||||
|
||||
export const trackArtist = pgTable(
|
||||
"track_artist",
|
||||
{
|
||||
track: uuid()
|
||||
.references(() => track.id)
|
||||
.notNull(),
|
||||
artist: uuid()
|
||||
.references(() => artist.id)
|
||||
.notNull(),
|
||||
},
|
||||
(trackArtist) => [
|
||||
primaryKey({
|
||||
columns: [trackArtist.track, trackArtist.artist],
|
||||
}),
|
||||
index().on([trackArtist.track]),
|
||||
index().on([trackArtist.artist]),
|
||||
],
|
||||
);
|
||||
|
||||
const topTimeline = pgEnum("top_timeline", [
|
||||
"short_term",
|
||||
"medium_term",
|
||||
"long_term",
|
||||
]);
|
||||
|
||||
export const topTrack = pgTable(
|
||||
"top_track",
|
||||
{
|
||||
track: uuid()
|
||||
.references(() => track.id)
|
||||
.notNull(),
|
||||
position: integer().notNull(),
|
||||
user: text()
|
||||
.references(() => user.id)
|
||||
.notNull(),
|
||||
timeline: topTimeline().notNull(),
|
||||
},
|
||||
(topTrack) => [
|
||||
primaryKey({
|
||||
columns: [topTrack.track, topTrack.user, topTrack.timeline],
|
||||
}),
|
||||
index().on([topTrack.user]),
|
||||
],
|
||||
);
|
||||
|
||||
export const topArtist = pgTable(
|
||||
"top_artist",
|
||||
{
|
||||
artist: uuid()
|
||||
.references(() => artist.id)
|
||||
.notNull(),
|
||||
position: integer().notNull(),
|
||||
user: text()
|
||||
.references(() => user.id)
|
||||
.notNull(),
|
||||
timeline: topTimeline().notNull(),
|
||||
},
|
||||
(topArtist) => [
|
||||
primaryKey({
|
||||
columns: [topArtist.artist, topArtist.user, topArtist.timeline],
|
||||
}),
|
||||
index().on([topArtist.user]),
|
||||
],
|
||||
);
|
||||
|
||||
export const savedAlbum = pgTable(
|
||||
"saved_album",
|
||||
{
|
||||
album: uuid()
|
||||
.references(() => album.id)
|
||||
.notNull(),
|
||||
user: text()
|
||||
.references(() => user.id)
|
||||
.notNull(),
|
||||
saved_at: timestamp("saved_at").defaultNow().notNull(),
|
||||
},
|
||||
(savedAlbum) => [
|
||||
primaryKey({
|
||||
columns: [savedAlbum.album, savedAlbum.user],
|
||||
}),
|
||||
index().on([savedAlbum.user]),
|
||||
],
|
||||
);
|
||||
|
||||
export const savedTrack = pgTable(
|
||||
"saved_track",
|
||||
{
|
||||
track: uuid()
|
||||
.references(() => track.id)
|
||||
.notNull(),
|
||||
user: text()
|
||||
.references(() => user.id)
|
||||
.notNull(),
|
||||
saved_at: timestamp("saved_at").defaultNow().notNull(),
|
||||
},
|
||||
(savedTrack) => [
|
||||
primaryKey({
|
||||
columns: [savedTrack.track, savedTrack.user],
|
||||
}),
|
||||
index().on([savedTrack.user]),
|
||||
],
|
||||
);
|
||||
|
||||
export const followedArtist = pgTable(
|
||||
"followed_artist",
|
||||
{
|
||||
artist: uuid()
|
||||
.references(() => artist.id)
|
||||
.notNull(),
|
||||
user: text()
|
||||
.references(() => user.id)
|
||||
.notNull(),
|
||||
},
|
||||
(followedArtist) => [
|
||||
primaryKey({
|
||||
columns: [followedArtist.artist, followedArtist.user],
|
||||
}),
|
||||
index().on([followedArtist.user]),
|
||||
],
|
||||
);
|
||||
|
||||
export const playbackHistory = pgTable(
|
||||
"playback_history",
|
||||
{
|
||||
id: uuid().defaultRandom().primaryKey().notNull(),
|
||||
track: uuid()
|
||||
.references(() => track.id)
|
||||
.notNull(),
|
||||
user: text()
|
||||
.references(() => user.id)
|
||||
.notNull(),
|
||||
played_at: timestamp("played_at").defaultNow().notNull(),
|
||||
},
|
||||
(playbackHistory) => [index().on([playbackHistory.user])],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Elysia, t } from "elysia";
|
||||
import { betterAuthElysia } from "./auth";
|
||||
import { syncApp } from "./routes/sync";
|
||||
|
||||
const app = new Elysia().use(betterAuthElysia).listen(4000);
|
||||
const app = new Elysia().use(betterAuthElysia).use(syncApp).listen(4000);
|
||||
|
||||
export type App = typeof app;
|
||||
|
|
|
|||
37
api/src/routes/sync.ts
Normal file
37
api/src/routes/sync.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import Elysia from "elysia";
|
||||
import { auth, betterAuthElysia, SPOTIFY_CLIENT_ID } from "../auth";
|
||||
import { SpotifyApi } from "@spotify/web-api-ts-sdk";
|
||||
|
||||
export const syncApp = new Elysia().use(betterAuthElysia).post(
|
||||
"/sync",
|
||||
async ({ user }) => {
|
||||
const accessToken = await auth.api.getAccessToken({
|
||||
body: {
|
||||
userId: user.id,
|
||||
providerId: "spotify",
|
||||
},
|
||||
});
|
||||
const sdk = SpotifyApi.withAccessToken(SPOTIFY_CLIENT_ID, {
|
||||
access_token: accessToken.accessToken,
|
||||
expires_in: Date.now() - Number(accessToken.accessTokenExpiresAt!),
|
||||
expires: Number(accessToken.accessTokenExpiresAt),
|
||||
refresh_token: "",
|
||||
token_type: "",
|
||||
});
|
||||
for (const timeline of [
|
||||
"short_term",
|
||||
"medium_term",
|
||||
"long_term",
|
||||
] as const) {
|
||||
const topArtists = await sdk.currentUser.topItems(
|
||||
"artists",
|
||||
timeline,
|
||||
50,
|
||||
);
|
||||
const topTracks = await sdk.currentUser.topItems("tracks", timeline, 50);
|
||||
}
|
||||
},
|
||||
{
|
||||
auth: true,
|
||||
},
|
||||
);
|
||||
Loading…
Reference in a new issue