feat: 新增tvcat.cc视频来源, 设置页面支持多来源切换
This commit is contained in:
@@ -1,16 +1,22 @@
|
|||||||
package com.videoapp.tv
|
package com.videoapp.tv
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.AdapterView
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
|
import android.widget.Spinner
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.videoapp.tv.data.ConfigRepository
|
import com.videoapp.tv.data.ConfigRepository
|
||||||
import com.videoapp.tv.data.SiteConfig
|
import com.videoapp.tv.data.SiteConfig
|
||||||
|
import com.videoapp.tv.data.SitePreset
|
||||||
|
|
||||||
class SettingsActivity : AppCompatActivity() {
|
class SettingsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var configRepo: ConfigRepository
|
private lateinit var configRepo: ConfigRepository
|
||||||
|
private lateinit var spinnerPreset: Spinner
|
||||||
private lateinit var editBaseUrl: EditText
|
private lateinit var editBaseUrl: EditText
|
||||||
private lateinit var editSearchPath: EditText
|
private lateinit var editSearchPath: EditText
|
||||||
private lateinit var editSearchMethod: EditText
|
private lateinit var editSearchMethod: EditText
|
||||||
@@ -24,6 +30,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
private lateinit var editSourceEpisodeGroupSelector: EditText
|
private lateinit var editSourceEpisodeGroupSelector: EditText
|
||||||
private lateinit var btnSave: Button
|
private lateinit var btnSave: Button
|
||||||
private lateinit var btnRestore: Button
|
private lateinit var btnRestore: Button
|
||||||
|
private var ignoringSpinner = false
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -31,6 +38,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
configRepo = ConfigRepository(this)
|
configRepo = ConfigRepository(this)
|
||||||
|
|
||||||
|
spinnerPreset = findViewById(R.id.spinner_preset)
|
||||||
editBaseUrl = findViewById(R.id.edit_base_url)
|
editBaseUrl = findViewById(R.id.edit_base_url)
|
||||||
editSearchPath = findViewById(R.id.edit_search_path)
|
editSearchPath = findViewById(R.id.edit_search_path)
|
||||||
editSearchMethod = findViewById(R.id.edit_search_method)
|
editSearchMethod = findViewById(R.id.edit_search_method)
|
||||||
@@ -45,18 +53,49 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
btnSave = findViewById(R.id.btn_save)
|
btnSave = findViewById(R.id.btn_save)
|
||||||
btnRestore = findViewById(R.id.btn_restore)
|
btnRestore = findViewById(R.id.btn_restore)
|
||||||
|
|
||||||
|
setupPresetSpinner()
|
||||||
loadConfig()
|
loadConfig()
|
||||||
|
|
||||||
btnSave.setOnClickListener { saveConfig() }
|
btnSave.setOnClickListener { saveConfig() }
|
||||||
btnRestore.setOnClickListener {
|
btnRestore.setOnClickListener {
|
||||||
configRepo.restoreDefault()
|
configRepo.restoreDefault()
|
||||||
|
ignoringSpinner = true
|
||||||
|
spinnerPreset.setSelection(0)
|
||||||
|
ignoringSpinner = false
|
||||||
loadConfig()
|
loadConfig()
|
||||||
Toast.makeText(this, R.string.config_restored, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.config_restored, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadConfig() {
|
private fun setupPresetSpinner() {
|
||||||
val config = configRepo.getConfig()
|
val presets = configRepo.getPresets()
|
||||||
|
val presetNames = presets.map { it.name }
|
||||||
|
val adapter = ArrayAdapter(
|
||||||
|
this,
|
||||||
|
android.R.layout.simple_spinner_item,
|
||||||
|
presetNames
|
||||||
|
)
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
|
spinnerPreset.adapter = adapter
|
||||||
|
|
||||||
|
spinnerPreset.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
|
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||||
|
if (ignoringSpinner) return
|
||||||
|
val preset = presets.getOrNull(position) ?: return
|
||||||
|
configRepo.applyPreset(preset)
|
||||||
|
loadConfigFromPreset(preset.config)
|
||||||
|
Toast.makeText(
|
||||||
|
this@SettingsActivity,
|
||||||
|
"已切换到 ${preset.name}",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadConfigFromPreset(config: SiteConfig) {
|
||||||
editBaseUrl.setText(config.baseUrl)
|
editBaseUrl.setText(config.baseUrl)
|
||||||
editSearchPath.setText(config.searchPath)
|
editSearchPath.setText(config.searchPath)
|
||||||
editSearchMethod.setText(config.searchMethod)
|
editSearchMethod.setText(config.searchMethod)
|
||||||
@@ -72,6 +111,21 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
editSourceEpisodeGroupSelector.setText(config.sourceEpisodeGroupSelector)
|
editSourceEpisodeGroupSelector.setText(config.sourceEpisodeGroupSelector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadConfig() {
|
||||||
|
val config = configRepo.getConfig()
|
||||||
|
loadConfigFromPreset(config)
|
||||||
|
|
||||||
|
val presets = configRepo.getPresets()
|
||||||
|
val matchedIndex = presets.indexOfFirst {
|
||||||
|
it.config.baseUrl == config.baseUrl
|
||||||
|
}
|
||||||
|
if (matchedIndex >= 0) {
|
||||||
|
ignoringSpinner = true
|
||||||
|
spinnerPreset.setSelection(matchedIndex)
|
||||||
|
ignoringSpinner = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun saveConfig() {
|
private fun saveConfig() {
|
||||||
val extraParams = parseExtraParams(editExtraParams.text.toString())
|
val extraParams = parseExtraParams(editExtraParams.text.toString())
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,12 @@ class ConfigRepository(context: Context) {
|
|||||||
saveConfig(SiteConfig.default())
|
saveConfig(SiteConfig.default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPresets(): List<SitePreset> = SitePreset.PRESETS
|
||||||
|
|
||||||
|
fun applyPreset(preset: SitePreset) {
|
||||||
|
saveConfig(preset.config)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val KEY_CONFIG = "site_config_json"
|
private const val KEY_CONFIG = "site_config_json"
|
||||||
}
|
}
|
||||||
|
|||||||
61
app/src/main/java/com/videoapp/tv/data/SitePreset.kt
Normal file
61
app/src/main/java/com/videoapp/tv/data/SitePreset.kt
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package com.videoapp.tv.data
|
||||||
|
|
||||||
|
data class SitePreset(
|
||||||
|
val name: String,
|
||||||
|
val config: SiteConfig
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
val PRESETS = listOf(
|
||||||
|
SitePreset(
|
||||||
|
name = "xb6v (星辰影视)",
|
||||||
|
config = SiteConfig(
|
||||||
|
baseUrl = "https://www.xb6v.com",
|
||||||
|
searchPath = "/e/search/11index.php",
|
||||||
|
searchMethod = "POST",
|
||||||
|
keywordParam = "keyboard",
|
||||||
|
extraParams = mapOf(
|
||||||
|
"show" to "title",
|
||||||
|
"tempid" to "1",
|
||||||
|
"tbname" to "article",
|
||||||
|
"mid" to "1",
|
||||||
|
"dopost" to "search"
|
||||||
|
),
|
||||||
|
resultSelector = "li.post",
|
||||||
|
titleSelector = "h2 a",
|
||||||
|
coverSelector = ".thumbnail img",
|
||||||
|
linkSelector = ".thumbnail a",
|
||||||
|
categorySelector = ".info_category a",
|
||||||
|
dateSelector = ".info_date",
|
||||||
|
episodeSelector = "a.lBtn",
|
||||||
|
sourceSelector = ".playfrom a, .play_source a, .source-list a",
|
||||||
|
sourceEpisodeGroupSelector = ".playlist > ul, .play_list > ul, .episode-list",
|
||||||
|
iframeSelector = ".video iframe",
|
||||||
|
videoSelector = "video source, video[src]"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
SitePreset(
|
||||||
|
name = "tvcat (电视猫)",
|
||||||
|
config = SiteConfig(
|
||||||
|
baseUrl = "https://tvcat.cc",
|
||||||
|
searchPath = "/search",
|
||||||
|
searchMethod = "GET",
|
||||||
|
keywordParam = "q",
|
||||||
|
resultSelector = "li.col-md-2.col-sm-3.col-4",
|
||||||
|
titleSelector = "a[title]",
|
||||||
|
coverSelector = "img",
|
||||||
|
linkSelector = "a",
|
||||||
|
categorySelector = ".text-muted",
|
||||||
|
dateSelector = "",
|
||||||
|
episodeSelector = "li.list-inline-item a",
|
||||||
|
sourceSelector = "h2",
|
||||||
|
sourceEpisodeGroupSelector = "ul.list-unstyled",
|
||||||
|
iframeSelector = "iframe",
|
||||||
|
videoSelector = "video source, video[src]"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getPresetByName(name: String): SitePreset? =
|
||||||
|
PRESETS.find { it.name == name }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -185,7 +185,11 @@ class SearchFragment : Fragment() {
|
|||||||
val path = config.searchPath.trimStart('/')
|
val path = config.searchPath.trimStart('/')
|
||||||
val params = "${config.keywordParam}=${java.net.URLEncoder.encode(keyword, "UTF-8")}"
|
val params = "${config.keywordParam}=${java.net.URLEncoder.encode(keyword, "UTF-8")}"
|
||||||
val extraParams = config.extraParams.entries.joinToString("&") { "${it.key}=${it.value}" }
|
val extraParams = config.extraParams.entries.joinToString("&") { "${it.key}=${it.value}" }
|
||||||
val url = "$base/$path?$params&$extraParams"
|
val url = if (extraParams.isNotEmpty()) {
|
||||||
|
"$base/$path?$params&$extraParams"
|
||||||
|
} else {
|
||||||
|
"$base/$path?$params"
|
||||||
|
}
|
||||||
|
|
||||||
fallbackWebView.visibility = View.VISIBLE
|
fallbackWebView.visibility = View.VISIBLE
|
||||||
resultsGrid.visibility = View.GONE
|
resultsGrid.visibility = View.GONE
|
||||||
|
|||||||
@@ -12,7 +12,23 @@
|
|||||||
android:text="@string/site_config"
|
android:text="@string/site_config"
|
||||||
android:textColor="@color/primary"
|
android:textColor="@color/primary"
|
||||||
android:textSize="24sp"
|
android:textSize="24sp"
|
||||||
android:layout_marginBottom="24dp" />
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/source_preset"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinner_preset"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="@drawable/search_bg"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:focusable="true" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -24,5 +24,6 @@
|
|||||||
<string name="back">返回</string>
|
<string name="back">返回</string>
|
||||||
<string name="config_saved">配置已保存</string>
|
<string name="config_saved">配置已保存</string>
|
||||||
<string name="config_restored">配置已恢复默认</string>
|
<string name="config_restored">配置已恢复默认</string>
|
||||||
|
<string name="source_preset">视频来源</string>
|
||||||
<string name="load_webpage">在网页中打开</string>
|
<string name="load_webpage">在网页中打开</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user