implemented cookies
This commit is contained in:
parent
f5ad2aee1d
commit
6fc87df98d
23 changed files with 1241 additions and 5 deletions
421
app/schemas/com.deniscerri.ytdlnis.database.DBManager/3.json
Normal file
421
app/schemas/com.deniscerri.ytdlnis.database.DBManager/3.json
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 3,
|
||||
"identityHash": "f911bed4915605d5b09bfd82892e2d7a",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "results",
|
||||
"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, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `formats` TEXT NOT NULL, `creationTime` 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": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistTitle",
|
||||
"columnName": "playlistTitle",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "formats",
|
||||
"columnName": "formats",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "creationTime",
|
||||
"columnName": "creationTime",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"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` INTEGER NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `format` TEXT 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": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadPath",
|
||||
"columnName": "downloadPath",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "format",
|
||||
"columnName": "format",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "downloads",
|
||||
"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, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0)",
|
||||
"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": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"columnName": "duration",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "format",
|
||||
"columnName": "format",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadSections",
|
||||
"columnName": "downloadSections",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "allFormats",
|
||||
"columnName": "allFormats",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadPath",
|
||||
"columnName": "downloadPath",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadSize",
|
||||
"columnName": "downloadSize",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistTitle",
|
||||
"columnName": "playlistTitle",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "audioPreferences",
|
||||
"columnName": "audioPreferences",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "videoPreferences",
|
||||
"columnName": "videoPreferences",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "customFileNameTemplate",
|
||||
"columnName": "customFileNameTemplate",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "SaveThumb",
|
||||
"columnName": "SaveThumb",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "status",
|
||||
"columnName": "status",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "'Queued'"
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadStartTime",
|
||||
"columnName": "downloadStartTime",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "commandTemplates",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "searchHistory",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "query",
|
||||
"columnName": "query",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "templateShortcuts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `content` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "cookies",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `content` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"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, 'f911bed4915605d5b09bfd82892e2d7a')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -144,6 +144,32 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ui.more.CookiesActivity"
|
||||
android:configChanges="layoutDirection|locale"
|
||||
android:exported="true"
|
||||
android:parentActivityName=".MainActivity"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="ytdlnis.CookiesActivity" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ui.more.WebViewActivity"
|
||||
android:configChanges="layoutDirection|locale"
|
||||
android:exported="true"
|
||||
android:parentActivityName=".MainActivity"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="ytdlnis.WebViewActivity" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver android:name=".receiver.CancelDownloadNotificationReceiver" />
|
||||
|
||||
<service
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.ui.HomeFragment
|
||||
import com.deniscerri.ytdlnis.ui.downloads.DownloadQueueActivity
|
||||
|
|
@ -48,6 +49,7 @@ class MainActivity : AppCompatActivity() {
|
|||
lateinit var context: Context
|
||||
private lateinit var preferences: SharedPreferences
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
private lateinit var cookieViewModel: CookieViewModel
|
||||
private lateinit var bottomNav: BottomNavigationView
|
||||
private lateinit var navHostFragment : NavHostFragment
|
||||
|
||||
|
|
@ -58,6 +60,7 @@ class MainActivity : AppCompatActivity() {
|
|||
setContentView(R.layout.activity_main)
|
||||
context = baseContext
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
cookieViewModel = ViewModelProvider(this)[CookieViewModel::class.java]
|
||||
preferences = context.getSharedPreferences("root_preferences", MODE_PRIVATE)
|
||||
|
||||
if (preferences.getBoolean("incognito", false)){
|
||||
|
|
@ -99,6 +102,10 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
cookieViewModel.getCookiesFromDB().getOrNull()?.let{
|
||||
File(cacheDir, "cookies.txt").apply { writeText(it) }
|
||||
}
|
||||
|
||||
val intent = intent
|
||||
handleIntents(intent)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
|
||||
class CookieAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<CookieItem?, CookieAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
|
||||
init {
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
val item: ConstraintLayout
|
||||
|
||||
init {
|
||||
item = itemView.findViewById(R.id.command_template_item_constraint)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.command_template_item, parent, false)
|
||||
return ViewHolder(cardView, onItemClickListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
val card = holder.item
|
||||
|
||||
val title = card.findViewById<TextView>(R.id.title)
|
||||
title.text = item?.url
|
||||
|
||||
val content = card.findViewById<TextView>(R.id.content)
|
||||
content.visibility = View.GONE
|
||||
|
||||
card.setOnClickListener {
|
||||
onItemClickListener.onItemClick(item!!)
|
||||
}
|
||||
|
||||
card.setOnLongClickListener {
|
||||
onItemClickListener.onDelete(item!!); true
|
||||
}
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
fun onItemClick(commandTemplate: CookieItem)
|
||||
fun onSelected(commandTemplate: CookieItem)
|
||||
fun onDelete(commandTemplate: CookieItem)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<CookieItem> = object : DiffUtil.ItemCallback<CookieItem>() {
|
||||
override fun areItemsTheSame(oldItem: CookieItem, newItem: CookieItem): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: CookieItem, newItem: CookieItem): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,16 +2,16 @@ package com.deniscerri.ytdlnis.database
|
|||
|
||||
import android.content.Context
|
||||
import androidx.room.*
|
||||
import androidx.room.migration.AutoMigrationSpec
|
||||
import com.deniscerri.ytdlnis.database.dao.*
|
||||
import com.deniscerri.ytdlnis.database.models.*
|
||||
|
||||
@TypeConverters(Converters::class)
|
||||
@Database(
|
||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class],
|
||||
version = 2,
|
||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class],
|
||||
version = 3,
|
||||
autoMigrations = [
|
||||
AutoMigration (from = 1, to = 2)
|
||||
AutoMigration (from = 1, to = 2),
|
||||
AutoMigration (from = 2, to = 3)
|
||||
]
|
||||
)
|
||||
abstract class DBManager : RoomDatabase(){
|
||||
|
|
@ -20,6 +20,7 @@ abstract class DBManager : RoomDatabase(){
|
|||
abstract val downloadDao : DownloadDao
|
||||
abstract val commandTemplateDao : CommandTemplateDao
|
||||
abstract val searchHistoryDao: SearchHistoryDao
|
||||
abstract val cookieDao: CookieDao
|
||||
|
||||
companion object {
|
||||
//prevents multiple instances of db getting created at the same time
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package com.deniscerri.ytdlnis.database.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
|
||||
@Dao
|
||||
interface CookieDao {
|
||||
@Query("SELECT * FROM cookies ORDER BY id DESC")
|
||||
fun getAllCookies() : List<CookieItem>
|
||||
|
||||
@Query("SELECT * FROM cookies ORDER BY id DESC")
|
||||
fun getAllCookiesLiveData() : LiveData<List<CookieItem>>
|
||||
|
||||
@Query("SELECT * FROM cookies WHERE url=:url")
|
||||
fun checkIfExistsWithSameURL(url: String) : CookieItem
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insert(item: CookieItem)
|
||||
|
||||
@Query("DELETE FROM cookies")
|
||||
suspend fun deleteAll()
|
||||
|
||||
@Query("DELETE FROM cookies WHERE id=:itemId")
|
||||
suspend fun delete(itemId: Long)
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun update(item: CookieItem)
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "cookies")
|
||||
data class CookieItem(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long,
|
||||
var url: String,
|
||||
var content: String
|
||||
)
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.deniscerri.ytdlnis.database.repository
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.deniscerri.ytdlnis.database.dao.CookieDao
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
|
||||
class CookieRepository(private val cookieDao: CookieDao) {
|
||||
val items : LiveData<List<CookieItem>> = cookieDao.getAllCookiesLiveData()
|
||||
|
||||
fun getAll() : List<CookieItem> {
|
||||
return cookieDao.getAllCookies()
|
||||
}
|
||||
|
||||
|
||||
suspend fun insert(item: CookieItem){
|
||||
try{
|
||||
cookieDao.checkIfExistsWithSameURL(item.url)
|
||||
}catch(e: Exception){
|
||||
cookieDao.insert(item)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun delete(item: CookieItem){
|
||||
cookieDao.delete(item.id)
|
||||
}
|
||||
|
||||
|
||||
suspend fun deleteAll(){
|
||||
cookieDao.deleteAll()
|
||||
}
|
||||
|
||||
suspend fun update(item: CookieItem){
|
||||
cookieDao.update(item)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
package com.deniscerri.ytdlnis.database.viewmodel
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteDatabase.OPEN_READONLY
|
||||
import android.webkit.CookieManager
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplateExport
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import com.deniscerri.ytdlnis.database.repository.CookieRepository
|
||||
import com.deniscerri.ytdlnis.ui.more.WebViewActivity
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class CookieViewModel(private val application: Application) : AndroidViewModel(application) {
|
||||
private val repository: CookieRepository
|
||||
val items: LiveData<List<CookieItem>>
|
||||
private val jsonFormat = Json { prettyPrint = true }
|
||||
|
||||
|
||||
init {
|
||||
val dao = DBManager.getInstance(application).cookieDao
|
||||
repository = CookieRepository(dao)
|
||||
items = repository.items
|
||||
}
|
||||
|
||||
fun getAll(): List<CookieItem> {
|
||||
return repository.getAll()
|
||||
}
|
||||
|
||||
fun insert(item: CookieItem) = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.insert(item)
|
||||
}
|
||||
|
||||
fun delete(item: CookieItem) = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.delete(item)
|
||||
}
|
||||
|
||||
fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.deleteAll()
|
||||
}
|
||||
|
||||
fun update(item: CookieItem) = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.update(item)
|
||||
}
|
||||
|
||||
object CookieObject {
|
||||
const val NAME = "name"
|
||||
const val VALUE = "value"
|
||||
const val SECURE = "is_secure"
|
||||
const val EXPIRY = "expires_utc"
|
||||
const val HOST = "host_key"
|
||||
const val PATH = "path"
|
||||
}
|
||||
|
||||
@SuppressLint("SdCardPath")
|
||||
fun getCookiesFromDB() : Result<String> = kotlin.runCatching {
|
||||
CookieManager.getInstance().run {
|
||||
if (!hasCookies()) throw Exception("There is no cookies in the database!")
|
||||
flush()
|
||||
}
|
||||
SQLiteDatabase.openDatabase(
|
||||
"/data/data/com.deniscerri.ytdl/app_webview/Default/Cookies", null, OPEN_READONLY
|
||||
).run {
|
||||
val projection = arrayOf(
|
||||
CookieObject.HOST,
|
||||
CookieObject.EXPIRY,
|
||||
CookieObject.PATH,
|
||||
CookieObject.NAME,
|
||||
CookieObject.VALUE,
|
||||
CookieObject.SECURE
|
||||
)
|
||||
val cookieList = mutableListOf<WebViewActivity.CookieItem>()
|
||||
query(
|
||||
"cookies", projection, null, null, null, null, null
|
||||
).run {
|
||||
while (moveToNext()) {
|
||||
val expiry = getLong(getColumnIndexOrThrow(CookieObject.EXPIRY))
|
||||
val name = getString(getColumnIndexOrThrow(CookieObject.NAME))
|
||||
val value = getString(getColumnIndexOrThrow(CookieObject.VALUE))
|
||||
val path = getString(getColumnIndexOrThrow(CookieObject.PATH))
|
||||
val secure = getLong(getColumnIndexOrThrow(CookieObject.SECURE)) == 1L
|
||||
val hostKey = getString(getColumnIndexOrThrow(CookieObject.HOST))
|
||||
|
||||
val host = if (hostKey[0] != '.') ".$hostKey" else hostKey
|
||||
cookieList.add(
|
||||
WebViewActivity.CookieItem(
|
||||
domain = host,
|
||||
name = name,
|
||||
value = value,
|
||||
path = path,
|
||||
secure = secure,
|
||||
expiry = expiry
|
||||
)
|
||||
)
|
||||
}
|
||||
close()
|
||||
}
|
||||
close()
|
||||
val header = "# Netscape HTTP Cookie File\n" +
|
||||
"# WebView Generated by the YTDLnis app\n"
|
||||
cookieList.fold(StringBuilder(header)) { acc, cookie ->
|
||||
acc.append(cookie.toNetscapeFormat()).append("\n")
|
||||
}.toString()
|
||||
}
|
||||
}
|
||||
|
||||
fun exportToClipboard() = viewModelScope.launch {
|
||||
try{
|
||||
val clipboard: ClipboardManager =
|
||||
application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
|
||||
getCookiesFromDB().getOrNull()?.let {
|
||||
clipboard.setText(it)
|
||||
}
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import com.deniscerri.ytdlnis.MainActivity
|
|||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
|
|
@ -45,6 +46,7 @@ class ShareActivity : AppCompatActivity() {
|
|||
lateinit var context: Context
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
private lateinit var cookieViewModel: CookieViewModel
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
|
||||
|
||||
|
|
@ -73,8 +75,13 @@ class ShareActivity : AppCompatActivity() {
|
|||
context = baseContext
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
cookieViewModel = ViewModelProvider(this)[CookieViewModel::class.java]
|
||||
sharedPreferences = getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
|
||||
|
||||
cookieViewModel.getCookiesFromDB().getOrNull()?.let{
|
||||
File(cacheDir, "cookies.txt").apply { writeText(it) }
|
||||
}
|
||||
|
||||
val intent = intent
|
||||
handleIntents(intent)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,149 @@
|
|||
package com.deniscerri.ytdlnis.ui.more
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.CookieAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.net.CookieManager
|
||||
|
||||
|
||||
class CookiesActivity : AppCompatActivity(), CookieAdapter.OnItemClickListener {
|
||||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var listAdapter: CookieAdapter
|
||||
private lateinit var topAppBar: MaterialToolbar
|
||||
private lateinit var cookiesViewModel: CookieViewModel
|
||||
private lateinit var uiUtil: UiUtil
|
||||
var context: Context? = null
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_cookies)
|
||||
context = baseContext
|
||||
|
||||
topAppBar = findViewById(R.id.logs_toolbar)
|
||||
topAppBar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
|
||||
|
||||
listAdapter =
|
||||
CookieAdapter(
|
||||
this,
|
||||
this@CookiesActivity
|
||||
)
|
||||
recyclerView = findViewById(R.id.template_recyclerview)
|
||||
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||
recyclerView.adapter = listAdapter
|
||||
|
||||
uiUtil = UiUtil(FileUtil())
|
||||
|
||||
cookiesViewModel = ViewModelProvider(this)[CookieViewModel::class.java]
|
||||
cookiesViewModel.items.observe(this) {
|
||||
listAdapter.submitList(it)
|
||||
}
|
||||
initMenu()
|
||||
initChips()
|
||||
}
|
||||
|
||||
private fun initMenu() {
|
||||
topAppBar.setOnMenuItemClickListener { m: MenuItem ->
|
||||
when (m.itemId) {
|
||||
R.id.delete_cookies -> {
|
||||
val deleteDialog = MaterialAlertDialogBuilder(this)
|
||||
deleteDialog.setTitle(getString(R.string.confirm_delete_history))
|
||||
deleteDialog.setMessage(getString(R.string.confirm_delete_cookies_desc))
|
||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
android.webkit.CookieManager.getInstance().removeAllCookies(null)
|
||||
kotlin.runCatching {
|
||||
File(cacheDir, "cookies.txt").apply { writeText("") }
|
||||
}
|
||||
}
|
||||
deleteDialog.show()
|
||||
}
|
||||
R.id.export_clipboard -> {
|
||||
cookiesViewModel.exportToClipboard()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun initChips() {
|
||||
val new = findViewById<Chip>(R.id.newCookie)
|
||||
new.setOnClickListener {
|
||||
showDialog("")
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDialog(url: String){
|
||||
val builder = MaterialAlertDialogBuilder(this)
|
||||
builder.setTitle(getString(R.string.cookies))
|
||||
val inputLayout = layoutInflater.inflate(R.layout.textinput, null)
|
||||
val editText = inputLayout.findViewById<EditText>(R.id.url_edittext)
|
||||
editText.setText(url)
|
||||
builder.setView(inputLayout)
|
||||
builder.setPositiveButton(
|
||||
getString(R.string.get_cookies)
|
||||
) { dialog: DialogInterface?, which: Int ->
|
||||
val myIntent = Intent(this, WebViewActivity::class.java)
|
||||
myIntent.putExtra("url", editText.text.toString())
|
||||
startActivity(myIntent)
|
||||
}
|
||||
|
||||
// handle the negative button of the alert dialog
|
||||
builder.setNegativeButton(
|
||||
getString(R.string.cancel)
|
||||
) { dialog: DialogInterface?, which: Int -> }
|
||||
val dialog = builder.create()
|
||||
editText.setOnKeyListener { view, i, keyEvent ->
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
false
|
||||
}
|
||||
dialog.show()
|
||||
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
editText!!.postDelayed({
|
||||
editText.requestFocus()
|
||||
imm.showSoftInput(editText, 0)
|
||||
}, 300)
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "CookiesActivity"
|
||||
}
|
||||
|
||||
override fun onItemClick(cookie: CookieItem) {
|
||||
showDialog(cookie.url)
|
||||
}
|
||||
|
||||
override fun onSelected(cookie: CookieItem) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onDelete(cookie: CookieItem) {
|
||||
val deleteDialog = MaterialAlertDialogBuilder(this)
|
||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + cookie.url + "\"!")
|
||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
cookiesViewModel.delete(cookie)
|
||||
}
|
||||
deleteDialog.show()
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ class MoreFragment : Fragment() {
|
|||
private lateinit var logs: TextView
|
||||
private lateinit var commandTemplates: TextView
|
||||
private lateinit var downloadQueue: TextView
|
||||
private lateinit var cookies: TextView
|
||||
private lateinit var terminateApp: TextView
|
||||
private lateinit var settings: TextView
|
||||
private lateinit var mainActivity: MainActivity
|
||||
|
|
@ -52,6 +53,7 @@ class MoreFragment : Fragment() {
|
|||
logs = view.findViewById(R.id.logs)
|
||||
commandTemplates = view.findViewById(R.id.command_templates)
|
||||
downloadQueue = view.findViewById(R.id.download_queue)
|
||||
cookies = view.findViewById(R.id.cookies)
|
||||
terminateApp = view.findViewById(R.id.terminate)
|
||||
settings = view.findViewById(R.id.settings)
|
||||
|
||||
|
|
@ -84,6 +86,11 @@ class MoreFragment : Fragment() {
|
|||
startActivity(intent)
|
||||
}
|
||||
|
||||
cookies.setOnClickListener {
|
||||
val intent = Intent(context, CookiesActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
terminateApp.setOnClickListener {
|
||||
if (mainSharedPreferences.getBoolean("ask_terminate_app", true)){
|
||||
var doNotShowAgain = false
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
package com.deniscerri.ytdlnis.ui.more
|
||||
|
||||
import android.os.Bundle
|
||||
import android.webkit.CookieManager
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import java.io.File
|
||||
|
||||
|
||||
class WebViewActivity : AppCompatActivity() {
|
||||
private lateinit var cookiesViewModel: CookieViewModel
|
||||
private lateinit var webView: WebView
|
||||
private lateinit var toolbar: MaterialToolbar
|
||||
private lateinit var generateBtn: MaterialButton
|
||||
private lateinit var cookieManager: CookieManager
|
||||
private lateinit var url: String
|
||||
private lateinit var cookies: String
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.webview_activity)
|
||||
url = intent.extras!!.getString("url")!!
|
||||
cookies = ""
|
||||
cookiesViewModel = ViewModelProvider(this)[CookieViewModel::class.java]
|
||||
val appbar = findViewById<AppBarLayout>(R.id.webview_appbarlayout)
|
||||
toolbar = appbar.findViewById(R.id.webviewToolbar)
|
||||
generateBtn = toolbar.findViewById(R.id.generate)
|
||||
cookieManager = CookieManager.getInstance()
|
||||
|
||||
webView = findViewById(R.id.webview)
|
||||
webView.settings.javaScriptEnabled = true
|
||||
webView.settings.domStorageEnabled = true
|
||||
webView.settings.javaScriptCanOpenWindowsAutomatically = true
|
||||
|
||||
cookieManager = CookieManager.getInstance()
|
||||
|
||||
toolbar.setNavigationOnClickListener {
|
||||
cookieManager.flush()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
val webViewClient: WebViewClient = object : WebViewClient() {
|
||||
|
||||
override fun onPageFinished(view: WebView, url: String) {
|
||||
super.onPageFinished(view, url)
|
||||
kotlin.runCatching {
|
||||
toolbar.title = view.title
|
||||
cookies = CookieManager.getInstance().getCookie(view.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
webView.webViewClient = webViewClient
|
||||
|
||||
generateBtn.setOnClickListener {
|
||||
cookiesViewModel.getCookiesFromDB().getOrNull()?.let {
|
||||
File(cacheDir , "/cookies.txt").apply { writeText(it) }
|
||||
}
|
||||
kotlin.runCatching {
|
||||
cookiesViewModel.insert(
|
||||
CookieItem(
|
||||
0,
|
||||
url,
|
||||
""
|
||||
)
|
||||
)
|
||||
}.onFailure {
|
||||
Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
cookieManager.flush()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
webView.loadUrl(url)
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "WebViewActivity"
|
||||
}
|
||||
|
||||
data class CookieItem(
|
||||
val domain: String = "",
|
||||
val name: String = "",
|
||||
val value: String = "",
|
||||
val includeSubdomains: Boolean = true,
|
||||
val path: String = "/",
|
||||
val secure: Boolean = true,
|
||||
val expiry: Long = 0L,
|
||||
) {
|
||||
constructor(
|
||||
url: String,
|
||||
name: String,
|
||||
value: String
|
||||
) : this(domain = url.replace(Regex("""http(s)?://(\w*(www|m|account|sso))?|/.*"""), ""), name = name, value = value)
|
||||
|
||||
fun toNetscapeFormat(): String {
|
||||
val stringList = listOf(domain,
|
||||
includeSubdomains.toString().uppercase(),
|
||||
path,
|
||||
secure.toString().uppercase(),
|
||||
expiry.toString(),
|
||||
name,
|
||||
value)
|
||||
|
||||
val builder = StringBuilder(stringList.first())
|
||||
|
||||
for (s in stringList.subList(1, stringList.size)) {
|
||||
if (s.isNotEmpty()) {
|
||||
if (builder.isNotEmpty())
|
||||
builder.append("\u0009")
|
||||
builder.append(s)
|
||||
}
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.deniscerri.ytdlnis.util
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
|
|
@ -13,13 +14,14 @@ import org.json.JSONArray
|
|||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class InfoUtil(context: Context) {
|
||||
class InfoUtil(private val context: Context) {
|
||||
private var items: ArrayList<ResultItem?>
|
||||
private var key: String? = null
|
||||
private var useInvidous = false
|
||||
|
|
@ -494,6 +496,12 @@ class InfoUtil(context: Context) {
|
|||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
if (!query.contains("http")) request.addOption("--default-search", "ytsearch25")
|
||||
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
val results: Array<String?> = try {
|
||||
val lineSeparator = System.getProperty("line.separator")
|
||||
|
|
@ -637,6 +645,12 @@ class InfoUtil(context: Context) {
|
|||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
val results: Array<String?> = try {
|
||||
val lineSeparator = System.getProperty("line.separator")
|
||||
|
|
|
|||
|
|
@ -132,6 +132,11 @@ class DownloadWorker(
|
|||
request.addOption("--restrict-filenames")
|
||||
}
|
||||
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
|
||||
when(type){
|
||||
DownloadViewModel.Type.audio -> {
|
||||
var audioQualityId : String = downloadItem.format.format_id
|
||||
|
|
|
|||
|
|
@ -56,6 +56,11 @@ class TerminalDownloadWorker(
|
|||
}.absolutePath
|
||||
)
|
||||
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
|
||||
request.addOption("-P", tempFileDir.absolutePath)
|
||||
|
||||
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
|
||||
|
|
|
|||
5
app/src/main/res/drawable/baseline_cookie_24.xml
Normal file
5
app/src/main/res/drawable/baseline_cookie_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?android:colorAccent" android:pathData="M21.95,10.99c-1.79,-0.03 -3.7,-1.95 -2.68,-4.22c-2.98,1 -5.77,-1.59 -5.19,-4.56C6.95,0.71 2,6.58 2,12c0,5.52 4.48,10 10,10C17.89,22 22.54,16.92 21.95,10.99zM8.5,15C7.67,15 7,14.33 7,13.5S7.67,12 8.5,12s1.5,0.67 1.5,1.5S9.33,15 8.5,15zM10.5,10C9.67,10 9,9.33 9,8.5S9.67,7 10.5,7S12,7.67 12,8.5S11.33,10 10.5,10zM15,16c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C16,15.55 15.55,16 15,16z"/>
|
||||
</vector>
|
||||
61
app/src/main/res/layout/activity_cookies.xml
Normal file
61
app/src/main/res/layout/activity_cookies.xml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.deniscerri.ytdlnis.ui.more.TerminalActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:liftOnScroll="true"
|
||||
android:background="@android:color/transparent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/logs_toolbar"
|
||||
android:elevation="0dp"
|
||||
app:title="@string/cookies"
|
||||
app:menu="@menu/cookies_menu"
|
||||
android:layout_width="match_parent"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="10dp"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/newCookie"
|
||||
style="@style/Widget.Material3.Chip.Assist"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/new_cookie"
|
||||
app:chipIcon="@drawable/ic_plus" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:layout_below="@+id/newCookie"
|
||||
android:id="@+id/template_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
>
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -81,6 +81,21 @@
|
|||
android:paddingHorizontal="15dp"
|
||||
app:drawableStartCompat="@drawable/ic_concurrent_downloads" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cookies"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="35dp"
|
||||
android:textSize="16sp"
|
||||
android:paddingVertical="15dp"
|
||||
android:text="@string/cookies"
|
||||
android:textStyle="bold"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingHorizontal="15dp"
|
||||
app:drawableStartCompat="@drawable/baseline_cookie_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/terminate"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
26
app/src/main/res/layout/textinput.xml
Normal file
26
app/src/main/res/layout/textinput.xml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/url_textinput"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="URL"
|
||||
android:padding="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/url_edittext"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
57
app/src/main/res/layout/webview_activity.xml
Normal file
57
app/src/main/res/layout/webview_activity.xml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/webview_appbarlayout"
|
||||
app:liftOnScroll="true"
|
||||
android:background="@android:color/transparent"
|
||||
android:elevation="0dp"
|
||||
app:elevation="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/webviewToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_scrollFlags="scroll"
|
||||
app:navigationIcon="?attr/homeAsUpIndicator"
|
||||
android:theme="@style/Toolbar"
|
||||
>
|
||||
|
||||
<Button
|
||||
android:id="@+id/generate"
|
||||
android:layout_gravity="end"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:text="@string/ok"
|
||||
app:icon="@drawable/ic_check"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="PrivateResource" />
|
||||
|
||||
</com.google.android.material.appbar.MaterialToolbar>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
13
app/src/main/res/menu/cookies_menu.xml
Normal file
13
app/src/main/res/menu/cookies_menu.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/delete_cookies"
|
||||
android:title="@string/delete_all_cookies"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/export_clipboard"
|
||||
android:title="@string/export_from_clipboard"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
|
|
@ -197,4 +197,11 @@
|
|||
<string name="suggested">Suggested</string>
|
||||
<string name="select_all">Select All</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="cookies">Cookies</string>
|
||||
<string name="new_cookie">New Cookie</string>
|
||||
<string name="cookie">Cookie</string>
|
||||
<string name="create_cookie">Create Cookie</string>
|
||||
<string name="get_cookies">Get Cookies</string>
|
||||
<string name="delete_all_cookies">Delete All Cookies</string>
|
||||
<string name="confirm_delete_cookies_desc">Delete all the cookies, permanently</string>
|
||||
</resources>
|
||||
Loading…
Reference in a new issue