From 73892596b1dc0ef0e8df2021e229ac7067c5ad77 Mon Sep 17 00:00:00 2001 From: tongtongstudio Date: Fri, 27 Mar 2026 09:35:56 +0800 Subject: [PATCH] =?UTF-8?q?1.1.9=20=E6=98=BE=E7=A4=BA=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E5=B0=81=E9=9D=A2=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E8=A7=86=E9=A2=91=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 4 +- .../online/CategoryVideoActivity.java | 34 ++ .../online/CategoryVideoViewModel.java | 14 +- .../vc/adapter/CategoryVideoAdapter.java | 306 +++++++++++------- .../com/hainaos/vc/adapter/VideoAdapter.java | 14 +- .../java/com/hainaos/vc/utils/FileUtils.java | 74 +++++ 6 files changed, 326 insertions(+), 120 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3d09f37..f618eea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { //There are no CERT files because If the mini sdk version is 23+, the AGP will ignore the V1 scheme signature. minSdkVersion 23 targetSdkVersion 29 - versionCode 19 - versionName "1.1.8" + versionCode 20 + versionName "1.1.9" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoActivity.java b/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoActivity.java index 59a1c41..fe88a39 100644 --- a/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoActivity.java +++ b/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoActivity.java @@ -1,6 +1,7 @@ package com.hainaos.vc.activity.category.online; import android.content.Intent; +import android.util.Log; import android.view.View; import androidx.annotation.NonNull; @@ -29,7 +30,12 @@ import com.hjq.toast.Toaster; import com.tencent.mmkv.MMKV; import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; public class CategoryVideoActivity extends BaseMvvmActivity { private static final String TAG = "CategoryActivity"; @@ -118,6 +124,34 @@ public class CategoryVideoActivity extends BaseMvvmActivity categoryVideoInfos = videoListData.getData(); + + File file = new File(FileUtils.getHainaVideoPath(CategoryVideoActivity.this) + mCategoryInfo.getFolder()); + if (file.exists()) { + String[] strings = file.list(); + Log.e(TAG, "getViedoList: " + Arrays.toString(strings)); + if (strings != null) { + List paths = new ArrayList<>(Arrays.asList(strings)); + ArrayList localVideoInfos = paths.stream() + .filter(new Predicate() { + @Override + public boolean test(String s) { + return FileUtils.isVideoFile(s); + } + }) + .map(new Function() { + @Override + public CategoryVideoInfo apply(String s) { + CategoryVideoInfo categoryVideoInfo = new CategoryVideoInfo(); + categoryVideoInfo.setName(FileUtils.getFileNameWithoutExtension(s)); + categoryVideoInfo.setFile_url(new File(file.getAbsolutePath() + File.separator + s).getAbsolutePath()); + return categoryVideoInfo; + } + }).collect(Collectors.toCollection(ArrayList::new)); + + categoryVideoInfos.addAll(localVideoInfos); + } + } + mCategoryVideoAdapter.setData(categoryVideoInfos); diff --git a/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoViewModel.java b/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoViewModel.java index 475bdbb..ac23dcc 100644 --- a/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoViewModel.java +++ b/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoViewModel.java @@ -6,7 +6,7 @@ import androidx.lifecycle.MutableLiveData; import com.hainaos.vc.base.mvvm.BaseViewModel; import com.hainaos.vc.bean.BaseResponse; -import com.hainaos.vc.bean.LocalVideoInfo; +import com.hainaos.vc.bean.CategoryVideoInfo; import com.hainaos.vc.bean.VideoListData; import com.hainaos.vc.bean.VideoUpdate; import com.hainaos.vc.config.CommonConfig; @@ -46,7 +46,7 @@ public class CategoryVideoViewModel extends BaseViewModel> mLocalVideoInfosData = new MutableLiveData<>(); + public MutableLiveData> mLocalVideoInfosData = new MutableLiveData<>(); @Deprecated public void getViedoList(String dir) { @@ -56,12 +56,12 @@ public class CategoryVideoViewModel extends BaseViewModel paths = new ArrayList<>(Arrays.asList(strings)); - ArrayList localVideoInfos = paths.stream().map(new Function() { + ArrayList localVideoInfos = paths.stream().map(new Function() { @Override - public LocalVideoInfo apply(String s) { - LocalVideoInfo localVideoInfo = new LocalVideoInfo(); - localVideoInfo.setFile_name(FileUtils.getFileNameWithoutExtension(s)); - localVideoInfo.setLocalPath(new File(file.getAbsolutePath() + File.separator + s).getAbsolutePath()); + public CategoryVideoInfo apply(String s) { + CategoryVideoInfo localVideoInfo = new CategoryVideoInfo(); + localVideoInfo.setName(FileUtils.getFileNameWithoutExtension(s)); + localVideoInfo.setFile_url(new File(file.getAbsolutePath() + File.separator + s).getAbsolutePath()); return localVideoInfo; } }).collect(Collectors.toCollection(ArrayList::new)); diff --git a/app/src/main/java/com/hainaos/vc/adapter/CategoryVideoAdapter.java b/app/src/main/java/com/hainaos/vc/adapter/CategoryVideoAdapter.java index 4e43068..e0e114a 100644 --- a/app/src/main/java/com/hainaos/vc/adapter/CategoryVideoAdapter.java +++ b/app/src/main/java/com/hainaos/vc/adapter/CategoryVideoAdapter.java @@ -24,12 +24,14 @@ import com.arialyy.annotations.Download; import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.task.DownloadTask; +import com.bumptech.glide.Glide; import com.hainaos.vc.R; import com.hainaos.vc.activity.player.DecryptionPlayerActivity; import com.hainaos.vc.activity.preview.VideoPreviewActivity; import com.hainaos.vc.bean.CategoryVideoInfo; import com.hainaos.vc.config.Permissions; import com.hainaos.vc.dialog.PermissionsDialog; +import com.hainaos.vc.utils.FFmpegUtils; import com.hainaos.vc.utils.FileUtils; import com.hainaos.vc.utils.GlideLoadUtils; import com.hainaos.vc.utils.TimeUtils; @@ -43,6 +45,8 @@ import com.shehuan.niv.NiceImageView; import java.io.File; import java.util.List; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; import me.jessyan.autosize.AutoSizeCompat; public class CategoryVideoAdapter extends RecyclerView.Adapter { @@ -82,131 +86,187 @@ public class CategoryVideoAdapter extends RecyclerView.Adapter() { + @Override + public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) { + + } + + @Override + public void onNext(@io.reactivex.rxjava3.annotations.NonNull Integer integer) { + holder.tv_duration.setText("视频时长: " + TimeUtils.TimeFormat(integer * 1000)); + } + + @Override + public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) { + + } + + @Override + public void onComplete() { + + } + }); + } + + holder.tv_size.setText("视频大小: " + fileSize); + holder.tv_download.setText("删除"); holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_delete_button)); - } else { - holder.tv_download.setText("下载"); - holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); - } - } else { - int state = entity.getState(); - switch (state) { - case 1: - if (file.exists()) { - holder.tv_download.setText("删除"); - holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_delete_button)); - } else { - holder.tv_download.setText("下载"); - holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); + holder.tv_download.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { +// if (file.exists()) { + showDeleteLocalDialog(file.getAbsolutePath(), position); +// } } - break; - case 2: - holder.tv_download.setText("停止"); - holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); - break; - case 3: - holder.tv_download.setText("等待"); - holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); - break; - case -1: - case 0: - case 5: - case 6: - case 7: + }); + } + } else { + String cover = categoryVideoInfo.getCover(); + String md5 = categoryVideoInfo.getMd5(); + long sizeBytes = categoryVideoInfo.getFile_size(); + String fileSize = Formatter.formatFileSize(mContext, sizeBytes); + holder.tv_size.setText("视频大小: " + fileSize); + + String fileName = FileUtils.getFileNamefromURL(url); + + File file = new File(FileUtils.getHainaVideoPath(mContext) + mDirName + File.separator + fileName); + + DownloadEntity entity = Aria.download(mContext).getFirstDownloadEntity(url); + if (entity == null) { + if (file.exists()) { + holder.tv_download.setText("删除"); + holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_delete_button)); + } else { holder.tv_download.setText("下载"); holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); - break; - case 4: - int percent = entity.getPercent(); - holder.tv_download.setText(percent + "%"); - holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); - break; - } - } + } - - GlideLoadUtils.getInstance().glideLoad(mContext, cover, holder.video_image); - - holder.tv_duration.setText("视频时长: " + TimeUtils.TimeFormat(categoryVideoInfo.getDuration() * 1000)); - - holder.tv_download.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (entity == null) { - if (file.exists()) { - showDialog(file.getAbsolutePath(), position); - } else { - if (XXPermissions.isGranted(mContext, Permissions.STORAGE_PERMISSIONS)) { - FileUtils.ariaDownload(mContext, mDirName, url, md5); - FileUtils.ariaDownload(mContext, mDirName, cover); -// FileUtils.ariaDownloadCover(mContext, mDirName, cover, md5); + } else { + int state = entity.getState(); + switch (state) { + case 1: + if (file.exists()) { + holder.tv_download.setText("删除"); + holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_delete_button)); } else { - showPermissionsDialog(mContext); + holder.tv_download.setText("下载"); + holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); + } + break; + case 2: + holder.tv_download.setText("停止"); + holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); + break; + case 3: + holder.tv_download.setText("等待"); + holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); + break; + case -1: + case 0: + case 5: + case 6: + case 7: + holder.tv_download.setText("下载"); + holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); + break; + case 4: + int percent = entity.getPercent(); + holder.tv_download.setText(percent + "%"); + holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_download_button)); + break; + } + } + + GlideLoadUtils.getInstance().glideLoad(mContext, cover, holder.video_image); + + holder.tv_duration.setText("视频时长: " + TimeUtils.TimeFormat(categoryVideoInfo.getDuration() * 1000)); + + holder.tv_download.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (entity == null) { + if (file.exists()) { + showDialog(file.getAbsolutePath(), position); + } else { + if (XXPermissions.isGranted(mContext, Permissions.STORAGE_PERMISSIONS)) { + FileUtils.ariaDownload(mContext, mDirName, url, md5); + FileUtils.ariaDownload(mContext, mDirName, cover); +// FileUtils.ariaDownloadCover(mContext, mDirName, cover, md5); + } else { + showPermissionsDialog(mContext); + } + } + } else { + int state = entity.getState(); + switch (state) { + case 1: + if (file.exists()) { + showDialog(file.getAbsolutePath(), position); + } else { + if (XXPermissions.isGranted(mContext, Permissions.STORAGE_PERMISSIONS)) { + FileUtils.ariaDownload(mContext, mDirName, url, md5); + FileUtils.ariaDownload(mContext, mDirName, cover); +// FileUtils.ariaDownloadCover(mContext, mDirName, cover, md5); + } else { + showPermissionsDialog(mContext); + } + } + break; + case -1: + case 0: + case 2: + case 3: + case 5: + case 6: + case 7: + case 4: + } } - } else { - int state = entity.getState(); - switch (state) { - case 1: - if (file.exists()) { - showDialog(file.getAbsolutePath(), position); - } else { - if (XXPermissions.isGranted(mContext, Permissions.STORAGE_PERMISSIONS)) { - FileUtils.ariaDownload(mContext, mDirName, url, md5); - FileUtils.ariaDownload(mContext, mDirName, cover); -// FileUtils.ariaDownloadCover(mContext, mDirName, cover, md5); - } else { - showPermissionsDialog(mContext); - } - } - break; - case -1: - case 0: - case 2: - case 3: - case 5: - case 6: - case 7: - case 4: + } + }); - } - } - } - }); - holder.video_image.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (file.exists()) { - if (file.getAbsolutePath().endsWith(".hnv")) { - Intent intent = new Intent(mContext, DecryptionPlayerActivity.class); - intent.putExtra("url", file.getAbsolutePath()); - mContext.startActivity(intent); + holder.video_image.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (file.exists()) { + if (file.getAbsolutePath().endsWith(".hnv")) { + Intent intent = new Intent(mContext, DecryptionPlayerActivity.class); + intent.putExtra("url", file.getAbsolutePath()); + mContext.startActivity(intent); + } else { + Intent intent = new Intent(mContext, VideoPreviewActivity.class); + intent.putExtra("cover", cover); + intent.putExtra("url", file.getAbsolutePath()); + mContext.startActivity(intent); + } } else { - Intent intent = new Intent(mContext, VideoPreviewActivity.class); - intent.putExtra("cover", cover); - intent.putExtra("url", file.getAbsolutePath()); - mContext.startActivity(intent); + Toaster.show("请先下载视频"); } - } else { - Toaster.show("请先下载视频"); } - } - }); + }); + } + } private PermissionsDialog mPermissionsDialog; @@ -284,6 +344,34 @@ public class CategoryVideoAdapter extends RecyclerView.Adapter final String localPath = localVideoInfo.getLocalPath(); Log.e(TAG, "onBindViewHolder: " + localPath); String videoFileName = FileUtils.getFileName(localPath); + String videoFileNameWithoutEx = FileUtils.getFileNameWithoutExtension(localPath); holder.title.setText(videoFileName); File file = new File(localPath); @@ -109,6 +110,7 @@ public class VideoAdapter extends RecyclerView.Adapter if (file.getName().endsWith(".hnv")) { String dirPaht = file.getParent(); Log.e(TAG, "onBindViewHolder: dirPaht = " + dirPaht); + File localCoverFile = new File(dirPaht + File.separator + videoFileNameWithoutEx + ".png"); if (mCoverMap != null) { String coverUrl = mCoverMap.get(videoFileName); Log.e(TAG, "onBindViewHolder: coverUrl = " + coverUrl); @@ -123,10 +125,18 @@ public class VideoAdapter extends RecyclerView.Adapter FileUtils.ariaDownloadCover(mContext, coverFile.getParent(), coverUrl); } } else { - holder.video_image.setImageDrawable(mContext.getDrawable(R.drawable.picture_split)); + if (localCoverFile.exists()) { + Glide.with(mContext).load(localCoverFile).centerCrop().error(R.drawable.picture_split).into(holder.video_image); + } else { + holder.video_image.setImageDrawable(mContext.getDrawable(R.drawable.picture_split)); + } } } else { - holder.video_image.setImageDrawable(mContext.getDrawable(R.drawable.picture_split)); + if (localCoverFile.exists()) { + Glide.with(mContext).load(localCoverFile).centerCrop().error(R.drawable.picture_split).into(holder.video_image); + } else { + holder.video_image.setImageDrawable(mContext.getDrawable(R.drawable.picture_split)); + } } } else { Glide.with(mContext).load(file).centerCrop().error(R.drawable.picture_split).into(holder.video_image); diff --git a/app/src/main/java/com/hainaos/vc/utils/FileUtils.java b/app/src/main/java/com/hainaos/vc/utils/FileUtils.java index d779b56..ab4c136 100644 --- a/app/src/main/java/com/hainaos/vc/utils/FileUtils.java +++ b/app/src/main/java/com/hainaos/vc/utils/FileUtils.java @@ -2,6 +2,7 @@ package com.hainaos.vc.utils; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.os.Environment; import android.text.TextUtils; import android.util.Log; @@ -17,6 +18,8 @@ import com.hainaos.vc.service.DownloadService; import java.io.File; import java.text.DecimalFormat; +import java.util.HashSet; +import java.util.Set; public class FileUtils { private static final String TAG = "FileUtils"; @@ -40,6 +43,77 @@ public class FileUtils { return name; } + public static boolean isLocalFileUriType(String uriString) { + if (TextUtils.isEmpty(uriString)) { + return false; + } + if (uriString.startsWith("/")) { + return true; + } + // 将字符串解析为 Uri 对象 + Uri uri = Uri.parse(uriString); + // 获取 Scheme + String scheme = uri.getScheme(); + if (scheme != null) { + Log.e(TAG, "isLocalFileUriType: " + scheme); + switch (scheme.toLowerCase()) { + case "http": + case "https": + return false; + case "content": + case "file": + return true; + default: + return false; + } + } else { + return false; + } + } + + private static Set videoFormat = new HashSet() {{ + this.add(".hnv"); + this.add(".mp4"); + this.add(".avi"); + this.add(".mkv"); + this.add(".flv"); + }}; + private static Set pictureFormat = new HashSet() {{ + this.add(".png"); + this.add(".jpg"); + this.add(".jpeg"); + this.add(".bmp"); + }}; + + public static boolean isVideoFile(String fileName) { + if (TextUtils.isEmpty(fileName)) { + return false; + } else { + if (!fileName.startsWith(".")) { + return videoFormat.contains(getFileType(fileName)); + } else { + return videoFormat.contains(fileName); + } + } + } + + public static String getFileType(String url) { + if (TextUtils.isEmpty(url)) { + return ""; + } + Log.e(TAG, "getFileType: " + url); + if (!url.contains("/")) { + if (url.contains(".")) { + return url.substring(url.indexOf(".")); + } else { + return ""; + } + } else { + String fileName = url.substring(url.lastIndexOf("/")); + return fileName.substring(fileName.indexOf(".")); + } + } + /** * 转换文件大小 MB */