ytdlnis/app/src/main/java/com/deniscerri/ytdl/page/CustomCommandActivity.java
Denis Çerri 709a3778a2
other new features
- check for updates when app launches
- remove scrollview so that recyclerview can recycle. It wont hide the top bar but thats a sacrifice for the greater good.
- remove download all mini card and made it into a floating action button
- made video loading from playlists as fast as possible even if you have thousands of videos in a list. It adds videos in recyclerview in a form of pagination
- fixed preferences when you just installed the app and you never opened the preference screen you can still download without erroring out
2022-09-18 00:27:36 +02:00

176 lines
7 KiB
Java

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.page.settings.SettingsFragment;
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();
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", getString(R.string.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 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;
}
}