diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml
index d1fac0cd..2375cff6 100644
--- a/.idea/assetWizardSettings.xml
+++ b/.idea/assetWizardSettings.xml
@@ -320,7 +320,7 @@
@@ -331,7 +331,7 @@
diff --git a/.idea/misc.xml b/.idea/misc.xml
index be2898d8..d739b9ab 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -37,6 +37,7 @@
+
@@ -45,6 +46,7 @@
+
@@ -70,6 +72,7 @@
+
@@ -96,7 +99,7 @@
-
+
diff --git a/.idea/navEditor.xml b/.idea/navEditor.xml
new file mode 100644
index 00000000..8ab47ce5
--- /dev/null
+++ b/.idea/navEditor.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 7cea4b05..960b5f4c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -68,6 +68,8 @@ dependencies {
implementation 'androidx.core:core:1.8.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.preference:preference:1.2.0'
+ implementation 'androidx.navigation:navigation-fragment:2.5.2'
+ implementation 'androidx.navigation:navigation-ui:2.5.2'
testImplementation "junit:junit:$junitVer"
androidTestImplementation "androidx.test.ext:junit:$androidJunitVer"
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVer"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 44deca19..bc7b1bbb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -49,6 +49,10 @@
android:name=".DownloaderService"
android:enabled="true"
android:exported="false" />
+
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.java b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.java
index 7a9622db..e93e94c3 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.java
+++ b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.java
@@ -1,10 +1,12 @@
package com.deniscerri.ytdlnis;
+import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
@@ -13,7 +15,6 @@ import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
-
import com.deniscerri.ytdlnis.database.Video;
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding;
import com.deniscerri.ytdlnis.page.HistoryFragment;
@@ -99,11 +100,11 @@ public class MainActivity extends AppCompatActivity{
this.setTitle(R.string.app_name);;
}
replaceFragment(homeFragment);
- }else if(id == R.id.history){
+ }else if(id == R.id.downloads){
if(lastFragment == historyFragment){
historyFragment.scrollToTop();
}else {
- this.setTitle(getString(R.string.history));
+ this.setTitle(getString(R.string.downloads));
}
replaceFragment(historyFragment);
}else if(id == R.id.more){
@@ -215,8 +216,11 @@ public class MainActivity extends AppCompatActivity{
}
private void checkUpdate(){
- UpdateUtil updateUtil = new UpdateUtil(this);
- updateUtil.updateApp();
+ SharedPreferences preferences = context.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE);
+ if(preferences.getBoolean("update_app", false)){
+ UpdateUtil updateUtil = new UpdateUtil(this);
+ updateUtil.updateApp();
+ }
}
public void updateHistoryFragment(){
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/HistoryRecyclerViewAdapter.java b/app/src/main/java/com/deniscerri/ytdlnis/adapter/HistoryRecyclerViewAdapter.java
index 3e9267d6..9ded68fb 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/HistoryRecyclerViewAdapter.java
+++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/HistoryRecyclerViewAdapter.java
@@ -2,6 +2,8 @@ package com.deniscerri.ytdlnis.adapter;
import android.content.Context;
import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
@@ -21,6 +23,7 @@ import com.deniscerri.ytdlnis.R;
import com.deniscerri.ytdlnis.database.Video;
import com.squareup.picasso.Picasso;
+import java.io.File;
import java.util.ArrayList;
public class HistoryRecyclerViewAdapter extends RecyclerView.Adapter {
@@ -97,6 +100,12 @@ public class HistoryRecyclerViewAdapter extends RecyclerView.Adapter onItemClickListener.onCardClick(position));
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/page/HomeFragment.java b/app/src/main/java/com/deniscerri/ytdlnis/page/HomeFragment.java
index 4b04d397..f3ac6164 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/page/HomeFragment.java
+++ b/app/src/main/java/com/deniscerri/ytdlnis/page/HomeFragment.java
@@ -110,10 +110,13 @@ public class HomeFragment extends Fragment implements HomeRecyclerViewAdapter.On
public void onDownloadProgress(DownloadInfo info) {
activity.runOnUiThread(() -> {
try{
+ int progress = info.getProgress();
progressBar = fragmentView.findViewWithTag(info.getVideo().getVideoId()+"##progress");
progressBar.setVisibility(View.VISIBLE);
- progressBar.setIndeterminate(false);
- progressBar.setProgress(info.getProgress());
+ if (progress > 1){
+ progressBar.setIndeterminate(false);
+ progressBar.setProgress(info.getProgress());
+ }
}catch(Exception ignored){}
});
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/page/MoreFragment.java b/app/src/main/java/com/deniscerri/ytdlnis/page/MoreFragment.java
index 4a527319..38bf1c6c 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/page/MoreFragment.java
+++ b/app/src/main/java/com/deniscerri/ytdlnis/page/MoreFragment.java
@@ -1,40 +1,13 @@
package com.deniscerri.ytdlnis.page;
import android.os.Bundle;
-import android.widget.Toast;
-
-import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
-
import com.deniscerri.ytdlnis.R;
-import com.deniscerri.ytdlnis.util.UpdateUtil;
public class MoreFragment extends PreferenceFragmentCompat {
- Preference updateYTDL;
- Preference updateApp;
public static final String TAG = "MoreFragment";
- private UpdateUtil updateUtil;
-
-
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.more_preferences, rootKey);
-
- updateYTDL = findPreference("update_ytdl");
- updateApp = findPreference("update_app");
-
- updateUtil = new UpdateUtil(getContext());
-
- updateYTDL.setOnPreferenceClickListener(preference -> {
- updateUtil.updateYoutubeDL();
- return true;
- });
-
- updateApp.setOnPreferenceClickListener(preference -> {
- if(!updateUtil.updateApp()){
- Toast.makeText(getContext(), R.string.you_are_in_latest_version, Toast.LENGTH_SHORT).show();
- }
- return true;
- });
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/page/settings/SettingsFragment.java b/app/src/main/java/com/deniscerri/ytdlnis/page/settings/SettingsFragment.java
index 60820d9d..bd9213b0 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/page/settings/SettingsFragment.java
+++ b/app/src/main/java/com/deniscerri/ytdlnis/page/settings/SettingsFragment.java
@@ -43,6 +43,8 @@ public class SettingsFragment extends PreferenceFragmentCompat {
ListPreference videoFormat;
SeekBarPreference audioQuality;
+ Preference updateYTDL;
+ SwitchPreferenceCompat updateApp;
Preference version;
private UpdateUtil updateUtil;
@@ -58,7 +60,6 @@ public class SettingsFragment extends PreferenceFragmentCompat {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
updateUtil = new UpdateUtil(requireContext());
-
initPreferences();
initListeners();
}
@@ -85,6 +86,8 @@ public class SettingsFragment extends PreferenceFragmentCompat {
videoFormat = findPreference("video_format");
audioQuality = findPreference("audio_quality");
+ updateYTDL = findPreference("update_ytdl");
+ updateApp = findPreference("update_app");
version = findPreference("version");
version.setSummary(BuildConfig.VERSION_NAME);
@@ -110,6 +113,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
editor.putString("audio_format", audioFormat.getValue());
editor.putString("video_format", videoFormat.getValue());
editor.putInt("audio_quality", audioQuality.getValue());
+ editor.putBoolean("update_app", updateApp.isChecked());
editor.apply();
}
@@ -222,6 +226,18 @@ public class SettingsFragment extends PreferenceFragmentCompat {
return true;
});
+ updateYTDL.setOnPreferenceClickListener(preference -> {
+ updateUtil.updateYoutubeDL();
+ return true;
+ });
+
+ updateApp.setOnPreferenceChangeListener((preference, newValue) -> {
+ boolean enable = (Boolean) newValue;
+ editor.putBoolean("update_app", enable);
+ editor.apply();
+ return true;
+ });
+
version.setOnPreferenceClickListener(preference -> {
if(!updateUtil.updateApp()){
Toast.makeText(getContext(), R.string.you_are_in_latest_version, Toast.LENGTH_SHORT).show();
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.java b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.java
index c05dec88..e996f5b3 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.java
+++ b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.java
@@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.text.Html;
import android.util.Log;
import android.widget.Toast;
@@ -35,6 +36,9 @@ public class InfoUtil {
try{
SharedPreferences sharedPreferences = context.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE);
key = sharedPreferences.getString("api_key", "");
+ applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
+ if (key.isEmpty()) key = applicationInfo.metaData.getString("ytAPIkey");
+ Log.e(TAG, key);
dbManager = new DBManager(context);
Thread thread = new Thread(() -> {
@@ -60,6 +64,7 @@ public class InfoUtil {
videos = new ArrayList<>();
//short data
JSONObject res = genericRequest("https://youtube.googleapis.com/youtube/v3/search?part=snippet&q="+query+"&maxResults=25®ionCode="+countryCODE+"&key="+key);
+ if (!res.has("items")) return getFromYTDL(query);
JSONArray dataArray = res.getJSONArray("items");
//extra data
@@ -110,6 +115,7 @@ public class InfoUtil {
String url = "https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet&pageToken="+nextPageToken+"&maxResults=50®ionCode="+countryCODE+"&playlistId="+id+"&key="+key;
//short data
JSONObject res = genericRequest(url);
+ if (!res.has("items")) return new PlaylistTuple("", getFromYTDL("https://www.youtube.com/playlist?list="+id));
JSONArray dataArray = res.getJSONArray("items");
//extra data
@@ -155,6 +161,7 @@ public class InfoUtil {
//short data
JSONObject res = genericRequest("https://youtube.googleapis.com/youtube/v3/videos?part=snippet,contentDetails&id="+id+"&key="+key);
+ if (!res.has("items")) return getFromYTDL("https://www.youtube.com/watch?v="+id).get(0);
String duration = res.getJSONArray("items").getJSONObject(0).getJSONObject("contentDetails").getString("duration");
duration = formatDuration(duration);
@@ -264,59 +271,57 @@ public class InfoUtil {
try {
YoutubeDLRequest request = new YoutubeDLRequest(query);
request.addOption("--flat-playlist");
- request.addOption("-J");
+ request.addOption("-j");
request.addOption("--skip-download");
+ request.addOption("-R", "1");
+ request.addOption("--socket-timeout", "5");
if (!query.contains("http")) request.addOption("--default-search", "ytsearch25");
YoutubeDLResponse youtubeDLResponse = YoutubeDL.getInstance().execute(request);
- JSONObject jsonObject = new JSONObject(youtubeDLResponse.getOut());
+ String[] results;
+ try {
+ results = youtubeDLResponse.getOut().split(System.getProperty("line.separator"));
+ }catch(Exception e){
+ results = new String[]{youtubeDLResponse.getOut()};
+ }
+
+ int isPlaylist = 0;
+ JSONObject pl = new JSONObject(results[0]);
+ if (pl.has("playlist")){
+ if (! pl.getString("playlist").equals(query)) isPlaylist = 1;
+ }
+
+ for (String result : results) {
+ JSONObject jsonObject = new JSONObject(result);
+ if (jsonObject.getString("title").equals("[Private video]")) continue;
- if(!jsonObject.has("entries")){
String url = jsonObject.getString("webpage_url");
+ String thumb = "";
+ if (jsonObject.has("thumbnail")){
+ thumb = jsonObject.getString("thumbnail");
+ }else {
+ JSONArray thumbs = jsonObject.getJSONArray("thumbnails");
+ thumb = thumbs.getJSONObject(thumbs.length()-1).getString("url");
+ }
+
+ String website = "";
+ if (jsonObject.has("ie_key")) website = jsonObject.getString("ie_key");
+ else website = jsonObject.getString("extractor");
+
+
videos.add(new Video(
jsonObject.getString("id"),
url,
jsonObject.getString("title"),
jsonObject.getString("uploader"),
formatIntegerDuration(jsonObject.getInt("duration")),
- jsonObject.getString("thumbnail"),
+ thumb,
dbManager.checkDownloaded(url, "audio"),
dbManager.checkDownloaded(url, "video"),
- 0,
- jsonObject.getString("extractor"))
+ isPlaylist,
+ website)
);
- }else{
- JSONArray jsonArray = jsonObject.getJSONArray("entries");
-
- for (int i = 0; i < jsonArray.length(); i++){
- jsonObject = jsonArray.getJSONObject(i);
- String url = jsonObject.getString("url");
- String thumb = "";
- if (jsonObject.has("thumbnail")){
- thumb = jsonObject.getString("thumbnail");
- }else {
- JSONArray thumbs = jsonObject.getJSONArray("thumbnails");
- thumb = thumbs.getJSONObject(thumbs.length()-1).getString("url");
- }
- String website = "";
- if (jsonObject.has("ie_key")) website = jsonObject.getString("ie_key");
- else website = jsonObject.getString("extractor");
-
- videos.add(new Video(
- jsonObject.getString("id"),
- url,
- jsonObject.getString("title"),
- jsonObject.getString("uploader"),
- formatIntegerDuration(jsonObject.getInt("duration")),
- thumb,
- dbManager.checkDownloaded(url, "audio"),
- dbManager.checkDownloaded(url, "video"),
- 0,
- website)
- );
- }
}
-
}catch(Exception e){
e.printStackTrace();
}
@@ -335,6 +340,8 @@ public class InfoUtil {
//extra data from the same videos
JSONObject contentDetails = genericRequest("https://www.googleapis.com/youtube/v3/videos?part=contentDetails&chart=mostPopular&videoCategoryId=10®ionCode="+countryCODE+"&maxResults=25&key="+key);
+ if(!contentDetails.has("items")) return new ArrayList<>();
+
JSONArray dataArray = res.getJSONArray("items");
JSONArray extraDataArray = contentDetails.getJSONArray("items");
for(int i = 0; i < dataArray.length(); i++){
@@ -358,55 +365,30 @@ public class InfoUtil {
}
public String formatDuration(String dur){
-
if(dur.equals("P0D")){
return "LIVE";
}
+ boolean hours = false;
String duration = "";
- String tmp = "";
- String hours = "";
- String minutes = "";
- String seconds = "";
- //removing P
- dur = dur.substring(1);
- for(int i = 0; i < dur.length(); i++){
- char c = dur.charAt(i);
- if(!Character.isDigit(c)){
- int nr = Character.getNumericValue(c);
- if(nr < 10){
- tmp = "0" + tmp;
- }
- if (c == 'D'){
- hours = String.valueOf(Integer.parseInt(tmp) * 24);
- }else if(c == 'T'){
- continue;
- }else if(c == 'H'){
- hours = tmp;
- }else if(c == 'M'){
- minutes = tmp;
- }else if(c == 'S'){
- seconds = tmp;
- }
- tmp = "";
- continue;
- }
- tmp = tmp + c;
+ dur = dur.substring(2);
+ if (dur.contains("H")) {
+ hours = true;
+ duration += String.format(Locale.getDefault(), "%02d", Integer.parseInt(dur.substring(0, dur.indexOf("H")))) + ":";
+ dur = dur.substring(dur.indexOf("H")+1);
+ }
+ if (dur.contains("M")) {
+ duration += String.format(Locale.getDefault(), "%02d", Integer.parseInt(dur.substring(0, dur.indexOf("M")))) + ":";
+ dur = dur.substring(dur.indexOf("M")+1);
+ }else if(hours) duration += "00:";
+ if (dur.contains("S")){
+ if(duration.isEmpty()) duration = "00:";
+ duration += String.format(Locale.getDefault(), "%02d", Integer.parseInt(dur.substring(0, dur.indexOf("S"))));
+ }else{
+ duration += "00";
}
- if(seconds.isEmpty()) seconds = "00";
- else if(Integer.parseInt(seconds) < 10) seconds = "0" + seconds;
- if(minutes.isEmpty()){
- minutes = "0";
- }
- duration = minutes + ":" + seconds;
-
- if(!hours.isEmpty()){
- if(Integer.parseInt(minutes) < 10) minutes = "0" + minutes;
- duration = hours + ":" + minutes + ":" + seconds;
- }
-
- if(duration.equals("0:00:00")){
+ if(duration.equals("00:00")){
duration = "";
}
diff --git a/app/src/main/res/drawable/ic_app_icon.xml b/app/src/main/res/drawable/ic_app_icon.xml
new file mode 100644
index 00000000..d6a5584c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_app_icon.xml
@@ -0,0 +1,15 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_downloads.xml b/app/src/main/res/drawable/ic_downloads.xml
new file mode 100644
index 00000000..ad08ddb0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_downloads.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_history.xml b/app/src/main/res/drawable/ic_history.xml
deleted file mode 100644
index 98a82168..00000000
--- a/app/src/main/res/drawable/ic_history.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/layout/fragment_more.xml b/app/src/main/res/layout/fragment_more.xml
index ebbe9341..469c74d4 100644
--- a/app/src/main/res/layout/fragment_more.xml
+++ b/app/src/main/res/layout/fragment_more.xml
@@ -1,27 +1,62 @@
-
+ android:layout_height="wrap_content">
-
+ android:layout_height="?attr/actionBarSize"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/preference_coordinatorLayout"
+ xmlns:android="http://schemas.android.com/apk/res/android">
-
+ android:layout_height="match_parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/result_card.xml b/app/src/main/res/layout/result_card.xml
index 43e63b15..74e611a0 100644
--- a/app/src/main/res/layout/result_card.xml
+++ b/app/src/main/res/layout/result_card.xml
@@ -36,6 +36,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
+
+
-
-
diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml
index 9cd49e2f..73d1eeab 100644
--- a/app/src/main/res/menu/bottom_nav_menu.xml
+++ b/app/src/main/res/menu/bottom_nav_menu.xml
@@ -4,9 +4,9 @@
-
+
diff --git a/app/src/main/res/values-sq-rAL/strings.xml b/app/src/main/res/values-sq-rAL/strings.xml
index 5de79ea1..42c260ec 100644
--- a/app/src/main/res/values-sq-rAL/strings.xml
+++ b/app/src/main/res/values-sq-rAL/strings.xml
@@ -45,8 +45,7 @@
Redaktori i Muzikës
Komanda
Më Shumë
- Përditëso Aplikacionin
- Shkarko versionin e fundit të aplikacionit
+ Kontrollo për përditësime
Versioni
Ekzekuto Komandën
Shkruaj komandën yt-dlp
@@ -96,4 +95,6 @@
Linku u kopjua
Çelësi API i YouTube
Përdor një çelës api për të marrë rezultate më të shpejta nga YouTube
+ Njoftohu kur një përditësim është i vlefshëm
+ Shkarkimet
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 837f77b6..c22a85b9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -45,8 +45,7 @@
Music Editor
Commands
More
- Update App
- Download the latest version of the app
+ Check for updates
Version
Run Custom Command
Write yt-dlp command
@@ -99,4 +98,6 @@
Link copied to clipboard
YouTube API Key
Use an api key to get faster results from YouTube
+ Let you know when updates are available right when you open the application
+ Downloads
diff --git a/app/src/main/res/xml/more_preferences.xml b/app/src/main/res/xml/more_preferences.xml
index c622d9ca..f383e16c 100644
--- a/app/src/main/res/xml/more_preferences.xml
+++ b/app/src/main/res/xml/more_preferences.xml
@@ -4,32 +4,15 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
+
+
+
+
+
+
+