Ditched external server calls & made the app show all playlist items and not first 50 videos

pull/1/head v1.0.1
Denis Çerri 4 years ago
parent 217c0f431f
commit 9230185930
No known key found for this signature in database
GPG Key ID: 3F50F14A8E7F7A13

@ -23,10 +23,13 @@
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/drawable/ic_launcher_background.xml" value="0.1275" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/drawable/ic_music.xml" value="0.1275" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/drawable/ic_search.xml" value="0.1275" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/drawable/round_corner.xml" value="0.1275" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/layout/activity_main.xml" value="0.27704147071398033" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/layout/download_all_card.xml" value="0.33" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/layout/fragment_history.xml" value="0.2057460611677479" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/layout/fragment_history_list.xml" value="0.2057460611677479" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/layout/fragment_home.xml" value="0.2057460611677479" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/layout/result_card.xml" value="0.25" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/menu/bottom_nav_menu.xml" value="0.2057460611677479" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/menu/history_menu.xml" value="0.25" />
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/menu/main_menu.xml" value="0.2057460611677479" />

2
app/.gitignore vendored

@ -1 +1 @@
/build
/build

@ -1,4 +1,8 @@
apply plugin: 'com.android.application'
plugins {
id 'com.android.application'
id 'com.google.secrets_gradle_plugin' version '0.4'
}
android {
compileSdkVersion 31
@ -43,7 +47,6 @@ android {
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

@ -28,6 +28,11 @@
</intent-filter>
</activity>
<meta-data
android:name = "ytAPIkey"
android:value = "${ytAPI}"
/>
</application>
</manifest>

@ -27,29 +27,23 @@ import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.SearchView;
import androidx.cardview.widget.CardView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import com.deniscerri.ytdl.api.YoutubeAPIManager;
import com.deniscerri.ytdl.database.DBManager;
import com.deniscerri.ytdl.database.Video;
import com.squareup.picasso.Picasso;
import com.yausername.youtubedl_android.DownloadProgressCallback;
import com.yausername.youtubedl_android.YoutubeDL;
import com.yausername.youtubedl_android.YoutubeDLRequest;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -68,11 +62,7 @@ import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
/**
* A simple {@link Fragment} subclass.
* Use the {@link HomeFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class HomeFragment extends Fragment implements View.OnClickListener{
private boolean downloading = false;
@ -82,9 +72,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
private LinearLayout linearLayout;
private ScrollView scrollView;
private JSONObject requestData;
private String videoID;
private static final String TAG = "HomeFragment";
private ArrayList<Video> resultObjects;
@ -94,6 +81,7 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private DBManager dbManager;
private YoutubeAPIManager youtubeAPIManager;
private final DownloadProgressCallback callback = new DownloadProgressCallback() {
@Override
@ -110,6 +98,7 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
public HomeFragment() {
// Required empty public constructor
}
@ -139,6 +128,7 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
// Inflate the layout for this fragment
fragmentView = inflater.inflate(R.layout.fragment_home, container, false);
initViews();
fragmentView.setOnScrollChangeListener((view, i, i1, i2, i3) -> positions = new int[]{i,i1});
@ -167,7 +157,7 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
}
private void initViews() {
private void initViews(){
linearLayout = fragmentView.findViewById(R.id.linearLayout1);
scrollView = fragmentView.findViewById(R.id.scrollView1);
}
@ -228,11 +218,16 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
inputQuery = intent.getStringExtra(Intent.EXTRA_TEXT);
}
public void scrollToTop(){
fragmentView.scrollTo(0,0);
}
private void parseQuery() {
linearLayout.removeAllViews();
resultObjects = new ArrayList<>();
dbManager = new DBManager(requireContext());
youtubeAPIManager = new YoutubeAPIManager(requireContext());
String type = "Search";
Pattern p = Pattern.compile("^(https?)://(www.)?youtu(.be)?");
@ -240,7 +235,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
if(m.find()){
type = "Video";
if (inputQuery.contains("list=")) {
type = "Playlist";
}
@ -253,29 +247,16 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
case "Search": {
Thread thread = new Thread(() -> {
try {
requestData = makeRequest("https://ytdl.deniscerri.repl.co/search?Query=" + inputQuery);
resultObjects = youtubeAPIManager.search(inputQuery);
}catch(Exception e){
Log.e(TAG, e.toString());
}
});
thread.start();
thread.join();
JSONArray dataArray = requestData.getJSONArray("items");
for(int i = 0; i < dataArray.length(); i++){
JSONObject element = dataArray.getJSONObject(i);
JSONObject snippet = element.getJSONObject("snippet");
if(element.getJSONObject("id").getString("kind").equals("youtube#video")){
videoID = element.getJSONObject("id").getString("videoId");
snippet.put("videoID", videoID);
snippet = fixThumbnail(snippet);
Video video = createVideofromJSON(snippet);
resultObjects.add(video);
createCard(video);
}
for(int i = 0; i < resultObjects.size(); i++){
createCard(resultObjects.get(i));
}
dbManager.shtoVideoRezultat(resultObjects);
break;
}case "Video": {
@ -288,28 +269,22 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
Thread thread = new Thread(() -> {
try {
requestData = makeRequest("https://ytdl.deniscerri.repl.co/video?id=" + inputQuery).getJSONArray("items").getJSONObject(0);
videoID = requestData.getString("id");
requestData = requestData.getJSONObject("snippet");
requestData.put("videoID", videoID);
resultObjects.add(youtubeAPIManager.getVideo(inputQuery));
}catch(Exception e){
Log.e(TAG, e.toString());
}
});
thread.start();
thread.join();
requestData = fixThumbnail(requestData);
Video video = createVideofromJSON(requestData);
resultObjects.add(video);
dbManager.shtoVideoRezultat(resultObjects);
createCard(video);
createCard(resultObjects.get(0));
break;
}case "Playlist": {
inputQuery = inputQuery.split("list=")[1];
Thread thread = new Thread(() -> {
try {
requestData = makeRequest("https://ytdl.deniscerri.repl.co/ytPlaylist?id=" + inputQuery);
resultObjects = youtubeAPIManager.getPlaylist(inputQuery, "");
}catch(Exception e){
Log.e(TAG, e.toString());
}
@ -317,20 +292,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
thread.start();
thread.join();
JSONArray dataArray = requestData.getJSONArray("items");
for(int i = 0; i < dataArray.length(); i++){
JSONObject element = dataArray.getJSONObject(i);
JSONObject snippet = element.getJSONObject("snippet");
if(snippet.getJSONObject("resourceId").getString("kind").equals("youtube#video")){
videoID = snippet.getJSONObject("resourceId").getString("videoId");
snippet.put("videoID", videoID);
snippet = fixThumbnail(snippet);
Video video = createVideofromJSON(snippet);
video.setIsPlaylistItem(1);
resultObjects.add(video);
}
}
dbManager.shtoVideoRezultat(resultObjects);
// DOWNLOAD ALL BUTTON
@ -350,20 +311,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
}
private Video createVideofromJSON(JSONObject obj){
Video video = null;
try{
String id = obj.getString("videoID");
String title = obj.getString("title");
String author = obj.getString("channelTitle");
String thumb = obj.getString("thumb");
video = new Video(id, title, author, thumb);
}catch(Exception ignored){}
return video;
}
private void createDownloadAllCard(){
RelativeLayout r = new RelativeLayout(getContext());
r.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
@ -429,63 +376,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
}
private JSONObject fixThumbnail(JSONObject o){
String imageURL = "";
try{
JSONObject thumbs = o.getJSONObject("thumbnails");
imageURL = thumbs.getJSONObject("maxres").getString("url");
}catch(Exception e){
try {
JSONObject thumbs = o.getJSONObject("thumbnails");
imageURL = thumbs.getJSONObject("high").getString("url");
}catch(Exception ignored){}
}
try{
o.put("thumb", imageURL);
}catch(Exception ignored){}
return o;
}
private JSONObject makeRequest(String query){
Log.e(TAG, query);
BufferedReader reader;
String line;
StringBuilder responseContent = new StringBuilder();
HttpURLConnection conn;
JSONObject json = new JSONObject();
try{
URL url = new URL(query);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(10000);
conn.setReadTimeout(5000);
if(conn.getResponseCode() < 300){
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while((line = reader.readLine()) != null){
responseContent.append(line);
}
json = new JSONObject(responseContent.toString());
if(json.has("error")){
throw new Exception();
}
}
}catch(Exception e){
Log.e(TAG, e.toString());
}
return json;
}
private int getDp(int value){
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics());
}
@ -521,14 +411,18 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
// TITLE ----------------------------------
TextView videoTitle = new TextView(getContext());
videoTitle.setLayoutParams(new RelativeLayout.LayoutParams(getDp(300), getDp(100)));
videoTitle.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, getDp(100)));
int padding = getDp(20);
videoTitle.setPadding(padding, padding, padding, padding);
String title = video.getTitle();
title = title.replace("&amp;", "&").replace("&quot;", "\"");
if(title.length() > 50){
title = title.substring(0, 40) + "...";
}
videoTitle.setText(title);
videoTitle.setTextSize(getSp(5));
videoTitle.setTextColor(ContextCompat.getColor(requireContext(), R.color.white));
@ -620,7 +514,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
}
@Override
public void onClick(View v) {
//do what you want to do when button is clicked

@ -82,6 +82,9 @@ public class MainActivity extends AppCompatActivity{
binding.bottomNavigationView.setOnItemSelectedListener(item -> {
switch(item.getItemId()){
case R.id.home:
if(lastFragment == homeFragment){
homeFragment.scrollToTop();
}
replaceFragment(homeFragment);
break;
case R.id.history:

@ -0,0 +1,191 @@
package com.deniscerri.ytdl.api;
import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;
import android.widget.Toast;
import com.deniscerri.ytdl.database.Video;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Array;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
public class YoutubeAPIManager {
private static final String TAG = "API MANAGER";
private ArrayList<Video> videos;
private String key;
Properties properties = new Properties();
public YoutubeAPIManager(Context context) {
AssetManager assetManager = context.getAssets();
try{
InputStream inputStream = assetManager.open("config.properties");
properties.load(inputStream);
key = properties.getProperty("ytAPI");
}catch(Exception ignored){
Toast.makeText(context, "Couldn't find API Key for the request", Toast.LENGTH_SHORT).show();
}
videos = new ArrayList<>();
}
public ArrayList<Video> search(String query) throws JSONException{
JSONObject res = genericRequest("https://youtube.googleapis.com/youtube/v3/search?part=snippet&q="+query+"&maxResults=25&regionCode=US&key="+key);
JSONArray dataArray = res.getJSONArray("items");
for(int i = 0; i < dataArray.length(); i++){
JSONObject element = dataArray.getJSONObject(i);
JSONObject snippet = element.getJSONObject("snippet");
if(element.getJSONObject("id").getString("kind").equals("youtube#video")){
snippet.put("videoID", element.getJSONObject("id").getString("videoId"));
snippet = fixThumbnail(snippet);
Video v = createVideofromJSON(snippet);
v.setTitle(v.getTitle().replace("&amp;", "&").replace("&quot;", "\""));
v.setAuthor(v.getAuthor().replace("&amp;", "&").replace("&quot;", "\""));
videos.add(createVideofromJSON(snippet));
}
}
return videos;
}
public ArrayList<Video> getPlaylist(String id, String nextPageToken) throws JSONException{
String url = "https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet&pageToken="+nextPageToken+"&maxResults=50&playlistId="+id+"&key="+key;
JSONObject res = genericRequest(url);
JSONArray dataArray = res.getJSONArray("items");
for(int i = 0; i < dataArray.length(); i++){
JSONObject element = dataArray.getJSONObject(i);
JSONObject snippet = element.getJSONObject("snippet");
if(snippet.getJSONObject("resourceId").getString("kind").equals("youtube#video")){
snippet.put("videoID", snippet.getJSONObject("resourceId").getString("videoId"));
snippet = fixThumbnail(snippet);
Video v = createVideofromJSON(snippet);
if(v.getThumb().isEmpty()){
continue;
}
v.setIsPlaylistItem(1);
v.setTitle(v.getTitle().replace("&amp;", "&").replace("&quot;", "\""));
v.setAuthor(v.getAuthor().replace("&amp;", "&").replace("&quot;", "\""));
videos.add(v);
}
}
String next = res.optString("nextPageToken");
if(next != ""){
ArrayList<Video> nextPage = getPlaylist(id,next);
}
return videos;
}
public Video getVideo(String id) throws JSONException {
JSONObject res = genericRequest("https://youtube.googleapis.com/youtube/v3/videos?part=snippet&id="+id+"&key="+key);
res = res.getJSONObject("snippet");
res.put("videoID", res.getString("id"));
res = fixThumbnail(res);
Video v = createVideofromJSON(res);
v.setTitle(v.getTitle().replace("&amp;", "&").replace("&quot;", "\""));
v.setAuthor(v.getAuthor().replace("&amp;", "&").replace("&quot;", "\""));
return v;
}
private Video createVideofromJSON(JSONObject obj){
Video video = null;
try{
String id = obj.getString("videoID");
String title = obj.getString("title");
String author = obj.getString("channelTitle");
String thumb = obj.getString("thumb");
video = new Video(id, title, author, thumb);
}catch(Exception ignored){}
return video;
}
private JSONObject genericRequest(String url){
Log.e(TAG, url);
BufferedReader reader;
String line;
StringBuilder responseContent = new StringBuilder();
HttpURLConnection conn;
JSONObject json = new JSONObject();
try{
URL req = new URL(url);
conn = (HttpURLConnection) req.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(10000);
conn.setReadTimeout(5000);
if(conn.getResponseCode() < 300){
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while((line = reader.readLine()) != null){
responseContent.append(line);
}
json = new JSONObject(responseContent.toString());
if(json.has("error")){
throw new Exception();
}
}
}catch(Exception e){
Log.e(TAG, e.toString());
}
return json;
}
private JSONObject fixThumbnail(JSONObject o){
String imageURL = "";
try{
JSONObject thumbs = o.getJSONObject("thumbnails");
imageURL = thumbs.getJSONObject("maxres").getString("url");
}catch(Exception e){
try {
JSONObject thumbs = o.getJSONObject("thumbnails");
imageURL = thumbs.getJSONObject("high").getString("url");
}catch(Exception u){
try{
JSONObject thumbs = o.getJSONObject("thumbnails");
imageURL = thumbs.getJSONObject("default").getString("url");
}catch(Exception ignored){}
}
}
try{
o.put("thumb", imageURL);
}catch(Exception ignored){}
return o;
}
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#33DDFF" />
<corners android:radius="10dp" />
</shape>

@ -14,6 +14,10 @@
android:layout_height="wrap_content"
android:id="@+id/linearLayout1"
android:layout_margin="10dp"
android:orientation="vertical" />
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
Loading…
Cancel
Save