switch source
This commit is contained in:
parent
20ddba6ad7
commit
3b01debf7f
|
|
@ -46,7 +46,7 @@ static def VersionName() {
|
|||
try {
|
||||
def process = 'git describe --tags --always'.execute()
|
||||
process.waitFor()
|
||||
return process.text.trim()
|
||||
return process.text.trim() - "v"
|
||||
} catch (ignored) {
|
||||
return "1.0.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ class CardPresenter(private val lifecycleScope: LifecycleCoroutineScope) : Prese
|
|||
val tv = item as TV
|
||||
val cardView = viewHolder.view as ImageCardView
|
||||
|
||||
if (tv.videoUrl != null) {
|
||||
cardView.titleText = tv.title
|
||||
cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT)
|
||||
cardView.tag = tv.videoUrl
|
||||
|
|
@ -45,7 +44,6 @@ class CardPresenter(private val lifecycleScope: LifecycleCoroutineScope) : Prese
|
|||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnbindViewHolder(viewHolder: ViewHolder) {
|
||||
val cardView = viewHolder.view as ImageCardView
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@ class MainActivity : FragmentActivity() {
|
|||
mainFragment.next()
|
||||
}
|
||||
|
||||
fun prevSource() {
|
||||
mainFragment.prevSource()
|
||||
}
|
||||
|
||||
fun nextSource() {
|
||||
mainFragment.nextSource()
|
||||
}
|
||||
|
||||
fun switchMainFragment() {
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
|
||||
|
|
@ -57,7 +65,7 @@ class MainActivity : FragmentActivity() {
|
|||
transaction.commit()
|
||||
}
|
||||
|
||||
fun focusMainFragment() {
|
||||
private fun focusMainFragment() {
|
||||
mainFragment.focus()
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +73,7 @@ class MainActivity : FragmentActivity() {
|
|||
return mainFragment.isHidden
|
||||
}
|
||||
|
||||
fun hideMainFragment() {
|
||||
private fun hideMainFragment() {
|
||||
if (!mainFragment.isHidden) {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.hide(mainFragment)
|
||||
|
|
@ -146,13 +154,13 @@ class MainActivity : FragmentActivity() {
|
|||
|
||||
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||
if (mainFragment.isHidden) {
|
||||
prev()
|
||||
prevSource()
|
||||
}
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||
if (mainFragment.isHidden) {
|
||||
next()
|
||||
nextSource()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ package com.lizongying.mytv
|
|||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.leanback.app.BrowseSupportFragment
|
||||
import androidx.leanback.widget.ArrayObjectAdapter
|
||||
import androidx.leanback.widget.HeaderItem
|
||||
|
|
@ -29,24 +27,17 @@ class MainFragment : BrowseSupportFragment() {
|
|||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
setupUIElements()
|
||||
|
||||
loadRows()
|
||||
|
||||
setupEventListeners()
|
||||
}
|
||||
|
||||
fun show() {
|
||||
if (!view?.isVisible!!) {
|
||||
view?.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupUIElements() {
|
||||
// set fastLane (or headers) background color
|
||||
brandColor = ContextCompat.getColor(context!!, R.color.fastlane_background)
|
||||
// headersState = HEADERS_DISABLED
|
||||
}
|
||||
|
||||
private var count: Int = 0
|
||||
|
||||
private fun loadRows() {
|
||||
val list = TVList.list
|
||||
val rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
|
||||
|
|
@ -55,9 +46,20 @@ class MainFragment : BrowseSupportFragment() {
|
|||
var idx: Long = 0
|
||||
for ((k, v) in list) {
|
||||
val listRowAdapter = ArrayObjectAdapter(cardPresenter)
|
||||
for ((idx2, v1) in v.withIndex()) {
|
||||
var idx2 = 0
|
||||
for ((k1, v1) in v) {
|
||||
listRowAdapter.add(v1)
|
||||
list2.add(Info(idx.toInt(), idx2, v1))
|
||||
list2.add(
|
||||
Info(
|
||||
idx.toInt(), idx2, TV(
|
||||
count,
|
||||
k1,
|
||||
v1.toList()
|
||||
)
|
||||
)
|
||||
)
|
||||
count++
|
||||
idx2++
|
||||
}
|
||||
val header = HeaderItem(idx, k)
|
||||
rowsAdapter.add(ListRow(header, listRowAdapter))
|
||||
|
|
@ -66,7 +68,7 @@ class MainFragment : BrowseSupportFragment() {
|
|||
|
||||
adapter = rowsAdapter
|
||||
|
||||
(activity as? MainActivity)?.play(list.values.first()[0])
|
||||
(activity as? MainActivity)?.play(list2.first().item as TV)
|
||||
(activity as? MainActivity)?.switchMainFragment()
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +93,7 @@ class MainFragment : BrowseSupportFragment() {
|
|||
)
|
||||
// Toast.makeText(
|
||||
// activity,
|
||||
// "${l.title} $selectedPosition $itemPosition",
|
||||
// "${l.title} ${tv.videoIndex}",
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
}
|
||||
|
|
@ -112,7 +114,45 @@ class MainFragment : BrowseSupportFragment() {
|
|||
)
|
||||
// Toast.makeText(
|
||||
// activity,
|
||||
// "${l.title} $selectedPosition $itemPosition",
|
||||
// "${l.title} ${tv.videoIndex}",
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun prevSource() {
|
||||
view?.post {
|
||||
val item = list2[itemPosition]
|
||||
val tv = item.item as TV
|
||||
|
||||
tv.videoIndex--
|
||||
if (tv.videoIndex == -1) {
|
||||
tv.videoIndex = tv.videoUrl.size - 1
|
||||
}
|
||||
|
||||
(activity as? MainActivity)?.play(tv)
|
||||
// Toast.makeText(
|
||||
// activity,
|
||||
// "${l.title} ${tv.videoIndex}",
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun nextSource() {
|
||||
view?.post {
|
||||
val item = list2[itemPosition]
|
||||
val tv = item.item as TV
|
||||
|
||||
tv.videoIndex++
|
||||
if (tv.videoIndex == tv.videoUrl.size) {
|
||||
tv.videoIndex = 0
|
||||
}
|
||||
|
||||
(activity as? MainActivity)?.play(tv)
|
||||
// Toast.makeText(
|
||||
// activity,
|
||||
// "${l.title} ${tv.videoIndex}",
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ class PlaybackControlGlue(
|
|||
|
||||
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||
if ((context as? MainActivity)?.mainFragmentIsHidden() == true) {
|
||||
(context as? MainActivity)?.prev()
|
||||
(context as? MainActivity)?.prevSource()
|
||||
}
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||
if ((context as? MainActivity)?.mainFragmentIsHidden() == true) {
|
||||
(context as? MainActivity)?.next()
|
||||
(context as? MainActivity)?.nextSource()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,17 +30,14 @@ class PlaybackFragment : VideoSupportFragment() {
|
|||
}
|
||||
|
||||
fun play(tv: TV) {
|
||||
if (tv.videoUrl.isNullOrBlank()) {
|
||||
Log.e(TAG, "videoUrl is empty")
|
||||
return
|
||||
}
|
||||
val videoUrl = tv.videoUrl[tv.videoIndex]
|
||||
|
||||
if (tv.videoUrl.equals(lastVideoUrl)) {
|
||||
if (videoUrl == lastVideoUrl) {
|
||||
Log.e(TAG, "videoUrl is duplication")
|
||||
return
|
||||
}
|
||||
|
||||
lastVideoUrl = tv.videoUrl!!
|
||||
lastVideoUrl = videoUrl
|
||||
|
||||
playerAdapter?.reset()
|
||||
|
||||
|
|
@ -50,7 +47,7 @@ class PlaybackFragment : VideoSupportFragment() {
|
|||
mTransportControlGlue.playWhenPrepared()
|
||||
|
||||
try {
|
||||
playerAdapter?.setDataSource(Uri.parse(tv.videoUrl))
|
||||
playerAdapter?.setDataSource(Uri.parse(videoUrl))
|
||||
} catch (e: IOException) {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import java.io.Serializable
|
|||
|
||||
data class TV(
|
||||
var id: Int = 0,
|
||||
var title: String? = null,
|
||||
var videoUrl: String? = null,
|
||||
var title: String,
|
||||
var videoUrl: List<String>,
|
||||
var videoIndex: Int = 0,
|
||||
) : Serializable {
|
||||
|
||||
override fun toString(): String {
|
||||
|
|
@ -13,6 +14,7 @@ data class TV(
|
|||
"id=" + id +
|
||||
", title='" + title + '\'' +
|
||||
", videoUrl='" + videoUrl + '\'' +
|
||||
", videoIndex='" + videoIndex + '\'' +
|
||||
'}'
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,57 +1,54 @@
|
|||
package com.lizongying.mytv
|
||||
|
||||
object TVList {
|
||||
val list: Map<String, List<TV>> by lazy {
|
||||
val list: Map<String, Map<String, Set<String>>> by lazy {
|
||||
setupTV()
|
||||
}
|
||||
private var count: Int = 0
|
||||
|
||||
private fun setupTV(): Map<String, List<TV>> {
|
||||
private fun setupTV(): Map<String, Map<String, Set<String>>> {
|
||||
val tvs = """
|
||||
央视频道,CCTV1,http://hlsbkmgsplive.miguvideo.com/migu/kailu/cctv1hd265/57/20191230/index.m3u8?&encrypt=
|
||||
央视频道,CCTV2,https://iptv.luas.edu.cn/liverespath/6b13fe5368d391761312a985ace065c0ecad2f5e/877097d2fa-0-0-b7736e6941fd5cb71f45ef9397b68092/index.m3u8
|
||||
央视频道,CCTV2,http://hlsbkmgsplive.miguvideo.com/migu/kailu/cctv2hd265/55/20200407/index.m3u8?&encrypt=
|
||||
央视频道,CCTV3,https://iptv.luas.edu.cn/liverespath/f76f9947c68be18d7a456e25aa59a08c5747e6a5/0df24da9ec-0-0-dca40ddadd2a051ce1a83536d9310820/index.m3u8
|
||||
央视频道,CCTV3,http://hlsbkmgsplive.miguvideo.com/wd_r2/ocn/cctv3hd/3000/index.m3u8?&encrypt=
|
||||
央视频道,CCTV4,http://hlsbkmgsplive.miguvideo.com/wd_r2/cctv/cctv4hd/1500/index.m3u8?&encrypt=
|
||||
央视频道,CCTV4美洲,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv4meihd/57/index.m3u8?&encrypt=
|
||||
央视频道,CCTV4欧洲,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv4ouhd/51/index.m3u8?&encrypt=
|
||||
央视频道,CCTV4 中文国际,http://39.134.24.161/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226191/index.m3u8
|
||||
央视频道,CCTV4 中文国际,http://hlsbkmgsplive.miguvideo.com/wd_r2/cctv/cctv4hd/1500/index.m3u8?&encrypt=
|
||||
央视频道,CCTV4 美洲,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv4meihd/57/index.m3u8?&encrypt=
|
||||
央视频道,CCTV4 欧洲,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv4ouhd/51/index.m3u8?&encrypt=
|
||||
央视频道,CCTV5,http://hlsbkmgsplive.miguvideo.com/migu/kailu/cctv5hd265/57/20191230/index.m3u8?&encrypt=
|
||||
央视频道,CCTV5+,http://hlsbkmgsplive.miguvideo.com/wd_r2/cctv/cctv5plusnew/2500/index.m3u8?&encrypt=
|
||||
央视频道,CCTV6,https://iptv.luas.edu.cn/liverespath/f2f39ee2105c85c32df375728a51b5d89d3afab4/113ed89f48-0-0-85216e55861329ec31ba1437a2ff37c9/index.m3u8
|
||||
央视频道,CCTV6,http://hlsbkmgsplive.miguvideo.com/wd_r2/ocn/cctv6hd/3000/index.m3u8?&encrypt=
|
||||
央视频道,CCTV7,https://iptv.luas.edu.cn/liverespath/f116a0a5035935a3435155998163d8eaa60554c3/4ba629f762-0-0-0a66b18805ff859ce68ab1137157079e/index.m3u8
|
||||
央视频道,CCTV7,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv7hd/51/index.m3u8?&encrypt=
|
||||
央视频道,CCTV8,https://iptv.luas.edu.cn/liverespath/9e6e3b618b5dc902d992949f0c669bb674f6cde8/cae4471c68-0-0-316245c664c3311072c7279ec29672fe/index.m3u8
|
||||
央视频道,CCTV8,http://hlsbkmgsplive.miguvideo.com/wd_r2/ocn/cctv8hd/3000/index.m3u8?&encrypt=
|
||||
央视频道,CCTV9,http://39.134.24.162/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8
|
||||
央视频道,CCTV9,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv9hd/57/index.m3u8?&encrypt=
|
||||
央视频道,CCTV10,https://iptv.luas.edu.cn/liverespath/924e6292a0e6f7440e8380075908fed9915b3c00/780499a193-0-0-c50d57fd93cf32a5144ec8d889eb3ed9/index.m3u8
|
||||
央视频道,CCTV10,http://hlsbkmgsplive.miguvideo.com/wd_r2/2018/ocn/cctv10hd/2000/index.m3u8?&encrypt=
|
||||
央视频道,CCTV11,https://iptv.luas.edu.cn/liverespath/3d0aa0f1604f13f0ae90c2dc0590ca22a1bcaaa2/646e868153-0-0-a53121a1df5b93a74d1980270e652878/index.m3u8
|
||||
央视频道,CCTV11,http://hlsbkmgsplive.miguvideo.com/migu/kailu/cctv11hd/57/20200103/index.m3u8?&encrypt=
|
||||
央视频道,CCTV12,https://iptv.luas.edu.cn/liverespath/fb84bde1de15cdb0308a7910cebc0497594ae94e/e2d8885f42-0-0-6e1f55986652ba786606a116c5cc0775/index.m3u8
|
||||
央视频道,CCTV12,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv12hd/57/index.m3u8?&encrypt=
|
||||
央视频道,CCTV13,https://live-play.cctvnews.cctv.com/cctv/merge_cctv13.m3u8
|
||||
央视频道,CCTV13,http://hlsbkmgsplive.miguvideo.com/envivo_x/2018/SD/cctv13/2000/index.m3u8?&encrypt=
|
||||
央视频道,CCTV14,https://iptv.luas.edu.cn/liverespath/0e0973e58d4835f4b872548164462930003f77b4/0ef01acfdb-0-0-3c10e95bcde07ba14f0f93a8d831b684/index.m3u8
|
||||
央视频道,CCTV14,http://hlsbkmgsplive.miguvideo.com/wd_r2/ocn/cctv14hd/3000/index.m3u8?&encrypt=
|
||||
央视频道,CCTV15 音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8
|
||||
央视频道,CCTV15,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv15hd/51/index.m3u8?&encrypt=
|
||||
央视频道,CCTV17,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv17hd/57/index.m3u8?&encrypt=
|
||||
央视频道,CGTN,http://hlsbkmgsplive.miguvideo.com/envivo_x/2018/SD/cctvnews/1000/index.m3u8?&encrypt=
|
||||
|
||||
央视频道,CCTV2,https://iptv.luas.edu.cn/liverespath/6b13fe5368d391761312a985ace065c0ecad2f5e/877097d2fa-0-0-b7736e6941fd5cb71f45ef9397b68092/index.m3u8
|
||||
央视频道,CCTV3,https://iptv.luas.edu.cn/liverespath/f76f9947c68be18d7a456e25aa59a08c5747e6a5/0df24da9ec-0-0-dca40ddadd2a051ce1a83536d9310820/index.m3u8
|
||||
央视频道,CCTV4 中文国际,http://39.134.24.161/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226191/index.m3u8
|
||||
央视频道,CCTV6,https://iptv.luas.edu.cn/liverespath/f2f39ee2105c85c32df375728a51b5d89d3afab4/113ed89f48-0-0-85216e55861329ec31ba1437a2ff37c9/index.m3u8
|
||||
央视频道,CCTV7,https://iptv.luas.edu.cn/liverespath/f116a0a5035935a3435155998163d8eaa60554c3/4ba629f762-0-0-0a66b18805ff859ce68ab1137157079e/index.m3u8
|
||||
央视频道,CCTV8,https://iptv.luas.edu.cn/liverespath/9e6e3b618b5dc902d992949f0c669bb674f6cde8/cae4471c68-0-0-316245c664c3311072c7279ec29672fe/index.m3u8
|
||||
央视频道,CCTV9,http://39.134.24.162/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8
|
||||
央视频道,CCTV10,https://iptv.luas.edu.cn/liverespath/924e6292a0e6f7440e8380075908fed9915b3c00/780499a193-0-0-c50d57fd93cf32a5144ec8d889eb3ed9/index.m3u8
|
||||
央视频道,CCTV11,https://iptv.luas.edu.cn/liverespath/3d0aa0f1604f13f0ae90c2dc0590ca22a1bcaaa2/646e868153-0-0-a53121a1df5b93a74d1980270e652878/index.m3u8
|
||||
央视频道,CCTV12,https://iptv.luas.edu.cn/liverespath/fb84bde1de15cdb0308a7910cebc0497594ae94e/e2d8885f42-0-0-6e1f55986652ba786606a116c5cc0775/index.m3u8
|
||||
央视频道,CCTV13,https://live-play.cctvnews.cctv.com/cctv/merge_cctv13.m3u8
|
||||
央视频道,CCTV14,https://iptv.luas.edu.cn/liverespath/0e0973e58d4835f4b872548164462930003f77b4/0ef01acfdb-0-0-3c10e95bcde07ba14f0f93a8d831b684/index.m3u8
|
||||
央视频道,CCTV15 音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8
|
||||
央视频道,CGTN 新闻频道,http://live.cgtn.com/1000/prog_index.m3u8
|
||||
央视频道,CGTN 纪录频道,https://livedoc.cgtn.com/500d/prog_index.m3u8
|
||||
央视频道,CGTN 法语频道,https://livefr.cgtn.com/1000f/prog_index.m3u8
|
||||
央视频道,CGTN 俄语频道,http://liveru.cgtn.com/1000r/prog_index.m3u8
|
||||
央视频道,CGTN 西班牙语频道,http://livees.cgtn.com/500e/prog_index.m3u8
|
||||
央视频道,CGTN 阿拉伯语频道,http://livear.cgtn.com/1000a/prog_index.m3u8
|
||||
央视频道,CGTN 拉丁美洲频道,http://livees.cgtn.com/1000e/prog_index.m3u8
|
||||
央视频道,书画频道,http://211.103.180.178:8234/live_hls/hdmi.m3u8
|
||||
|
||||
CGTN,新闻频道,http://live.cgtn.com/1000/prog_index.m3u8
|
||||
CGTN,纪录频道,https://livedoc.cgtn.com/500d/prog_index.m3u8
|
||||
CGTN,法语频道,https://livefr.cgtn.com/1000f/prog_index.m3u8
|
||||
CGTN,俄语频道,http://liveru.cgtn.com/1000r/prog_index.m3u8
|
||||
CGTN,西班牙语频道,http://livees.cgtn.com/500e/prog_index.m3u8
|
||||
CGTN,阿拉伯语频道,http://livear.cgtn.com/1000a/prog_index.m3u8
|
||||
CGTN,拉丁美洲频道,http://livees.cgtn.com/1000e/prog_index.m3u8
|
||||
|
||||
地方频道,东方卫视,http://hlsbkmgsplive.miguvideo.com/wd_r4/dfl/dongfangwshd/3000/index.m3u8?&encrypt=
|
||||
地方频道,内蒙古卫视,http://hlsbkmgsplive.miguvideo.com/envivo_w/2018/SD/neimeng/1000/index.m3u8?&encrypt=
|
||||
地方频道,湖南卫视,http://hlsbkmgsplive.miguvideo.com/wd-hunanhd-2500/index.m3u8?&encrypt=
|
||||
|
|
@ -107,26 +104,19 @@ CGTN,拉丁美洲频道,http://livees.cgtn.com/1000e/prog_index.m3u8
|
|||
地方频道,延边卫视,http://live.ybtvyun.com/video/s10006-44f040627ca1/index.m3u8
|
||||
""".trimIndent()
|
||||
|
||||
val map: MutableMap<String, MutableList<TV>> = mutableMapOf()
|
||||
val map: MutableMap<String, MutableMap<String, LinkedHashSet<String>>> = mutableMapOf()
|
||||
|
||||
for (i in tvs.split("\n")) {
|
||||
val (channel, title, videoUrl) = i.split(",")
|
||||
val videoList = map[channel] ?: mutableListOf()
|
||||
videoList.add(buildTV(title, videoUrl))
|
||||
map[channel] = videoList
|
||||
val (channel, title, url) = i.split(",")
|
||||
val titleMap = map[channel] ?: mutableMapOf()
|
||||
|
||||
val urlSet = titleMap[title] ?: LinkedHashSet()
|
||||
urlSet.add(url)
|
||||
|
||||
titleMap[title] = urlSet
|
||||
map[channel] = titleMap
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
|
||||
private fun buildTV(
|
||||
title: String,
|
||||
videoUrl: String,
|
||||
): TV {
|
||||
val tv = TV()
|
||||
tv.id = count++
|
||||
tv.title = title
|
||||
tv.videoUrl = videoUrl
|
||||
return tv
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue