diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index fc78d2d99..bbba30acc 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -7,7 +7,10 @@ import android.content.Intent; import android.graphics.drawable.Drawable; import android.net.Uri; import android.text.Html; +import android.text.SpannableString; +import android.text.Spanned; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; @@ -58,6 +61,7 @@ import com.fongmi.android.tv.player.Source; import com.fongmi.android.tv.player.danmu.Parser; import com.fongmi.android.tv.ui.adapter.QualityAdapter; import com.fongmi.android.tv.ui.base.BaseActivity; +import com.fongmi.android.tv.ui.custom.CustomClickSpan; import com.fongmi.android.tv.ui.custom.CustomKeyDownVod; import com.fongmi.android.tv.ui.custom.dialog.DescDialog; import com.fongmi.android.tv.ui.custom.dialog.TrackDialog; @@ -75,6 +79,7 @@ import com.fongmi.android.tv.utils.ResUtil; import com.fongmi.android.tv.utils.Sniffer; import com.fongmi.android.tv.utils.Traffic; import com.fongmi.android.tv.utils.Utils; +import com.github.bassaer.library.MDColor; import com.github.catvod.net.OkHttp; import com.permissionx.guolindev.PermissionX; @@ -89,9 +94,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.regex.Matcher; import master.flame.danmaku.danmaku.model.BaseDanmaku; import master.flame.danmaku.danmaku.model.IDisplay; @@ -517,9 +524,35 @@ public class VideoActivity extends BaseActivity implements CustomKeyDownVod.List } private void setText(TextView view, int resId, String text) { - view.setVisibility(text.isEmpty() ? View.GONE : View.VISIBLE); - view.setText(resId > 0 ? getString(resId, text) : text); view.setTag(text); + view.setLinksClickable(true); + view.setLinkTextColor(MDColor.YELLOW_500); + view.setMovementMethod(LinkMovementMethod.getInstance()); + view.setVisibility(text.isEmpty() ? View.GONE : View.VISIBLE); + view.setText(getSpan(resId, text), TextView.BufferType.SPANNABLE); + } + + private SpannableString getSpan(int resId, String text) { + if (resId > 0) text = getString(resId, text); + Map map = new HashMap<>(); + text = findClicker(text, map); + SpannableString span = new SpannableString(text); + for (String s : map.keySet()) { + int index = text.indexOf(s); + span.setSpan(CustomClickSpan.create(this, getKey(), map.get(s)), index, index + s.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + return span; + } + + private String findClicker(String text, Map map) { + Matcher m = Sniffer.CLICKER.matcher(text); + while (m.find()) { + String val = m.group(1); + String key = m.group(2); + text = text.replace(m.group(), key); + map.put(key, val); + } + return text; } private void setFlagActivated(Flag item) { @@ -654,7 +687,7 @@ public class VideoActivity extends BaseActivity implements CustomKeyDownVod.List } private void onDesc() { - String desc = mBinding.content.getTag().toString(); + CharSequence desc = mBinding.content.getText(); if (desc.length() > 0) DescDialog.show(this, desc); } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomClickSpan.java b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomClickSpan.java new file mode 100644 index 000000000..bfe262699 --- /dev/null +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomClickSpan.java @@ -0,0 +1,33 @@ +package com.fongmi.android.tv.ui.custom; + +import android.app.Activity; +import android.text.style.ClickableSpan; +import android.view.View; + +import androidx.annotation.NonNull; + +import com.fongmi.android.tv.bean.Result; +import com.fongmi.android.tv.ui.activity.VodActivity; + +public class CustomClickSpan extends ClickableSpan { + + private final Activity activity; + private final String json; + private final String key; + + public static CustomClickSpan create(Activity activity, String key, String json) { + return new CustomClickSpan(activity, key, json); + } + + public CustomClickSpan(Activity activity, String key, String json) { + this.activity = activity; + this.json = json; + this.key = key; + } + + @Override + public void onClick(@NonNull View view) { + VodActivity.start(activity, key, Result.type(json)); + } +} + diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/DescDialog.java b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/DescDialog.java index 0a4755094..3d29962e9 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/DescDialog.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/DescDialog.java @@ -1,24 +1,34 @@ package com.fongmi.android.tv.ui.custom.dialog; import android.app.Activity; +import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; +import android.widget.TextView; import androidx.appcompat.app.AlertDialog; import com.fongmi.android.tv.databinding.DialogDescBinding; +import com.github.bassaer.library.MDColor; import com.google.android.material.dialog.MaterialAlertDialogBuilder; public class DescDialog { - public static void show(Activity activity, String desc) { + public static void show(Activity activity, CharSequence desc) { new DescDialog().create(activity, desc); } - public void create(Activity activity, String desc) { + public void create(Activity activity, CharSequence desc) { DialogDescBinding binding = DialogDescBinding.inflate(LayoutInflater.from(activity)); AlertDialog dialog = new MaterialAlertDialogBuilder(activity).setView(binding.getRoot()).create(); dialog.getWindow().setDimAmount(0); - binding.text.setText(desc); + initView(binding.text, desc); dialog.show(); } + + private void initView(TextView view, CharSequence desc) { + view.setLinksClickable(true); + view.setLinkTextColor(MDColor.BLUE_500); + view.setText(desc, TextView.BufferType.SPANNABLE); + view.setMovementMethod(LinkMovementMethod.getInstance()); + } } diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Class.java b/app/src/main/java/com/fongmi/android/tv/bean/Class.java index e15c06612..98c256691 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Class.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Class.java @@ -5,6 +5,7 @@ import android.os.Parcelable; import android.text.TextUtils; import com.github.catvod.utils.Trans; +import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; import org.simpleframework.xml.Attribute; @@ -20,11 +21,11 @@ import java.util.List; public class Class implements Parcelable { @Attribute(name = "id", required = false) - @SerializedName("type_id") + @SerializedName(value = "type_id", alternate = "id") private String typeId; @Text - @SerializedName("type_name") + @SerializedName(value = "type_name", alternate = "name") private String typeName; @SerializedName("type_flag") @@ -39,6 +40,10 @@ public class Class implements Parcelable { public Class() { } + public static Class objectFrom(String json) { + return new Gson().fromJson(json, Class.class); + } + public String getTypeId() { return TextUtils.isEmpty(typeId) ? "" : typeId; } diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Result.java b/app/src/main/java/com/fongmi/android/tv/bean/Result.java index 9529202f8..a8d3a9afe 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Result.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Result.java @@ -125,6 +125,12 @@ public class Result implements Parcelable { return result; } + public static Result type(String json) { + Result result = new Result(); + result.setTypes(List.of(Class.objectFrom(json))); + return result; + } + public static Result list(List items) { Result result = new Result(); result.setList(items); diff --git a/app/src/main/java/com/fongmi/android/tv/utils/Sniffer.java b/app/src/main/java/com/fongmi/android/tv/utils/Sniffer.java index 5fa8a903c..db1526a8c 100644 --- a/app/src/main/java/com/fongmi/android/tv/utils/Sniffer.java +++ b/app/src/main/java/com/fongmi/android/tv/utils/Sniffer.java @@ -13,11 +13,13 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; public class Sniffer { private static final String TAG = Sniffer.class.getSimpleName(); + public static final Pattern CLICKER = Pattern.compile("\\[a=cr:(\\S+)\\/](\\S+)\\[\\/a]"); public static final String CHROME = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"; public static final String RULE = "http((?!http).){12,}?\\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg|m4a|mp3)\\?.*|http((?!http).){12,}\\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg|m4a|mp3)|http((?!http).)*?video/tos*"; public static final List PUSH = Arrays.asList("smb", "http", "https", "thunder", "magnet", "ed2k", "mitv", "jianpian"); diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index a6198632f..a9b0b867f 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -12,7 +12,10 @@ import android.net.Uri; import android.os.Bundle; import android.support.v4.media.MediaMetadataCompat; import android.text.Html; +import android.text.SpannableString; +import android.text.Spanned; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -29,6 +32,7 @@ import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import androidx.media3.common.C; import androidx.media3.common.Player; +import androidx.media3.common.util.Log; import androidx.media3.ui.PlayerView; import androidx.recyclerview.widget.RecyclerView; import androidx.viewbinding.ViewBinding; @@ -70,6 +74,7 @@ import com.fongmi.android.tv.ui.adapter.QualityAdapter; import com.fongmi.android.tv.ui.adapter.QuickAdapter; import com.fongmi.android.tv.ui.base.BaseActivity; import com.fongmi.android.tv.ui.base.ViewType; +import com.fongmi.android.tv.ui.custom.CustomClickSpan; import com.fongmi.android.tv.ui.custom.CustomKeyDownVod; import com.fongmi.android.tv.ui.custom.SpaceItemDecoration; import com.fongmi.android.tv.ui.custom.dialog.CastDialog; @@ -87,6 +92,7 @@ import com.fongmi.android.tv.utils.ResUtil; import com.fongmi.android.tv.utils.Sniffer; import com.fongmi.android.tv.utils.Traffic; import com.fongmi.android.tv.utils.Utils; +import com.github.bassaer.library.MDColor; import com.github.catvod.net.OkHttp; import com.github.catvod.utils.Util; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; @@ -100,9 +106,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.regex.Matcher; import master.flame.danmaku.danmaku.model.BaseDanmaku; import master.flame.danmaku.danmaku.model.IDisplay; @@ -495,9 +503,35 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo } private void setText(TextView view, int resId, String text) { - view.setVisibility(text.isEmpty() ? View.GONE : View.VISIBLE); - view.setText(resId > 0 ? getString(resId, text) : text); view.setTag(text); + view.setLinksClickable(true); + view.setLinkTextColor(MDColor.YELLOW_500); + view.setMovementMethod(LinkMovementMethod.getInstance()); + view.setVisibility(text.isEmpty() ? View.GONE : View.VISIBLE); + view.setText(getSpan(resId, text), TextView.BufferType.SPANNABLE); + } + + private SpannableString getSpan(int resId, String text) { + if (resId > 0) text = getString(resId, text); + Map map = new HashMap<>(); + text = findClicker(text, map); + SpannableString span = new SpannableString(text); + for (String s : map.keySet()) { + int index = text.indexOf(s); + span.setSpan(CustomClickSpan.create(this, getKey(), map.get(s)), index, index + s.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + return span; + } + + private String findClicker(String text, Map map) { + Matcher m = Sniffer.CLICKER.matcher(text); + while (m.find()) { + String val = m.group(1); + String key = m.group(2); + text = text.replace(m.group(), key); + map.put(key, val); + } + return text; } private void setOther(TextView view, Vod item) { diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/custom/CustomClickSpan.java b/app/src/mobile/java/com/fongmi/android/tv/ui/custom/CustomClickSpan.java new file mode 100644 index 000000000..a0fb0b0d7 --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/custom/CustomClickSpan.java @@ -0,0 +1,32 @@ +package com.fongmi.android.tv.ui.custom; + +import android.app.Activity; +import android.text.style.ClickableSpan; +import android.view.View; + +import androidx.annotation.NonNull; + +import com.fongmi.android.tv.bean.Result; +import com.fongmi.android.tv.ui.activity.FolderActivity; + +public class CustomClickSpan extends ClickableSpan { + + private final Activity activity; + private final String json; + private final String key; + + public static CustomClickSpan create(Activity activity, String key, String json) { + return new CustomClickSpan(activity, key, json); + } + + public CustomClickSpan(Activity activity, String key, String json) { + this.activity = activity; + this.json = json; + this.key = key; + } + + @Override + public void onClick(@NonNull View view) { + FolderActivity.start(activity, key, Result.type(json)); + } +}