Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Made it possible to choose which client to use when sending innertube requests and define new clients #132

Merged
merged 24 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0c7e8d8
fixed downloading with innertube
iexavl Sep 27, 2024
1102dc1
Roughly the idea for enumerating the traits of clients
iexavl Sep 28, 2024
fe0a538
Working example
iexavl Sep 28, 2024
c749065
Revert "Working example"
iexavl Sep 28, 2024
1845543
Example
iexavl Sep 28, 2024
cfe4fbb
Forgot to remove test class
iexavl Sep 28, 2024
cec8e95
Made videoinfo, playlist and search continuation requests use clients…
iexavl Sep 28, 2024
9d53521
ClientType changed from enum to class to make it more user-extensible
iexavl Sep 28, 2024
3346891
Added some more clients and made ANDROID_TV with highest priority for…
iexavl Sep 28, 2024
07d4d37
Made ClientType constructors access modifiers public
iexavl Sep 28, 2024
467b2e5
Added method for directly accessing ClientType body string
iexavl Sep 28, 2024
5faf4d4
Made getter for ClientType name
iexavl Sep 28, 2024
cd5fd0b
reversed wrong ordering for comparator in byPriority
iexavl Sep 28, 2024
a672879
Added IOS and ANDROID_MUSIC and changed highest priority to IOS, beca…
iexavl Sep 28, 2024
aaf53fd
Deleted ClientTraits and replaced all uses in downloader with just Cl…
iexavl Sep 30, 2024
751f090
Added the rest of the clients
iexavl Oct 1, 2024
153f456
Determined default clients
iexavl Oct 1, 2024
9554d17
Added missing Itags
iexavl Oct 3, 2024
c3afd9c
Added more missing Itags
iexavl Oct 3, 2024
534f132
Made getter for arbitrary jsurl when using clients and deciphering is…
iexavl Oct 4, 2024
79a4c03
Reordered clients according to latest test results
iexavl Oct 4, 2024
66c78db
Changed arbitrary video id to one passed to parseVideoAndroid
iexavl Oct 4, 2024
3896426
Moved InvalidJsUrlException to YoutubeException
iexavl Oct 5, 2024
912e1f6
Deleted mysterious video file
iexavl Oct 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/main/java/com/github/kiulian/downloader/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ public Builder proxy(String host, int port, String userName, String password) {
ProxyAuthenticator.addAuthentication(host, port, userName, password);
return this;
}
public Builder proxy(Proxy proxy){
this.proxy=proxy;
return this;
}


