Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.xyoye.common_component.source.base
import com.xyoye.common_component.source.inter.ExtraSource
import com.xyoye.common_component.source.inter.VideoSource
import com.xyoye.data_component.bean.LocalDanmuBean
import com.xyoye.data_component.entity.PlayHistoryEntity


/**
Expand Down Expand Up @@ -43,4 +44,6 @@ abstract class BaseVideoSource(
override fun getStoragePath(): String? {
return null
}

abstract fun updateFileHistory(playHistory: PlayHistoryEntity?)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.xyoye.common_component.storage.file.impl.TorrentStorageFile
import com.xyoye.common_component.utils.getFileName
import com.xyoye.common_component.utils.thunder.ThunderManager
import com.xyoye.data_component.bean.LocalDanmuBean
import com.xyoye.data_component.entity.PlayHistoryEntity
import com.xyoye.data_component.enums.MediaType

/**
Expand Down Expand Up @@ -92,6 +93,13 @@ class StorageVideoSource(
return file.storagePath()
}

override fun updateFileHistory(playHistory: PlayHistoryEntity?) {
file.playHistory = playHistory
file.storage.updateFileHistory(file, playHistory)
videoSources.firstOrNull { it.uniqueKey() == file.uniqueKey() }
?.let { it.playHistory = playHistory }
}

fun getTorrentPath(): String? {
if (file is TorrentStorageFile) {
return file.filePath()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.xyoye.common_component.utils.subtitle.SubtitleUtils
import com.xyoye.data_component.bean.LocalDanmuBean
import com.xyoye.data_component.data.DanmuEpisodeData
import com.xyoye.data_component.entity.MediaLibraryEntity
import com.xyoye.data_component.entity.PlayHistoryEntity
import java.io.File

/**
Expand Down Expand Up @@ -96,4 +97,10 @@ abstract class AbstractStorage(
override suspend fun test(): Boolean {
return true
}

override fun updateFileHistory(file: StorageFile, history: PlayHistoryEntity?) {
directoryFiles
.firstOrNull { it.uniqueKey() == file.uniqueKey() }
?.let { it.playHistory = history }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ interface Storage {
*/
suspend fun test(): Boolean

/**
* 更新文件播放历史
*/
fun updateFileHistory(file: StorageFile, history: PlayHistoryEntity?)

/**
* 关闭媒体库
*/
Expand Down
9 changes: 9 additions & 0 deletions common_component/src/main/java/com/xyoye/open_cc/OpenCC.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.xyoye.open_cc

import android.util.Log
import com.google.common.base.Utf8
import java.io.File

