Compare commits
1 Commits
master
...
ytm_integr
Author | SHA1 | Date |
---|---|---|
|
dff4acab25 | 5 years ago |
12 changed files with 276 additions and 13 deletions
@ -0,0 +1,6 @@ |
|||||||
|
[submodule "client/submodules/youtube-music-api"] |
||||||
|
path = client/submodules/youtube-music-api |
||||||
|
url = https://github.com/SanderVocke/youtube-music-api.git |
||||||
|
[submodule "client/src/submodules/youtube-music-api"] |
||||||
|
path = client/src/submodules/youtube-music-api |
||||||
|
url = https://github.com/SanderVocke/youtube-music-api.git |
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 944 B |
@ -0,0 +1,12 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import Integration from '../../integrations/Integration'; |
||||||
|
|
||||||
|
export default function IntegrationsWidget(props: { |
||||||
|
integrations: Integration[] |
||||||
|
}) { |
||||||
|
return <> |
||||||
|
{props.integrations.map((integration: Integration) => { |
||||||
|
return integration.getIcon({ style: { height: '30px', width: '30px' } }); |
||||||
|
})} |
||||||
|
</> |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
import React, { ReactFragment } from 'react'; |
||||||
|
|
||||||
|
export interface IntegrationAlbum { |
||||||
|
name?: string, |
||||||
|
storeLink?: string, |
||||||
|
} |
||||||
|
|
||||||
|
export interface IntegrationArtist { |
||||||
|
name?: string, |
||||||
|
storeLink?: string, |
||||||
|
} |
||||||
|
|
||||||
|
export interface IntegrationSong { |
||||||
|
title?: string, |
||||||
|
album?: IntegrationAlbum, |
||||||
|
artist?: IntegrationArtist, |
||||||
|
storeLink?: string, |
||||||
|
} |
||||||
|
|
||||||
|
export enum IntegrationFeature { |
||||||
|
// Used to get a bucket of songs (typically: the whole library)
|
||||||
|
GetSongs = 0, |
||||||
|
|
||||||
|
// Used to search songs and get some amount of candidate results.
|
||||||
|
SearchSong, |
||||||
|
|
||||||
|
// If included, the integration is required to be connected to work.
|
||||||
|
// Methods connect() and isConnected() have to be used for this.
|
||||||
|
UsesConnection, |
||||||
|
} |
||||||
|
|
||||||
|
export interface IntegrationDescriptor { |
||||||
|
supports: IntegrationFeature[], |
||||||
|
} |
||||||
|
|
||||||
|
export default class Integration { |
||||||
|
constructor() { } |
||||||
|
|
||||||
|
// Common
|
||||||
|
getFeatures(): IntegrationFeature[] { return []; } |
||||||
|
getIcon(props: any): ReactFragment { return <></> } |
||||||
|
|
||||||
|
// Feature: UsesConnection
|
||||||
|
async connect(connectParams: any) { } |
||||||
|
isConnected(): boolean { return false; } |
||||||
|
|
||||||
|
// Feature: GetSongs
|
||||||
|
async getSongs(getSongsParams: any): Promise<IntegrationSong[]> { return []; } |
||||||
|
|
||||||
|
// Feature: SearchSongs
|
||||||
|
async searchSong(songProps: IntegrationSong): Promise<IntegrationSong | null> { return null; } |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
|
||||||
|
import React from 'react'; |
||||||
|
import Integration, { IntegrationFeature, IntegrationSong } from "../Integration"; |
||||||
|
import StoreLinkIcon, { ExternalStore } from "../../components/common/StoreLinkIcon"; |
||||||
|
const YoutubeMusicApi = require('../../submodules/youtube-music-api'); |
||||||
|
|
||||||
|
export interface YoutubeMusicConnectionParams {} |
||||||
|
|
||||||
|
export default class YoutubeMusicIntegration extends Integration { |
||||||
|
lastConnected: Date | null = null; |
||||||
|
connectionIntervalMs: number = 1000 * 60 * 2; // 2 minutes
|
||||||
|
connectionParams: YoutubeMusicConnectionParams | null = null; |
||||||
|
api: any = null; |
||||||
|
|
||||||
|
getFeatures() : IntegrationFeature[] { |
||||||
|
return [ |
||||||
|
IntegrationFeature.SearchSong, |
||||||
|
IntegrationFeature.UsesConnection, |
||||||
|
] |
||||||
|
} |
||||||
|
|
||||||
|
getIcon(props: any) { |
||||||
|
return <StoreLinkIcon whichStore={ExternalStore.YoutubeMusic} {...props}/> |
||||||
|
} |
||||||
|
|
||||||
|
async connect(connectionParams: YoutubeMusicConnectionParams) { |
||||||
|
const newApi = new YoutubeMusicApi(); |
||||||
|
await newApi.initalize(); |
||||||
|
this.api = newApi; |
||||||
|
this.lastConnected = new Date(); |
||||||
|
|
||||||
|
// TODO start keepalive service worker?
|
||||||
|
} |
||||||
|
|
||||||
|
isConnected() { |
||||||
|
if(!this.connectionParams || !this.lastConnected) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// Last successful connection must be less than 2 minutes ago.
|
||||||
|
return ((new Date().valueOf()) - this.lastConnected.valueOf()) < this.connectionIntervalMs; |
||||||
|
} |
||||||
|
|
||||||
|
async searchSong(songProps: IntegrationSong) { |
||||||
|
var query: string = ""; |
||||||
|
if(songProps.title) { query += " " + songProps.title } |
||||||
|
if(songProps.artist && songProps.artist.name) { query += " " + songProps.artist.name } |
||||||
|
|
||||||
|
const result = await this.api.search(query.trim(), "song"); |
||||||
|
|
||||||
|
console.log("Search result: ", result) |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
const { createProxyMiddleware } = require('http-proxy-middleware'); |
||||||
|
|
||||||
|
module.exports = function(app) { |
||||||
|
app.use( |
||||||
|
'/api', |
||||||
|
createProxyMiddleware({ |
||||||
|
target: 'http://localhost:5000', |
||||||
|
changeOrigin: true, |
||||||
|
}) |
||||||
|
); |
||||||
|
app.use( |
||||||
|
'/integrations/ytm', |
||||||
|
createProxyMiddleware({ |
||||||
|
target: 'https://music.youtube.com', |
||||||
|
changeOrigin: true, |
||||||
|
}) |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1 @@ |
|||||||
|
Subproject commit 0184b80d4b36f92b2874a0aece6e01d92af0c92c |
Loading…
Reference in new issue