兼容加载base64图片;简易修正个别直播配置加载失败的问题

pull/121/head
于俊 11 months ago
parent ff3a4a92d8
commit a2bf2356bf
  1. 167
      app/src/main/java/com/github/tvbox/osc/ui/adapter/GridAdapter.java
  2. 38
      app/src/main/java/com/github/tvbox/osc/ui/adapter/HomeHotVodAdapter.java
  3. 47
      app/src/main/java/com/github/tvbox/osc/util/live/TxtSubscribe.java

@ -1,10 +1,15 @@
package com.github.tvbox.osc.ui.adapter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Base64;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.collection.LruCache;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.github.tvbox.osc.R;
@ -12,51 +17,71 @@ import com.github.tvbox.osc.bean.Movie;
import com.github.tvbox.osc.picasso.RoundTransformation;
import com.github.tvbox.osc.util.DefaultConfig;
import com.github.tvbox.osc.util.MD5;
import com.squareup.picasso.MemoryPolicy;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import me.jessyan.autosize.utils.AutoSizeUtils;
/**
* @author pj567
* @date :2020/12/21
* @description:
*/
public class GridAdapter extends BaseQuickAdapter<Movie.Video, BaseViewHolder> {
private boolean mShowList = false;
// 内存缓存
private LruCache<String, Bitmap> bitmapCache;
// 线程池
private ExecutorService executorService;
public GridAdapter(boolean l) {
super( l ? R.layout.item_list:R.layout.item_grid, new ArrayList<>());
super(l ? R.layout.item_list : R.layout.item_grid, new ArrayList<>());
this.mShowList = l;
// 初始化内存缓存,缓存大小为运行内存的 1/8
int cacheSize = (int) (Runtime.getRuntime().maxMemory() / 8);
bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
};
// 初始化线程池
executorService = Executors.newFixedThreadPool(5); // 可根据需要调整线程数量
}
@Override
protected void convert(BaseViewHolder helper, Movie.Video item) {
if(this.mShowList) {
if (this.mShowList) {
helper.setText(R.id.tvNote, item.note);
helper.setText(R.id.tvName, item.name);
ImageView ivThumb = helper.getView(R.id.ivThumb);
//由于部分电视机使用glide报错
if (!TextUtils.isEmpty(item.pic)) {
item.pic=item.pic.trim();
Picasso.get()
.load(DefaultConfig.checkReplaceProxy(item.pic))
.transform(new RoundTransformation(MD5.string2MD5(item.pic))
.centerCorp(true)
.override(AutoSizeUtils.mm2px(mContext, 240), AutoSizeUtils.mm2px(mContext, 320))
.roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL))
.placeholder(R.drawable.img_loading_placeholder)
.noFade()
.error(R.drawable.img_loading_placeholder)
.into(ivThumb);
item.pic = item.pic.trim();
if (isBase64Image(item.pic)) {
// 异步加载 Base64 图片
loadBase64ImageAsync(item.pic, ivThumb);
} else {
// 加载网络图片
Picasso.get()
.load(DefaultConfig.checkReplaceProxy(item.pic))
.transform(new RoundTransformation(MD5.string2MD5(item.pic))
.centerCorp(true)
.override(AutoSizeUtils.mm2px(mContext, 240), AutoSizeUtils.mm2px(mContext, 320))
.roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL))
.placeholder(R.drawable.img_loading_placeholder)
.noFade()
.error(R.drawable.img_loading_placeholder)
.into(ivThumb);
}
} else {
ivThumb.setImageResource(R.drawable.img_loading_placeholder);
}
return;
}
// 处理列表模式的其他逻辑
TextView tvYear = helper.getView(R.id.tvYear);
if (item.year <= 0) {
tvYear.setVisibility(View.GONE);
@ -66,20 +91,9 @@ public class GridAdapter extends BaseQuickAdapter<Movie.Video, BaseViewHolder> {
}
TextView tvLang = helper.getView(R.id.tvLang);
tvLang.setVisibility(View.GONE);
/*if (TextUtils.isEmpty(item.lang)) {
tvLang.setVisibility(View.GONE);
} else {
tvLang.setText(item.lang);
tvLang.setVisibility(View.VISIBLE);
}*/
TextView tvArea = helper.getView(R.id.tvArea);
tvArea.setVisibility(View.GONE);
/*if (TextUtils.isEmpty(item.area)) {
tvArea.setVisibility(View.GONE);
} else {
tvArea.setText(item.area);
tvArea.setVisibility(View.VISIBLE);
}*/
if (TextUtils.isEmpty(item.note)) {
helper.setVisible(R.id.tvNote, false);
} else {
@ -89,21 +103,84 @@ public class GridAdapter extends BaseQuickAdapter<Movie.Video, BaseViewHolder> {
helper.setText(R.id.tvName, item.name);
helper.setText(R.id.tvActor, item.actor);
ImageView ivThumb = helper.getView(R.id.ivThumb);
//由于部分电视机使用glide报错
if (!TextUtils.isEmpty(item.pic)) {
item.pic=item.pic.trim();
Picasso.get()
.load(DefaultConfig.checkReplaceProxy(item.pic))
.transform(new RoundTransformation(MD5.string2MD5(item.pic))
.centerCorp(true)
.override(AutoSizeUtils.mm2px(mContext, 240), AutoSizeUtils.mm2px(mContext, 320))
.roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL))
.placeholder(R.drawable.img_loading_placeholder)
.noFade()
.error(R.drawable.img_loading_placeholder)
.into(ivThumb);
item.pic = item.pic.trim();
if (isBase64Image(item.pic)) {
loadBase64ImageAsync(item.pic, ivThumb);
} else {
Picasso.get()
.load(DefaultConfig.checkReplaceProxy(item.pic))
.transform(new RoundTransformation(MD5.string2MD5(item.pic))
.centerCorp(true)
.override(AutoSizeUtils.mm2px(mContext, 240), AutoSizeUtils.mm2px(mContext, 320))
.roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL))
.placeholder(R.drawable.img_loading_placeholder)
.noFade()
.error(R.drawable.img_loading_placeholder)
.into(ivThumb);
}
} else {
ivThumb.setImageResource(R.drawable.img_loading_placeholder);
}
}
}
private boolean isBase64Image(String picUrl) {
return picUrl.startsWith("data:image");
}
private void loadBase64ImageAsync(String base64Str, ImageView imageView) {
Bitmap cachedBitmap = bitmapCache.get(base64Str);
if (cachedBitmap != null) {
// 如果缓存中有,直接加载
imageView.setImageBitmap(cachedBitmap);
} else {
// 异步加载
executorService.execute(() -> {
Bitmap bitmap = decodeBase64ToBitmap(base64Str);
if (bitmap != null) {
// 存入缓存
bitmapCache.put(base64Str, bitmap);
// 更新 UI
imageView.post(() -> imageView.setImageBitmap(bitmap));
}
});
}
}
private Bitmap decodeBase64ToBitmap(String base64Str) {
try {
// 提取 Base64 数据部分
String base64Data = base64Str.substring(base64Str.indexOf(",") + 1);
byte[] decodedBytes = Base64.decode(base64Data, Base64.DEFAULT);
// 限制解码图片尺寸,防止内存过高
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 只解析尺寸
BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length, options);
options.inSampleSize = calculateInSampleSize(options, 180, 260); // 设置缩放比例
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length, options);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
int height = options.outHeight;
int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
}

