mirror of
https://github.com/janishutz/MusicPlayer.git
synced 2026-09-10 14:25:24 +02:00
feat: set up backend
This commit is contained in:
@@ -5,3 +5,4 @@ apple_private_key.p8
|
|||||||
musicplayerv2-server.zip
|
musicplayerv2-server.zip
|
||||||
dist
|
dist
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/cors": "^2.8.19",
|
"@janishutz/login-sdk-server": "^1.4.0",
|
||||||
|
"@janishutz/login-sdk-server-stubs": "^1.4.0",
|
||||||
|
"@janishutz/store-sdk": "^1.2.1",
|
||||||
"cors": "^2.8.6",
|
"cors": "^2.8.6",
|
||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
"express-session": "^1.19.0",
|
"express-session": "^1.19.0",
|
||||||
"jsonwebtoken": "^9.0.3"
|
"jsonwebtoken": "^9.0.3",
|
||||||
|
"typescript": "^6.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@stylistic/eslint-plugin": "^5.10.0",
|
"@stylistic/eslint-plugin": "^5.10.0",
|
||||||
|
"@types/cors": "^2.8.19",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
"@types/express-session": "^1.19.0",
|
"@types/express-session": "^1.19.0",
|
||||||
"@types/jsonwebtoken": "^9.0.10",
|
"@types/jsonwebtoken": "^9.0.10",
|
||||||
|
|||||||
+56
-11
@@ -1,33 +1,78 @@
|
|||||||
|
import {
|
||||||
|
getLoginSdk,
|
||||||
|
getStoreSdk
|
||||||
|
} from './sdk';
|
||||||
import devtoken from './routes/devtoken';
|
import devtoken from './routes/devtoken';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import expressSession from 'express-session';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
// TODO: configurable
|
||||||
|
const sdk = getLoginSdk( false );
|
||||||
|
const storeSdk = getStoreSdk( false );
|
||||||
|
|
||||||
|
|
||||||
const run = () => {
|
const run = () => {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
const sdkConfig = JSON.parse( fs.readFileSync( path.join(
|
||||||
|
__dirname,
|
||||||
|
'/config/sdk.config.testing.json'
|
||||||
|
) ).toString() );
|
||||||
|
|
||||||
// TODO: Use db store for this (via sdk or stubs)
|
// Load id.janishutz.com SDK and allow signing in
|
||||||
app.use( expressSession( {
|
sdk.setUp(
|
||||||
'secret': 'dev',
|
{
|
||||||
'resave': true,
|
'prod': false,
|
||||||
'saveUninitialized': false
|
'service': {
|
||||||
} ) );
|
'serviceID': 'jh-music',
|
||||||
|
'serviceToken': sdkConfig[ 'token' ]
|
||||||
|
},
|
||||||
|
'user-agent': sdkConfig[ 'ua' ],
|
||||||
|
'sessionType': 'memory',
|
||||||
|
'frontendURL': 'https://music.janishutz.com',
|
||||||
|
'corsWhitelist': [ 'https://music.janishutz.com' ],
|
||||||
|
'recheckTimeout': 300 * 1000,
|
||||||
|
'advancedVerification': 'sdk'
|
||||||
|
},
|
||||||
|
app,
|
||||||
|
async () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
async ( uid: string ) => {
|
||||||
|
fs.writeFileSync( path.join( __dirname, '/data/', uid ), '{}' );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Load store sdk
|
||||||
|
const storeConfig = JSON.parse( fs.readFileSync( path.join(
|
||||||
|
__dirname,
|
||||||
|
'/config/store-sdk.config.secret.json'
|
||||||
|
) ).toString() );
|
||||||
|
|
||||||
|
storeSdk.configure( storeConfig );
|
||||||
|
|
||||||
app.get( '/', ( _request: express.Request, response: express.Response ) => {
|
app.get( '/', ( _request: express.Request, response: express.Response ) => {
|
||||||
response.send( 'HELLO WORLD' );
|
response.send( 'HELLO WORLD' );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
// Load extra routes
|
||||||
|
devtoken.routes( app );
|
||||||
|
|
||||||
|
|
||||||
app.use( ( _request: express.Request, response: express.Response ) => {
|
app.use( ( _request: express.Request, response: express.Response ) => {
|
||||||
response.sendFile( path.join( __dirname, '' ) );
|
response.sendFile( path.join( __dirname, '' ) );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
||||||
devtoken.routes( app );
|
|
||||||
|
|
||||||
|
|
||||||
const PORT = process.env.PORT || 8080;
|
const PORT = process.env.PORT || 8080;
|
||||||
|
|
||||||
app.listen( PORT );
|
app.listen( PORT );
|
||||||
|
|||||||
Vendored
+55
@@ -0,0 +1,55 @@
|
|||||||
|
export interface UserPlaylistFile {
|
||||||
|
'version': '1',
|
||||||
|
'userid': string,
|
||||||
|
'playlists': Playlist[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Playlist {
|
||||||
|
'name': string;
|
||||||
|
'songs': PlaylistSongs;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PlaylistSongs = Song[];
|
||||||
|
|
||||||
|
export interface Song {
|
||||||
|
/**
|
||||||
|
* Where the song can be found
|
||||||
|
*/
|
||||||
|
'source': 'local' | 'applemusic';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier for the song so it can be found again (such as Apple Music ID or URL for playback)
|
||||||
|
*/
|
||||||
|
'identifier': string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any additional identifiers (such as filename, etc) to associate.
|
||||||
|
* Even if this is not used, set this value if local files are needed
|
||||||
|
*/
|
||||||
|
'additional-identifier'?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional info, such as dance type to be displayed on remote screens
|
||||||
|
*/
|
||||||
|
'additional-info': string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The artist of the song
|
||||||
|
*/
|
||||||
|
'artist': string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the song
|
||||||
|
*/
|
||||||
|
'name': string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cover image as a URL
|
||||||
|
*/
|
||||||
|
'artwork': string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Song duration
|
||||||
|
*/
|
||||||
|
'duration': number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import {
|
||||||
|
RoomStore
|
||||||
|
} from './room';
|
||||||
|
|
||||||
|
const rooms: RoomStore = {};
|
||||||
|
|
||||||
|
const getRoom = ( room: string ) => {};
|
||||||
|
|
||||||
|
const createRoom = ( name: string ) => {};
|
||||||
Vendored
+26
@@ -0,0 +1,26 @@
|
|||||||
|
import {
|
||||||
|
Playlist
|
||||||
|
} from '../../dtype/file';
|
||||||
|
import {
|
||||||
|
Response
|
||||||
|
} from 'express';
|
||||||
|
|
||||||
|
export interface Room {
|
||||||
|
'playlist': Playlist;
|
||||||
|
'playing': boolean;
|
||||||
|
'index': number;
|
||||||
|
'start': number;
|
||||||
|
'token': string;
|
||||||
|
'lastUpdate': number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to determine if the playlist needs to be sent in polling mode
|
||||||
|
*/
|
||||||
|
'lastPlaylistUpdate': number;
|
||||||
|
|
||||||
|
'clients': Response[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoomStore {
|
||||||
|
[id: string]: Room
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import loginSdk from '@janishutz/login-sdk-server';
|
||||||
|
import loginSdkStub from '@janishutz/login-sdk-server-stubs';
|
||||||
|
import storeSdk from '@janishutz/store-sdk';
|
||||||
|
import storeSdkStub from './store-sdk-stub';
|
||||||
|
|
||||||
|
export const getLoginSdk = ( foss: boolean ) => {
|
||||||
|
if ( foss ) return loginSdkStub;
|
||||||
|
else return loginSdk;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getStoreSdk = ( foss: boolean ) => {
|
||||||
|
if ( foss ) return storeSdkStub;
|
||||||
|
else return storeSdk;
|
||||||
|
};
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
interface StoreSDKConfig {
|
||||||
|
'backendURL': string;
|
||||||
|
'signingSecret': string;
|
||||||
|
'name': string;
|
||||||
|
'loglevel': 'debug' | 'info' | 'log' | 'warn' | 'error' | 'none';
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const getSubscriptions = ( _uid: string ) => {
|
const getSubscriptions = ( _uid: string ) => {
|
||||||
return [ {
|
return [ {
|
||||||
@@ -7,6 +14,9 @@ const getSubscriptions = ( _uid: string ) => {
|
|||||||
} ];
|
} ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const configure = ( _config: StoreSDKConfig ) => {}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getSubscriptions
|
getSubscriptions,
|
||||||
|
configure
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-2
@@ -15,6 +15,7 @@
|
|||||||
"@fortawesome/fontawesome-svg-core": "^7.3.1",
|
"@fortawesome/fontawesome-svg-core": "^7.3.1",
|
||||||
"@fortawesome/free-regular-svg-icons": "^7.3.1",
|
"@fortawesome/free-regular-svg-icons": "^7.3.1",
|
||||||
"@globalhive/vuejs-tour": "^3.0.1",
|
"@globalhive/vuejs-tour": "^3.0.1",
|
||||||
|
"@janishutz/login-sdk-browser": "^1.1.0",
|
||||||
"@kyvg/vue3-notification": "^3.4.2",
|
"@kyvg/vue3-notification": "^3.4.2",
|
||||||
"music-metadata": "^11.15.0",
|
"music-metadata": "^11.15.0",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
@@ -29,13 +30,14 @@
|
|||||||
"@types/node": "^24.13.3",
|
"@types/node": "^24.13.3",
|
||||||
"@vitejs/plugin-vue": "^6.0.8",
|
"@vitejs/plugin-vue": "^6.0.8",
|
||||||
"@vue/tsconfig": "^0.9.1",
|
"@vue/tsconfig": "^0.9.1",
|
||||||
|
"eslint": "^10.9.1",
|
||||||
"eslint-plugin-vue": "^10.10.0",
|
"eslint-plugin-vue": "^10.10.0",
|
||||||
"globals": "^17.11.0",
|
"globals": "^17.12.0",
|
||||||
"musickitjs-v3-types": "^1.2.1",
|
"musickitjs-v3-types": "^1.2.1",
|
||||||
"npm-run-all2": "^9.0.2",
|
"npm-run-all2": "^9.0.2",
|
||||||
"sass-embedded": "^1.103.1",
|
"sass-embedded": "^1.103.1",
|
||||||
"typescript": "~6.0.0",
|
"typescript": "~6.0.0",
|
||||||
"typescript-eslint": "^8.67.0",
|
"typescript-eslint": "^8.69.0",
|
||||||
"vite": "^8.1.5",
|
"vite": "^8.1.5",
|
||||||
"vite-plugin-vue-devtools": "^8.1.5",
|
"vite-plugin-vue-devtools": "^8.1.5",
|
||||||
"vue-tsc": "^3.3.7"
|
"vue-tsc": "^3.3.7"
|
||||||
|
|||||||
Reference in New Issue
Block a user