diff --git a/README.md b/README.md index 5c1393b3..b9dea27c 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ Android version + + GitHub license + GitHub license @@ -61,7 +64,7 @@ * #### ⭐**Star**鼓励开发者 * #### 👁️Watch关注开发进度 * #### 📇Pull requests(**请尽量贴合项目的源码和commit风格**) -* #### 💡加入[群组](https://discord.com/invite/K5GN7FaQuX)讨论反馈 +* #### 💡加入[群组](https://pd.qq.com/s/1cii5y637)讨论反馈 ## 安全说明 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a0db391c..1946b029 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + diff --git a/app/src/main/java/com/su/mediabox/App.kt b/app/src/main/java/com/su/mediabox/App.kt index 1723fecd..35dba4a4 100644 --- a/app/src/main/java/com/su/mediabox/App.kt +++ b/app/src/main/java/com/su/mediabox/App.kt @@ -3,6 +3,8 @@ package com.su.mediabox import android.annotation.SuppressLint import android.app.Application import android.content.Context +import android.os.Handler +import android.os.Looper import android.util.Log import android.webkit.WebView import com.liulishuo.filedownloader.FileDownloader @@ -83,6 +85,7 @@ class App : Application() { companion object { @SuppressLint("StaticFieldLeak") lateinit var context: Context + val mainHandler = Handler(Looper.getMainLooper()) init { // 防止内存泄漏 diff --git a/app/src/main/java/com/su/mediabox/config/Const.kt b/app/src/main/java/com/su/mediabox/config/Const.kt index a74e7409..cc85e4fb 100644 --- a/app/src/main/java/com/su/mediabox/config/Const.kt +++ b/app/src/main/java/com/su/mediabox/config/Const.kt @@ -31,7 +31,7 @@ interface Const { "https://ryensx.github.io/MediaBoxPluginRepository/" const val GITHUB_PLUGIN_REPO_DEV_DOC_URL = "https://github.com/RyensX/MediaBox/wiki" const val USER_NOTICE_VERSION = 2 - const val GROUP_URL = "https://discord.com/invite/K5GN7FaQuX" + const val GROUP_URL = "https://pd.qq.com/s/1cii5y637" const val ANNOUNCEMENT="https://raw.githubusercontent.com/RyensX/MediaBox/dev/doc/announcement.json" val licenses = listOf( diff --git a/app/src/main/java/com/su/mediabox/net/DnsServer.kt b/app/src/main/java/com/su/mediabox/net/DnsServer.kt index 7ffbe762..801e7e07 100644 --- a/app/src/main/java/com/su/mediabox/net/DnsServer.kt +++ b/app/src/main/java/com/su/mediabox/net/DnsServer.kt @@ -29,7 +29,7 @@ object DnsServer { override fun equals(other: Any?): Boolean { return when (other) { null -> false - other === this -> true + (other === this) -> true is String -> other == dnsServer is Dns -> other.dnsServer == this.dnsServer && other.dnsName == this.dnsName else -> false diff --git a/app/src/main/java/com/su/mediabox/plugin/Plugin.kt b/app/src/main/java/com/su/mediabox/plugin/Plugin.kt index 74b32155..85d93ce5 100644 --- a/app/src/main/java/com/su/mediabox/plugin/Plugin.kt +++ b/app/src/main/java/com/su/mediabox/plugin/Plugin.kt @@ -40,6 +40,8 @@ import java.io.File object PluginManager { + private const val TAG = "PluginManager" + val appApiVersion by unsafeLazy { val appInfo: ApplicationInfo = App.context.packageManager .getApplicationInfo( @@ -284,7 +286,7 @@ object PluginManager { * @param pluginInfo 至少要保证包含有效[PluginInfo.sourcePath](作为下载地址) * @param directInstall 直接下载安装,一般只用于官方仓库插件,不经安装器验证直接安装 */ - fun downloadPlugin(pluginInfo: PluginInfo, directInstall: Boolean = false) { + fun downloadPlugin(pluginInfo: PluginInfo, directInstall: Boolean = false) = runCatching { val downloadManager = App.context.getSystemService(AppCompatActivity.DOWNLOAD_SERVICE) as DownloadManager val uri: Uri = Uri @@ -302,6 +304,10 @@ object PluginManager { setAllowedOverRoaming(true) } downloadManager.enqueue(request) + }.onFailure { + logE(TAG, "downloadPlugin: error=${it.message} directInstall=$directInstall pluginInfo=$pluginInfo") + "插件下载失败: ${it.message}".showToast() + it.printStackTrace() } fun initPluginEnv() { diff --git a/app/src/main/java/com/su/mediabox/util/Activity.kt b/app/src/main/java/com/su/mediabox/util/Activity.kt index 31da630c..0f5610c8 100644 --- a/app/src/main/java/com/su/mediabox/util/Activity.kt +++ b/app/src/main/java/com/su/mediabox/util/Activity.kt @@ -29,12 +29,12 @@ fun putAction(action: T) { } @Suppress("UNCHECKED_CAST") -fun getActionIns(actionClass: Class): T? = +fun consumeActionIns(actionClass: Class): T? = (actionPoolMap[actionClass.simpleName] as? T)?.also { actionPoolMap.remove(actionClass.simpleName) } -inline fun getAction(): T? = getActionIns(T::class.java) +inline fun consumeAction(): T? = consumeActionIns(T::class.java) fun Activity.viewBind(inflater: (LayoutInflater) -> VB) = lazy(LazyThreadSafetyMode.NONE) { diff --git a/app/src/main/java/com/su/mediabox/util/CoroutineUtil.kt b/app/src/main/java/com/su/mediabox/util/CoroutineUtil.kt index 317707d7..6b6645c7 100644 --- a/app/src/main/java/com/su/mediabox/util/CoroutineUtil.kt +++ b/app/src/main/java/com/su/mediabox/util/CoroutineUtil.kt @@ -52,10 +52,10 @@ private class ViewCoroutineInterceptor( private class ViewStateListener(private val view: View, private val job: Job) : View.OnAttachStateChangeListener, CompletionHandler { - override fun onViewAttachedToWindow(v: View?) {} + override fun onViewAttachedToWindow(v: View) {} //在Recyclerview上使用LinearLayoutManager可能并不会调用,取决于mRecycleChildrenOnDetach,因此必须手动调用setRecycleChildrenOnDetach(true) - override fun onViewDetachedFromWindow(v: View?) { + override fun onViewDetachedFromWindow(v: View) { logD("View协程", "分离视图->取消") view.removeOnAttachStateChangeListener(this) job.cancel() diff --git a/app/src/main/java/com/su/mediabox/util/coil/CoilUtil.kt b/app/src/main/java/com/su/mediabox/util/coil/CoilUtil.kt index e5180a51..3f3aceb0 100644 --- a/app/src/main/java/com/su/mediabox/util/coil/CoilUtil.kt +++ b/app/src/main/java/com/su/mediabox/util/coil/CoilUtil.kt @@ -53,6 +53,7 @@ object CoilUtil { logE("loadImage", "图片来源有误!") return@runCatching } + logD("加载图片","url=$urlOrBase64") val time = System.currentTimeMillis() when { urlOrBase64.startsWith("data:image") -> { @@ -90,10 +91,10 @@ object CoilUtil { ?.let { addHeader("Referer", it) } - addHeader("Host", URL(urlOrBase64).host) - addHeader("Accept", "*/*") - addHeader("Accept-Encoding", "gzip, deflate") - addHeader("Connection", "keep-alive") +// addHeader("Host", URL(urlOrBase64).host) +// addHeader("Accept", "*/*") +// addHeader("Accept-Encoding", "gzip, deflate") +// addHeader("Connection", "keep-alive") addHeader("User-Agent", Constant.Request.getRandomUserAgent()) listener { _, _ -> logD("图片加载完毕", "time=$time url=$urlOrBase64", false) diff --git a/app/src/main/java/com/su/mediabox/util/html/source/web/GettingWebView.kt b/app/src/main/java/com/su/mediabox/util/html/source/web/GettingWebView.kt index d87308ed..c0c3b87f 100644 --- a/app/src/main/java/com/su/mediabox/util/html/source/web/GettingWebView.kt +++ b/app/src/main/java/com/su/mediabox/util/html/source/web/GettingWebView.kt @@ -40,8 +40,6 @@ class GettingWebView @JvmOverloads constructor( } mWebSettings.javaScriptCanOpenWindowsAutomatically = true mWebSettings.loadsImagesAutomatically = false - mWebSettings.setAppCacheEnabled(true) - mWebSettings.setAppCachePath(context.cacheDir.absolutePath) mWebSettings.databaseEnabled = true mWebSettings.setGeolocationDatabasePath(context.getDir("database", 0).path) mWebSettings.setGeolocationEnabled(true) diff --git a/app/src/main/java/com/su/mediabox/view/activity/MediaClassifyActivity.kt b/app/src/main/java/com/su/mediabox/view/activity/MediaClassifyActivity.kt index cca3dfaf..e36452c1 100644 --- a/app/src/main/java/com/su/mediabox/view/activity/MediaClassifyActivity.kt +++ b/app/src/main/java/com/su/mediabox/view/activity/MediaClassifyActivity.kt @@ -128,11 +128,12 @@ class MediaClassifyActivity : BasePluginActivity() { mBinding.mediaClassifyFabProgress.invisible() "加载分类错误:${it.throwable?.message}".showToast() } + else -> {} } } //如果传入分类,则直接开始加载分类数据,否则自动加载分类项数据并打开弹窗 - getAction()?.also { + consumeAction()?.also { mediaClassify.currentClassifyAction = it viewModel.getClassifyData(it) } ?: viewModel.getClassifyItemData() diff --git a/app/src/main/java/com/su/mediabox/view/activity/MediaDetailActivity.kt b/app/src/main/java/com/su/mediabox/view/activity/MediaDetailActivity.kt index dc57dde3..723aeca3 100644 --- a/app/src/main/java/com/su/mediabox/view/activity/MediaDetailActivity.kt +++ b/app/src/main/java/com/su/mediabox/view/activity/MediaDetailActivity.kt @@ -32,7 +32,7 @@ class MediaDetailActivity : BasePluginActivity() { logD("获取VM", "@${viewModel}") - getAction()?.also { + consumeAction()?.also { viewModel.partUrl = it.url } @@ -111,7 +111,7 @@ class MediaDetailActivity : BasePluginActivity() { override fun startActivity(intent: Intent?, options: Bundle?) { //主动向下一级路由目标提供一些信息 intent?.apply { - getAction()?.apply { + consumeAction()?.apply { coverUrl = viewModel.cover detailPartUrl = viewModel.partUrl videoName = viewModel.title diff --git a/app/src/main/java/com/su/mediabox/view/activity/MediaSearchActivity.kt b/app/src/main/java/com/su/mediabox/view/activity/MediaSearchActivity.kt index a92cc1be..6c88f2e8 100644 --- a/app/src/main/java/com/su/mediabox/view/activity/MediaSearchActivity.kt +++ b/app/src/main/java/com/su/mediabox/view/activity/MediaSearchActivity.kt @@ -133,7 +133,7 @@ class MediaSearchActivity : BasePluginActivity() { } } - getAction()?.also { + consumeAction()?.also { viewModel.getSearchData(it.keyWork) } } diff --git a/app/src/main/java/com/su/mediabox/view/activity/VideoMediaPlayActivity.kt b/app/src/main/java/com/su/mediabox/view/activity/VideoMediaPlayActivity.kt index bff5558d..0b1492b2 100644 --- a/app/src/main/java/com/su/mediabox/view/activity/VideoMediaPlayActivity.kt +++ b/app/src/main/java/com/su/mediabox/view/activity/VideoMediaPlayActivity.kt @@ -36,7 +36,6 @@ class VideoMediaPlayActivity : BasePluginActivity(), VideoMediaPlayer.PlayOperatingProxy { companion object { - var playList: List? = null private const val DEFAULT_SEEK_LENGTH = 15000L const val DEFAULT_VIDEO_PRELOAD_SIZE = 5 } @@ -63,10 +62,12 @@ class VideoMediaPlayActivity : BasePluginActivity(), setFullScreen(window) - getAction()?.also { action -> + consumeAction()?.also { action -> this.action = action init() viewModel.apply { + val playList = action.extraData as? List + playList?.let { init(it) } detailPartUrl = action.detailPartUrl coverUrl = action.coverUrl videoName = action.videoName @@ -85,6 +86,7 @@ class VideoMediaPlayActivity : BasePluginActivity(), } visible() } + is DataState.Success -> dataState.data?.also { mBinding.vmPlay.playVideo( it.videoPlayUrl, @@ -93,6 +95,7 @@ class VideoMediaPlayActivity : BasePluginActivity(), mBinding.vmLoadingLayer.gone() mBinding.vmErrorRetry.gone() } + is DataState.Failed -> { dataState.throwable?.message?.showToast() mBinding.vmLoadingLayer.apply { @@ -102,6 +105,7 @@ class VideoMediaPlayActivity : BasePluginActivity(), visible() } } + else -> Unit } } @@ -211,6 +215,7 @@ class VideoMediaPlayActivity : BasePluginActivity(), onVideoResume() } } + KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_MEDIA_STEP_BACKWARD -> //减速 if (event?.isShiftPressed == true) { @@ -270,8 +275,6 @@ class VideoMediaPlayActivity : BasePluginActivity(), mBinding.vmPlay.setVideoAllCallBack(null) GSYVideoManager.releaseAllVideos() orientationUtils.releaseListener() - //释放播放列表 - playList = null } super.onDestroy() } diff --git a/app/src/main/java/com/su/mediabox/view/activity/WebViewActivity.kt b/app/src/main/java/com/su/mediabox/view/activity/WebViewActivity.kt index abaf9f14..adec5a7f 100644 --- a/app/src/main/java/com/su/mediabox/view/activity/WebViewActivity.kt +++ b/app/src/main/java/com/su/mediabox/view/activity/WebViewActivity.kt @@ -12,7 +12,7 @@ import com.su.mediabox.databinding.ActivityWebViewBinding import com.su.mediabox.plugin.WebUtilImpl.clearWeb import com.su.mediabox.pluginapi.action.WebBrowserAction import com.su.mediabox.util.Util.openUrl -import com.su.mediabox.util.getAction +import com.su.mediabox.util.consumeAction import com.su.mediabox.util.logD import com.su.mediabox.util.logE import com.su.mediabox.util.viewBind @@ -27,7 +27,7 @@ class WebViewActivity : BasePluginActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - mAction = getAction() ?: run { + mAction = consumeAction() ?: run { finish() return } diff --git a/app/src/main/java/com/su/mediabox/view/component/PointView.kt b/app/src/main/java/com/su/mediabox/view/component/PointView.kt index 51e6b868..128b75ef 100644 --- a/app/src/main/java/com/su/mediabox/view/component/PointView.kt +++ b/app/src/main/java/com/su/mediabox/view/component/PointView.kt @@ -31,10 +31,10 @@ class PointView(context: Context, attributeSet: AttributeSet) : View(context, at } get() = paint.color - override fun onDraw(canvas: Canvas?) { + override fun onDraw(canvas: Canvas) { super.onDraw(canvas) val radius = pointSize / 2 - canvas?.drawCircle(width / 2F, height / 2F, radius, paint) + canvas.drawCircle(width / 2F, height / 2F, radius, paint) } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { diff --git a/app/src/main/java/com/su/mediabox/view/component/player/VideoMediaPlayer.kt b/app/src/main/java/com/su/mediabox/view/component/player/VideoMediaPlayer.kt index 63b66c11..810150aa 100644 --- a/app/src/main/java/com/su/mediabox/view/component/player/VideoMediaPlayer.kt +++ b/app/src/main/java/com/su/mediabox/view/component/player/VideoMediaPlayer.kt @@ -42,6 +42,7 @@ import com.su.mediabox.view.component.ZoomView import com.su.mediabox.view.component.player.autoSkip.VideoAutoSkipViewController import com.su.mediabox.view.component.textview.TypefaceTextView import com.su.mediabox.view.listener.dsl.setOnSeekBarChangeListener +import com.su.mediabox.viewmodel.VideoMediaPlayViewModel import kotlinx.coroutines.* import java.io.File import kotlin.math.abs @@ -426,14 +427,15 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { tvEpisode = findViewById(R.id.tv_episode) //播放列表 tvEpisode?.apply { + val playList = VideoMediaPlayViewModel.getCurrentPlayList(context) //只有存在选集数据和VM才显示选集 - if (VideoMediaPlayActivity.playList == null || playOperatingProxy == null) { + if (playList == null || playOperatingProxy == null) { gone() return@apply } visible() rvEpisode - ?.grid(if (VideoMediaPlayActivity.playList!!.size > 8) 4 else 1) + ?.grid(if (playList.size > 8) 4 else 1) ?.initTypeList(DataViewMapList().registerDataViewMap()) { vHCreateDSL { setOnClickListener(itemView) { pos -> @@ -478,7 +480,7 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { //为了使下一集按钮有效,需要在第一次加载时初始化播放列表的初始定位 playPositionMemoryStoreCoroutineScope.launch { //查找初始定位 - VideoMediaPlayActivity.playList?.forEachIndexed { index, episodeData -> + VideoMediaPlayViewModel.getCurrentPlayList(context)?.forEachIndexed { index, episodeData -> if (episodeData.url.isNotBlank() && episodeData.url == playOperatingProxy?.currentPlayEpisodeUrl) { logD("找到初始标记", index.toString()) rvEpisode?.typeAdapter()?.setTag(index) @@ -500,8 +502,8 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { fun playNextEpisode(): Boolean { val episodeAdapter = rvEpisode?.typeAdapter() episodeAdapter?.getTag()?.also { pos -> - if (pos < (VideoMediaPlayActivity.playList?.size ?: pos) - 1) - VideoMediaPlayActivity.playList?.getOrNull(pos + 1)?.url?.also { + if (pos < (VideoMediaPlayViewModel.getCurrentPlayList(context)?.size ?: pos) - 1) + VideoMediaPlayViewModel.getCurrentPlayList(context)?.getOrNull(pos + 1)?.url?.also { currentPlayer.onVideoPause() episodeAdapter.apply { //更新上次选项 @@ -784,12 +786,15 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { NO_REVERSE -> { // 正常 transform.setScale(1f, 1f, mTextureView.width / 2.toFloat(), 0f) } + HORIZONTAL_REVERSE -> { // 左右镜像 transform.setScale(-1f, 1f, mTextureView.width / 2.toFloat(), 0f) } + VERTICAL_REVERSE -> { // 上下镜像 transform.setScale(1f, -1f, 0f, mTextureView.height / 2.toFloat()) } + else -> return } mTextureViewTransform = transformSize @@ -819,12 +824,15 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { GSYVideoView.CURRENT_STATE_PLAYING -> { imageView.setImageDrawable(getResDrawable(R.drawable.ic_pause_white_24)) } + GSYVideoView.CURRENT_STATE_ERROR -> { imageView.setImageDrawable(getResDrawable(R.drawable.ic_play_white_24)) } + GSYVideoView.CURRENT_STATE_AUTO_COMPLETE -> { imageView.setImageDrawable(getResDrawable(R.drawable.ic_refresh_white_24)) } + else -> { imageView.setImageDrawable(getResDrawable(R.drawable.ic_play_white_24)) } @@ -888,7 +896,7 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { viewTopContainerShadow?.visible() mUiCleared = false - if (VideoMediaPlayActivity.playList != null) + if (VideoMediaPlayViewModel.getCurrentPlayList(context) != null) ivNextEpisode?.gone() playErrorRetry?.gone() @@ -906,7 +914,7 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { initFirstLoad = false mUiCleared = false - if (VideoMediaPlayActivity.playList != null) + if (VideoMediaPlayViewModel.getCurrentPlayList(context) != null) ivNextEpisode?.visible() ivSetting?.visible() @@ -1019,11 +1027,13 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { startDismissControlViewTimer() } } + R.id.thumb -> { vgSettingContainer?.gone() vgRightContainer?.gone() rvEpisode?.gone() } + R.id.back -> (context as Activity).finish() //重试 R.id.play_error_retry -> prepareVideo() @@ -1049,7 +1059,7 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { val adapter = typeAdapter() isVisible = true showRightContainer() - adapter.submitList(VideoMediaPlayActivity.playList) { + adapter.submitList(VideoMediaPlayViewModel.getCurrentPlayList(context)) { //定位 adapter.getTag()?.also { smartScrollToPosition(it) @@ -1156,6 +1166,7 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { MotionEvent.ACTION_DOWN -> { touchSurfaceDown(x, y) } + MotionEvent.ACTION_MOVE -> { val deltaX = x - mDownX val deltaY = y - mDownY @@ -1170,6 +1181,7 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { } touchSurfaceMove(deltaX, deltaY, y) } + MotionEvent.ACTION_UP -> { startDismissControlViewTimer() touchSurfaceUp() @@ -1271,7 +1283,10 @@ open class VideoMediaPlayer : StandardGSYVideoPlayer { override fun startAfterPrepared() { super.startAfterPrepared() - logD(PLAY_POS_TAG, "开始播放,当前进度:pos=${gsyVideoManager.currentPosition} url=$mOriginUrl") + logD( + PLAY_POS_TAG, + "开始播放,当前进度:pos=${gsyVideoManager.currentPosition} url=$mOriginUrl" + ) } override fun setProgressAndTime( diff --git a/app/src/main/java/com/su/mediabox/view/fragment/page/SettingsPageFragment.kt b/app/src/main/java/com/su/mediabox/view/fragment/page/SettingsPageFragment.kt index 64c9fe7d..70e2b4a6 100644 --- a/app/src/main/java/com/su/mediabox/view/fragment/page/SettingsPageFragment.kt +++ b/app/src/main/java/com/su/mediabox/view/fragment/page/SettingsPageFragment.kt @@ -87,7 +87,6 @@ class SettingsPageFragment : PreferenceFragmentCompat(), Preference.OnPreference } preferenceCategory { - titleRes(R.string.net_category_title) switchPreference { key = Const.Setting.NET_REPO_PROXY @@ -171,7 +170,7 @@ class SettingsPageFragment : PreferenceFragmentCompat(), Preference.OnPreference } lifecycleCollect(mediaUpdateCheckWorkerIsRunning) { isRunning -> - listView.post { + App.mainHandler.post { auto.isEnabled = !isRunning interval.isEnabled = !isRunning onMeteredNet.isEnabled = !isRunning @@ -191,7 +190,7 @@ class SettingsPageFragment : PreferenceFragmentCompat(), Preference.OnPreference summaryRes(R.string.player_bottom_progress_summary) lifecycleCollect(Pref.isShowPlayerBottomProgressBar) { - listView.post { + App.mainHandler.post { isChecked = it } } @@ -234,12 +233,16 @@ class SettingsPageFragment : PreferenceFragmentCompat(), Preference.OnPreference AppUpdateHelper.instance.apply { getUpdateStatus() .observe(this@SettingsPageFragment) { - isEnabled = it != AppUpdateStatus.CHECKING - when (it) { - AppUpdateStatus.VALID -> - context.getString(R.string.app_no_update_hint).showToast() - AppUpdateStatus.DATED -> noticeUpdate(requireActivity() as AppCompatActivity) - else -> Unit + App.mainHandler.post { + isEnabled = it != AppUpdateStatus.CHECKING + when (it) { + AppUpdateStatus.VALID -> + context.getString(R.string.app_no_update_hint) + .showToast() + + AppUpdateStatus.DATED -> noticeUpdate(requireActivity() as AppCompatActivity) + else -> Unit + } } } } diff --git a/app/src/main/java/com/su/mediabox/view/viewcomponents/VideoPlayListViewHolder.kt b/app/src/main/java/com/su/mediabox/view/viewcomponents/VideoPlayListViewHolder.kt index 531daf12..055d1539 100644 --- a/app/src/main/java/com/su/mediabox/view/viewcomponents/VideoPlayListViewHolder.kt +++ b/app/src/main/java/com/su/mediabox/view/viewcomponents/VideoPlayListViewHolder.kt @@ -156,7 +156,7 @@ class VideoPlayListViewHolder private constructor(private val binding: ItemHoriz val playList = bindingTypeAdapter.getTag>(Const.ViewComponent.EPISODE_LIST_TAG) if (playList != null) { - VideoMediaPlayActivity.playList = playList + action.extraData = playList } } action?.go(bindingContext) diff --git a/app/src/main/java/com/su/mediabox/view/viewcomponents/ViewPagerViewHolder.kt b/app/src/main/java/com/su/mediabox/view/viewcomponents/ViewPagerViewHolder.kt index 62bc4fbd..a90f7b55 100644 --- a/app/src/main/java/com/su/mediabox/view/viewcomponents/ViewPagerViewHolder.kt +++ b/app/src/main/java/com/su/mediabox/view/viewcomponents/ViewPagerViewHolder.kt @@ -166,20 +166,21 @@ class ViewPagerViewHolder private constructor(private val binding: ViewComponent class PageViewModel : ViewModel() { - private var pageLoader by Delegates.notNull() - private var page by Delegates.notNull() + private var pageLoader: ViewPagerData.PageLoader? = null + private var page: Int = 0 fun bindData(pageLoader: ViewPagerData.PageLoader?, page: Int?) { - pageLoader?.also { this.pageLoader = it } + this.pageLoader = pageLoader page?.also { this.page = it } } - private val _pageDataLiveData: MutableLiveData> = MutableLiveData() + private val _pageDataLiveData: MutableLiveData?> = + MutableLiveData?>() val pageDataLiveData = _pageDataLiveData.toLiveData() fun getData() { viewModelScope.launch(Dispatchers.PluginIO) { - _pageDataLiveData.postValue(pageLoader.loadData(page)) + _pageDataLiveData.postValue(pageLoader?.loadData(page)) } } diff --git a/app/src/main/java/com/su/mediabox/viewmodel/PluginInstallerViewModel.kt b/app/src/main/java/com/su/mediabox/viewmodel/PluginInstallerViewModel.kt index 9b15d420..08c59458 100644 --- a/app/src/main/java/com/su/mediabox/viewmodel/PluginInstallerViewModel.kt +++ b/app/src/main/java/com/su/mediabox/viewmodel/PluginInstallerViewModel.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.graphics.Color import android.graphics.Typeface import android.net.Uri +import android.util.Log import android.view.Gravity import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -23,6 +24,8 @@ import com.su.mediabox.util.ResourceUtil.getString class PluginInstallerViewModel : ViewModel() { + private val tag = "PluginInstaller" + private val _pluginInstallState = MutableLiveData(PluginInstallState.LOADING) val pluginInstallState = _pluginInstallState.toLiveData() @@ -63,6 +66,9 @@ class PluginInstallerViewModel : ViewModel() { ) } } + else -> { + logE(tag, "install error: $data") + } } } } @@ -230,6 +236,9 @@ class PluginInstallerViewModel : ViewModel() { is PluginInstallState.PREVIEW -> { PluginManager.downloadPlugin(data.pluginInfo) } + else -> { + logE(tag, "downloadPlugin: $data") + } } } diff --git a/app/src/main/java/com/su/mediabox/viewmodel/VideoMediaPlayViewModel.kt b/app/src/main/java/com/su/mediabox/viewmodel/VideoMediaPlayViewModel.kt index 2766aab9..8d042669 100644 --- a/app/src/main/java/com/su/mediabox/viewmodel/VideoMediaPlayViewModel.kt +++ b/app/src/main/java/com/su/mediabox/viewmodel/VideoMediaPlayViewModel.kt @@ -1,7 +1,11 @@ package com.su.mediabox.viewmodel +import android.content.Context +import androidx.activity.ComponentActivity import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.get import androidx.lifecycle.viewModelScope import com.kuaishou.akdanmaku.data.DanmakuItemData import com.su.mediabox.Pref @@ -9,16 +13,29 @@ import com.su.mediabox.database.DatabaseOperations.insertHistoryData import com.su.mediabox.database.DatabaseOperations.updateFavoriteData import com.su.mediabox.pluginapi.data.VideoPlayMedia import com.su.mediabox.pluginapi.components.IVideoPlayPageDataComponent +import com.su.mediabox.pluginapi.data.EpisodeData import com.su.mediabox.util.* import com.su.mediabox.view.activity.VideoMediaPlayActivity import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.launch +import kotlin.math.min import kotlin.properties.Delegates class VideoMediaPlayViewModel : ViewModel() { + companion object { + fun getCurrentPlayList(context: Context): List? { + return if (context !is ComponentActivity) + null + else { + ViewModelProvider(context).get().playList + } + } + } + private val playComponent by lazyAcquireComponent() lateinit var detailPartUrl: String @@ -28,6 +45,9 @@ class VideoMediaPlayViewModel : ViewModel() { var currentPlayEpisodeUrl = "" private set + var playList: List? = null + private set + private val _currentVideoPlayMedia = MutableLiveData>() private val _currentDanmakuData = MutableLiveData?>() @@ -42,6 +62,12 @@ class VideoMediaPlayViewModel : ViewModel() { private val episode2VideoInfoMap = mutableMapOf() + private var lastAutoJob: Job? = null + + fun init(playList: List) { + this.playList = playList + } + fun playVideoMedia(episodeUrl: String = currentPlayEpisodeUrl) { if (episodeUrl.isNotBlank()) { _currentVideoPlayMedia.postValue(DataState.Loading) @@ -82,16 +108,17 @@ class VideoMediaPlayViewModel : ViewModel() { private fun preloadVideo(curEpisodeUrl: String) { if (!Pref.videoPreload.value) return - VideoMediaPlayActivity.playList?.let { + playList?.let { logD("preloadVideo", "load start: cur=$curEpisodeUrl") - viewModelScope.launch(Dispatchers.IO) { + lastAutoJob?.cancel() + lastAutoJob = viewModelScope.launch(Dispatchers.IO) { //定位当前 val startPre = it.indexOfFirst { it.url == curEpisodeUrl } if (startPre != -1) { var endIndex = startPre + VideoMediaPlayActivity.DEFAULT_VIDEO_PRELOAD_SIZE - if (endIndex > (it.size - 1)) { - endIndex = it.size - 1 - } + endIndex = min(endIndex, it.size - 1) + logD("preloadVideo", "start $startPre to $endIndex") + var realSize = 0 for (i in (startPre + 1)..endIndex) { val episodeUrl = it[i].url //TODO 因为内置的WebUtil内部WebView问题,暂时先串行解析 @@ -105,10 +132,12 @@ class VideoMediaPlayViewModel : ViewModel() { "load episodeUrl=$episodeUrl success result=$result" ) episode2VideoInfoMap[episodeUrl] = result + realSize++ } } } } + logD("preloadVideo", "preload success: size=$realSize") } } } @@ -124,6 +153,7 @@ class VideoMediaPlayViewModel : ViewModel() { ) true } + else -> false } } @@ -142,7 +172,13 @@ class VideoMediaPlayViewModel : ViewModel() { } } } + else -> logD("加载弹幕失败", "当前无播放媒体") } } + + override fun onCleared() { + playList = null + super.onCleared() + } } \ No newline at end of file diff --git a/app/src/main/java/com/su/mediabox/work/MediaUpdateCheckWorker.kt b/app/src/main/java/com/su/mediabox/work/MediaUpdateCheckWorker.kt index 16502132..d292bf17 100644 --- a/app/src/main/java/com/su/mediabox/work/MediaUpdateCheckWorker.kt +++ b/app/src/main/java/com/su/mediabox/work/MediaUpdateCheckWorker.kt @@ -68,6 +68,10 @@ internal class MediaUpdateCheckWorker(context: Context, workerParameters: Worker private val TAG = "媒体检查更新Worker" private val key = ResourceUtil.getString(R.string.media_update_check_title) + private val notifyFlag = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_IMMUTABLE + else PendingIntent.FLAG_UPDATE_CURRENT + private fun createForegroundInfo(): ForegroundInfo { // val cancel = applicationContext.getString(R.string.cancel) // val intent = WorkManager.getInstance(applicationContext) @@ -77,7 +81,7 @@ internal class MediaUpdateCheckWorker(context: Context, workerParameters: Worker flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val notifyPendingIntent = PendingIntent.getActivity( - applicationContext, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT + applicationContext, 0, notifyIntent, notifyFlag ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -179,7 +183,7 @@ internal class MediaUpdateCheckWorker(context: Context, workerParameters: Worker val pluginMediaDataManageNotifyPendingIntent = PendingIntent.getActivity( applicationContext, index, - pluginMediaDataManageIntent, PendingIntent.FLAG_UPDATE_CURRENT + pluginMediaDataManageIntent, notifyFlag ) val pluginMediaUpdateNofBuilder = @@ -216,7 +220,7 @@ internal class MediaUpdateCheckWorker(context: Context, workerParameters: Worker Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val notifyPendingIntent = PendingIntent.getActivity( - applicationContext, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT + applicationContext, 0, notifyIntent, notifyFlag ) val mediaUpdateCheckNofBuilder = diff --git a/build.gradle b/build.gradle index 49db0ad0..7760a015 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { ext { secret = "${rootDir}/secret.gradle" andresguard = "${rootDir}/andresguard.gradle" - kotlinVersion = '1.6.21' + kotlinVersion = '1.8.0' } repositories { google() diff --git a/version.gradle b/version.gradle index cc74b1c5..dcf20a68 100644 --- a/version.gradle +++ b/version.gradle @@ -1,9 +1,9 @@ -ext.version_code = 62 -ext.version_name = "2.62" +ext.version_code = 63 +ext.version_name = "2.63" def build_versions = [:] -build_versions.compile_sdk = 31 -build_versions.build_tools = "31.0.0" +build_versions.compile_sdk = 34 +build_versions.build_tools = "34.0.0" build_versions.min_sdk = 21 build_versions.target_sdk = 31 ext.build_versions = build_versions @@ -11,8 +11,8 @@ ext.build_versions = build_versions def deps = [:] def kotlin = [:] -kotlin.kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib:1.6.10" -kotlin.core_ktx = "androidx.core:core-ktx:1.6.0" +kotlin.kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib:1.8.0" +kotlin.core_ktx = "androidx.core:core-ktx:1.8.0" deps.kotlin = kotlin def settings = [:] @@ -60,9 +60,10 @@ okhttp3.okhttp_dnsoverhttps = "com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.0" deps.okhttp3 = okhttp3 def room = [:] -room.room_runtime = "androidx.room:room-runtime:2.4.2" -room.room_ktx = "androidx.room:room-ktx:2.4.2" -room.room_compiler = "androidx.room:room-compiler:2.4.2" +def room_version = "2.5.1" +room.room_runtime = "androidx.room:room-runtime:$room_version" +room.room_ktx = "androidx.room:room-ktx:$room_version" +room.room_compiler = "androidx.room:room-compiler:$room_version" deps.room = room def jsoup = [:] @@ -103,7 +104,7 @@ nanohttpd.nanohttpd = "org.nanohttpd:nanohttpd:2.3.1" deps.nanohttpd = nanohttpd def coil_kt = [:] -coil_kt.coil = "io.coil-kt:coil:2.0.0" +coil_kt.coil = "io.coil-kt:coil:2.5.0" deps.coil_kt = coil_kt def smart = [:]