Skip to content

Commit

Permalink
Add ANDROID_EMBEDDED and ANDROID_MUSIC clients.
Browse files Browse the repository at this point in the history
  • Loading branch information
devoxin committed Jul 20, 2024
1 parent f22d382 commit f560b48
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 35 deletions.
69 changes: 34 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,25 +122,24 @@ plugins:
- MUSIC
- ANDROID_TESTSUITE
- WEB
- TVHTML5EMBEDDED

# You can configure individual clients with the following.
# Any options or clients left unspecified will use their default values
# for those individual clients.
# Client configurations will ONLY take effect if the client is registered above,
# otherwise they are ignored.
# ---------------- WARNING ----------------
# This part of the config is for DEMONSTRATION PURPOSES ONLY!
# Do NOT use this config before understanding what the options do.
# You do NOT need to copy this config just because it is published here.
# ---------------- WARNING ----------------
WEB: # names are specified as they are written below under "Available Clients".
# This will disable using the WEB client for video playback.
# The below section of the config allows setting specific options for each client, such as the requests they will handle.
# If an option, or client, is unspecified, then the default option value/client values will be used instead.
# If a client is configured, but is not registered above, the options for that client will be ignored.

# WARNING!: THE BELOW CONFIG IS FOR ILLUSTRATION PURPOSES. DO NOT COPY OR USE THIS WITHOUT UNDERSTANDING WHAT IT DOES.
# WARNING!: MISCONFIGURATION WILL HINDER YOUTUBE-SOURCE'S ABILITY TO WORK PROPERLY.

# Write the names of clients as they are specified under the heading "Available Clients".
WEB:
# Example: Disabling a client's playback capabilities.
playback: false
TVHTML5EMBEDDED:
# The below config disables everything except playback for this client.
playlistLoading: false # Disables loading of playlists and mixes for this client.
videoLoading: false # Disables loading of videos for this client (playback is still allowed).
searching: false # Disables the ability to search for videos for this client.
# Example: Configuring a client to exclusively be used for playback.
playlistLoading: false # Disables loading of playlists and mixes.
videoLoading: false # Disables loading of videos for this client (does not affect playback).
searching: false # Disables the ability to search for videos.
```
> [!IMPORTANT]
Expand All @@ -159,32 +158,32 @@ so these don't need changing.
Currently, the following clients are available for use:

- `MUSIC`
- Provides support for searching YouTube music (`ytmsearch:`)
- **This client CANNOT be used to play tracks.** You must also register one of the
below clients for track playback.
- ✔ Provides support for searching YouTube music (`ytmsearch:`).
- ❌ Cannot be used for playback.
- `WEB`
- ✔ Opus formats.
- `ANDROID`
- Usage of this client is no longer advised due to the frequency at which it breaks.
As of the time of writing, this client has been broken by YouTube with no known fix.
- ❌ Heavily restricted, frequently dysfunctional.
- `ANDROID_TESTSUITE`
- This client has restrictions imposed, notably: it does NOT support loading of mixes or playlists,
and it is unable to yield any supported formats when playing livestreams.
It is advised not to use this client on its own for that reason, if those features are required.
- ✔ Opus formats.
- ❌ No mix/playlist/livestream support. Advised to use in conjunction with other clients.
- `ANDROID_LITE`
- This client **does not receive Opus formats** so transcoding is required.
- Similar restrictions to that of `ANDROID_TESTSUITE` except livestreams are playable.
- ❌ No Opus formats (requires transcoding).
- ❌ Restricted similarly to `ANDROID_TESTSUITE` (except livestreams are playable).
- `ANDROID_EMBEDDED`
- ✔ Opus formats.
- ❌ Restrictions currently unknown.
- `ANDROID_MUSIC`
- ✔ Opus formats.
- ❌ Restrictions currently unknown.
- `MEDIA_CONNECT`
- This client **does not receive Opus formats** so transcoding is required.
- This client has restrictions imposed, including but possibly not limited to:
- Unable to load playlists.
- Unable to use search.
- ❌ No Opus formats (requires transcoding).
- ❌ No playlist/search support.
- `IOS`
- This client **does not receive Opus formats**, so transcoding is required. This can
increase resource consumption. It is recommended not to use this client unless it has
the least priority (specified last), or where hardware usage is not a concern.
- ❌ No Opus formats (requires transcoding).
- `TVHTML5EMBEDDED`
- This client is useful for playing age-restricted tracks. Do keep in mind that, even with this
client enabled, age-restricted tracks are **not** guaranteed to play.
- ✔ Opus formats.
- ✔ Age-restricted video playback.

## Migration from Lavaplayer's built-in YouTube source

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package dev.lavalink.youtube.clients;

import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity;
import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterface;
import com.sedmelluq.discord.lavaplayer.track.AudioItem;
import dev.lavalink.youtube.YoutubeAudioSourceManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class AndroidEmbedded extends Android {
public static ClientConfig BASE_CONFIG = new ClientConfig()
.withApiKey(Android.BASE_CONFIG.getApiKey())
.withClientName("ANDROID_EMBEDDED_PLAYER");

public AndroidEmbedded() {
this(ClientOptions.DEFAULT);
}

public AndroidEmbedded(@NotNull ClientOptions options) {
super(options, false);
}

@Override
@NotNull
protected ClientConfig getBaseClientConfig(@NotNull HttpInterface httpInterface) {
return BASE_CONFIG.copy();
}

@Override
@NotNull
public String getIdentifier() {
return BASE_CONFIG.getName();
}

@Override
public boolean canHandleRequest(@NotNull String identifier) {
// loose check to avoid loading mixes/playlists.
return !identifier.contains("list=") && super.canHandleRequest(identifier);
}

@Override
public AudioItem loadMix(@NotNull YoutubeAudioSourceManager source,
@NotNull HttpInterface httpInterface,
@NotNull String mixId,
@Nullable String selectedVideoId) {
// Considered returning null but an exception makes it clearer as to why a mix couldn't be loaded,
// assuming someone tries to only register this client with the source manager.
// Also, an exception will halt further loading so other source managers won't be queried.
// N.B. This client genuinely cannot load mixes for whatever reason. You can get the mix metadata
// but there are no videos in the response JSON. Weird.
throw new FriendlyException("This client cannot load mixes", Severity.COMMON,
new RuntimeException("ANDROID_EMBEDDED cannot be used to load mixes"));
}

@Override
public AudioItem loadPlaylist(@NotNull YoutubeAudioSourceManager source,
@NotNull HttpInterface httpInterface,
@NotNull String playlistId,
@Nullable String selectedVideoId) {
// Similar to mixes except server returns status code 500 when trying to load playlists.
throw new FriendlyException("This client cannot load playlists", Severity.COMMON,
new RuntimeException("ANDROID_EMBEDDED cannot be used to load playlists"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package dev.lavalink.youtube.clients;

import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity;
import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterface;
import com.sedmelluq.discord.lavaplayer.track.AudioItem;
import dev.lavalink.youtube.YoutubeAudioSourceManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class AndroidMusic extends Android {
public static String CLIENT_VERSION = "6.42.52";

public static ClientConfig BASE_CONFIG = new ClientConfig()
.withApiKey(Android.BASE_CONFIG.getApiKey())
.withClientName("ANDROID_MUSIC")
.withClientField("clientVersion", CLIENT_VERSION)
.withUserAgent(String.format("com.google.android.apps.youtube.music/%s (Linux; U; Android %s) gzip", CLIENT_VERSION, ANDROID_VERSION.getOsVersion()));

public AndroidMusic() {
this(ClientOptions.DEFAULT);
}

public AndroidMusic(@NotNull ClientOptions options) {
super(options, false);
}

@Override
@NotNull
protected ClientConfig getBaseClientConfig(@NotNull HttpInterface httpInterface) {
return BASE_CONFIG.copy();
}

@Override
@NotNull
public String getIdentifier() {
return BASE_CONFIG.getName();
}

@Override
public boolean canHandleRequest(@NotNull String identifier) {
// loose check to avoid loading mixes/playlists.
return !identifier.contains("list=") && super.canHandleRequest(identifier);
}

@Override
public AudioItem loadMix(@NotNull YoutubeAudioSourceManager source,
@NotNull HttpInterface httpInterface,
@NotNull String mixId,
@Nullable String selectedVideoId) {
// Considered returning null but an exception makes it clearer as to why a mix couldn't be loaded,
// assuming someone tries to only register this client with the source manager.
// Also, an exception will halt further loading so other source managers won't be queried.
// N.B. This client genuinely cannot load mixes for whatever reason. You can get the mix metadata
// but there are no videos in the response JSON. Weird.
throw new FriendlyException("This client cannot load mixes", Severity.COMMON,
new RuntimeException("ANDROID_MUSIC cannot be used to load mixes"));
}

@Override
public AudioItem loadPlaylist(@NotNull YoutubeAudioSourceManager source,
@NotNull HttpInterface httpInterface,
@NotNull String playlistId,
@Nullable String selectedVideoId) {
// Similar to mixes except server returns status code 500 when trying to load playlists.
throw new FriendlyException("This client cannot load playlists", Severity.COMMON,
new RuntimeException("ANDROID_MUSIC cannot be used to load playlists"));
}
}
2 changes: 2 additions & 0 deletions common/src/main/java/dev/lavalink/youtube/clients/Music.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public ClientConfig getBaseClientConfig(@NotNull HttpInterface httpInterface) {
public String getPlayerParams() {
// This client is not used for format loading so, we don't have
// any player parameters attached to it.
// TODO?: This client *can* do playback, so maybe look into allowing
// this client to be used in playback rotation.
throw new UnsupportedOperationException();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ private enum ClientMapping implements ClientReference {
ANDROID(Android::new),
ANDROID_TESTSUITE(AndroidTestsuite::new),
ANDROID_LITE(AndroidLite::new),
ANDROID_EMBEDDED(AndroidEmbedded::new),
ANDROID_MUSIC(AndroidMusic::new),
IOS(Ios::new),
MUSIC(Music::new),
TVHTML5EMBEDDED(TvHtml5Embedded::new),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ private enum ClientMapping implements ClientReference {
ANDROID(AndroidWithThumbnail::new),
ANDROID_TESTSUITE(AndroidTestsuiteWithThumbnail::new),
ANDROID_LITE(AndroidLiteWithThumbnail::new),
ANDROID_EMBEDDED(AndroidEmbeddedWithThumbnail::new),
ANDROID_MUSIC(AndroidMusicWithThumbnail::new),
IOS(IosWithThumbnail::new),
MUSIC(MusicWithThumbnail::new),
TVHTML5EMBEDDED(TvHtml5EmbeddedWithThumbnail::new),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dev.lavalink.youtube.clients;

import dev.lavalink.youtube.clients.skeleton.NonMusicClientWithThumbnail;
import org.jetbrains.annotations.NotNull;

public class AndroidEmbeddedWithThumbnail extends AndroidEmbedded implements NonMusicClientWithThumbnail {
public AndroidEmbeddedWithThumbnail() {
super();
}

public AndroidEmbeddedWithThumbnail(@NotNull ClientOptions options) {
super(options);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dev.lavalink.youtube.clients;

import dev.lavalink.youtube.clients.skeleton.NonMusicClientWithThumbnail;
import org.jetbrains.annotations.NotNull;

public class AndroidMusicWithThumbnail extends AndroidMusic implements NonMusicClientWithThumbnail {
public AndroidMusicWithThumbnail() {
super();
}

public AndroidMusicWithThumbnail(@NotNull ClientOptions options) {
super(options);
}
}

0 comments on commit f560b48

Please sign in to comment.