/**
Expand Down Expand Up @@ -34,6 +36,13 @@ object OpenCC {

private fun convert(text: String, config: File): String {
return try {
// 检查是否是符合 Unicode 6.0 的格式的UFT-8字符串
// Bugly#2456345
if (Utf8.isWellFormed(text.toByteArray()).not()) {
Log.d("OpenCC", "invalid utf-8 string: $text")
return text
}

convert(text, config.absolutePath)
} catch (t: Throwable) {
t.printStackTrace()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,21 +106,31 @@ class BindExtraSourceViewModel : BaseViewModel() {
* 解析分词结果
*/
private fun parseSegmentResult(json: String): List<String>? {
val responseJson = JSONObject(json)
val resultKey = responseJson.names()?.get(0)?.toString()
?: return null
val jsonArray = responseJson.optJSONArray(resultKey)
?: return null
val wordArray = jsonArray.optJSONArray(0)
?: return null

val words = mutableListOf<String>()
val wordLength = wordArray.length()
for (i in 0 until wordLength) {
val word = wordArray.optString(i)
words.add(word)
if (json.isEmpty()) {
return null
}
return words

try {
val responseJson = JSONObject(json)
val resultKey = responseJson.names()?.get(0)?.toString()
?: return null
val jsonArray = responseJson.optJSONArray(resultKey)
?: return null
val wordArray = jsonArray.optJSONArray(0)
?: return null

val words = mutableListOf<String>()
val wordLength = wordArray.length()
for (i in 0 until wordLength) {
val word = wordArray.optString(i)
words.add(word)
}
return words
} catch (e: Exception) {
e.printStackTrace()
}

return null
}

private fun matchSearchTextCache(target: StorageFile): String? {
Expand Down
2 changes: 2 additions & 0 deletions player_component/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,8 @@
<data android:mimeType="application/x-ogg" />
<data android:mimeType="audio/mpegurl" />
<data android:mimeType="audio/x-mpegurl" />
<data android:mimeType="application/x-bittorrent" />
<data android:mimeType="application/torrent" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class SettingTracksView @JvmOverloads constructor(

if (tracks.size > 0) {
viewBinding.rvTrack.requestIndexChildFocus(0)
} else {
viewBinding.tvAddTrack.requestFocus()
}
return true
}
Expand Down Expand Up @@ -158,7 +160,9 @@ class SettingTracksView @JvmOverloads constructor(
return false
}
val targetIndex = getTargetIndexByKeyCode(keyCode, focusedChildIndex)
viewBinding.rvTrack.requestIndexChildFocus(targetIndex)
if (targetIndex != -1) {
viewBinding.rvTrack.requestIndexChildFocus(targetIndex)
}
return true
}

Expand All @@ -169,11 +173,22 @@ class SettingTracksView @JvmOverloads constructor(
return when (keyCode) {
//左、上规则
KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP -> {
tracks.previousItemIndex<VideoTrackBean>(focusedIndex)
if (focusedIndex == 0) {
viewBinding.tvAddTrack.requestFocus()
-1
} else {
tracks.previousItemIndex<VideoTrackBean>(focusedIndex)
}
}
//右、下规则
KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN -> {
tracks.nextItemIndex<VideoTrackBean>(focusedIndex)
val itemCount = viewBinding.rvTrack.adapter?.itemCount ?: 0
if (focusedIndex == itemCount - 1) {
viewBinding.tvAddTrack.requestFocus()
-1
} else {
tracks.nextItemIndex<VideoTrackBean>(focusedIndex)
}
}

else -> {
Expand All @@ -199,6 +214,9 @@ class SettingTracksView @JvmOverloads constructor(
viewBinding.rvTrack.setData(tracks)

viewBinding.tvEmptyTrack.isVisible = tracks.isEmpty()
if (tracks.isEmpty()) {
viewBinding.tvAddTrack.requestFocus()
}
}

fun setTrackType(trackType: TrackType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.os.Environment
import android.util.AttributeSet
import android.view.Gravity
import android.view.KeyEvent
import android.view.View
import androidx.annotation.Dimension
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
Expand Down Expand Up @@ -273,6 +274,7 @@ class SwitchSourceView(
mPathData.addAll(pathData)
viewBinding.rvPath.setData(mPathData)
viewBinding.rvPath.scrollToPosition(mPathData.size - 1)
viewBinding.rvPath.post { viewBinding.rvPath.requestFocus(View.FOCUS_LEFT) }

mFileData.clear()
mFileData.addAll(getDirectoryChildData(directory))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,6 @@ class PlayerControlView(context: Context): InterControllerView {

private fun updateLockVisible(isVisible: Boolean) {
if (isVisible) {
if (mControlWrapper.isLocked()) {
viewBinding.playerLockIv.postDelayed({
viewBinding.playerLockIv.requestFocus()
}, 100)
}
viewBinding.playerLockIv.isVisible = true
ViewCompat.animate(viewBinding.playerLockIv)
.translationX(0f)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import com.xyoye.player_component.R
import com.xyoye.player_component.databinding.LayoutPlayerTopBinding
import com.xyoye.player_component.ui.activities.overlay_permission.OverlayPermissionActivity
import com.xyoye.player_component.utils.BatteryHelper
import java.util.*
import java.util.Date

/**
* Created by xyoye on 2020/11/3.
Expand All @@ -41,6 +41,10 @@ class PlayerTopView(
private lateinit var mControlWrapper: ControlWrapper

init {
// 新增焦点占位视图,避免焦点默认落在返回按钮上
viewBinding.focusPlaceholder.setOnClickListener {
mControlWrapper.togglePlay()
}

viewBinding.backIv.setOnClickListener {
exitPlayerObserver?.invoke()
Expand All @@ -59,7 +63,7 @@ class PlayerTopView(
}

// 将初始焦点置于标题,而不是返回按钮
post { viewBinding.videoTitleTv.requestFocus() }
post { viewBinding.focusPlaceholder.requestFocus() }
}

override fun attach(controlWrapper: ControlWrapper) {
Expand All @@ -77,7 +81,7 @@ class PlayerTopView(

ViewCompat.animate(viewBinding.playerTopLl).translationY(0f).setDuration(300).start()
} else {
viewBinding.videoTitleTv.requestFocus()
viewBinding.focusPlaceholder.requestFocus()
val height = viewBinding.playerTopLl.height.toFloat()
ViewCompat.animate(viewBinding.playerTopLl).translationY(-height)
.setDuration(300).start()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.xyoye.data_component.bean.LocalDanmuBean
import com.xyoye.data_component.bean.SendDanmuBean
import com.xyoye.data_component.bean.VideoTrackBean
import com.xyoye.data_component.entity.DanmuBlockEntity
import com.xyoye.data_component.entity.PlayHistoryEntity
import com.xyoye.data_component.enums.TrackType
import kotlinx.coroutines.launch
import master.flame.danmaku.danmaku.model.BaseDanmaku
Expand All @@ -27,31 +28,47 @@ class PlayerViewModel : BaseViewModel() {
val historyDao = DatabaseManager.instance.getPlayHistoryDao()

viewModelScope.launch {
val playHistory = DatabaseManager.instance
.getPlayHistoryDao().getPlayHistory(uniqueKey, storageId)
?: PlayHistoryEntity(
0,
"",
"",
mediaType = videoSource.getMediaType(),
uniqueKey = uniqueKey,
storageId = storageId,
)

when (track.type) {
TrackType.AUDIO -> {
val audioPath = track.type.getAudio(track.trackResource)
if (audioPath != null && audioPath != videoSource.getAudioPath()) {
videoSource.setAudioPath(audioPath)
historyDao.updateAudio(uniqueKey, storageId, audioPath)
playHistory.audioPath = audioPath
}
}

TrackType.SUBTITLE -> {
val subtitlePath = track.type.getSubtitle(track.trackResource)
if (subtitlePath != null && subtitlePath != videoSource.getSubtitlePath()) {
videoSource.setSubtitlePath(subtitlePath)
historyDao.updateSubtitle(uniqueKey, storageId, subtitlePath)
playHistory.subtitlePath = subtitlePath
}
}

TrackType.DANMU -> {
val danmu = track.type.getDanmu(track.trackResource)
if (danmu != null && danmu != videoSource.getDanmu()) {
videoSource.setDanmu(danmu)
historyDao.updateDanmu(uniqueKey, storageId, danmu.danmuPath, danmu.episodeId)
playHistory.danmuPath = danmu.danmuPath
playHistory.episodeId = danmu.episodeId
}
}
}

historyDao.insert(playHistory)
val newHistory = historyDao.getPlayHistory(uniqueKey, storageId)
videoSource.updateFileHistory(newHistory)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.xyoye.player_component.ui.activities.player_intent

import android.net.Uri
import androidx.core.net.toFile
import androidx.core.net.toUri
import com.alibaba.android.arouter.launcher.ARouter
import com.gyf.immersionbar.BarHide
import com.gyf.immersionbar.ImmersionBar
import com.xyoye.common_component.base.BaseActivity
import com.xyoye.common_component.config.RouteTable
import com.xyoye.common_component.extension.decodeUrl
import com.xyoye.common_component.utils.MediaUtils
import com.xyoye.common_component.utils.isTorrentFile
import com.xyoye.data_component.entity.MediaLibraryEntity
import com.xyoye.player_component.BR
import com.xyoye.player_component.R
import com.xyoye.player_component.databinding.ActivityPlayerIntentBinding
Expand Down Expand Up @@ -53,6 +57,11 @@ class PlayerIntentActivity : BaseActivity<PlayerIntentViewModel, ActivityPlayerI
viewModel.addUnrecognizedFile(videoUrl)
}

if (isTorrentIntent(videoUrl, intentData, intent.type)) {
openTorrentStorage(videoUrl)
return
}

viewModel.openIntentUrl(videoUrl)
}

Expand All @@ -64,4 +73,33 @@ class PlayerIntentActivity : BaseActivity<PlayerIntentViewModel, ActivityPlayerI
finish()
}
}

private fun isTorrentIntent(url: String, uri: Uri, mimeType: String?): Boolean {
if (mimeType == "application/x-bittorrent" || mimeType == "application/torrent") {
return true
}
if (isTorrentFile(url)) {
return true
}
val uriText = uri.toString()
return isTorrentFile(uriText) || isTorrentFile(uri.lastPathSegment ?: "")
}

private fun openTorrentStorage(url: String) {
if (url.startsWith("file://").not()) {
return
}

val filePath = url.runCatching { toUri().toFile().absolutePath }.getOrNull()
if (filePath.isNullOrEmpty()) {
return
}

val library = MediaLibraryEntity.TORRENT.copy(url = filePath)
ARouter.getInstance()
.build(RouteTable.Stream.StorageFile)
.withParcelable("storageLibrary", library)
.navigation()
finish()
}
}
Loading