core
core copied to clipboard
Media Source API
Currently, media sources have three API methods:
-
search
-
get
-
import
search
and get
are quite clear and good now, but import
is basically a wildcard and requires custom client support. This issue is intended to scope out the features that would be required in a more restrictive API.
Feature Checklist
- [ ] Flagging support for the below features Probably just assign each a name. It could be implicit on the implementer end, so Core would determine it based on which methods are available.
- [ ] Import a playlist from a URL
Like the current YouTube source, on the web client this should open a panel that lists all the media in a playlist, and that has an "import all" button that can be used to import the entire thing into a new üWave playlist.
- [ ] One feature that would be good to have that does not exist right now is pagination; this may be quite difficult though because not all third parties support the type of pagination that üWave needs.
- [ ] Optionally, view playlists belonging to a user account / [other similar concept].
- [ ] Optionally, view playlists of the current user (if account is connected).
- How to do the account connection stuff?
- [ ] ...
interface MediaSource {
api?: number;
name: string;
get(context: SourceContext, sourceIDs: string[]): Promise<MediaItem[]>;
search(context: SourceContext, query: string, pagination?: any): Promise<MediaItem[]>;
// Get media items in a playlist. sourceID may be ID or a playlist URL or etc
getPlaylistItems(context: SourceContext, sourceID: string): Promise<MediaItem[]>;
// Get playlists owned by the user [throw error if user has no connected account]
getSelfPlaylists(context: SourceContext): Promise<PlaylistMeta[]>;
// Get (public) playlists owned by some other user or similar concept.
getUserPlaylists(context: SourceContext, userID: string): Promise<PlaylistMeta[]>;
// maybe?
searchPlaylists(context: SourceContext, query: string): Promise<PlaylistMeta[]>;
}
We're going to need an API rework to support runtime configuration. It's kind of possible already because media sources have access to the uw
object, but it's unergonomic. You can't use the options
parameter that uw.source()
gives you because that is static.
For runtime configuration, sources should be managed more strictly by üWave Core. Maybe an API could look like this:
interface MediaItem {
...
}
interface PlaylistMeta {
...
}
// Maybe a generic parameter for the options object?
// Maybe a generic parameter for the SourceData?
abstract class MediaSource {
static api: number = 3;
static name: string;
// This schema would automatically be merged with an `{ enabled: { type: boolean } }` schema using `allOf`
static schema: JSONSchema;
constructor(options: object /* or maybe a generic type */);
get(context: SourceContext, sourceIDs: string[]): Promise<MediaItem[]>;
search(context: SourceContext, query: string, pagination?: any): Promise<MediaItem[]>;
// Get media items in a playlist. sourceID may be ID or a playlist URL or etc
// optional
getPlaylistItems(context: SourceContext, sourceID: string): Promise<MediaItem[]>;
// Get playlists owned by the user [throw error if user has no connected account]
// optional
getSelfPlaylists(context: SourceContext): Promise<PlaylistMeta[]>;
// Get (public) playlists owned by some other user or similar concept.
// optional
getUserPlaylists(context: SourceContext, userID: string): Promise<PlaylistMeta[]>;
// maybe?
// optional
searchPlaylists(context: SourceContext, query: string): Promise<PlaylistMeta[]>;
// optional
close(): Promise<void> | void {}
}
Turns out static abstract members are not a thing. That was the reason for using an abstract class
in the sketch above instead of an interface.
Perhaps it could be an interface and a @u-wave/media-source
function that wraps it:
import { createMediaSource, MediaSource } = require('@u-wave/media-source');
class YouTubeSource implements MediaSource {
// ...
}
export = createMediaSource(YouTubeSource, {
name: 'youtube',
schema: {
// ...
},
})