diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml
index cd6d91a3..0f95f84e 100644
--- a/.idea/assetWizardSettings.xml
+++ b/.idea/assetWizardSettings.xml
@@ -23,7 +23,7 @@
@@ -34,7 +34,7 @@
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 53c71f02..8afb8e95 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -37,6 +37,7 @@
+
@@ -46,6 +47,7 @@
+
@@ -53,17 +55,21 @@
+
+
+
+
@@ -79,6 +85,7 @@
+
diff --git a/app/build.gradle b/app/build.gradle
index 80581e87..2d84a367 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -65,8 +65,6 @@ 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"
@@ -80,5 +78,4 @@ dependencies {
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
implementation 'com.facebook.shimmer:shimmer:0.5.0'
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5e51f8c2..53d5818d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,22 +1,23 @@
+ package="com.deniscerri.ytdl" >
+
-
+ android:theme="@style/AppDefaultTheme" >
+
@@ -26,20 +27,31 @@
-
+ android:parentActivityName=".MainActivity" >
+
+
+
+
+
+
+
+
+
+
+
+ android:name="ytAPIkey"
+ android:value="${ytAPI}" />
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdl/App.java b/app/src/main/java/com/deniscerri/ytdl/App.java
index 24c70d87..785cff17 100644
--- a/app/src/main/java/com/deniscerri/ytdl/App.java
+++ b/app/src/main/java/com/deniscerri/ytdl/App.java
@@ -4,6 +4,7 @@ import android.app.Application;
import android.util.Log;
import android.widget.Toast;
+import com.deniscerri.ytdl.util.NotificationUtil;
import com.google.android.material.color.DynamicColors;
import com.yausername.ffmpeg.FFmpeg;
import com.yausername.youtubedl_android.YoutubeDL;
@@ -20,8 +21,6 @@ public class App extends Application {
private static final String TAG = "App";
public static NotificationUtil notificationUtil;
- public static String arch = System.getProperty("os.arch");
- public static String versionName = BuildConfig.VERSION_NAME;
@Override
public void onCreate() {
diff --git a/app/src/main/java/com/deniscerri/ytdl/DownloaderService.java b/app/src/main/java/com/deniscerri/ytdl/DownloaderService.java
index e53f6bf5..6600590c 100644
--- a/app/src/main/java/com/deniscerri/ytdl/DownloaderService.java
+++ b/app/src/main/java/com/deniscerri/ytdl/DownloaderService.java
@@ -6,6 +6,8 @@ import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
+import android.widget.Toast;
+
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
@@ -21,9 +23,10 @@ public class DownloaderService extends Service {
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, theIntent, PendingIntent.FLAG_IMMUTABLE);
String title = intent.getStringExtra("title");
+ int id = intent.getIntExtra("id", 1);
Notification notification = App.notificationUtil.createDownloadServiceNotification(pendingIntent,title);
- startForeground(NotificationUtil.DOWNLOAD_NOTIFICATION_ID, notification);
+ startForeground(id, notification);
return binder;
}
diff --git a/app/src/main/java/com/deniscerri/ytdl/MainActivity.java b/app/src/main/java/com/deniscerri/ytdl/MainActivity.java
index e28c7f56..3689ca53 100644
--- a/app/src/main/java/com/deniscerri/ytdl/MainActivity.java
+++ b/app/src/main/java/com/deniscerri/ytdl/MainActivity.java
@@ -13,6 +13,9 @@ import androidx.fragment.app.FragmentManager;
import com.deniscerri.ytdl.databinding.ActivityMainBinding;
import com.deniscerri.ytdl.page.HistoryFragment;
import com.deniscerri.ytdl.page.HomeFragment;
+import com.deniscerri.ytdl.page.MoreFragment;
+import com.deniscerri.ytdl.page.MusicEditorFragment;
+import com.deniscerri.ytdl.page.settings.SettingsActivity;
public class MainActivity extends AppCompatActivity{
@@ -24,6 +27,9 @@ public class MainActivity extends AppCompatActivity{
private HomeFragment homeFragment;
private HistoryFragment historyFragment;
+ private MusicEditorFragment musicEditorFragment;
+ private MoreFragment moreFragment;
+
private Fragment lastFragment;
private FragmentManager fm;
@@ -59,33 +65,37 @@ public class MainActivity extends AppCompatActivity{
homeFragment = new HomeFragment();
historyFragment = new HistoryFragment();
+ moreFragment = new MoreFragment();
+ musicEditorFragment = new MusicEditorFragment();
- fm.beginTransaction()
- .replace(R.id.frame_layout, homeFragment)
- .add(R.id.frame_layout, historyFragment)
- .hide(historyFragment)
- .commit();
-
- lastFragment = homeFragment;
+ initFragments();
binding.bottomNavigationView.setOnItemSelectedListener(item -> {
- switch(item.getItemId()){
- case R.id.home:
- if(lastFragment == homeFragment){
- homeFragment.scrollToTop();
- }else{
- this.setTitle(R.string.app_name);;
- }
- replaceFragment(homeFragment);
- break;
- case R.id.history:
- if(lastFragment == historyFragment){
- historyFragment.scrollToTop();
- }else {
- this.setTitle(getString(R.string.history));
- }
- replaceFragment(historyFragment);
- break;
+ int id = item.getItemId();
+ if(id == R.id.home){
+ if(lastFragment == homeFragment){
+ homeFragment.scrollToTop();
+ }else{
+ this.setTitle(R.string.app_name);;
+ }
+ replaceFragment(homeFragment);
+ }else if(id == R.id.history){
+ if(lastFragment == historyFragment){
+ historyFragment.scrollToTop();
+ }else {
+ this.setTitle(getString(R.string.history));
+ }
+ replaceFragment(historyFragment);
+ }else if(id == R.id.more){
+ if(lastFragment == moreFragment){
+ Intent intent = new Intent(context, SettingsActivity.class);
+ startActivity(intent);
+ }else{
+ this.setTitle(getString(R.string.more));
+ }
+ replaceFragment(moreFragment);
+ }else if(id == R.id.music_editor){
+ replaceFragment(musicEditorFragment);
}
return true;
});
@@ -109,25 +119,34 @@ public class MainActivity extends AppCompatActivity{
historyFragment = new HistoryFragment();
homeFragment.handleIntent(intent);
- fm.beginTransaction()
- .replace(R.id.frame_layout, homeFragment)
- .add(R.id.frame_layout, historyFragment)
- .hide(historyFragment)
- .commit();
-
- lastFragment = homeFragment;
+ initFragments();
}
}
+ private void initFragments(){
+ fm.beginTransaction()
+ .replace(R.id.frame_layout, homeFragment)
+ .add(R.id.frame_layout, historyFragment)
+ .add(R.id.frame_layout, moreFragment)
+ .add(R.id.frame_layout, musicEditorFragment)
+ .hide(historyFragment)
+ .hide(moreFragment)
+ .hide(musicEditorFragment)
+ .commit();
+
+ lastFragment = homeFragment;
+ }
+
private void replaceFragment(Fragment f){
fm.beginTransaction().hide(lastFragment).show(f).commit();
lastFragment = f;
}
- public void startDownloadService(String title){
+ public void startDownloadService(String title, int id){
if(isDownloadServiceRunning) return;
Intent serviceIntent = new Intent(context, DownloaderService.class);
serviceIntent.putExtra("title", title);
+ serviceIntent.putExtra("id", id);
context.getApplicationContext().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
diff --git a/app/src/main/java/com/deniscerri/ytdl/page/CustomCommandActivity.java b/app/src/main/java/com/deniscerri/ytdl/page/CustomCommandActivity.java
new file mode 100644
index 00000000..854d78ca
--- /dev/null
+++ b/app/src/main/java/com/deniscerri/ytdl/page/CustomCommandActivity.java
@@ -0,0 +1,191 @@
+package com.deniscerri.ytdl.page;
+
+import static com.deniscerri.ytdl.App.notificationUtil;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.media.MediaScannerConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import com.deniscerri.ytdl.BuildConfig;
+import com.deniscerri.ytdl.DownloaderService;
+import com.deniscerri.ytdl.R;
+import com.deniscerri.ytdl.util.NotificationUtil;
+import com.google.android.material.appbar.MaterialToolbar;
+import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
+import com.yausername.youtubedl_android.DownloadProgressCallback;
+import com.yausername.youtubedl_android.YoutubeDL;
+import com.yausername.youtubedl_android.YoutubeDLRequest;
+import java.io.File;
+import java.util.Collections;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+public class CustomCommandActivity extends AppCompatActivity {
+ private static final String TAG = "CustomCommandActivity";
+ private MaterialToolbar topAppBar;
+ private boolean running = false;
+ private boolean isDownloadServiceRunning = false;
+ public DownloaderService downloaderService;
+ private CompositeDisposable compositeDisposable = new CompositeDisposable();
+ private TextView output;
+ private EditText input;
+ private ExtendedFloatingActionButton fab;
+ Context context;
+
+ private final DownloadProgressCallback callback = (progress, etaInSeconds, line) -> CustomCommandActivity.this.runOnUiThread(() -> {
+ output.append(line);
+ notificationUtil.updateDownloadNotification(NotificationUtil.COMMAND_DOWNLOAD_NOTIFICATION_ID,
+ line, (int) progress, 0, getString(R.string.running_ytdlp_command));
+ });
+
+ private final ServiceConnection serviceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ downloaderService = ((DownloaderService.LocalBinder) service).getService();
+ isDownloadServiceRunning = true;
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ downloaderService = null;
+ isDownloadServiceRunning = false;
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_custom_command);
+
+ context = getBaseContext();
+ topAppBar = findViewById(R.id.custom_command_toolbar);
+ topAppBar.setNavigationOnClickListener(view -> onBackPressed());
+ output = findViewById(R.id.custom_command_output);
+ output.setMovementMethod(new ScrollingMovementMethod());
+
+ input = findViewById(R.id.command_edittext);
+ input.requestFocus();
+
+ fab = findViewById(R.id.command_fab);
+ fab.setOnClickListener(view -> {
+ runCommand(input.getText().toString());
+ });
+ }
+
+ @Override
+ public void onBackPressed() {
+ super.onBackPressed();
+ }
+
+ private void runCommand(String text){
+ if (running) {
+ Toast.makeText(this, "Cannot start command! A command is already in progress", Toast.LENGTH_LONG).show();
+ return;
+ }
+ if(!text.startsWith("yt-dlp ")){
+ Toast.makeText(context, "Wrong input! Try Again!", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ fab.hide();
+ input.setEnabled(false);
+
+ output.setText("");
+ startDownloadService(getString(R.string.running_ytdlp_command), NotificationUtil.COMMAND_DOWNLOAD_NOTIFICATION_ID);
+ text = text.substring(6).trim();
+
+ if (!isStoragePermissionGranted()) {
+ Toast.makeText(context, R.string.try_again_after_permission, Toast.LENGTH_LONG).show();
+ stopDownloadService();
+ return;
+ }
+
+ YoutubeDLRequest request = new YoutubeDLRequest(Collections.emptyList());
+ String commandRegex = "\"([^\"]*)\"|(\\S+)";
+ Matcher m = Pattern.compile(commandRegex).matcher(text);
+ while (m.find()) {
+ if (m.group(1) != null) {
+ request.addOption(m.group(1));
+ } else {
+ request.addOption(m.group(2));
+ }
+ }
+
+ SharedPreferences sharedPreferences = context.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE);
+ String downloadsDir = sharedPreferences.getString("command_path", "");
+ File youtubeDLDir = new File(downloadsDir);
+ if (!youtubeDLDir.exists()) {
+ boolean isDirCreated = youtubeDLDir.mkdir();
+ if (!isDirCreated) {
+ Toast.makeText(context, R.string.failed_making_directory, Toast.LENGTH_LONG).show();
+ }
+ }
+ request.addOption("-o", youtubeDLDir.getAbsolutePath() + "/%(title)s.%(ext)s");
+
+ running = true;
+
+ Disposable disposable = Observable.fromCallable(() -> YoutubeDL.getInstance().execute(request, callback))
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(youtubeDLResponse -> {
+ output.append(youtubeDLResponse.getOut());
+ running = false;
+ stopDownloadService();
+ // MEDIA SCAN
+ MediaScannerConnection.scanFile(context, new String[]{"/storage"}, null, null);
+ fab.show();
+ input.setEnabled(true);
+ }, e -> {
+ if (BuildConfig.DEBUG) Log.e(TAG, getString(R.string.failed_download), e);
+ output.append(e.getMessage());
+ running = false;
+ stopDownloadService();
+ fab.show();
+ input.setEnabled(true);
+ });
+ compositeDisposable.add(disposable);
+ }
+
+ public boolean isStoragePermissionGranted() {
+ if (ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else {
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
+ return false;
+ }
+ }
+
+ public void startDownloadService(String title, int id){
+ if(isDownloadServiceRunning) return;
+ Intent serviceIntent = new Intent(context, DownloaderService.class);
+ serviceIntent.putExtra("title", title);
+ serviceIntent.putExtra("id", id);
+ context.getApplicationContext().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ public void stopDownloadService(){
+ if(!isDownloadServiceRunning) return;
+ context.getApplicationContext().unbindService(serviceConnection);
+ isDownloadServiceRunning = false;
+ }
+}
diff --git a/app/src/main/java/com/deniscerri/ytdl/page/HistoryFragment.java b/app/src/main/java/com/deniscerri/ytdl/page/HistoryFragment.java
index 2b5660dc..7fcb37be 100644
--- a/app/src/main/java/com/deniscerri/ytdl/page/HistoryFragment.java
+++ b/app/src/main/java/com/deniscerri/ytdl/page/HistoryFragment.java
@@ -7,6 +7,7 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.appcompat.widget.SearchView;
+import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
@@ -31,6 +32,7 @@ import com.deniscerri.ytdl.adapter.HistoryRecyclerViewAdapter;
import com.deniscerri.ytdl.database.DBManager;
import com.deniscerri.ytdl.database.Video;
import com.facebook.shimmer.ShimmerFrameLayout;
+import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
@@ -50,6 +52,7 @@ public class HistoryFragment extends Fragment implements HistoryRecyclerViewAdap
private ShimmerFrameLayout shimmerCards;
private MaterialToolbar topAppBar;
private RecyclerView recyclerView;
+ private NestedScrollView scrollView;
private HistoryRecyclerViewAdapter historyRecyclerViewAdapter;
private BottomSheetDialog bottomSheet;
private Handler uiHandler;
@@ -91,6 +94,7 @@ public class HistoryFragment extends Fragment implements HistoryRecyclerViewAdap
historyObjects = new ArrayList<>();
recyclerView = fragmentView.findViewById(R.id.recycler_view_history);
+ scrollView = fragmentView.findViewById(R.id.history_scrollview);
historyRecyclerViewAdapter = new HistoryRecyclerViewAdapter(historyObjects, this, context);
recyclerView.setAdapter(historyRecyclerViewAdapter);
@@ -128,7 +132,8 @@ public class HistoryFragment extends Fragment implements HistoryRecyclerViewAdap
}
public void scrollToTop(){
- recyclerView.smoothScrollToPosition(0);
+ scrollView.smoothScrollTo(-100,-100);
+ new Handler(Looper.getMainLooper()).post(() -> ((AppBarLayout) topAppBar.getParent()).setExpanded(true, true));
}
private void addNoResultsView(){
diff --git a/app/src/main/java/com/deniscerri/ytdl/page/HomeFragment.java b/app/src/main/java/com/deniscerri/ytdl/page/HomeFragment.java
index fe614efa..5fc57780 100644
--- a/app/src/main/java/com/deniscerri/ytdl/page/HomeFragment.java
+++ b/app/src/main/java/com/deniscerri/ytdl/page/HomeFragment.java
@@ -39,8 +39,8 @@ import com.deniscerri.ytdl.adapter.HomeRecyclerViewAdapter;
import com.deniscerri.ytdl.api.YoutubeAPIManager;
import com.deniscerri.ytdl.database.DBManager;
import com.deniscerri.ytdl.database.Video;
-import com.deniscerri.ytdl.NotificationUtil;
import com.deniscerri.ytdl.page.settings.SettingsActivity;
+import com.deniscerri.ytdl.util.NotificationUtil;
import com.facebook.shimmer.ShimmerFrameLayout;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.MaterialToolbar;
@@ -487,10 +487,6 @@ public class HomeFragment extends Fragment implements HomeRecyclerViewAdapter.On
}
if (type.equals("mp3")) {
- boolean embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false);
- if(embedThumb){
- request.addOption("--embed-thumbnail");
- }
boolean removeNonMusic = sharedPreferences.getBoolean("remove_non_music", false);
if(removeNonMusic){
request.addOption("--sponsorblock-remove", "all");
@@ -502,12 +498,15 @@ public class HomeFragment extends Fragment implements HomeRecyclerViewAdapter.On
String format = sharedPreferences.getString("audio_format", "");
request.addOption("--audio-format", format);
+ if(format.equals("mp3") || format.equals("m4a") || format.equals("flac")){
+ boolean embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false);
+ if(embedThumb){
+ request.addOption("--embed-thumbnail");
+ }
+ }
+
clickedButton = recyclerView.findViewWithTag(id + "##mp3");
} else if (type.equals("mp4")) {
- boolean embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false);
- if(embedThumb){
- request.addOption("--embed-thumbnail");
- }
boolean addChapters = sharedPreferences.getBoolean("add_chapters", false);
if(addChapters){
request.addOption("--sponsorblock-mark", "all");
@@ -516,8 +515,16 @@ public class HomeFragment extends Fragment implements HomeRecyclerViewAdapter.On
if(embedSubs){
request.addOption("--embed-subs", "");
}
+ request.addOption("-f", "bestvideo+bestaudio/best");
String format = sharedPreferences.getString("video_format", "");
- request.addOption("-f", "bestvideo[ext="+format+"]+bestaudio[ext=m4a]/best[ext="+format+"]/best");
+ request.addOption("--merge-output-format", format);
+
+ if(!format.equals("webm")){
+ boolean embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false);
+ if(embedThumb){
+ request.addOption("--embed-thumbnail");
+ }
+ }
clickedButton = recyclerView.findViewWithTag(id + "##mp4");
}
@@ -655,7 +662,7 @@ public class HomeFragment extends Fragment implements HomeRecyclerViewAdapter.On
Toast.makeText(context, R.string.added_to_queue, Toast.LENGTH_LONG).show();
return;
}
- mainActivity.startDownloadService(vid.getTitle());
+ mainActivity.startDownloadService(vid.getTitle(), NotificationUtil.DOWNLOAD_NOTIFICATION_ID);
startDownload(downloadQueue);
}
@@ -689,7 +696,7 @@ public class HomeFragment extends Fragment implements HomeRecyclerViewAdapter.On
Toast.makeText(context, R.string.added_to_queue, Toast.LENGTH_LONG).show();
return;
}
- mainActivity.startDownloadService(downloadQueue.peek().getTitle());
+ mainActivity.startDownloadService(downloadQueue.peek().getTitle(), NotificationUtil.DOWNLOAD_NOTIFICATION_ID);
startDownload(downloadQueue);
}
}
diff --git a/app/src/main/java/com/deniscerri/ytdl/page/MoreFragment.java b/app/src/main/java/com/deniscerri/ytdl/page/MoreFragment.java
new file mode 100644
index 00000000..11e616e2
--- /dev/null
+++ b/app/src/main/java/com/deniscerri/ytdl/page/MoreFragment.java
@@ -0,0 +1,137 @@
+package com.deniscerri.ytdl.page;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+
+import com.deniscerri.ytdl.BuildConfig;
+import com.deniscerri.ytdl.R;
+import com.deniscerri.ytdl.util.UpdateUtil;
+import com.google.android.material.card.MaterialCardView;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import com.yausername.youtubedl_android.YoutubeDL;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+public class MoreFragment extends PreferenceFragmentCompat {
+ Preference updateYTDL;
+ Preference updateApp;
+ MaterialCardView materialCardView;
+
+ public static boolean updatingYTDL;
+ public static boolean updatingApp;
+ public static final String TAG = "MoreFragment";
+ private final CompositeDisposable compositeDisposable = new CompositeDisposable();
+
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ setPreferencesFromResource(R.xml.more_preferences, rootKey);
+
+ updateYTDL = findPreference("update_ytdl");
+ updateApp = findPreference("update_app");
+
+ updateYTDL.setOnPreferenceClickListener(preference -> {
+ updateYoutubeDL();
+ return true;
+ });
+
+ updateApp.setOnPreferenceClickListener(preference -> {
+ updateApp();
+ return true;
+ });
+ }
+
+
+
+ private void updateYoutubeDL() {
+ if (updatingYTDL) {
+ Toast.makeText(getContext(), getString(R.string.ytdl_already_updating), Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ Toast.makeText(getContext(), getString(R.string.ytdl_updating_started), Toast.LENGTH_SHORT).show();
+
+ updatingYTDL = true;
+ Disposable disposable = Observable.fromCallable(() -> YoutubeDL.getInstance().updateYoutubeDL(getContext()))
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(status -> {
+ switch (status) {
+ case DONE:
+ Toast.makeText(getContext(), getString(R.string.ytld_update_success), Toast.LENGTH_LONG).show();
+ break;
+ case ALREADY_UP_TO_DATE:
+ Toast.makeText(getContext(), getString(R.string.you_are_in_latest_version), Toast.LENGTH_LONG).show();
+ break;
+ default:
+ Toast.makeText(getContext(), status.toString(), Toast.LENGTH_LONG).show();
+ break;
+ }
+ updatingYTDL = false;
+ }, e -> {
+ if(BuildConfig.DEBUG) Log.e(TAG, getString(R.string.ytdl_update_failed), e);
+ Toast.makeText(getContext(), getString(R.string.ytdl_update_failed), Toast.LENGTH_LONG).show();
+ updatingYTDL = false;
+ });
+ compositeDisposable.add(disposable);
+ }
+
+
+ private void updateApp(){
+ if (updatingApp) {
+ Toast.makeText(getContext(), getString(R.string.ytdl_already_updating), Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ UpdateUtil updateUtil = new UpdateUtil(getContext());
+ AtomicReference res = new AtomicReference<>(new JSONObject());
+
+ try{
+ Thread thread = new Thread(() -> res.set(updateUtil.checkForAppUpdate()));
+ thread.start();
+ thread.join();
+ }catch(Exception e){
+ Log.e(TAG, e.toString());
+ }
+
+ if(res.get() == null){
+ Toast.makeText(getContext(), R.string.error_checking_latest_version, Toast.LENGTH_SHORT).show();
+ }
+
+ String version = "";
+ String body = "";
+ try {
+ version = res.get().getString("tag_name");
+ body = res.get().getString("body");
+ } catch (JSONException ignored) {}
+
+ if(version.equals("v"+BuildConfig.VERSION_NAME)){
+ getActivity().runOnUiThread(() -> Toast.makeText(getContext(), R.string.you_are_running_latest_version, Toast.LENGTH_SHORT).show());
+ return;
+ }
+
+ MaterialAlertDialogBuilder updateDialog = new MaterialAlertDialogBuilder(getContext())
+ .setTitle(version)
+ .setMessage(body)
+ .setIcon(R.drawable.ic_update_app)
+ .setNegativeButton("Cancel", (dialogInterface, i) -> {})
+ .setPositiveButton("Update", (dialogInterface, i) -> updateUtil.updateApp(res.get()));
+ updateDialog.show();
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdl/page/MusicEditorFragment.java b/app/src/main/java/com/deniscerri/ytdl/page/MusicEditorFragment.java
new file mode 100644
index 00000000..78656926
--- /dev/null
+++ b/app/src/main/java/com/deniscerri/ytdl/page/MusicEditorFragment.java
@@ -0,0 +1,30 @@
+package com.deniscerri.ytdl.page;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.deniscerri.ytdl.R;
+
+public class MusicEditorFragment extends Fragment {
+
+ public MusicEditorFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_music_editor, container, false);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdl/page/settings/SettingsFragment.java b/app/src/main/java/com/deniscerri/ytdl/page/settings/SettingsFragment.java
index 4be31ff2..74d43284 100644
--- a/app/src/main/java/com/deniscerri/ytdl/page/settings/SettingsFragment.java
+++ b/app/src/main/java/com/deniscerri/ytdl/page/settings/SettingsFragment.java
@@ -33,6 +33,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
Preference musicPath;
Preference videoPath;
+ Preference commandPath;
SeekBarPreference concurrentFragments;
EditTextPreference limitRate;
@@ -46,17 +47,13 @@ public class SettingsFragment extends PreferenceFragmentCompat {
ListPreference videoFormat;
SeekBarPreference audioQuality;
- Preference updateYTDL;
- Preference updateApp;
+ Preference version;
public static final int MUSIC_PATH_CODE = 33333;
public static final int VIDEO_PATH_CODE = 55555;
- public static boolean updatingYTDL;
- public static boolean updatingApp;
+ public static final int COMMAND_PATH_CODE = 77777;
private static boolean firstRun = true;
-
private static final String TAG = "SettingsFragment";
- private final CompositeDisposable compositeDisposable = new CompositeDisposable();
@Override
@@ -65,6 +62,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
musicPath = findPreference("music_path");
videoPath = findPreference("video_path");
+ commandPath = findPreference("command_path");
concurrentFragments = findPreference("concurrent_fragments");
limitRate = findPreference("limit_rate");
@@ -78,9 +76,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);
if(firstRun){
initPreferences();
@@ -98,6 +95,9 @@ public class SettingsFragment extends PreferenceFragmentCompat {
if(preferences.getString("video_path", "").isEmpty()){
editor.putString("video_path", "/storage/emulated/0/Movies/");
}
+ if(preferences.getString("command_path", "").isEmpty()){
+ editor.putString("command_path", "/storage/emulated/0/Download");
+ }
editor.putInt("concurrent_fragments", concurrentFragments.getValue());
editor.putString("limit_rate", limitRate.getText());
@@ -132,6 +132,13 @@ public class SettingsFragment extends PreferenceFragmentCompat {
return true;
});
+ commandPath.setSummary(preferences.getString("command_path", ""));
+ commandPath.setOnPreferenceClickListener(preference -> {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
+ commandPathResultLauncher.launch(intent);
+ return true;
+ });
+
concurrentFragments.setOnPreferenceChangeListener((preference, newValue) -> {
int value = Integer.parseInt(String.valueOf(newValue));
editor.putInt("concurrent_fragments", value);
@@ -180,14 +187,18 @@ public class SettingsFragment extends PreferenceFragmentCompat {
return true;
});
+ audioFormat.setSummary(preferences.getString("audio_format", ""));
audioFormat.setOnPreferenceChangeListener((preference, newValue) -> {
editor.putString("audio_format", String.valueOf(newValue));
+ audioFormat.setSummary(String.valueOf(newValue));
editor.apply();
return true;
});
+ videoFormat.setSummary(preferences.getString("video_format", ""));
videoFormat.setOnPreferenceChangeListener((preference, newValue) -> {
editor.putString("video_format", String.valueOf(newValue));
+ videoFormat.setSummary(String.valueOf(newValue));
editor.apply();
return true;
});
@@ -198,15 +209,6 @@ public class SettingsFragment extends PreferenceFragmentCompat {
return true;
});
- updateYTDL.setOnPreferenceClickListener(preference -> {
- updateYoutubeDL();
- return true;
- });
-
- updateApp.setOnPreferenceClickListener(preference -> {
- updateApp();
- return true;
- });
}
ActivityResultLauncher musicPathResultLauncher = registerForActivityResult(
@@ -231,6 +233,17 @@ public class SettingsFragment extends PreferenceFragmentCompat {
}
});
+ ActivityResultLauncher commandPathResultLauncher = registerForActivityResult(
+ new ActivityResultContracts.StartActivityForResult(),
+ new ActivityResultCallback() {
+ @Override
+ public void onActivityResult(ActivityResult result) {
+ if (result.getResultCode() == Activity.RESULT_OK) {
+ changePath(commandPath, result.getData(), COMMAND_PATH_CODE);
+ }
+ }
+ });
+
public void changePath(Preference p, Intent data, int requestCode){
Log.e("TEST", data.toUri(0));
String dataValue = data.getData().toString();
@@ -255,7 +268,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
path.append(pieces[i]).append("/");
}
- Log.e("TEST", path.toString());
+ Log.e(TAG, path.toString());
p.setSummary(path.toString());
SharedPreferences sharedPreferences = requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
@@ -266,76 +279,10 @@ public class SettingsFragment extends PreferenceFragmentCompat {
case VIDEO_PATH_CODE:
editor.putString("video_path", path.toString());
break;
+ case COMMAND_PATH_CODE:
+ editor.putString("command_path", path.toString());
+ break;
}
editor.apply();
}
-
- private void updateYoutubeDL() {
- if (updatingYTDL) {
- Toast.makeText(getContext(), getString(R.string.ytdl_already_updating), Toast.LENGTH_LONG).show();
- return;
- }
-
- Toast.makeText(getContext(), getString(R.string.ytdl_updating_started), Toast.LENGTH_SHORT).show();
-
- updatingYTDL = true;
- Disposable disposable = Observable.fromCallable(() -> YoutubeDL.getInstance().updateYoutubeDL(getContext()))
- .subscribeOn(Schedulers.newThread())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(status -> {
- switch (status) {
- case DONE:
- Toast.makeText(getContext(), getString(R.string.ytld_update_success), Toast.LENGTH_LONG).show();
- break;
- case ALREADY_UP_TO_DATE:
- Toast.makeText(getContext(), getString(R.string.you_are_in_latest_version), Toast.LENGTH_LONG).show();
- break;
- default:
- Toast.makeText(getContext(), status.toString(), Toast.LENGTH_LONG).show();
- break;
- }
- updatingYTDL = false;
- }, e -> {
- if(BuildConfig.DEBUG) Log.e(TAG, getString(R.string.ytdl_update_failed), e);
- Toast.makeText(getContext(), getString(R.string.ytdl_update_failed), Toast.LENGTH_LONG).show();
- updatingYTDL = false;
- });
- compositeDisposable.add(disposable);
- }
-
-
- private void updateApp(){
- if (updatingApp) {
- Toast.makeText(getContext(), getString(R.string.ytdl_already_updating), Toast.LENGTH_LONG).show();
- return;
- }
-
- Toast.makeText(getContext(), getString(R.string.ytdl_updating_started), Toast.LENGTH_SHORT).show();
-
- updatingApp = true;
- Disposable disposable = Observable.fromCallable(() -> YoutubeDL.getInstance().updateYoutubeDL(getContext()))
- .subscribeOn(Schedulers.newThread())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(status -> {
- switch (status) {
- case DONE:
- Toast.makeText(getContext(), getString(R.string.ytld_update_success), Toast.LENGTH_LONG).show();
- break;
- case ALREADY_UP_TO_DATE:
- Toast.makeText(getContext(), getString(R.string.you_are_in_latest_version), Toast.LENGTH_LONG).show();
- break;
- default:
- Toast.makeText(getContext(), status.toString(), Toast.LENGTH_LONG).show();
- break;
- }
- updatingApp = false;
- }, e -> {
- if(BuildConfig.DEBUG) Log.e(TAG, getString(R.string.ytdl_update_failed), e);
- Toast.makeText(getContext(), getString(R.string.ytdl_update_failed), Toast.LENGTH_LONG).show();
- updatingApp = false;
- });
- compositeDisposable.add(disposable);
- }
-
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdl/NotificationUtil.java b/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.java
similarity index 85%
rename from app/src/main/java/com/deniscerri/ytdl/NotificationUtil.java
rename to app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.java
index 2aa34828..3ac0f5d9 100644
--- a/app/src/main/java/com/deniscerri/ytdl/NotificationUtil.java
+++ b/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.java
@@ -1,4 +1,4 @@
-package com.deniscerri.ytdl;
+package com.deniscerri.ytdl.util;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -17,6 +17,10 @@ public class NotificationUtil {
Context context;
public static final String DOWNLOAD_SERVICE_CHANNEL_ID = "1";
public static final int DOWNLOAD_NOTIFICATION_ID = 1;
+
+ public static final String COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID = "2";
+ public static final int COMMAND_DOWNLOAD_NOTIFICATION_ID = 2;
+
public static NotificationCompat.Builder notificationBuilder;
private static int PROGRESS_MAX = 100;
private static int PROGRESS_CURR = 0;
@@ -30,12 +34,21 @@ public class NotificationUtil {
public void createNotificationChannel(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+
+ //gui downloads
CharSequence name = context.getString(R.string.download_notification_channel_name);
String description = context.getString(R.string.download_notification_channel_description);
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(DOWNLOAD_SERVICE_CHANNEL_ID, name, importance);
channel.setDescription(description);
- NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+ notificationManager.createNotificationChannel(channel);
+
+ //command downloads
+ name = "Command Downloads";
+ description = "Notification that shows the download progress of a yt-dlp command";
+ channel = new NotificationChannel(COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID, name, importance);
+ channel.setDescription(description);
notificationManager.createNotificationChannel(channel);
}
}
diff --git a/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.java b/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.java
new file mode 100644
index 00000000..ded1c4e6
--- /dev/null
+++ b/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.java
@@ -0,0 +1,108 @@
+package com.deniscerri.ytdl.util;
+
+
+import android.app.DownloadManager;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.deniscerri.ytdl.App;
+import com.deniscerri.ytdl.R;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class UpdateUtil {
+ Context context;
+ private final String TAG = "UpdateUtil";
+ private DownloadManager downloadManager;
+
+ public UpdateUtil(Context context){
+ this.context = context;
+ downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
+ }
+
+ public JSONObject checkForAppUpdate(){
+ String url = "https://api.github.com/repos/deniscerri/ytdlnis/releases/latest";
+
+ 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);
+ }
+ reader.close();
+
+ json = new JSONObject(responseContent.toString());
+ if(json.has("error")){
+ throw new Exception();
+ }
+ }
+ conn.disconnect();
+ }catch(Exception e){
+ Log.e(TAG, e.toString());
+ }
+
+
+
+
+ return json;
+ }
+
+ public void updateApp(JSONObject updateInfo){
+ try{
+ JSONArray versions = updateInfo.getJSONArray("assets");
+ String url = "";
+ String app_name = "";
+ for (int i = 0; i < versions.length(); i++){
+ JSONObject tmp = versions.getJSONObject(i);
+ if(tmp.getString("name").contains(Build.SUPPORTED_ABIS[0])){
+ url = tmp.getString("browser_download_url");
+ app_name = tmp.getString("name");
+ break;
+ }
+ }
+
+ if(url.isEmpty()){
+ Toast.makeText(context, R.string.couldnt_find_apk, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ Uri uri = Uri.parse(url);
+ Environment
+ .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
+ .mkdirs();
+
+ downloadManager.enqueue(new DownloadManager.Request(uri)
+ .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |
+ DownloadManager.Request.NETWORK_MOBILE)
+ .setAllowedOverRoaming(true)
+ .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
+ .setTitle(context.getString(R.string.downloading_update))
+ .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, app_name));
+
+ }catch(Exception ignored){}
+ }
+
+
+}
diff --git a/app/src/main/res/drawable/ic_baseline_keyboard_arrow_right_24.xml b/app/src/main/res/drawable/ic_baseline_keyboard_arrow_right_24.xml
new file mode 100644
index 00000000..15bfe6de
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_keyboard_arrow_right_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_delete_all.xml b/app/src/main/res/drawable/ic_delete_all.xml
index e6afffed..b6f77b76 100644
--- a/app/src/main/res/drawable/ic_delete_all.xml
+++ b/app/src/main/res/drawable/ic_delete_all.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/app/src/main/res/drawable/ic_info.xml b/app/src/main/res/drawable/ic_info.xml
new file mode 100644
index 00000000..7c3f0b35
--- /dev/null
+++ b/app/src/main/res/drawable/ic_info.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
index b240b830..487d9c85 100644
--- a/app/src/main/res/drawable/ic_settings.xml
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -1,5 +1,4 @@
-
-
+
diff --git a/app/src/main/res/layout/activity_custom_command.xml b/app/src/main/res/layout/activity_custom_command.xml
new file mode 100644
index 00000000..84906eaa
--- /dev/null
+++ b/app/src/main/res/layout/activity_custom_command.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_more.xml
similarity index 88%
rename from app/src/main/res/layout/fragment_settings.xml
rename to app/src/main/res/layout/fragment_more.xml
index 522b9976..ebbe9341 100644
--- a/app/src/main/res/layout/fragment_settings.xml
+++ b/app/src/main/res/layout/fragment_more.xml
@@ -1,14 +1,14 @@
@@ -17,10 +17,11 @@
android:id="@+id/home_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
- app:title="@string/settings"
+ app:title="@string/more"
app:menu="@menu/empty_menu"
/>
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_music_editor.xml b/app/src/main/res/layout/fragment_music_editor.xml
new file mode 100644
index 00000000..0641bc32
--- /dev/null
+++ b/app/src/main/res/layout/fragment_music_editor.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml
index e50f391f..a990783c 100644
--- a/app/src/main/res/menu/bottom_nav_menu.xml
+++ b/app/src/main/res/menu/bottom_nav_menu.xml
@@ -10,9 +10,6 @@
-
diff --git a/app/src/main/res/menu/history_menu.xml b/app/src/main/res/menu/history_menu.xml
index b13db6a2..964e8c7b 100644
--- a/app/src/main/res/menu/history_menu.xml
+++ b/app/src/main/res/menu/history_menu.xml
@@ -21,7 +21,7 @@
android:id="@+id/delete_history"
android:icon="@drawable/ic_delete_all"
android:title="@string/fshi_historin"
- app:showAsAction="never" />
+ app:showAsAction="ifRoom" />
diff --git a/app/src/main/res/values-land/dimens.xml b/app/src/main/res/values-land/dimens.xml
new file mode 100644
index 00000000..10125a35
--- /dev/null
+++ b/app/src/main/res/values-land/dimens.xml
@@ -0,0 +1,3 @@
+
+ 48dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w1240dp/dimens.xml b/app/src/main/res/values-w1240dp/dimens.xml
new file mode 100644
index 00000000..ec434d3d
--- /dev/null
+++ b/app/src/main/res/values-w1240dp/dimens.xml
@@ -0,0 +1,3 @@
+
+ 200dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index d3e2922a..e8943eb6 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -15,7 +15,16 @@
- mp4
- mkv
- - mov
- webm
+
+
+ - Reply
+ - Reply to all
+
+
+
+ - reply
+ - reply_all
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index a6b3daec..0247a957 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -1,2 +1,3 @@
-
\ No newline at end of file
+
+ 16dp
\ 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 7f0e5038..0ca150a9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -42,9 +42,19 @@
Confirm
Search from History
No Results
- TAG Editor
+ Music Editor
Commands
More
Update App
Download the latest version of the app
+ Version
+ Run Custom Command
+ Write yt-dlp command
+ Run
+ Running yt-dlp Custom Command
+ Custom Command Directory
+ You are running the latest version!
+ Error checking for latest version!
+ Couldn\'t find a suitable apk!
+ Downloading Update
diff --git a/app/src/main/res/xml/more_preferences.xml b/app/src/main/res/xml/more_preferences.xml
new file mode 100644
index 00000000..c622d9ca
--- /dev/null
+++ b/app/src/main/res/xml/more_preferences.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml
index f3f3226c..7a29095c 100644
--- a/app/src/main/res/xml/root_preferences.xml
+++ b/app/src/main/res/xml/root_preferences.xml
@@ -1,132 +1,113 @@
-
+
+
+
+
+ app:summary=" Number of fragments of a dash/hlsnative video that should be downloaded concurrently"
+ app:title="Concurrent Fragments" />
+ app:title="Limit Rate" />
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file