@ -1,6 +1,9 @@
package com.github.tvbox.osc.ui.adapter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Base64;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
@ -59,18 +62,33 @@ public class HomeHotVodAdapter extends BaseQuickAdapter<Movie.Video, BaseViewHol
//由于部分电视机使用glide报错
if (!TextUtils.isEmpty(item.pic)) {
item.pic=item.pic.trim();
Picasso.get()
.load(DefaultConfig.checkReplaceProxy(item.pic))
.transform(new RoundTransformation(MD5.string2MD5(item.pic))
.centerCorp(true)
.override(AutoSizeUtils.mm2px(mContext, 300), AutoSizeUtils.mm2px(mContext, 400))
.roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL))
.placeholder(R.drawable.img_loading_placeholder)
.noFade()
.error(R.drawable.img_loading_placeholder)
.into(ivThumb);
if(isBase64Image(item.pic)){
// 如果是 Base64 图片,解码并设置
ivThumb.setImageBitmap(decodeBase64ToBitmap(item.pic));
}else {
Picasso.get()
.load(DefaultConfig.checkReplaceProxy(item.pic))
.transform(new RoundTransformation(MD5.string2MD5(item.pic))
.centerCorp(true)
.override(AutoSizeUtils.mm2px(mContext, 300), AutoSizeUtils.mm2px(mContext, 400))
.roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL))
.placeholder(R.drawable.img_loading_placeholder)
.noFade()
.error(R.drawable.img_loading_placeholder)
.into(ivThumb);
}
} else {
ivThumb.setImageResource(R.drawable.img_loading_placeholder);
}
}
private boolean isBase64Image(String picUrl) {
return picUrl.startsWith("data:image");
}
private Bitmap decodeBase64ToBitmap(String base64Str) {
// 去掉 Base64 数据的头部前缀,例如 "data:image/png;base64,"
String base64Data = base64Str.substring(base64Str.indexOf(",") + 1);
byte[] decodedBytes = Base64.decode(base64Data, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
}
}