public Builder executorService(ExecutorService executorService) {
this.executorService = executorService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,10 @@ public CipherException(String message) {
super(message);
}
}
public static class InvalidJsUrlException extends YoutubeException.CipherException{
public InvalidJsUrlException(String message) {
super(message);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.github.kiulian.downloader.downloader.client;

import com.alibaba.fastjson.JSONObject;

import java.util.Objects;

public class Client{
private final ClientType type;
private final int priority;
Client(ClientType type){
this(type,0);
}
Client(ClientType type,int priority){
this.type=type;
this.priority=priority;

}



public ClientType getType() {
return type;
}

public int getPriority() {
return priority;
}




}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package com.github.kiulian.downloader.downloader.client;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class ClientType {
public static final ClientType WEB = new ClientType("WEB","2.20220918",base_json());
public static final ClientType MWEB = new ClientType("MWEB","2.20220918",base_json());
public static final ClientType ANDROID = new ClientType("ANDROID","17.36.4",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType IOS = new ClientType("IOS","17.36.4",base_json());
public static final ClientType TVHTML5 = new ClientType("TVHTML5","7.20220918",base_json());
public static final ClientType TVLITE = new ClientType("TVLITE","2",base_json());
public static final ClientType TVANDROID = new ClientType("TVANDROID","1.0",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType XBOXONEGUIDE = new ClientType("XBOXONEGUIDE","1.0",base_json());
public static final ClientType ANDROID_CREATOR = new ClientType("ANDROID_CREATOR","22.36.102",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType IOS_CREATOR = new ClientType("IOS_CREATOR","22.36.102",base_json());
public static final ClientType TVAPPLE = new ClientType("TVAPPLE","1.0",base_json());
public static final ClientType ANDROID_KIDS = new ClientType("ANDROID_KIDS","7.36.1",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType IOS_KIDS = new ClientType("IOS_KIDS","7.36.1",base_json());
public static final ClientType ANDROID_MUSIC = new ClientType("ANDROID_MUSIC","5.26.1",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType ANDROID_TV = new ClientType("ANDROID_TV","2.19.1.303051424",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType IOS_MUSIC = new ClientType("IOS_MUSIC","5.26.1",base_json());
public static final ClientType MWEB_TIER_2 = new ClientType("MWEB_TIER_2","9.20220918",base_json());
public static final ClientType ANDROID_VR = new ClientType("ANDROID_VR","1.37",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType ANDROID_UNPLUGGED = new ClientType("ANDROID_UNPLUGGED","6.36",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType ANDROID_TESTSUITE = new ClientType("ANDROID_TESTSUITE","1.9",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType WEB_MUSIC_ANALYTICS = new ClientType("WEB_MUSIC_ANALYTICS","0.2",base_json());
public static final ClientType IOS_UNPLUGGED = new ClientType("IOS_UNPLUGGED","6.36",base_json());
public static final ClientType ANDROID_LITE = new ClientType("ANDROID_LITE","3.26.1",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType IOS_EMBEDDED_PLAYER = new ClientType("IOS_EMBEDDED_PLAYER","2.4",base_json());
public static final ClientType WEB_UNPLUGGED = new ClientType("WEB_UNPLUGGED","1.20220918",base_json());
public static final ClientType WEB_EXPERIMENTS = new ClientType("WEB_EXPERIMENTS","1",base_json());
public static final ClientType TVHTML5_CAST = new ClientType("TVHTML5_CAST","1.1",base_json());
public static final ClientType ANDROID_EMBEDDED_PLAYER = new ClientType("ANDROID_EMBEDDED_PLAYER","17.36.4",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType WEB_EMBEDDED_PLAYER = new ClientType("WEB_EMBEDDED_PLAYER","9.20220918",base_json());
public static final ClientType TVHTML5_AUDIO = new ClientType("TVHTML5_AUDIO","2.0",base_json());
public static final ClientType TV_UNPLUGGED_CAST = new ClientType("TV_UNPLUGGED_CAST","0.1",base_json());
public static final ClientType TVHTML5_KIDS = new ClientType("TVHTML5_KIDS","3.20220918",base_json());
public static final ClientType WEB_HEROES = new ClientType("WEB_HEROES","0.1",base_json());
public static final ClientType WEB_MUSIC = new ClientType("WEB_MUSIC","1.0",base_json());
public static final ClientType WEB_CREATOR = new ClientType("WEB_CREATOR","1.20220918",base_json());
public static final ClientType TV_UNPLUGGED_ANDROID = new ClientType("TV_UNPLUGGED_ANDROID","1.37",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType IOS_LIVE_CREATION_EXTENSION = new ClientType("IOS_LIVE_CREATION_EXTENSION","17.36.4",base_json());
public static final ClientType TVHTML5_UNPLUGGED = new ClientType("TVHTML5_UNPLUGGED","6.36",base_json());
public static final ClientType IOS_MESSAGES_EXTENSION = new ClientType("IOS_MESSAGES_EXTENSION","17.36.4",base_json());
public static final ClientType WEB_REMIX = new ClientType("WEB_REMIX","1.20220918",base_json());
public static final ClientType IOS_UPTIME = new ClientType("IOS_UPTIME","1.0",base_json());
public static final ClientType WEB_UNPLUGGED_ONBOARDING = new ClientType("WEB_UNPLUGGED_ONBOARDING","0.1",base_json());
public static final ClientType WEB_UNPLUGGED_OPS = new ClientType("WEB_UNPLUGGED_OPS","0.1",base_json());
public static final ClientType WEB_UNPLUGGED_PUBLIC = new ClientType("WEB_UNPLUGGED_PUBLIC","0.1",base_json());
public static final ClientType TVHTML5_VR = new ClientType("TVHTML5_VR","0.1",base_json());
public static final ClientType ANDROID_TV_KIDS = new ClientType("ANDROID_TV_KIDS","1.19.1",base_json(),queryParam("context/client","androidSdkVersion","30"));
public static final ClientType TVHTML5_SIMPLY = new ClientType("TVHTML5_SIMPLY","1.0",base_json());
public static final ClientType WEB_KIDS = new ClientType("WEB_KIDS","2.20220918",base_json());
public static final ClientType MUSIC_INTEGRATIONS = new ClientType("MUSIC_INTEGRATIONS","0.1",base_json());
public static final ClientType TVHTML5_YONGLE = new ClientType("TVHTML5_YONGLE","0.1",base_json());
public static final ClientType GOOGLE_ASSISTANT = new ClientType("GOOGLE_ASSISTANT","0.1",base_json());
public static final ClientType TVHTML5_SIMPLY_EMBEDDED_PLAYER = new ClientType("TVHTML5_SIMPLY_EMBEDDED_PLAYER","2.0",base_json());
public static final ClientType WEB_INTERNAL_ANALYTICS = new ClientType("WEB_INTERNAL_ANALYTICS","0.1",base_json());
public static final ClientType WEB_PARENT_TOOLS = new ClientType("WEB_PARENT_TOOLS","1.20220918",base_json());
public static final ClientType GOOGLE_MEDIA_ACTIONS = new ClientType("GOOGLE_MEDIA_ACTIONS","0.1",base_json());
public static final ClientType WEB_PHONE_VERIFICATION = new ClientType("WEB_PHONE_VERIFICATION","1.0.0",base_json());
public static final ClientType IOS_PRODUCER = new ClientType("IOS_PRODUCER","0.1",base_json());
public static final ClientType TVHTML5_FOR_KIDS = new ClientType("TVHTML5_FOR_KIDS","7.20220918",base_json());
public static final ClientType GOOGLE_LIST_RECS = new ClientType("GOOGLE_LIST_RECS","0.1",base_json());
public static final ClientType MEDIA_CONNECT_FRONTEND = new ClientType("MEDIA_CONNECT_FRONTEND","0.1",base_json());


private final String body;
private final String version;
private final String name;
public ClientType(String name, String version, JSONObject body, QueryParameter... parameters){
this.name =name;
this.version=version;
JSONObject client = body.getJSONObject("context").getJSONObject("client");
client.fluentPut("clientName",name);
client.fluentPut("clientVersion",version);
JSONObject cur=body;
for (QueryParameter param:parameters) {
for (String p:param.path) {
cur=cur.getJSONObject(p);
}
cur.fluentPut(param.key,param.value);

}
this.body = body.toJSONString();

}
public ClientType(String name, String version, JSONObject body){
this.name=name;
this.version=version;
JSONObject client = body.getJSONObject("context").getJSONObject("client");
client.fluentPut("clientName",name);
client.fluentPut("clientVersion",version);
this.body = body.toJSONString();

}
public String getVersion() {
return version;
}
public String getName(){return name;}
public String getBodyString(){return body;}
public JSONObject getBody() {
return JSON.parseObject(body);
}
public static JSONObject base_json(){
/*
{
"context": {
"client": {
"hl": "en",
"gl": "US"
}
}
}
*/
JSONObject client = new JSONObject().fluentPut("hl", "en").fluentPut("gl", "US");
JSONObject context = new JSONObject().fluentPut("client", client);
return new JSONObject().fluentPut("context", context);
}
public static QueryParameter queryParam(String path, String key, String value){
return new QueryParameter(path,key,value);
}
public static QueryParameter queryParam(String key, String value){
return new QueryParameter(key,value);
}
public static class QueryParameter{
final String[] path;
final String value;
final String key;
QueryParameter(String path,String key,String value){
this.path=path.split("/");
this.value=value;
this.key=key;
}
QueryParameter(String key,String value){
this("",key,value);

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package com.github.kiulian.downloader.downloader.client;

import com.github.kiulian.downloader.model.videos.formats.Itag;
import com.github.kiulian.downloader.model.videos.quality.AudioQuality;
import com.github.kiulian.downloader.model.videos.quality.VideoQuality;

import java.lang.reflect.Field;
import java.util.*;

public class Clients {


private static final SortedSet<Client> defaultClients;
private static Client HIGHEST_PRIORITY_CLIENT;
private static final int MANUALLY_DETERMINED_PRIORITY= Integer.MAX_VALUE;




static{
Comparator<Client> comparator = ((Comparator<Client>) (o1, o2) -> {
if (o1.getType() == o2.getType()) {
return 0;
}
int res = Integer.compare(o1.getPriority(), o2.getPriority());
return res == 0 ? 1 : res;


}).reversed();
SortedSet<Client> clientSet = new TreeSet<Client>(comparator){
@Override
public boolean add(Client client) {
if(HIGHEST_PRIORITY_CLIENT==null ||client.getPriority() > HIGHEST_PRIORITY_CLIENT.getPriority()){
HIGHEST_PRIORITY_CLIENT=client;
}
return super.add(client);
}
};



clientSet.add(new Client(ClientType.WEB_HEROES,59));
clientSet.add(new Client(ClientType.TVHTML5_VR,58));
clientSet.add(new Client(ClientType.WEB_MUSIC_ANALYTICS,57));
clientSet.add(new Client(ClientType.ANDROID_VR,MANUALLY_DETERMINED_PRIORITY));
clientSet.add(new Client(ClientType.WEB_MUSIC,55));
clientSet.add(new Client(ClientType.WEB,54));
clientSet.add(new Client(ClientType.TVHTML5_SIMPLY,53));
clientSet.add(new Client(ClientType.MWEB,52));
clientSet.add(new Client(ClientType.WEB_REMIX,51));
clientSet.add(new Client(ClientType.TVHTML5,50));
clientSet.add(new Client(ClientType.TVHTML5_CAST,49));
clientSet.add(new Client(ClientType.GOOGLE_LIST_RECS,48));
clientSet.add(new Client(ClientType.IOS_EMBEDDED_PLAYER,47));
clientSet.add(new Client(ClientType.ANDROID_TV,46));
clientSet.add(new Client(ClientType.IOS_MESSAGES_EXTENSION,45));
clientSet.add(new Client(ClientType.ANDROID_EMBEDDED_PLAYER,44));
clientSet.add(new Client(ClientType.IOS_LIVE_CREATION_EXTENSION,43));
clientSet.add(new Client(ClientType.WEB_PHONE_VERIFICATION,42));
clientSet.add(new Client(ClientType.IOS_PRODUCER,41));
clientSet.add(new Client(ClientType.WEB_EXPERIMENTS,40));
clientSet.add(new Client(ClientType.TVANDROID,39));
clientSet.add(new Client(ClientType.MWEB_TIER_2,38));
clientSet.add(new Client(ClientType.MUSIC_INTEGRATIONS,37));
clientSet.add(new Client(ClientType.MEDIA_CONNECT_FRONTEND,36));
clientSet.add(new Client(ClientType.IOS,35));
clientSet.add(new Client(ClientType.TVHTML5_YONGLE,34));
clientSet.add(new Client(ClientType.GOOGLE_ASSISTANT,33));
clientSet.add(new Client(ClientType.XBOXONEGUIDE,32));
clientSet.add(new Client(ClientType.WEB_INTERNAL_ANALYTICS,31));
clientSet.add(new Client(ClientType.GOOGLE_MEDIA_ACTIONS,30));
clientSet.add(new Client(ClientType.WEB_PARENT_TOOLS,29));
clientSet.add(new Client(ClientType.IOS_MUSIC,28));
clientSet.add(new Client(ClientType.ANDROID_MUSIC,27));
clientSet.add(new Client(ClientType.WEB_CREATOR,26));
clientSet.add(new Client(ClientType.IOS_CREATOR,25));
clientSet.add(new Client(ClientType.ANDROID_CREATOR,24));
clientSet.add(new Client(ClientType.ANDROID_LITE,23));
clientSet.add(new Client(ClientType.TVAPPLE,22));
clientSet.add(new Client(ClientType.TVLITE,21));
clientSet.add(new Client(ClientType.WEB_EMBEDDED_PLAYER,20));
clientSet.add(new Client(ClientType.TVHTML5_SIMPLY_EMBEDDED_PLAYER,19));
clientSet.add(new Client(ClientType.WEB_UNPLUGGED_OPS,18));
clientSet.add(new Client(ClientType.WEB_UNPLUGGED,17));
clientSet.add(new Client(ClientType.WEB_UNPLUGGED_ONBOARDING,16));
clientSet.add(new Client(ClientType.TV_UNPLUGGED_CAST,15));
clientSet.add(new Client(ClientType.TVHTML5_UNPLUGGED,14));
clientSet.add(new Client(ClientType.ANDROID_UNPLUGGED,13));
clientSet.add(new Client(ClientType.TV_UNPLUGGED_ANDROID,12));
clientSet.add(new Client(ClientType.WEB_UNPLUGGED_PUBLIC,11));
clientSet.add(new Client(ClientType.IOS_UNPLUGGED,10));
clientSet.add(new Client(ClientType.IOS_UPTIME,9));
clientSet.add(new Client(ClientType.IOS_KIDS,8));
clientSet.add(new Client(ClientType.ANDROID_TV_KIDS,7));
clientSet.add(new Client(ClientType.TVHTML5_AUDIO,6));
clientSet.add(new Client(ClientType.TVHTML5_FOR_KIDS,5));
clientSet.add(new Client(ClientType.ANDROID_KIDS,4));
clientSet.add(new Client(ClientType.TVHTML5_KIDS,3));
clientSet.add(new Client(ClientType.WEB_KIDS,2));
clientSet.add(new Client(ClientType.ANDROID,1));
clientSet.add(new Client(ClientType.ANDROID_TESTSUITE,0));



defaultClients= Collections.unmodifiableSortedSet(clientSet);



}

/**Gets a list of all the default clients.
* @return an unmodifiable sorted set of all pre-initialized clients ordered by their priority.
* The priority of a client is generally determined by its reliability, although said reliability has a
* volatile nature and a given client can, at any time, become unreliable.*/
public static SortedSet<Client> defaultClients(){
return defaultClients;
}
public static ClientType highestPriorityClient(){
return HIGHEST_PRIORITY_CLIENT.getType();
}






}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.github.kiulian.downloader.downloader.request;

import com.github.kiulian.downloader.downloader.YoutubeCallback;
import com.github.kiulian.downloader.downloader.client.Client;
import com.github.kiulian.downloader.downloader.client.ClientType;
import com.github.kiulian.downloader.downloader.client.Clients;
import com.github.kiulian.downloader.downloader.proxy.ProxyAuthenticator;
import com.github.kiulian.downloader.downloader.proxy.ProxyCredentialsImpl;

Expand All @@ -15,6 +18,7 @@ public abstract class Request<T extends Request<T, S>, S> {
private boolean async;
private Integer maxRetries;
private Proxy proxy;
private ClientType client = Clients.highestPriorityClient();

public T proxy(String host, int port) {
this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
Expand Down Expand Up @@ -72,4 +76,12 @@ public T async() {
public boolean isAsync() {
return async;
}

public T client(ClientType client){
this.client=client;
return (T) this;
}
public ClientType getClient(){
return client;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,25 @@ public void setId(int id) {
i400(VideoQuality.hd1440),
i401(VideoQuality.hd2160),
i402(VideoQuality.hd2880p),
i571(VideoQuality.ultrahighres)
;
i571(VideoQuality.ultrahighres),

i597(VideoQuality.tiny),//avc1
i598(VideoQuality.tiny),//vp9
i599(AudioQuality.low), //mp4a
i600(AudioQuality.low), // audio webm opus

// av01 video only formats
i694(VideoQuality.tiny),
i695(VideoQuality.small),
i696(VideoQuality.medium),
i697(VideoQuality.large),
i698(VideoQuality.hd720),
i699(VideoQuality.hd1080),
i700(VideoQuality.hd1440),
i701(VideoQuality.hd2160),
//vp9
i779(VideoQuality.large),
i780(VideoQuality.large);

protected int id;
private VideoQuality videoQuality;
Expand Down
Loading