mirror of https://github.com/deniscerri/ytdlnis
parent
f2c4fc33a3
commit
604fd300c8
@ -0,0 +1 @@
|
|||||||
|
YTDLnis
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<bytecodeTargetLevel target="1.8" />
|
<bytecodeTargetLevel target="11" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@ -0,0 +1,192 @@
|
|||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 7,
|
||||||
|
"identityHash": "9951239671c916d8805c4156bb69cb6b",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "results",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `videoId` TEXT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `downloadedAudio` INTEGER NOT NULL, `downloadedVideo` INTEGER NOT NULL, `isPlaylistItem` INTEGER NOT NULL, `website` TEXT NOT NULL, `downloadingAudio` INTEGER NOT NULL, `downloadingVideo` INTEGER NOT NULL, `playlistTitle` TEXT NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "videoId",
|
||||||
|
"columnName": "videoId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "author",
|
||||||
|
"columnName": "author",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "duration",
|
||||||
|
"columnName": "duration",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "thumb",
|
||||||
|
"columnName": "thumb",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadedAudio",
|
||||||
|
"columnName": "downloadedAudio",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadedVideo",
|
||||||
|
"columnName": "downloadedVideo",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isPlaylistItem",
|
||||||
|
"columnName": "isPlaylistItem",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "website",
|
||||||
|
"columnName": "website",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadingAudio",
|
||||||
|
"columnName": "downloadingAudio",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadingVideo",
|
||||||
|
"columnName": "downloadingVideo",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "playlistTitle",
|
||||||
|
"columnName": "playlistTitle",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"autoGenerate": true
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "history",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `time` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `isQueuedDownload` INTEGER NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "author",
|
||||||
|
"columnName": "author",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "duration",
|
||||||
|
"columnName": "duration",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "thumb",
|
||||||
|
"columnName": "thumb",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "time",
|
||||||
|
"columnName": "time",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadPath",
|
||||||
|
"columnName": "downloadPath",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "website",
|
||||||
|
"columnName": "website",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isQueuedDownload",
|
||||||
|
"columnName": "isQueuedDownload",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"autoGenerate": true
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"views": [],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9951239671c916d8805c4156bb69cb6b')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,359 +0,0 @@
|
|||||||
package com.deniscerri.ytdlnis;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
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.content.pm.PackageManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.WindowInsets;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
|
|
||||||
import com.deniscerri.ytdlnis.database.DBManager;
|
|
||||||
import com.deniscerri.ytdlnis.database.Video;
|
|
||||||
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding;
|
|
||||||
import com.deniscerri.ytdlnis.page.DownloadsFragment;
|
|
||||||
import com.deniscerri.ytdlnis.page.HomeFragment;
|
|
||||||
import com.deniscerri.ytdlnis.page.MoreFragment;
|
|
||||||
import com.deniscerri.ytdlnis.page.settings.SettingsActivity;
|
|
||||||
import com.deniscerri.ytdlnis.service.IDownloaderListener;
|
|
||||||
import com.deniscerri.ytdlnis.service.IDownloaderService;
|
|
||||||
import com.deniscerri.ytdlnis.util.UpdateUtil;
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity{
|
|
||||||
|
|
||||||
ActivityMainBinding binding;
|
|
||||||
Context context;
|
|
||||||
|
|
||||||
private static final String TAG = "MainActivity";
|
|
||||||
|
|
||||||
private HomeFragment homeFragment;
|
|
||||||
private DownloadsFragment downloadsFragment;
|
|
||||||
private MoreFragment moreFragment;
|
|
||||||
|
|
||||||
private Fragment lastFragment;
|
|
||||||
private FragmentManager fm;
|
|
||||||
|
|
||||||
private boolean isDownloadServiceRunning = false;
|
|
||||||
public DownloaderService downloaderService;
|
|
||||||
private ArrayList<IDownloaderListener> listeners = null;
|
|
||||||
private IDownloaderService iDownloaderService;
|
|
||||||
|
|
||||||
public final ServiceConnection serviceConnection = new ServiceConnection() {
|
|
||||||
@Override
|
|
||||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
|
||||||
downloaderService = ((DownloaderService.LocalBinder) service).getService();
|
|
||||||
iDownloaderService = (IDownloaderService) service;
|
|
||||||
isDownloadServiceRunning = true;
|
|
||||||
try{
|
|
||||||
iDownloaderService.addActivity(MainActivity.this, listeners);
|
|
||||||
for (int i = 0; i < listeners.size(); i++){
|
|
||||||
IDownloaderListener listener = listeners.get(i);
|
|
||||||
listener.onDownloadStart(iDownloaderService.getDownloadInfo());
|
|
||||||
}
|
|
||||||
}catch(Exception e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceDisconnected(ComponentName componentName) {
|
|
||||||
downloaderService = null;
|
|
||||||
iDownloaderService = null;
|
|
||||||
isDownloadServiceRunning = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_main);
|
|
||||||
setContentView(binding.getRoot());
|
|
||||||
context = getBaseContext();
|
|
||||||
reconnectDownloadService();
|
|
||||||
checkUpdate();
|
|
||||||
|
|
||||||
fm = getSupportFragmentManager();
|
|
||||||
|
|
||||||
homeFragment = new HomeFragment();
|
|
||||||
downloadsFragment = new DownloadsFragment();
|
|
||||||
moreFragment = new MoreFragment();
|
|
||||||
|
|
||||||
initFragments();
|
|
||||||
|
|
||||||
binding.bottomNavigationView.setOnItemSelectedListener(item -> {
|
|
||||||
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.downloads){
|
|
||||||
if(lastFragment == downloadsFragment){
|
|
||||||
downloadsFragment.scrollToTop();
|
|
||||||
}else {
|
|
||||||
this.setTitle(getString(R.string.downloads));
|
|
||||||
}
|
|
||||||
replaceFragment(downloadsFragment);
|
|
||||||
}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);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
getWindow().getDecorView().setOnApplyWindowInsetsListener((view, windowInsets) -> {
|
|
||||||
WindowInsetsCompat windowInsetsCompat = WindowInsetsCompat.toWindowInsetsCompat(windowInsets, view);
|
|
||||||
boolean isImeVisible = windowInsetsCompat.isVisible(WindowInsetsCompat.Type.ime());
|
|
||||||
binding.bottomNavigationView.setVisibility(isImeVisible ? View.GONE : View.VISIBLE);
|
|
||||||
view.onApplyWindowInsets(windowInsets);
|
|
||||||
return windowInsets;
|
|
||||||
});
|
|
||||||
|
|
||||||
askPermissions();
|
|
||||||
|
|
||||||
Intent intent = getIntent();
|
|
||||||
handleIntents(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
try {
|
|
||||||
iDownloaderService.removeActivity(this);
|
|
||||||
context.getApplicationContext().unbindService(serviceConnection);
|
|
||||||
}catch (Exception e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onNewIntent(Intent intent) {
|
|
||||||
super.onNewIntent(intent);
|
|
||||||
handleIntents(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleIntents(Intent intent){
|
|
||||||
String action = intent.getAction();
|
|
||||||
String type = intent.getType();
|
|
||||||
if(Intent.ACTION_SEND.equals(action) && type != null){
|
|
||||||
Log.e(TAG, action);
|
|
||||||
|
|
||||||
homeFragment = new HomeFragment();
|
|
||||||
downloadsFragment = new DownloadsFragment();
|
|
||||||
moreFragment = new MoreFragment();
|
|
||||||
if (type.equalsIgnoreCase("application/txt")){
|
|
||||||
try{
|
|
||||||
Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
|
||||||
InputStream is = getContentResolver().openInputStream(uri);
|
|
||||||
StringBuilder textBuilder = new StringBuilder();
|
|
||||||
Reader reader = new BufferedReader(new InputStreamReader
|
|
||||||
(is, Charset.forName(StandardCharsets.UTF_8.name())));
|
|
||||||
int c = 0;
|
|
||||||
while ((c = reader.read()) != -1) {
|
|
||||||
textBuilder.append((char) c);
|
|
||||||
}
|
|
||||||
List<String> l = Arrays.asList(textBuilder.toString().split("\n"));
|
|
||||||
LinkedList<String> lines = new LinkedList<>(l);
|
|
||||||
homeFragment.handleFileIntent(lines);
|
|
||||||
}catch (Exception e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
homeFragment.handleIntent(intent);
|
|
||||||
}
|
|
||||||
initFragments();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initFragments(){
|
|
||||||
fm.beginTransaction()
|
|
||||||
.replace(R.id.frame_layout, homeFragment)
|
|
||||||
.add(R.id.frame_layout, downloadsFragment)
|
|
||||||
.add(R.id.frame_layout, moreFragment)
|
|
||||||
.hide(downloadsFragment)
|
|
||||||
.hide(moreFragment)
|
|
||||||
.commit();
|
|
||||||
|
|
||||||
lastFragment = homeFragment;
|
|
||||||
|
|
||||||
listeners = new ArrayList<>();
|
|
||||||
listeners.add(homeFragment.listener);
|
|
||||||
listeners.add(downloadsFragment.listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void replaceFragment(Fragment f){
|
|
||||||
fm.beginTransaction().hide(lastFragment).show(f).commit();
|
|
||||||
lastFragment = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startDownloadService(ArrayList<Video> downloadQueue, IDownloaderListener awaitingListener){
|
|
||||||
addQueueToDownloads(downloadQueue);
|
|
||||||
if(isDownloadServiceRunning){
|
|
||||||
iDownloaderService.updateQueue(downloadQueue);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(!listeners.contains(awaitingListener)) listeners.add(awaitingListener);
|
|
||||||
Intent serviceIntent = new Intent(context, DownloaderService.class);
|
|
||||||
serviceIntent.putParcelableArrayListExtra("queue", downloadQueue);
|
|
||||||
context.getApplicationContext().startService(serviceIntent);
|
|
||||||
context.getApplicationContext().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addQueueToDownloads(ArrayList<Video> downloadQueue) {
|
|
||||||
try {
|
|
||||||
SharedPreferences sharedPreferences = context.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE);
|
|
||||||
if (!sharedPreferences.getBoolean("incognito", false)) {
|
|
||||||
DBManager dbManager = new DBManager(context);
|
|
||||||
for (int i = downloadQueue.size() - 1; i >= 0; i--){
|
|
||||||
Video v = downloadQueue.get(i);
|
|
||||||
v.setQueuedDownload(true);
|
|
||||||
dbManager.addToHistory(v);
|
|
||||||
}
|
|
||||||
dbManager.close();
|
|
||||||
downloadsFragment.setDownloading(true);
|
|
||||||
downloadsFragment.initCards();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopDownloadService(){
|
|
||||||
if(!isDownloadServiceRunning) return;
|
|
||||||
try {
|
|
||||||
iDownloaderService.removeActivity(this);
|
|
||||||
context.getApplicationContext().unbindService(serviceConnection);
|
|
||||||
context.getApplicationContext().stopService(new Intent(context.getApplicationContext(), DownloaderService.class));
|
|
||||||
}catch (Exception ignored){}
|
|
||||||
isDownloadServiceRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancelDownloadService(){
|
|
||||||
if(!isDownloadServiceRunning) return;
|
|
||||||
iDownloaderService.cancelDownload(true);
|
|
||||||
stopDownloadService();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeItemFromDownloadQueue(Video video, String type){
|
|
||||||
iDownloaderService.removeItemFromDownloadQueue(video, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDownloadServiceRunning() {
|
|
||||||
ActivityManager.RunningServiceInfo service = getService(DownloaderService.class);
|
|
||||||
if(service != null){
|
|
||||||
if (service.foreground) {
|
|
||||||
isDownloadServiceRunning = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reconnectDownloadService(){
|
|
||||||
ActivityManager.RunningServiceInfo service = getService(DownloaderService.class);
|
|
||||||
if(service != null){
|
|
||||||
Intent serviceIntent = new Intent(context.getApplicationContext(), DownloaderService.class);
|
|
||||||
serviceIntent.putExtra("rebind", true);
|
|
||||||
context.getApplicationContext().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
|
|
||||||
isDownloadServiceRunning = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ActivityManager.RunningServiceInfo getService(Class className){
|
|
||||||
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
|
||||||
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
|
||||||
if (className.getName().equals(service.service.getClassName())) {
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkUpdate(){
|
|
||||||
SharedPreferences preferences = context.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE);
|
|
||||||
if(preferences.getBoolean("update_app", false)){
|
|
||||||
UpdateUtil updateUtil = new UpdateUtil(this);
|
|
||||||
updateUtil.updateApp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void askPermissions(){
|
|
||||||
if(!checkFilePermission()){
|
|
||||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
Log.e(TAG, String.valueOf(grantResults[0]));
|
|
||||||
for(int i = 0; i < permissions.length; i++){
|
|
||||||
if(grantResults[i] == PackageManager.PERMISSION_DENIED){
|
|
||||||
createPermissionRequestDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void exit(){
|
|
||||||
this.finishAffinity();
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean checkFilePermission(){
|
|
||||||
return ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
||||||
== PackageManager.PERMISSION_GRANTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createPermissionRequestDialog(){
|
|
||||||
MaterialAlertDialogBuilder dialog = new MaterialAlertDialogBuilder(this);
|
|
||||||
dialog.setTitle(getString(R.string.warning));
|
|
||||||
dialog.setMessage(getString(R.string.request_permission_desc));
|
|
||||||
dialog.setOnCancelListener(dialogInterface -> exit());
|
|
||||||
dialog.setNegativeButton(getString(R.string.exit_app), (dialogInterface, i) -> exit());
|
|
||||||
dialog.setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> {
|
|
||||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", getPackageName(), null));
|
|
||||||
startActivity(intent);
|
|
||||||
System.exit(0);
|
|
||||||
});
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,363 @@
|
|||||||
|
package com.deniscerri.ytdlnis
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.ActivityManager
|
||||||
|
import android.content.*
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.WindowInsets
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import com.deniscerri.ytdlnis.DownloaderService.LocalBinder
|
||||||
|
import com.deniscerri.ytdlnis.database.DatabaseManager
|
||||||
|
import com.deniscerri.ytdlnis.database.Video
|
||||||
|
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding
|
||||||
|
import com.deniscerri.ytdlnis.page.DownloadsFragment
|
||||||
|
import com.deniscerri.ytdlnis.page.HomeFragment
|
||||||
|
import com.deniscerri.ytdlnis.page.MoreFragment
|
||||||
|
import com.deniscerri.ytdlnis.page.settings.SettingsActivity
|
||||||
|
import com.deniscerri.ytdlnis.service.IDownloaderListener
|
||||||
|
import com.deniscerri.ytdlnis.service.IDownloaderService
|
||||||
|
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
import java.io.Reader
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
private lateinit var binding: ActivityMainBinding
|
||||||
|
lateinit var context: Context
|
||||||
|
private lateinit var homeFragment: HomeFragment
|
||||||
|
private lateinit var downloadsFragment: DownloadsFragment
|
||||||
|
private lateinit var moreFragment: MoreFragment
|
||||||
|
private lateinit var lastFragment: Fragment
|
||||||
|
private lateinit var fm: FragmentManager
|
||||||
|
private var isDownloadServiceRunning = false
|
||||||
|
var downloaderService: DownloaderService? = null
|
||||||
|
private lateinit var listeners: ArrayList<IDownloaderListener>
|
||||||
|
private var iDownloaderService: IDownloaderService? = null
|
||||||
|
|
||||||
|
private val serviceConnection: ServiceConnection = object : ServiceConnection {
|
||||||
|
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||||
|
downloaderService = (service as LocalBinder).service
|
||||||
|
iDownloaderService = service
|
||||||
|
isDownloadServiceRunning = true
|
||||||
|
try {
|
||||||
|
iDownloaderService!!.addActivity(this@MainActivity, listeners)
|
||||||
|
for (i in listeners.indices) {
|
||||||
|
val listener = listeners[i]
|
||||||
|
listener.onDownloadStart(iDownloaderService!!.downloadInfo)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(componentName: ComponentName) {
|
||||||
|
downloaderService = null
|
||||||
|
iDownloaderService = null
|
||||||
|
isDownloadServiceRunning = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
setContentView(binding.root)
|
||||||
|
context = baseContext
|
||||||
|
reconnectDownloadService()
|
||||||
|
checkUpdate()
|
||||||
|
fm = supportFragmentManager
|
||||||
|
homeFragment = HomeFragment()
|
||||||
|
downloadsFragment = DownloadsFragment()
|
||||||
|
moreFragment = MoreFragment()
|
||||||
|
initFragments()
|
||||||
|
binding.bottomNavigationView.setOnItemSelectedListener { item: MenuItem ->
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.home -> {
|
||||||
|
if (lastFragment === homeFragment) {
|
||||||
|
homeFragment.scrollToTop()
|
||||||
|
} else {
|
||||||
|
this.setTitle(R.string.app_name)
|
||||||
|
}
|
||||||
|
replaceFragment(homeFragment)
|
||||||
|
}
|
||||||
|
R.id.downloads -> {
|
||||||
|
if (lastFragment === downloadsFragment) {
|
||||||
|
downloadsFragment.scrollToTop()
|
||||||
|
} else {
|
||||||
|
this.title = getString(R.string.downloads)
|
||||||
|
}
|
||||||
|
replaceFragment(downloadsFragment)
|
||||||
|
}
|
||||||
|
R.id.more -> {
|
||||||
|
if (lastFragment === moreFragment) {
|
||||||
|
val intent = Intent(context, SettingsActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
} else {
|
||||||
|
this.title = getString(R.string.more)
|
||||||
|
}
|
||||||
|
replaceFragment(moreFragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
window.decorView.setOnApplyWindowInsetsListener { view: View, windowInsets: WindowInsets? ->
|
||||||
|
val windowInsetsCompat = WindowInsetsCompat.toWindowInsetsCompat(
|
||||||
|
windowInsets!!, view
|
||||||
|
)
|
||||||
|
val isImeVisible = windowInsetsCompat.isVisible(WindowInsetsCompat.Type.ime())
|
||||||
|
binding.bottomNavigationView.visibility =
|
||||||
|
if (isImeVisible) View.GONE else View.VISIBLE
|
||||||
|
view.onApplyWindowInsets(windowInsets)
|
||||||
|
windowInsets
|
||||||
|
}
|
||||||
|
askPermissions()
|
||||||
|
val intent = intent
|
||||||
|
handleIntents(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
try {
|
||||||
|
iDownloaderService!!.removeActivity(this)
|
||||||
|
context.applicationContext.unbindService(serviceConnection)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewIntent(intent: Intent) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
handleIntents(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleIntents(intent: Intent) {
|
||||||
|
val action = intent.action
|
||||||
|
val type = intent.type
|
||||||
|
if (Intent.ACTION_SEND == action && type != null) {
|
||||||
|
Log.e(TAG, action)
|
||||||
|
homeFragment = HomeFragment()
|
||||||
|
downloadsFragment = DownloadsFragment()
|
||||||
|
moreFragment = MoreFragment()
|
||||||
|
if (type.equals("application/txt", ignoreCase = true)) {
|
||||||
|
try {
|
||||||
|
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
||||||
|
val `is` = contentResolver.openInputStream(uri!!)
|
||||||
|
val textBuilder = StringBuilder()
|
||||||
|
val reader: Reader = BufferedReader(
|
||||||
|
InputStreamReader(
|
||||||
|
`is`, Charset.forName(
|
||||||
|
StandardCharsets.UTF_8.name()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
var c: Int
|
||||||
|
while (reader.read().also { c = it } != -1) {
|
||||||
|
textBuilder.append(c.toChar())
|
||||||
|
}
|
||||||
|
val l = listOf(*textBuilder.toString().split("\n").toTypedArray())
|
||||||
|
val lines = LinkedList(l)
|
||||||
|
homeFragment.handleFileIntent(lines)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
homeFragment.handleIntent(intent)
|
||||||
|
}
|
||||||
|
initFragments()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initFragments() {
|
||||||
|
fm.beginTransaction()
|
||||||
|
.replace(R.id.frame_layout, homeFragment)
|
||||||
|
.add(R.id.frame_layout, downloadsFragment)
|
||||||
|
.add(R.id.frame_layout, moreFragment)
|
||||||
|
.hide(downloadsFragment)
|
||||||
|
.hide(moreFragment)
|
||||||
|
.commit()
|
||||||
|
lastFragment = homeFragment
|
||||||
|
listeners = ArrayList()
|
||||||
|
listeners.add(homeFragment.listener)
|
||||||
|
listeners.add(downloadsFragment.listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun replaceFragment(f: Fragment) {
|
||||||
|
fm.beginTransaction().hide(lastFragment).show(f).commit()
|
||||||
|
lastFragment = f
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startDownloadService(
|
||||||
|
downloadQueue: ArrayList<Video>,
|
||||||
|
awaitingListener: IDownloaderListener
|
||||||
|
) {
|
||||||
|
addQueueToDownloads(downloadQueue)
|
||||||
|
if (isDownloadServiceRunning) {
|
||||||
|
iDownloaderService?.updateQueue(downloadQueue)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!listeners.contains(awaitingListener)) listeners.add(awaitingListener)
|
||||||
|
val serviceIntent = Intent(context, DownloaderService::class.java)
|
||||||
|
serviceIntent.putParcelableArrayListExtra("queue", downloadQueue)
|
||||||
|
context.applicationContext.startService(serviceIntent)
|
||||||
|
context.applicationContext.bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addQueueToDownloads(downloadQueue: ArrayList<Video>) {
|
||||||
|
try {
|
||||||
|
val sharedPreferences = context.getSharedPreferences("root_preferences", MODE_PRIVATE)
|
||||||
|
if (!sharedPreferences.getBoolean("incognito", false)) {
|
||||||
|
val databaseManager = DatabaseManager(context)
|
||||||
|
for (i in downloadQueue.indices.reversed()) {
|
||||||
|
val v = downloadQueue[i]
|
||||||
|
v.isQueuedDownload = true
|
||||||
|
databaseManager.addToHistory(v)
|
||||||
|
}
|
||||||
|
databaseManager.close()
|
||||||
|
downloadsFragment.setDownloading(true)
|
||||||
|
downloadsFragment.initCards()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopDownloadService() {
|
||||||
|
if (!isDownloadServiceRunning) return
|
||||||
|
try {
|
||||||
|
iDownloaderService!!.removeActivity(this)
|
||||||
|
context.applicationContext.unbindService(serviceConnection)
|
||||||
|
context.applicationContext.stopService(
|
||||||
|
Intent(
|
||||||
|
context.applicationContext,
|
||||||
|
DownloaderService::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
}
|
||||||
|
isDownloadServiceRunning = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cancelDownloadService() {
|
||||||
|
if (!isDownloadServiceRunning) return
|
||||||
|
iDownloaderService!!.cancelDownload(true)
|
||||||
|
stopDownloadService()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeItemFromDownloadQueue(video: Video?, type: String?) {
|
||||||
|
iDownloaderService!!.removeItemFromDownloadQueue(video, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isDownloadServiceRunning(): Boolean {
|
||||||
|
val service = getService(DownloaderService::class.java)
|
||||||
|
if (service != null) {
|
||||||
|
if (service.foreground) {
|
||||||
|
isDownloadServiceRunning = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reconnectDownloadService() {
|
||||||
|
val service = getService(DownloaderService::class.java)
|
||||||
|
if (service != null) {
|
||||||
|
val serviceIntent = Intent(context.applicationContext, DownloaderService::class.java)
|
||||||
|
serviceIntent.putExtra("rebind", true)
|
||||||
|
context.applicationContext.bindService(
|
||||||
|
serviceIntent,
|
||||||
|
serviceConnection,
|
||||||
|
BIND_AUTO_CREATE
|
||||||
|
)
|
||||||
|
isDownloadServiceRunning = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getService(className: Class<*>): ActivityManager.RunningServiceInfo? {
|
||||||
|
val manager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
|
||||||
|
for (service in manager.getRunningServices(Int.MAX_VALUE)) {
|
||||||
|
if (className.name == service.service.className) {
|
||||||
|
return service
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkUpdate() {
|
||||||
|
val preferences = context.getSharedPreferences("root_preferences", MODE_PRIVATE)
|
||||||
|
if (preferences.getBoolean("update_app", false)) {
|
||||||
|
val updateUtil = UpdateUtil(this)
|
||||||
|
updateUtil.updateApp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun askPermissions() {
|
||||||
|
if (!checkFilePermission()) {
|
||||||
|
ActivityCompat.requestPermissions(
|
||||||
|
this,
|
||||||
|
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(
|
||||||
|
requestCode: Int,
|
||||||
|
permissions: Array<String>,
|
||||||
|
grantResults: IntArray
|
||||||
|
) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
Log.e(TAG, grantResults[0].toString())
|
||||||
|
for (i in permissions.indices) {
|
||||||
|
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
|
||||||
|
createPermissionRequestDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exit() {
|
||||||
|
finishAffinity()
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkFilePermission(): Boolean {
|
||||||
|
return (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
|
== PackageManager.PERMISSION_GRANTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createPermissionRequestDialog() {
|
||||||
|
val dialog = MaterialAlertDialogBuilder(this)
|
||||||
|
dialog.setTitle(getString(R.string.warning))
|
||||||
|
dialog.setMessage(getString(R.string.request_permission_desc))
|
||||||
|
dialog.setOnCancelListener { exit() }
|
||||||
|
dialog.setNegativeButton(getString(R.string.exit_app)) { _: DialogInterface?, _: Int -> exit() }
|
||||||
|
dialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||||
|
val intent = Intent(
|
||||||
|
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||||
|
Uri.fromParts("package", packageName, null)
|
||||||
|
)
|
||||||
|
startActivity(intent)
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "MainActivity"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.deniscerri.ytdlnis.database
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import com.deniscerri.ytdlnis.database.dao.HistoryDao
|
||||||
|
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||||
|
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
|
|
||||||
|
@Database(
|
||||||
|
entities = [ResultItem::class, HistoryItem::class],
|
||||||
|
version = 7,
|
||||||
|
autoMigrations = []
|
||||||
|
)
|
||||||
|
abstract class DBManager : RoomDatabase(){
|
||||||
|
abstract val resultDao : ResultDao
|
||||||
|
abstract val historyDao : HistoryDao
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Volatile
|
||||||
|
private var instance : DBManager? = null
|
||||||
|
|
||||||
|
fun getInstance(context: Context) : DBManager {
|
||||||
|
if (instance == null){
|
||||||
|
synchronized(this){
|
||||||
|
instance = buildDatabase(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDatabase(context: Context) : DBManager {
|
||||||
|
return Room.databaseBuilder(
|
||||||
|
context.applicationContext,
|
||||||
|
DBManager::class.java, "ytdlnis_db"
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
package com.deniscerri.ytdlnis.database.dao
|
||||||
|
|
||||||
|
import androidx.room.*
|
||||||
|
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||||
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface HistoryDao {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM history WHERE title LIKE '%'||:query||'%' AND type LIKE '%'||:format||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
|
||||||
|
"CASE WHEN :sort = 'ASC' THEN id END ASC," +
|
||||||
|
"CASE WHEN :sort = 'DESC' THEN id END DESC," +
|
||||||
|
"CASE WHEN :sort = '' THEN id END DESC ")
|
||||||
|
suspend fun getHistory(query : String, format : String, site : String, sort : String) : List<HistoryItem>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM history WHERE url=:url AND type=:type LIMIT 1")
|
||||||
|
suspend fun getHistoryItemByURLAndType(url: String, type: String) : HistoryItem
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun addToHistory(results: ArrayList<HistoryItem>)
|
||||||
|
|
||||||
|
@Query("DELETE FROM history")
|
||||||
|
suspend fun clearHistory()
|
||||||
|
|
||||||
|
@Query("DELETE FROM history where id=:id")
|
||||||
|
suspend fun deleteItem(id: Int)
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
suspend fun clearDeletedHistory(){
|
||||||
|
val fileUtil = FileUtil()
|
||||||
|
val items : List<HistoryItem> = getHistory("","","","")
|
||||||
|
items.forEach { item ->
|
||||||
|
if (!fileUtil.exists(item.downloadPath)){
|
||||||
|
clearHistoryItem(item, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
suspend fun clearDownloadingHistory(){
|
||||||
|
val items : List<HistoryItem> = getHistory("","","","")
|
||||||
|
items.forEach { item ->
|
||||||
|
if (item.isQueuedDownload == 1){
|
||||||
|
clearHistoryItem(item, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Query("DELETE FROM history WHERE id > (SELECT MIN(h.id) FROM history h WHERE h.url = history.url AND h.type = history.type)")
|
||||||
|
suspend fun clearDuplicates()
|
||||||
|
|
||||||
|
@Query("UPDATE results SET downloadedAudio=0, downloadedVideo=0 WHERE downloadedAudio=1 OR downloadedVideo=1")
|
||||||
|
suspend fun removeAllDownloadStatusesFromResults()
|
||||||
|
|
||||||
|
@Query("UPDATE results SET downloadedAudio=0 WHERE downloadedAudio=1 AND url=:url")
|
||||||
|
suspend fun removeAudioDownloadStatusFromOneResult(url: String)
|
||||||
|
|
||||||
|
@Query("UPDATE results SET downloadedVideo=0 WHERE downloadedVideo=1 AND url=:url")
|
||||||
|
suspend fun removeVideoDownloadStatusFromOneResult(url: String)
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
suspend fun clearDuplicateHistory(){
|
||||||
|
clearDuplicates()
|
||||||
|
removeAllDownloadStatusesFromResults()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
suspend fun clearHistoryItem(video: HistoryItem, delete_file : Boolean){
|
||||||
|
if (delete_file){
|
||||||
|
val fileUtil = FileUtil()
|
||||||
|
fileUtil.deleteFile(video.downloadPath)
|
||||||
|
}
|
||||||
|
deleteItem(video.id)
|
||||||
|
when(video.type){
|
||||||
|
"audio" -> removeAudioDownloadStatusFromOneResult(video.url)
|
||||||
|
"video" -> removeVideoDownloadStatusFromOneResult(video.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Update
|
||||||
|
suspend fun updateHistoryItem(item: HistoryItem)
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
suspend fun checkDownloaded(url: String, type: String) : Boolean {
|
||||||
|
val historyItem = getHistoryItemByURLAndType(url, type)
|
||||||
|
val fileUtil = FileUtil()
|
||||||
|
return fileUtil.exists(historyItem.downloadPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package com.deniscerri.ytdlnis.database.dao
|
||||||
|
|
||||||
|
import androidx.room.*
|
||||||
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface ResultDao {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM results")
|
||||||
|
suspend fun getResults() : List<ResultItem>
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun addToResults(results: ArrayList<ResultItem>)
|
||||||
|
|
||||||
|
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun updateResult(item: ResultItem)
|
||||||
|
|
||||||
|
@Query("DELETE FROM results")
|
||||||
|
suspend fun clearResults()
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package com.deniscerri.ytdlnis.database.models
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(tableName = "history")
|
||||||
|
data class HistoryItem(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
val id: Int,
|
||||||
|
val url: String,
|
||||||
|
val title: String,
|
||||||
|
val author: String,
|
||||||
|
val duration: String,
|
||||||
|
val thumb: String,
|
||||||
|
val type: String,
|
||||||
|
val time: String,
|
||||||
|
val downloadPath: String,
|
||||||
|
val website: String,
|
||||||
|
val isQueuedDownload: Int
|
||||||
|
)
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.deniscerri.ytdlnis.database.models
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(tableName = "results")
|
||||||
|
data class ResultItem(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
val id: Int,
|
||||||
|
val videoId: String,
|
||||||
|
val url: String,
|
||||||
|
val title: String,
|
||||||
|
val author: String,
|
||||||
|
val duration: String,
|
||||||
|
val thumb: String,
|
||||||
|
val downloadedAudio: Int,
|
||||||
|
val downloadedVideo: Int,
|
||||||
|
val isPlaylistItem: Int,
|
||||||
|
val website: String,
|
||||||
|
val downloadingAudio: Int,
|
||||||
|
val downloadingVideo: Int,
|
||||||
|
val playlistTitle: String
|
||||||
|
)
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package com.deniscerri.ytdlnis.util;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.work.ForegroundInfo;
|
||||||
|
import androidx.work.Worker;
|
||||||
|
import androidx.work.WorkerParameters;
|
||||||
|
|
||||||
|
import com.deniscerri.ytdlnis.MainActivity;
|
||||||
|
import com.deniscerri.ytdlnis.database.Video;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import kotlin.random.Random;
|
||||||
|
|
||||||
|
public class DownloadWorker extends Worker {
|
||||||
|
private Context context;
|
||||||
|
private WorkerParameters workerParams;
|
||||||
|
public DownloadWorker(
|
||||||
|
@NonNull Context appContext,
|
||||||
|
@NonNull WorkerParameters workerParams) {
|
||||||
|
super(appContext, workerParams);
|
||||||
|
this.context = appContext;
|
||||||
|
this.workerParams = workerParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Result doWork() {
|
||||||
|
//TODO
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.deniscerri.ytdlnis.util
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class FileUtil {
|
||||||
|
fun deleteFile(path: String){
|
||||||
|
val file = File(path)
|
||||||
|
if (file.exists()) {
|
||||||
|
file.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exists(path: String) : Boolean {
|
||||||
|
val file = File(path)
|
||||||
|
if (path.isEmpty()) return false
|
||||||
|
return file.exists()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,53 +1,44 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
|
||||||
|
def versionMajor = 1
|
||||||
|
def versionMinor = 4
|
||||||
|
def versionPatch = 6
|
||||||
|
def versionBuild = 0 // bump for dogfood builds, public betas, etc.
|
||||||
|
|
||||||
|
ext {
|
||||||
|
versionCode = versionMajor * 100000 + versionMinor * 1000 + versionPatch * 100 + versionBuild
|
||||||
|
versionName = "${versionMajor}.${versionMinor}.${versionPatch}"
|
||||||
|
// dependency versions
|
||||||
|
appCompatVer = '1.5.1'
|
||||||
|
junitVer = '4.13.2'
|
||||||
|
androidJunitVer = '1.1.1'
|
||||||
|
espressoVer = '3.2.0'
|
||||||
|
jacksonVer = '2.9.8'
|
||||||
|
// supports java 1.6
|
||||||
|
commonsIoVer = '2.5'
|
||||||
|
// supports java 1.6
|
||||||
|
commonsCompressVer = '1.12'
|
||||||
|
youtubedlAndroidVer = "master-SNAPSHOT"
|
||||||
|
workVer = "2.7.1"
|
||||||
|
composeVer = "1.3.2"
|
||||||
|
kotlinVer = "1.7.20"
|
||||||
|
}
|
||||||
repositories {
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
google()
|
google()
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
|
||||||
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
|
||||||
// in the individual module build.gradle files
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def versionMajor = 1
|
plugins {
|
||||||
def versionMinor = 4
|
id 'com.android.application' version '7.3.1' apply false
|
||||||
def versionPatch = 6
|
id 'com.android.library' version '7.3.1' apply false
|
||||||
def versionBuild = 0 // bump for dogfood builds, public betas, etc.
|
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
|
||||||
|
|
||||||
ext {
|
|
||||||
versionCode = versionMajor * 100000 + versionMinor * 1000 + versionPatch * 100 + versionBuild
|
|
||||||
versionName = "${versionMajor}.${versionMinor}.${versionPatch}"
|
|
||||||
// dependency versions
|
|
||||||
appCompatVer = '1.1.0'
|
|
||||||
junitVer = '4.12'
|
|
||||||
androidJunitVer = '1.1.1'
|
|
||||||
espressoVer = '3.2.0'
|
|
||||||
jacksonVer = '2.9.8'
|
|
||||||
// supports java 1.6
|
|
||||||
commonsIoVer = '2.5'
|
|
||||||
// supports java 1.6
|
|
||||||
commonsCompressVer = '1.12'
|
|
||||||
youtubedlAndroidVer = "master-SNAPSHOT"
|
|
||||||
workVer = "2.7.1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
|
||||||
group = 'com.github.deniscerri'
|
|
||||||
version = versionName
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
maven { url 'https://jitpack.io' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task clean(type: Delete) {
|
task clean(type: Delete) {
|
||||||
delete rootProject.buildDir
|
delete rootProject.buildDir
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#Wed Dec 07 20:51:43 CET 2022
|
#Tue Jan 03 22:34:47 CET 2023
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@ -1 +1,20 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
mavenCentral()
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rootProject.name = "YTDLnis"
|
||||||
|
|
||||||
include ':common', ':app', ':library', ':ffmpeg'
|
include ':common', ':app', ':library', ':ffmpeg'
|
||||||
|
|||||||
Loading…
Reference in New Issue