@ -26,34 +26,37 @@ public class TxtSubscribe {
ArrayList<String> urls;
try {
BufferedReader bufferedReader = new BufferedReader(new StringReader(str));
LinkedHashMap<String, ArrayList<String>> channel = new LinkedHashMap<>();
LinkedHashMap<String, ArrayList<String>> channelTemp = channel;
LinkedHashMap<String, ArrayList<String>> linkedHashMap2 = new LinkedHashMap<>();
LinkedHashMap<String, ArrayList<String>> channelTemp = linkedHashMap2;
String line;
while ((line = bufferedReader.readLine()) != null) {
if (line.equals("")) continue;
if (line.startsWith("#EXTM3U")) continue;
if (line.startsWith("#EXTINF")) {
if (isSetting(line)) continue;
if (line.startsWith("#EXTINF") || line.contains("#EXTINF")) {
String name = getStrByRegex(NAME_PATTERN, line);
String group = getStrByRegex(GROUP_PATTERN, line);
String url = bufferedReader.readLine().trim();
if (linkedHashMap.containsKey(group)) {
channelTemp = linkedHashMap.get(group);
} else {
channelTemp = new LinkedHashMap<>();
linkedHashMap.put(group, channelTemp);
}
if (null != channelTemp && channelTemp.containsKey(name)) {
urls = channelTemp.get(name);
} else {
urls = new ArrayList<>();
channelTemp.put(name, urls);
if (isUrl(url)) {
if (linkedHashMap.containsKey(group)) {
channelTemp = linkedHashMap.get(group);
} else {
channelTemp = new LinkedHashMap<>();
linkedHashMap.put(group, channelTemp);
}
if (null != channelTemp && channelTemp.containsKey(name)) {
urls = channelTemp.get(name);
} else {
urls = new ArrayList<>();
channelTemp.put(name, urls);
}
if (null != urls && !urls.contains(url)) urls.add(url);
}
if (null != urls && !urls.contains(url)) urls.add(url);
}
}
bufferedReader.close();
if (channel.isEmpty()) return;
linkedHashMap.put("未分组", channel);
if (linkedHashMap2.isEmpty()) return;
linkedHashMap.put("未分组", linkedHashMap2);
} catch (Exception e) {
e.printStackTrace();
}
@ -64,6 +67,14 @@ public class TxtSubscribe {
return pattern.pattern().equals(GROUP_PATTERN.pattern()) ? "未分组" : "未命名";
}
private static boolean isUrl(String url) {
return !url.isEmpty() && (url.startsWith("http") || url.startsWith("rtp") || url.startsWith("rtsp") || url.startsWith("rtmp"));
}
private static boolean isSetting(String line) {
return line.startsWith("ua") || line.startsWith("parse") || line.startsWith("click") || line.startsWith("player") || line.startsWith("header") || line.startsWith("format") || line.startsWith("origin") || line.startsWith("referer") || line.startsWith("#EXTHTTP:") || line.startsWith("#EXTVLCOPT:") || line.startsWith("#KODIPROP:");
}
public static void parseTxt(LinkedHashMap<String, LinkedHashMap<String, ArrayList<String>>> linkedHashMap, String str) {
ArrayList<String> arrayList;
try {
@ -91,7 +102,7 @@ public class TxtSubscribe {
String trim2 = split[0].trim();
for (String str2 : split[1].trim().split("#")) {
String trim3 = str2.trim();
if (!trim3.isEmpty() && (trim3.startsWith("http") || trim3.startsWith("rtp") || trim3.startsWith("rtsp") || trim3.startsWith("rtmp"))) {
if (isUrl(trim3)) {
if (!linkedHashMap3.containsKey(trim2)) {
arrayList = new ArrayList<>();
linkedHashMap3.put(trim2, arrayList);

Loading…
Cancel
Save