App finalization
Version 1.0.0 - Added delete history in history fragment - Stored every search result in a database so that you can see them even after app is closed - Fixed bad directory path text by converting it to UTF-8 - Made the app download the whole playlist - Made the app keep track of songs that have already been downloaded by showing the finished progress bar on them if the fragment gets reloaded - Fixed metadata on music files by adding thumbnail and proper metadata on author and title by using tags
This commit is contained in:
parent
0ef8f5bf7b
commit
8d178f6f1b
10 changed files with 386 additions and 103 deletions
|
|
@ -19,12 +19,15 @@
|
|||
<entry key="..\:/Users/denis/Desktop/youtubedl-android-0.13.1/youtubedl-android-0.13.1/app/src/main/res/menu/bottom_nav_menu.xml" value="0.2675925925925926" />
|
||||
<entry key="..\:/Users/denis/Desktop/youtubedl-android-0.13.1/youtubedl-android-0.13.1/app/src/main/res/menu/main_menu.xml" value="0.28888888888888886" />
|
||||
<entry key="..\:/Users/denis/Desktop/youtubedl-android-0.13.1/youtubedl-android-0.13.1/app/src/main/res/xml/root_preferences.xml" value="0.33" />
|
||||
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.1275" />
|
||||
<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/layout/activity_main.xml" value="0.27704147071398033" />
|
||||
<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/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" />
|
||||
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/xml/root_preferences.xml" value="0.33" />
|
||||
<entry key="..\:/Users/denis/Desktop/ytdlnis/ytdlnis/app/src/main/res/xml/shortcuts.xml" value="0.13852073535699017" />
|
||||
|
|
|
|||
|
|
@ -5,16 +5,24 @@ import android.graphics.PorterDuff;
|
|||
import android.graphics.Typeface;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import android.text.InputType;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
|
@ -51,7 +59,7 @@ public class HistoryFragment extends Fragment {
|
|||
|
||||
// TODO: Customize parameter initialization
|
||||
@SuppressWarnings("unused")
|
||||
public static HistoryFragment newInstance(int columnCount) {
|
||||
public static HistoryFragment newInstance() {
|
||||
HistoryFragment fragment = new HistoryFragment();
|
||||
Bundle args = new Bundle();
|
||||
return fragment;
|
||||
|
|
@ -71,7 +79,7 @@ public class HistoryFragment extends Fragment {
|
|||
initViews();
|
||||
|
||||
dbManager = new DBManager(requireContext());
|
||||
historyObjects = dbManager.merrVideot();
|
||||
historyObjects = dbManager.merrHistorine();
|
||||
|
||||
System.out.println(historyObjects);
|
||||
|
||||
|
|
@ -200,4 +208,23 @@ public class HistoryFragment extends Fragment {
|
|||
linearLayout = fragmentView.findViewById(R.id.linearLayout1);
|
||||
scrollView = fragmentView.findViewById(R.id.scrollView1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
||||
inflater.inflate(R.menu.history_menu, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.delete_history:
|
||||
dbManager.clearHistory();
|
||||
linearLayout.removeAllViews();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,14 +5,13 @@ import android.app.Activity;
|
|||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Typeface;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
|
@ -21,7 +20,6 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
|
|
@ -31,23 +29,20 @@ import android.widget.TextView;
|
|||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
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 androidx.preference.PreferenceManager;
|
||||
|
||||
import com.deniscerri.ytdl.database.DBManager;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
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.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
|
@ -57,11 +52,12 @@ import java.net.HttpURLConnection;
|
|||
import java.net.URL;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Locale;
|
||||
import java.util.Queue;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
|
@ -91,8 +87,11 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
|
||||
private static final String TAG = "HomeFragment";
|
||||
|
||||
private ArrayList<JSONObject> resultObjects;
|
||||
private ArrayList<Video> resultObjects;
|
||||
private Queue<Video> downloadQueue;
|
||||
private boolean hasResults = false;
|
||||
private boolean isPlaylist = false;
|
||||
private boolean downloadAll = false;
|
||||
private int[] positions = {0,0};
|
||||
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
|
@ -144,8 +143,14 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
|
||||
fragmentView.setOnScrollChangeListener((view, i, i1, i2, i3) -> positions = new int[]{i,i1});
|
||||
|
||||
if(hasResults){
|
||||
dbManager = new DBManager(requireContext());
|
||||
resultObjects = dbManager.merrRezultatet();
|
||||
|
||||
if(resultObjects != null){
|
||||
scrollView.post(() -> scrollView.scrollTo(positions[0], positions[1]));
|
||||
if(resultObjects.size() > 1 && resultObjects.get(1).getIsPlaylistItem() == 1){
|
||||
createDownloadAllCard();
|
||||
}
|
||||
for(int i = 0; i < resultObjects.size(); i++){
|
||||
createCard(resultObjects.get(i));
|
||||
}
|
||||
|
|
@ -205,7 +210,9 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
|
||||
private void parseQuery() {
|
||||
linearLayout.removeAllViews();
|
||||
|
||||
resultObjects = new ArrayList<>();
|
||||
dbManager = new DBManager(requireContext());
|
||||
|
||||
String type = "Search";
|
||||
Pattern p = Pattern.compile("^(https?)://(www.)?youtu(.be)?");
|
||||
|
|
@ -216,6 +223,7 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
|
||||
if (inputQuery.contains("list=")) {
|
||||
type = "Playlist";
|
||||
isPlaylist = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -244,10 +252,13 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
videoID = element.getJSONObject("id").getString("videoId");
|
||||
snippet.put("videoID", videoID);
|
||||
snippet = fixThumbnail(snippet);
|
||||
resultObjects.add(snippet);
|
||||
createCard(snippet);
|
||||
Video video = createVideofromJSON(snippet);
|
||||
resultObjects.add(video);
|
||||
createCard(video);
|
||||
}
|
||||
}
|
||||
|
||||
dbManager.shtoVideoRezultat(resultObjects);
|
||||
break;
|
||||
}case "Video": {
|
||||
String[] el = inputQuery.split("/");
|
||||
|
|
@ -271,9 +282,11 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
thread.join();
|
||||
|
||||
hasResults = true;
|
||||
resultObjects.add(requestData);
|
||||
requestData = fixThumbnail(requestData);
|
||||
createCard(requestData);
|
||||
Video video = createVideofromJSON(requestData);
|
||||
resultObjects.add(video);
|
||||
dbManager.shtoVideoRezultat(resultObjects);
|
||||
createCard(video);
|
||||
break;
|
||||
}case "Playlist": {
|
||||
inputQuery = inputQuery.split("list=")[1];
|
||||
|
|
@ -287,25 +300,118 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
thread.start();
|
||||
thread.join();
|
||||
|
||||
|
||||
JSONArray dataArray = requestData.getJSONArray("items");
|
||||
hasResults = true;
|
||||
for(int i = 0; i < dataArray.length(); i++){
|
||||
JSONObject element = dataArray.getJSONObject(i);
|
||||
JSONObject snippet = element.getJSONObject("snippet");
|
||||
videoID = element.getString("id");
|
||||
if(snippet.getJSONObject("resourceId").getString("kind").equals("youtube#video")){
|
||||
videoID = snippet.getJSONObject("resourceId").getString("videoId");
|
||||
snippet.put("videoID", videoID);
|
||||
resultObjects.add(snippet);
|
||||
snippet = fixThumbnail(snippet);
|
||||
createCard(snippet);
|
||||
Video video = createVideofromJSON(snippet);
|
||||
video.setIsPlaylistItem(1);
|
||||
resultObjects.add(video);
|
||||
}
|
||||
}
|
||||
dbManager.shtoVideoRezultat(resultObjects);
|
||||
|
||||
// DOWNLOAD ALL BUTTON
|
||||
if(resultObjects.size() > 1){
|
||||
createDownloadAllCard();
|
||||
}
|
||||
|
||||
for(int i = 0 ; i < resultObjects.size(); i++){
|
||||
createCard(resultObjects.get(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}catch(Exception e){
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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));
|
||||
r.getLayoutParams().height = getDp(90);
|
||||
|
||||
CardView card = new CardView(requireContext());
|
||||
card.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
card.setRadius(50);
|
||||
card.setCardElevation(10);
|
||||
card.setMaxCardElevation(12);
|
||||
card.setPreventCornerOverlap(true);
|
||||
card.setUseCompatPadding(true);
|
||||
card.setCardBackgroundColor(ContextCompat.getColor(requireContext(), R.color.black));
|
||||
|
||||
// TITLE ----------------------------------
|
||||
TextView videoTitle = new TextView(getContext());
|
||||
videoTitle.setLayoutParams(new RelativeLayout.LayoutParams(getDp(300), getDp(100)));
|
||||
int padding = getDp(20);
|
||||
videoTitle.setPadding(padding, padding, padding, padding);
|
||||
|
||||
videoTitle.setText("Shkarko të gjitha");
|
||||
videoTitle.setTextSize(getDp(5));
|
||||
videoTitle.setTextColor(ContextCompat.getColor(requireContext(), R.color.white));
|
||||
videoTitle.setShadowLayer(1, 1, 1, ContextCompat.getColor(requireContext(), R.color.colorPrimaryDark));
|
||||
videoTitle.setTypeface(null, Typeface.BOLD);
|
||||
videoTitle.setShadowLayer(1.5f, 4f, 4f, R.color.black);
|
||||
|
||||
// BUTTONS -------------------------------------------
|
||||
LinearLayout buttonLayout = new LinearLayout(requireContext());
|
||||
buttonLayout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
buttonLayout.setGravity(Gravity.BOTTOM);
|
||||
buttonLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
buttonLayout.setPadding(getDp(250), 0, getDp(20), getDp(10));
|
||||
|
||||
Button musicBtn = new Button(getContext());
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
getDp(48), getDp(48)
|
||||
);
|
||||
params.setMargins(0,0, getDp(10), 0);
|
||||
musicBtn.setLayoutParams(params);
|
||||
//musicBtn.setIconSize(getDp(24));
|
||||
musicBtn.setBackground(ContextCompat.getDrawable(requireContext(), R.drawable.ic_music));
|
||||
musicBtn.setTag("ALL##mp3");
|
||||
|
||||
Button videoBtn = new Button(requireContext());
|
||||
videoBtn.setLayoutParams(params);
|
||||
//videoBtn.setIconSize(getDp(24));
|
||||
videoBtn.setBackground(ContextCompat.getDrawable(requireContext(), R.drawable.ic_video));
|
||||
videoBtn.setTag("ALL##mp4");
|
||||
|
||||
buttonLayout.addView(musicBtn);
|
||||
buttonLayout.addView(videoBtn);
|
||||
|
||||
musicBtn.setOnClickListener(this);
|
||||
videoBtn.setOnClickListener(this);
|
||||
|
||||
card.addView(videoTitle);
|
||||
card.addView(buttonLayout);
|
||||
|
||||
r.addView(card);
|
||||
|
||||
linearLayout.addView(r);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private JSONObject fixThumbnail(JSONObject o){
|
||||
|
|
@ -369,7 +475,7 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
private void createCard(JSONObject info){
|
||||
private void createCard(Video video){
|
||||
|
||||
RelativeLayout r = new RelativeLayout(getContext());
|
||||
r.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
|
||||
|
|
@ -388,11 +494,7 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
|
||||
ImageView thumbnail = new ImageView(getContext());
|
||||
thumbnail.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
String imageURL= "";
|
||||
|
||||
try {
|
||||
imageURL = info.getString("thumb");
|
||||
}catch (Exception ignored){}
|
||||
String imageURL= video.getThumb();
|
||||
|
||||
Picasso.get().load(imageURL).into(thumbnail);
|
||||
thumbnail.setAdjustViewBounds(false);
|
||||
|
|
@ -403,12 +505,7 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
videoTitle.setLayoutParams(new RelativeLayout.LayoutParams(getDp(300), getDp(100)));
|
||||
int padding = getDp(20);
|
||||
videoTitle.setPadding(padding, padding, padding, padding);
|
||||
String title;
|
||||
try{
|
||||
title = info.getString("title");
|
||||
}catch(Exception e){
|
||||
title = "";
|
||||
}
|
||||
String title = video.getTitle();
|
||||
|
||||
if(title.length() > 50){
|
||||
title = title.substring(0, 40) + "...";
|
||||
|
|
@ -428,12 +525,8 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
videoAuthor.setPadding(getDp(20), 0, 0, getDp(10));
|
||||
videoAuthor.setShadowLayer(1.5f, 4f, 4f, R.color.black);
|
||||
|
||||
String author;
|
||||
try{
|
||||
author = info.getString("channelTitle");
|
||||
}catch(Exception e){
|
||||
author = "";
|
||||
}
|
||||
String author = video.getAuthor();
|
||||
|
||||
videoAuthor.setText(author);
|
||||
videoAuthor.setTextSize(getDp(3));
|
||||
videoAuthor.setTextColor(ContextCompat.getColor(requireContext(), R.color.white));
|
||||
|
|
@ -441,12 +534,8 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
videoAuthor.setTypeface(null, Typeface.BOLD);
|
||||
|
||||
// BUTTONS ----------------------------------
|
||||
String videoID;
|
||||
try{
|
||||
videoID = info.getString("videoID");
|
||||
}catch(Exception e){
|
||||
videoID = "";
|
||||
}
|
||||
String videoID = video.getVideoId();
|
||||
|
||||
|
||||
LinearLayout buttonLayout = new LinearLayout(requireContext());
|
||||
buttonLayout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
|
|
@ -487,6 +576,11 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
progressBar.setScaleY(2);
|
||||
progressBar.setTag(videoID + "##progress");
|
||||
|
||||
if(video.getDownloadedTime() != null){
|
||||
progressBar.setProgress(100);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
|
||||
// Adding all layouts to the card
|
||||
|
||||
|
|
@ -496,6 +590,9 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
card.addView(buttonLayout);
|
||||
card.addView(progressBar);
|
||||
|
||||
card.setTag(videoID + "##card");
|
||||
|
||||
|
||||
r.addView(card);
|
||||
|
||||
linearLayout.addView(r);
|
||||
|
|
@ -510,15 +607,47 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
Log.e(TAG, viewIdName);
|
||||
if(viewIdName.contains("mp3") || viewIdName.contains("mp4")){
|
||||
String[] buttonData = viewIdName.split("##");
|
||||
startDownload(buttonData[0], buttonData[1]);
|
||||
downloadQueue = new LinkedList<>();
|
||||
if(buttonData[0].equals("ALL")){
|
||||
for (int i = 0; i < resultObjects.size(); i++){
|
||||
Video vid = findVideo(resultObjects.get(i).getVideoId());
|
||||
vid.setDownloadedType(buttonData[1]);
|
||||
downloadQueue.add(vid);
|
||||
}
|
||||
|
||||
}else{
|
||||
Video vid = findVideo(buttonData[0]);
|
||||
vid.setDownloadedType(buttonData[1]);
|
||||
downloadQueue.add(vid);
|
||||
}
|
||||
|
||||
startDownload(downloadQueue);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Video findVideo(String id){
|
||||
for(int i = 0; i < resultObjects.size(); i++){
|
||||
Video v = resultObjects.get(i);
|
||||
if((v.getVideoId()).equals(id)){
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void startDownload(Queue<Video> videos) {
|
||||
Video video = null;
|
||||
try{
|
||||
video = videos.remove();
|
||||
}catch(Exception e){
|
||||
return;
|
||||
}
|
||||
|
||||
private void startDownload(String id, String type) {
|
||||
if (downloading) {
|
||||
Toast.makeText(getContext(), "Nuk mund te filloj! Nje shkarkim tjeter është në punë!", Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
|
|
@ -528,13 +657,18 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
Toast.makeText(getContext(), "Pranoje Lejen dhe provo përsëri!", Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
String id = video.getVideoId();
|
||||
String url = "https://www.youtube.com/watch?v=" + id;
|
||||
YoutubeDLRequest request = new YoutubeDLRequest(url);
|
||||
String type = video.getDownloadedType();
|
||||
File youtubeDLDir = getDownloadLocation(type);
|
||||
|
||||
Log.e(TAG, youtubeDLDir.getAbsolutePath());
|
||||
|
||||
if(type.equals("mp3")){
|
||||
request.addOption("--embed-thumbnail");
|
||||
request.addOption("--postprocessor-args", "-write_id3v1 1 -id3v2_version 3");
|
||||
request.addOption("--add-metadata");
|
||||
request.addOption("--no-mtime");
|
||||
request.addOption("-x");
|
||||
request.addOption("--audio-format", "mp3");
|
||||
|
|
@ -543,20 +677,32 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
}
|
||||
request.addOption("-o", youtubeDLDir.getAbsolutePath() + "/%(title)s.%(ext)s");
|
||||
|
||||
View card = fragmentView.findViewWithTag(id+"##card");
|
||||
int[] cardPosition = new int[2];
|
||||
card.getLocationInWindow(cardPosition);
|
||||
scrollView.post(() -> scrollView.scrollTo(cardPosition[0]-1000, cardPosition[1]-1000));
|
||||
|
||||
progressBar = fragmentView.findViewWithTag(id+"##progress");
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
showStart();
|
||||
downloading = true;
|
||||
|
||||
Video theVideo = video;
|
||||
Disposable disposable = Observable.fromCallable(() -> YoutubeDL.getInstance().execute(request, callback))
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(youtubeDLResponse -> {
|
||||
progressBar.setProgress(100);
|
||||
Toast.makeText(getContext(), "Shkarkimi i be me Sukses!", Toast.LENGTH_LONG).show();
|
||||
addToHistory(id, type, new Date());
|
||||
addToHistory(theVideo, new Date());
|
||||
downloading = false;
|
||||
|
||||
// MEDIA SCAN
|
||||
MediaScannerConnection.scanFile(requireContext(), new String[]{youtubeDLDir.getAbsolutePath()}, null, null);
|
||||
|
||||
// SCAN NEXT IN QUEUE
|
||||
startDownload(videos);
|
||||
}, e -> {
|
||||
if(BuildConfig.DEBUG) Log.e(TAG, "Deshtim ne shkarkim! :(", e);
|
||||
Toast.makeText(getContext(), "Deshtim ne shkarkim! :(", Toast.LENGTH_LONG).show();
|
||||
|
|
@ -567,9 +713,7 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
}
|
||||
|
||||
|
||||
public void addToHistory(String id, String downloadedType, Date date){
|
||||
JSONObject videoja = null;
|
||||
|
||||
public void addToHistory(Video video, Date date){
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
int day = cal.get(Calendar.DAY_OF_MONTH);
|
||||
|
|
@ -581,26 +725,20 @@ public class HomeFragment extends Fragment implements View.OnClickListener{
|
|||
String time = formatter.format(date);
|
||||
String downloadedTime = day + " " + month + " " + year + " " + time;
|
||||
|
||||
for(JSONObject o : resultObjects){
|
||||
try{
|
||||
if(o.getString("videoID").equals(id)){
|
||||
videoja = o;
|
||||
}
|
||||
}catch(Exception e){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
System.err.println(videoja);
|
||||
|
||||
if(videoja != null){
|
||||
if(video != null){
|
||||
dbManager = new DBManager(requireContext());
|
||||
try{
|
||||
String title = videoja.getString("title");
|
||||
String author = videoja.getString("channelTitle");
|
||||
String thumb = videoja.getString("thumb");
|
||||
String id = video.getVideoId();
|
||||
String title = video.getTitle();
|
||||
String author = video.getAuthor();
|
||||
String thumb = video.getThumb();
|
||||
String downloadedType = video.getDownloadedType();
|
||||
video.setDownloadedTime(downloadedTime);
|
||||
|
||||
dbManager.shtoVideoHistori(video);
|
||||
dbManager.shkoKohenRezultatit(id, downloadedTime);
|
||||
|
||||
|
||||
dbManager.shtoVideo(id, title, author, thumb, downloadedType, downloadedTime);
|
||||
}catch(Exception ignored){}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ import androidx.preference.PreferenceManager;
|
|||
|
||||
import com.yausername.youtubedl_android.YoutubeDL;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
|
@ -105,8 +108,12 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
Log.e("TEST", data.toUri(0));
|
||||
String dataValue = data.getData().toString();
|
||||
dataValue = dataValue.replace("content://com.android.externalstorage.documents/tree/", "");
|
||||
dataValue = dataValue.replace("%3A", "/");
|
||||
dataValue = dataValue.replace("%2F", "/");
|
||||
dataValue = dataValue.replaceAll("%3A", "/");
|
||||
|
||||
try{
|
||||
dataValue = java.net.URLDecoder.decode(dataValue, StandardCharsets.UTF_8.name());
|
||||
}catch(Exception ignored){}
|
||||
|
||||
String[] pieces = dataValue.split("/");
|
||||
|
||||
int index = 1;
|
||||
|
|
|
|||
|
|
@ -6,13 +6,15 @@ import android.database.Cursor;
|
|||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class DBManager extends SQLiteOpenHelper {
|
||||
|
||||
public static final String db_name = "ytdlnis";
|
||||
public static final int db_version = 1;
|
||||
public static final String table_name = "video";
|
||||
public static final String results_table_name = "videoResults";
|
||||
public static final String history_table_name = "videoHistory";
|
||||
public static final String id = "id";
|
||||
public static final String videoId = "videoId";
|
||||
public static final String title = "title";
|
||||
|
|
@ -20,6 +22,7 @@ public class DBManager extends SQLiteOpenHelper {
|
|||
public static final String thumb = "thumb";
|
||||
public static final String type = "type";
|
||||
public static final String time = "time";
|
||||
public static final String isPlaylistItem = "isPlaylistItem";
|
||||
|
||||
|
||||
public DBManager(Context context){
|
||||
|
|
@ -28,25 +31,71 @@ public class DBManager extends SQLiteOpenHelper {
|
|||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase sqLiteDatabase) {
|
||||
String query = "CREATE TABLE " + table_name + " ("
|
||||
String query = "CREATE TABLE " + results_table_name + " ("
|
||||
+ id + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ videoId + " TEXT,"
|
||||
+ title + " TEXT,"
|
||||
+ author + " TEXT,"
|
||||
+ thumb + " TEXT,"
|
||||
+ type + " TEXT,"
|
||||
+ time + " TEXT)";
|
||||
+ time + " TEXT,"
|
||||
+ isPlaylistItem + " INTENGER)";
|
||||
|
||||
sqLiteDatabase.execSQL(query);
|
||||
|
||||
query = "CREATE TABLE " + history_table_name + " ("
|
||||
+ id + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ videoId + " TEXT,"
|
||||
+ title + " TEXT,"
|
||||
+ author + " TEXT,"
|
||||
+ thumb + " TEXT,"
|
||||
+ type + " TEXT,"
|
||||
+ time + " TEXT,"
|
||||
+ isPlaylistItem + " INTEGER)";
|
||||
|
||||
sqLiteDatabase.execSQL(query);
|
||||
}
|
||||
|
||||
public void recreateResultsTable(SQLiteDatabase sqLiteDatabase){
|
||||
String query = "CREATE TABLE " + results_table_name + " ("
|
||||
+ id + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ videoId + " TEXT,"
|
||||
+ title + " TEXT,"
|
||||
+ author + " TEXT,"
|
||||
+ thumb + " TEXT,"
|
||||
+ type + " TEXT,"
|
||||
+ time + " TEXT,"
|
||||
+ isPlaylistItem + " BOOLEAN)";
|
||||
|
||||
sqLiteDatabase.execSQL(query);
|
||||
}
|
||||
|
||||
public void clearHistory(){
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
db.execSQL("DROP TABLE IF EXISTS " + history_table_name);
|
||||
|
||||
String query = "CREATE TABLE " + history_table_name + " ("
|
||||
+ id + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ videoId + " TEXT,"
|
||||
+ title + " TEXT,"
|
||||
+ author + " TEXT,"
|
||||
+ thumb + " TEXT,"
|
||||
+ type + " TEXT,"
|
||||
+ time + " TEXT,"
|
||||
+ isPlaylistItem + " BOOLEAN)";
|
||||
|
||||
db.execSQL(query);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
|
||||
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + table_name);
|
||||
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + results_table_name);
|
||||
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + history_table_name);
|
||||
onCreate(sqLiteDatabase);
|
||||
}
|
||||
|
||||
public ArrayList<Video> merrVideot(){
|
||||
public ArrayList<Video> merrVideot(String table_name){
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
Cursor cursor = db.rawQuery("SELECT * FROM " + table_name, null);
|
||||
ArrayList<Video> list = new ArrayList<>();
|
||||
|
|
@ -59,44 +108,66 @@ public class DBManager extends SQLiteOpenHelper {
|
|||
cursor.getString(3),
|
||||
cursor.getString(4),
|
||||
cursor.getString(5),
|
||||
cursor.getString(6)));
|
||||
cursor.getString(6),
|
||||
cursor.getInt(7)));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
return list;
|
||||
}
|
||||
//
|
||||
// public Video merrVideonmeID(String id){
|
||||
// SQLiteDatabase db = this.getReadableDatabase();
|
||||
// Cursor cursor = db.rawQuery("SELECT * FROM " + table_name + " WHERE "+ id + " = table_name.videoId", null);
|
||||
//
|
||||
// if(cursor.moveToFirst()){
|
||||
// String title = cursor.getString(2);
|
||||
// String author = cursor.getString(3);
|
||||
// String thumb = cursor.getString(4);
|
||||
//
|
||||
// return new Video(id, title, author, thumb);
|
||||
// }
|
||||
//
|
||||
// cursor.close();
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
|
||||
public void shtoVideo(String videoID, String videoTitle, String videoAuthor, String videoThumb, String downloadedType, String downloadedTime){
|
||||
public ArrayList<Video> merrRezultatet(){
|
||||
return merrVideot(results_table_name);
|
||||
}
|
||||
|
||||
public ArrayList<Video> merrHistorine(){
|
||||
return merrVideot(history_table_name);
|
||||
}
|
||||
|
||||
public Video shkoKohenRezultatit(String id, String downloadedTime){
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
ContentValues vlerat = new ContentValues();
|
||||
vlerat.put(time, downloadedTime);
|
||||
|
||||
db.update(results_table_name, vlerat, "videoId = ?", new String[]{id});
|
||||
return null;
|
||||
}
|
||||
|
||||
public void shtoVideoRezultat(ArrayList<Video> videot){
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
ContentValues vlerat = new ContentValues();
|
||||
|
||||
vlerat.put(videoId, videoID);
|
||||
vlerat.put(title, videoTitle);
|
||||
vlerat.put(author, videoAuthor);
|
||||
vlerat.put(thumb, videoThumb);
|
||||
vlerat.put(type, downloadedType);
|
||||
vlerat.put(time, downloadedTime);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + results_table_name);
|
||||
recreateResultsTable(db);
|
||||
|
||||
db.insert(table_name, null, vlerat);
|
||||
for(Video v : videot){
|
||||
vlerat.put(videoId, v.getVideoId());
|
||||
vlerat.put(title, v.getTitle());
|
||||
vlerat.put(author, v.getAuthor());
|
||||
vlerat.put(thumb, v.getThumb());
|
||||
vlerat.put(type, v.getDownloadedType());
|
||||
vlerat.put(time, v.getDownloadedTime());
|
||||
vlerat.put(isPlaylistItem, v.getIsPlaylistItem());
|
||||
|
||||
db.insert(results_table_name, null, vlerat);
|
||||
}
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
public void shtoVideoHistori(Video v){
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
ContentValues vlerat = new ContentValues();
|
||||
|
||||
vlerat.put(videoId, v.getVideoId());
|
||||
vlerat.put(title, v.getTitle());
|
||||
vlerat.put(author, v.getAuthor());
|
||||
vlerat.put(thumb, v.getThumb());
|
||||
vlerat.put(type, v.getDownloadedType());
|
||||
vlerat.put(time, v.getDownloadedTime());
|
||||
|
||||
db.insert(history_table_name, null, vlerat);
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,26 @@ public class Video {
|
|||
private String thumb;
|
||||
private String downloadedType;
|
||||
private String downloadedTime;
|
||||
private int isPlaylistItem;
|
||||
|
||||
public Video(String videoId, String title, String author, String thumb, String downloadedType, String downloadedTime) {
|
||||
public Video(String videoId, String title, String author, String thumb, String downloadedType, String downloadedTime, int isPlaylistItem) {
|
||||
this.videoId = videoId;
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.thumb = thumb;
|
||||
this.downloadedType = downloadedType;
|
||||
this.downloadedTime = downloadedTime;
|
||||
this.isPlaylistItem = isPlaylistItem;
|
||||
}
|
||||
|
||||
public Video(String videoId, String title, String author, String thumb) {
|
||||
this.videoId = videoId;
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.thumb = thumb;
|
||||
this.downloadedTime = null;
|
||||
this.downloadedType = null;
|
||||
this.isPlaylistItem = 0;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
|
|
@ -73,4 +85,12 @@ public class Video {
|
|||
public void setDownloadedTime(String downloadedTime) {
|
||||
this.downloadedTime = downloadedTime;
|
||||
}
|
||||
|
||||
public int getIsPlaylistItem() {
|
||||
return isPlaylistItem;
|
||||
}
|
||||
|
||||
public void setIsPlaylistItem(int playlistItem) {
|
||||
this.isPlaylistItem = playlistItem;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,4 +31,6 @@
|
|||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
|
||||
|
||||
</vector>
|
||||
|
|
|
|||
14
app/src/main/res/menu/history_menu.xml
Normal file
14
app/src/main/res/menu/history_menu.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".MainActivity" >
|
||||
|
||||
<item
|
||||
android:id="@+id/delete_history"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/fshi_historin"
|
||||
app:showAsAction="never" />
|
||||
|
||||
|
||||
</menu>
|
||||
|
||||
|
|
@ -40,4 +40,5 @@
|
|||
<string name="shkarko">Shkarko</string>
|
||||
<string name="shkruaj_url_e_youtube">Shkruaj URL e YouTube</string>
|
||||
<string name="download_path">sdcard/Download</string>
|
||||
<string name="fshi_historin">Fshi Historinë</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ buildscript {
|
|||
}
|
||||
}
|
||||
|
||||
def versionMajor = 0
|
||||
def versionMinor = 13
|
||||
def versionPatch = 1
|
||||
def versionMajor = 1
|
||||
def versionMinor = 0
|
||||
def versionPatch = 0
|
||||
def versionBuild = 0 // bump for dogfood builds, public betas, etc.
|
||||
|
||||
ext {
|
||||
|
|
|
|||
Loading…
Reference in a new issue