DetailActivity.java 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. package com.github.tvbox.osc.ui.activity;
  2. import android.annotation.SuppressLint;
  3. import android.content.DialogInterface;
  4. import android.content.Intent;
  5. import android.graphics.Rect;
  6. import android.os.Bundle;
  7. import android.text.Html;
  8. import android.text.TextUtils;
  9. import android.view.KeyEvent;
  10. import android.view.MotionEvent;
  11. import android.view.View;
  12. import android.view.ViewGroup;
  13. import android.widget.FrameLayout;
  14. import android.widget.ImageView;
  15. import android.widget.LinearLayout;
  16. import android.widget.TextView;
  17. import android.widget.Toast;
  18. import android.content.ClipboardManager;
  19. import android.content.ClipData;
  20. import androidx.fragment.app.FragmentContainerView;
  21. import androidx.lifecycle.Observer;
  22. import androidx.lifecycle.ViewModelProvider;
  23. import com.chad.library.adapter.base.BaseQuickAdapter;
  24. import com.github.tvbox.osc.R;
  25. import com.github.tvbox.osc.api.ApiConfig;
  26. import com.github.tvbox.osc.base.App;
  27. import com.github.tvbox.osc.base.BaseActivity;
  28. import com.github.tvbox.osc.bean.AbsXml;
  29. import com.github.tvbox.osc.bean.Movie;
  30. import com.github.tvbox.osc.bean.SourceBean;
  31. import com.github.tvbox.osc.bean.VodInfo;
  32. import com.github.tvbox.osc.cache.RoomDataManger;
  33. import com.github.tvbox.osc.event.RefreshEvent;
  34. import com.github.tvbox.osc.picasso.RoundTransformation;
  35. import com.github.tvbox.osc.ui.adapter.SeriesAdapter;
  36. import com.github.tvbox.osc.ui.adapter.SeriesFlagAdapter;
  37. import com.github.tvbox.osc.ui.dialog.QuickSearchDialog;
  38. import com.github.tvbox.osc.ui.fragment.PlayFragment;
  39. import com.github.tvbox.osc.util.DefaultConfig;
  40. import com.github.tvbox.osc.util.FastClickCheckUtil;
  41. import com.github.tvbox.osc.util.HawkConfig;
  42. import com.github.tvbox.osc.util.LOG;
  43. import com.github.tvbox.osc.util.MD5;
  44. import com.github.tvbox.osc.util.SearchHelper;
  45. import com.github.tvbox.osc.viewmodel.SourceViewModel;
  46. import com.google.gson.Gson;
  47. import com.google.gson.JsonArray;
  48. import com.google.gson.JsonElement;
  49. import com.lzy.okgo.OkGo;
  50. import com.lzy.okgo.callback.AbsCallback;
  51. import com.lzy.okgo.model.Response;
  52. import com.orhanobut.hawk.Hawk;
  53. import com.owen.tvrecyclerview.widget.TvRecyclerView;
  54. import com.owen.tvrecyclerview.widget.V7GridLayoutManager;
  55. import com.owen.tvrecyclerview.widget.V7LinearLayoutManager;
  56. import com.squareup.picasso.Picasso;
  57. import org.greenrobot.eventbus.EventBus;
  58. import org.greenrobot.eventbus.Subscribe;
  59. import org.greenrobot.eventbus.ThreadMode;
  60. import org.json.JSONObject;
  61. import java.io.ByteArrayInputStream;
  62. import java.io.ByteArrayOutputStream;
  63. import java.io.ObjectInputStream;
  64. import java.io.ObjectOutputStream;
  65. import java.net.URLEncoder;
  66. import java.util.ArrayList;
  67. import java.util.HashMap;
  68. import java.util.List;
  69. import java.util.concurrent.ExecutorService;
  70. import java.util.concurrent.Executors;
  71. import me.jessyan.autosize.utils.AutoSizeUtils;
  72. import android.graphics.Paint;
  73. import android.text.TextPaint;
  74. import androidx.annotation.NonNull;
  75. import android.graphics.Typeface;
  76. import androidx.recyclerview.widget.RecyclerView;
  77. /**
  78. * @author pj567
  79. * @date :2020/12/22
  80. * @description:
  81. */
  82. public class DetailActivity extends BaseActivity {
  83. private LinearLayout llLayout;
  84. private FragmentContainerView llPlayerFragmentContainer;
  85. private View llPlayerFragmentContainerBlock;
  86. private View llPlayerPlace;
  87. private PlayFragment playFragment = null;
  88. private ImageView ivThumb;
  89. private TextView tvName;
  90. private TextView tvYear;
  91. private TextView tvSite;
  92. private TextView tvArea;
  93. private TextView tvLang;
  94. private TextView tvType;
  95. private TextView tvActor;
  96. private TextView tvDirector;
  97. private TextView tvPlayUrl;
  98. private TextView tvDes;
  99. private TextView tvPlay;
  100. private TextView tvSort;
  101. private TextView tvQuickSearch;
  102. private TextView tvCollect;
  103. private TvRecyclerView mGridViewFlag;
  104. private TvRecyclerView mGridView;
  105. private LinearLayout mEmptyPlayList;
  106. private SourceViewModel sourceViewModel;
  107. private Movie.Video mVideo;
  108. private VodInfo vodInfo;
  109. private SeriesFlagAdapter seriesFlagAdapter;
  110. private SeriesAdapter seriesAdapter;
  111. public String vodId;
  112. public String sourceKey;
  113. boolean seriesSelect = false;
  114. private View seriesFlagFocus = null;
  115. private boolean isReverse;
  116. private String preFlag="";
  117. private boolean firstReverse;
  118. private V7GridLayoutManager mGridViewLayoutMgr = null;
  119. private HashMap<String, String> mCheckSources = null;
  120. //画中画
  121. private BroadcastReceiver pipActionReceiver;
  122. private static final int PIP_BOARDCAST_ACTION_PREV = 0;
  123. private static final int PIP_BOARDCAST_ACTION_PLAYPAUSE = 1;
  124. private static final int PIP_BOARDCAST_ACTION_NEXT = 2;
  125. @Override
  126. public void onUserLeaveHint() {
  127. // takagen99 : Additional check for external player
  128. if (supportsPiPMode() && showPreview && !playFragment.extPlay && PIP) {
  129. List<RemoteAction> actions = new ArrayList<>();
  130. actions.add(generateRemoteAction(android.R.drawable.ic_media_previous, PIP_BOARDCAST_ACTION_PREV, "Prev", "Play Previous"));
  131. actions.add(generateRemoteAction(android.R.drawable.ic_media_play, PIP_BOARDCAST_ACTION_PLAYPAUSE, "Play", "Play/Pause"));
  132. actions.add(generateRemoteAction(android.R.drawable.ic_media_next, PIP_BOARDCAST_ACTION_NEXT, "Next", "Play Next"));
  133. PictureInPictureParams params = new PictureInPictureParams.Builder().setActions(actions).build();
  134. if (!fullWindows) {
  135. toggleFullPreview();
  136. }
  137. enterPictureInPictureMode(params);
  138. playFragment.getVodController().hideBottom();
  139. }
  140. }
  141. @Override
  142. public void onReceive(Context context, Intent intent) {
  143. if (intent == null || !intent.getAction().equals("PIP_VOD_CONTROL") || playFragment.getVodController() == null) {
  144. return;
  145. }
  146. int currentStatus = intent.getIntExtra("action", 1);
  147. if (currentStatus == PIP_BOARDCAST_ACTION_PREV) {
  148. playFragment.playPrevious();
  149. } else if (currentStatus == PIP_BOARDCAST_ACTION_PLAYPAUSE) {
  150. playFragment.getVodController().togglePlay();
  151. } else if (currentStatus == PIP_BOARDCAST_ACTION_NEXT) {
  152. playFragment.playNext();
  153. }
  154. }
  155. };
  156. registerReceiver(pipActionReceiver, new IntentFilter("PIP_VOD_CONTROL"));
  157. } else {
  158. unregisterReceiver(pipActionReceiver);
  159. pipActionReceiver = null;
  160. }
  161. }
  162. @Override
  163. protected int getLayoutResID() {
  164. return R.layout.activity_detail;
  165. }
  166. @Override
  167. protected void init() {
  168. EventBus.getDefault().register(this);
  169. initView();
  170. initViewModel();
  171. initData();
  172. }
  173. private void initView() {
  174. llLayout = findViewById(R.id.llLayout);
  175. llPlayerPlace = findViewById(R.id.previewPlayerPlace);
  176. llPlayerFragmentContainer = findViewById(R.id.previewPlayer);
  177. llPlayerFragmentContainerBlock = findViewById(R.id.previewPlayerBlock);
  178. ivThumb = findViewById(R.id.ivThumb);
  179. llPlayerPlace.setVisibility(showPreview ? View.VISIBLE : View.GONE);
  180. ivThumb.setVisibility(!showPreview ? View.VISIBLE : View.GONE);
  181. tvName = findViewById(R.id.tvName);
  182. tvYear = findViewById(R.id.tvYear);
  183. tvSite = findViewById(R.id.tvSite);
  184. tvArea = findViewById(R.id.tvArea);
  185. tvLang = findViewById(R.id.tvLang);
  186. tvType = findViewById(R.id.tvType);
  187. tvActor = findViewById(R.id.tvActor);
  188. tvDirector = findViewById(R.id.tvDirector);
  189. tvPlayUrl = findViewById(R.id.tvPlayUrl);
  190. tvDes = findViewById(R.id.tvDes);
  191. tvPlay = findViewById(R.id.tvPlay);
  192. tvSort = findViewById(R.id.tvSort);
  193. tvCollect = findViewById(R.id.tvCollect);
  194. tvQuickSearch = findViewById(R.id.tvQuickSearch);
  195. mEmptyPlayList = findViewById(R.id.mEmptyPlaylist);
  196. mGridView = findViewById(R.id.mGridView);
  197. mGridView.setHasFixedSize(true);
  198. mGridView.setHasFixedSize(false);
  199. this.mGridViewLayoutMgr = new V7GridLayoutManager(this.mContext, isBaseOnWidth() ? 6 : 7);
  200. mGridView.setLayoutManager(this.mGridViewLayoutMgr);
  201. seriesAdapter = new SeriesAdapter();
  202. mGridView.setAdapter(seriesAdapter);
  203. mGridViewFlag = findViewById(R.id.mGridViewFlag);
  204. mGridViewFlag.setHasFixedSize(true);
  205. mGridViewFlag.setLayoutManager(new V7LinearLayoutManager(this.mContext, 0, false));
  206. seriesFlagAdapter = new SeriesFlagAdapter();
  207. mGridViewFlag.setAdapter(seriesFlagAdapter);
  208. isReverse = false;
  209. firstReverse = false;
  210. preFlag = "";
  211. if (showPreview) {
  212. playFragment = new PlayFragment();
  213. getSupportFragmentManager().beginTransaction().add(R.id.previewPlayer, playFragment).commit();
  214. getSupportFragmentManager().beginTransaction().show(playFragment).commitAllowingStateLoss();
  215. tvPlay.setText("全屏");
  216. }
  217. //禁用播放地址焦点
  218. tvPlayUrl.setFocusable(false);
  219. tvSort.setOnClickListener(new View.OnClickListener() {
  220. @SuppressLint("NotifyDataSetChanged")
  221. @Override
  222. public void onClick(View v) {
  223. if (vodInfo != null && vodInfo.seriesMap.size() > 0) {
  224. vodInfo.reverseSort = !vodInfo.reverseSort;
  225. isReverse = !isReverse;
  226. vodInfo.reverse();
  227. vodInfo.playIndex=(vodInfo.seriesMap.get(vodInfo.playFlag).size()-1)-vodInfo.playIndex;
  228. // insertVod(sourceKey, vodInfo);
  229. firstReverse = true;
  230. seriesAdapter.notifyDataSetChanged();
  231. }
  232. }
  233. });
  234. tvPlay.setOnClickListener(new View.OnClickListener() {
  235. @Override
  236. public void onClick(View v) {
  237. FastClickCheckUtil.check(v);
  238. if (showPreview) {
  239. toggleFullPreview();
  240. if(firstReverse){
  241. jumpToPlay();
  242. firstReverse=false;
  243. }
  244. } else {
  245. jumpToPlay();
  246. }
  247. }
  248. });
  249. tvQuickSearch.setOnClickListener(new View.OnClickListener() {
  250. @Override
  251. public void onClick(View v) {
  252. startQuickSearch();
  253. QuickSearchDialog quickSearchDialog = new QuickSearchDialog(DetailActivity.this);
  254. EventBus.getDefault().post(new RefreshEvent(RefreshEvent.TYPE_QUICK_SEARCH, quickSearchData));
  255. EventBus.getDefault().post(new RefreshEvent(RefreshEvent.TYPE_QUICK_SEARCH_WORD, quickSearchWord));
  256. quickSearchDialog.show();
  257. if (pauseRunnable != null && pauseRunnable.size() > 0) {
  258. searchExecutorService = Executors.newFixedThreadPool(5);
  259. for (Runnable runnable : pauseRunnable) {
  260. searchExecutorService.execute(runnable);
  261. }
  262. pauseRunnable.clear();
  263. pauseRunnable = null;
  264. }
  265. quickSearchDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
  266. @Override
  267. public void onDismiss(DialogInterface dialog) {
  268. try {
  269. if (searchExecutorService != null) {
  270. pauseRunnable = searchExecutorService.shutdownNow();
  271. searchExecutorService = null;
  272. }
  273. } catch (Throwable th) {
  274. th.printStackTrace();
  275. }
  276. }
  277. });
  278. }
  279. });
  280. tvCollect.setOnClickListener(new View.OnClickListener() {
  281. @Override
  282. public void onClick(View v) {
  283. String text = tvCollect.getText().toString();
  284. if ("加入收藏".equals(text)) {
  285. RoomDataManger.insertVodCollect(sourceKey, vodInfo);
  286. Toast.makeText(DetailActivity.this, "已加入收藏夹", Toast.LENGTH_SHORT).show();
  287. tvCollect.setText("取消收藏");
  288. } else {
  289. RoomDataManger.deleteVodCollect(sourceKey, vodInfo);
  290. Toast.makeText(DetailActivity.this, "已移除收藏夹", Toast.LENGTH_SHORT).show();
  291. tvCollect.setText("加入收藏");
  292. }
  293. }
  294. });
  295. tvPlayUrl.setOnClickListener(new View.OnClickListener() {
  296. @Override
  297. public void onClick(View v) {
  298. //获取剪切板管理器
  299. ClipboardManager cm = (ClipboardManager)getSystemService(mContext.CLIPBOARD_SERVICE);
  300. //设置内容到剪切板
  301. cm.setPrimaryClip(ClipData.newPlainText(null, tvPlayUrl.getText().toString().replace("播放地址:","")));
  302. Toast.makeText(DetailActivity.this, "已复制", Toast.LENGTH_SHORT).show();
  303. }
  304. });
  305. mGridView.setOnItemListener(new TvRecyclerView.OnItemListener() {
  306. @Override
  307. public void onItemPreSelected(TvRecyclerView parent, View itemView, int position) {
  308. seriesSelect = false;
  309. }
  310. @Override
  311. public void onItemSelected(TvRecyclerView parent, View itemView, int position) {
  312. seriesSelect = true;
  313. }
  314. @Override
  315. public void onItemClick(TvRecyclerView parent, View itemView, int position) {
  316. }
  317. });
  318. mGridViewFlag.setOnItemListener(new TvRecyclerView.OnItemListener() {
  319. private void refresh(View itemView, int position) {
  320. String newFlag = seriesFlagAdapter.getData().get(position).name;
  321. if (vodInfo != null && !vodInfo.playFlag.equals(newFlag)) {
  322. for (int i = 0; i < vodInfo.seriesFlags.size(); i++) {
  323. VodInfo.VodSeriesFlag flag = vodInfo.seriesFlags.get(i);
  324. if (flag.name.equals(vodInfo.playFlag)) {
  325. flag.selected = false;
  326. seriesFlagAdapter.notifyItemChanged(i);
  327. break;
  328. }
  329. }
  330. VodInfo.VodSeriesFlag flag = vodInfo.seriesFlags.get(position);
  331. flag.selected = true;
  332. // clean pre flag select status
  333. if (vodInfo.seriesMap.get(vodInfo.playFlag).size() > vodInfo.playIndex) {
  334. vodInfo.seriesMap.get(vodInfo.playFlag).get(vodInfo.playIndex).selected = false;
  335. }
  336. vodInfo.playFlag = newFlag;
  337. seriesFlagAdapter.notifyItemChanged(position);
  338. refreshList();
  339. }
  340. seriesFlagFocus = itemView;
  341. }
  342. @Override
  343. public void onItemPreSelected(TvRecyclerView parent, View itemView, int position) {
  344. // seriesSelect = false;
  345. }
  346. @Override
  347. public void onItemSelected(TvRecyclerView parent, View itemView, int position) {
  348. refresh(itemView, position);
  349. // if(isReverse)vodInfo.reverse();
  350. }
  351. @Override
  352. public void onItemClick(TvRecyclerView parent, View itemView, int position) {
  353. refresh(itemView, position);
  354. // if(isReverse)vodInfo.reverse();
  355. }
  356. });
  357. seriesAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
  358. @Override
  359. public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
  360. FastClickCheckUtil.check(view);
  361. if (vodInfo != null && vodInfo.seriesMap.get(vodInfo.playFlag).size() > 0) {
  362. boolean reload = false;
  363. for (int j = 0; j < vodInfo.seriesMap.get(vodInfo.playFlag).size(); j++) {
  364. seriesAdapter.getData().get(j).selected = false;
  365. seriesAdapter.notifyItemChanged(j);
  366. }
  367. //解决倒叙不刷新
  368. if (vodInfo.playIndex != position) {
  369. seriesAdapter.getData().get(position).selected = true;
  370. seriesAdapter.notifyItemChanged(position);
  371. vodInfo.playIndex = position;
  372. reload = true;
  373. }
  374. //解决当前集不刷新的BUG
  375. if (!preFlag.isEmpty() && !vodInfo.playFlag.equals(preFlag)) {
  376. reload = true;
  377. }
  378. seriesAdapter.getData().get(vodInfo.playIndex).selected = true;
  379. seriesAdapter.notifyItemChanged(vodInfo.playIndex);
  380. //选集全屏 想选集不全屏的注释下面一行
  381. if (showPreview && !fullWindows) toggleFullPreview();
  382. if (!showPreview || reload) {
  383. jumpToPlay();
  384. firstReverse=false;
  385. }
  386. }
  387. }
  388. });
  389. setLoadSir(llLayout);
  390. }
  391. private void initCheckedSourcesForSearch() {
  392. mCheckSources = SearchHelper.getSourcesForSearch();
  393. }
  394. private List<Runnable> pauseRunnable = null;
  395. private void jumpToPlay() {
  396. if (vodInfo != null && vodInfo.seriesMap.get(vodInfo.playFlag).size() > 0) {
  397. preFlag = vodInfo.playFlag;
  398. //更新播放地址
  399. setTextShow(tvPlayUrl, "播放地址:", vodInfo.seriesMap.get(vodInfo.playFlag).get(vodInfo.playIndex).url);
  400. Bundle bundle = new Bundle();
  401. //保存历史
  402. insertVod(sourceKey, vodInfo);
  403. bundle.putString("sourceKey", sourceKey);
  404. // bundle.putSerializable("VodInfo", vodInfo);
  405. App.getInstance().setVodInfo(vodInfo);
  406. if (showPreview) {
  407. if (previewVodInfo == null) {
  408. try {
  409. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  410. ObjectOutputStream oos = new ObjectOutputStream(bos);
  411. oos.writeObject(vodInfo);
  412. oos.flush();
  413. oos.close();
  414. ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
  415. previewVodInfo = (VodInfo) ois.readObject();
  416. } catch (Exception e) {
  417. e.printStackTrace();
  418. }
  419. }
  420. if (previewVodInfo != null) {
  421. previewVodInfo.playerCfg = vodInfo.playerCfg;
  422. previewVodInfo.playFlag = vodInfo.playFlag;
  423. previewVodInfo.playIndex = vodInfo.playIndex;
  424. previewVodInfo.seriesMap = vodInfo.seriesMap;
  425. // bundle.putSerializable("VodInfo", previewVodInfo);
  426. App.getInstance().setVodInfo(previewVodInfo);
  427. }
  428. playFragment.setData(bundle);
  429. } else {
  430. jumpActivity(PlayActivity.class, bundle);
  431. }
  432. }
  433. }
  434. void refreshList() {
  435. if (vodInfo.seriesMap.get(vodInfo.playFlag).size() <= vodInfo.playIndex) {
  436. vodInfo.playIndex = 0;
  437. }
  438. if (vodInfo.seriesMap.get(vodInfo.playFlag) != null) {
  439. boolean canSelect = true;
  440. for (int j = 0; j < vodInfo.seriesMap.get(vodInfo.playFlag).size(); j++) {
  441. if(vodInfo.seriesMap.get(vodInfo.playFlag).get(j).selected == true){
  442. canSelect = false;
  443. break;
  444. }
  445. }
  446. if(canSelect)vodInfo.seriesMap.get(vodInfo.playFlag).get(vodInfo.playIndex).selected = true;
  447. }
  448. Paint pFont = new Paint();
  449. // pFont.setTypeface(Typeface.DEFAULT );
  450. Rect rect = new Rect();
  451. List<VodInfo.VodSeries> list = vodInfo.seriesMap.get(vodInfo.playFlag);
  452. int w = 1;
  453. for(int i =0; i < list.size(); ++i){
  454. String name = list.get(i).name;
  455. pFont.getTextBounds(name, 0, name.length(), rect);
  456. if(w < rect.width()){
  457. w = rect.width();
  458. }
  459. }
  460. w += 32;
  461. int screenWidth = getWindowManager().getDefaultDisplay().getWidth()/3;
  462. int offset = screenWidth/w;
  463. if(offset <=1) offset =1;
  464. if(offset > 6) offset =6;
  465. this.mGridViewLayoutMgr.setSpanCount(offset);
  466. seriesAdapter.setNewData(vodInfo.seriesMap.get(vodInfo.playFlag));
  467. mGridView.postDelayed(new Runnable() {
  468. @Override
  469. public void run() {
  470. mGridView.scrollToPosition(vodInfo.playIndex);
  471. }
  472. }, 100);
  473. }
  474. private void setTextShow(TextView view, String tag, String info) {
  475. if (info == null || info.trim().isEmpty()) {
  476. view.setVisibility(View.GONE);
  477. return;
  478. }
  479. view.setVisibility(View.VISIBLE);
  480. view.setText(Html.fromHtml(getHtml(tag, info)));
  481. }
  482. private String removeHtmlTag(String info) {
  483. if (info == null)
  484. return "";
  485. return info.replaceAll("\\<.*?\\>", "").replaceAll("\\s", "");
  486. }
  487. private void initViewModel() {
  488. sourceViewModel = new ViewModelProvider(this).get(SourceViewModel.class);
  489. sourceViewModel.detailResult.observe(this, new Observer<AbsXml>() {
  490. @Override
  491. public void onChanged(AbsXml absXml) {
  492. if (absXml != null && absXml.movie != null && absXml.movie.videoList != null && absXml.movie.videoList.size() > 0) {
  493. showSuccess();
  494. mVideo = absXml.movie.videoList.get(0);
  495. vodInfo = new VodInfo();
  496. vodInfo.setVideo(mVideo);
  497. vodInfo.sourceKey = mVideo.sourceKey;
  498. tvName.setText(mVideo.name);
  499. setTextShow(tvSite, "来源:", ApiConfig.get().getSource(mVideo.sourceKey).getName());
  500. setTextShow(tvYear, "年份:", mVideo.year == 0 ? "" : String.valueOf(mVideo.year));
  501. setTextShow(tvArea, "地区:", mVideo.area);
  502. setTextShow(tvLang, "语言:", mVideo.lang);
  503. setTextShow(tvType, "类型:", mVideo.type);
  504. setTextShow(tvActor, "演员:", mVideo.actor);
  505. setTextShow(tvDirector, "导演:", mVideo.director);
  506. setTextShow(tvDes, "内容简介:", removeHtmlTag(mVideo.des));
  507. if (!TextUtils.isEmpty(mVideo.pic)) {
  508. Picasso.get()
  509. .load(DefaultConfig.checkReplaceProxy(mVideo.pic))
  510. .transform(new RoundTransformation(MD5.string2MD5(mVideo.pic + mVideo.name))
  511. .centerCorp(true)
  512. .override(AutoSizeUtils.mm2px(mContext, 300), AutoSizeUtils.mm2px(mContext, 400))
  513. .roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL))
  514. .placeholder(R.drawable.img_loading_placeholder)
  515. .error(R.drawable.img_loading_placeholder)
  516. .into(ivThumb);
  517. } else {
  518. ivThumb.setImageResource(R.drawable.img_loading_placeholder);
  519. }
  520. if (vodInfo.seriesMap != null && vodInfo.seriesMap.size() > 0) {
  521. mGridViewFlag.setVisibility(View.VISIBLE);
  522. mGridView.setVisibility(View.VISIBLE);
  523. tvPlay.setVisibility(View.VISIBLE);
  524. mEmptyPlayList.setVisibility(View.GONE);
  525. VodInfo vodInfoRecord = RoomDataManger.getVodInfo(sourceKey, vodId);
  526. // 读取历史记录
  527. if (vodInfoRecord != null) {
  528. vodInfo.playIndex = Math.max(vodInfoRecord.playIndex, 0);
  529. vodInfo.playFlag = vodInfoRecord.playFlag;
  530. vodInfo.playerCfg = vodInfoRecord.playerCfg;
  531. vodInfo.reverseSort = vodInfoRecord.reverseSort;
  532. } else {
  533. vodInfo.playIndex = 0;
  534. vodInfo.playFlag = null;
  535. vodInfo.playerCfg = "";
  536. vodInfo.reverseSort = false;
  537. }
  538. if (vodInfo.reverseSort) {
  539. vodInfo.reverse();
  540. }
  541. if (vodInfo.playFlag == null || !vodInfo.seriesMap.containsKey(vodInfo.playFlag))
  542. vodInfo.playFlag = (String) vodInfo.seriesMap.keySet().toArray()[0];
  543. int flagScrollTo = 0;
  544. for (int j = 0; j < vodInfo.seriesFlags.size(); j++) {
  545. VodInfo.VodSeriesFlag flag = vodInfo.seriesFlags.get(j);
  546. if (flag.name.equals(vodInfo.playFlag)) {
  547. flagScrollTo = j;
  548. flag.selected = true;
  549. } else
  550. flag.selected = false;
  551. }
  552. //设置播放地址
  553. setTextShow(tvPlayUrl, "播放地址:", vodInfo.seriesMap.get(vodInfo.playFlag).get(0).url);
  554. seriesFlagAdapter.setNewData(vodInfo.seriesFlags);
  555. mGridViewFlag.scrollToPosition(flagScrollTo);
  556. refreshList();
  557. if (showPreview) {
  558. jumpToPlay();
  559. llPlayerFragmentContainer.setVisibility(View.VISIBLE);
  560. llPlayerFragmentContainerBlock.setVisibility(View.VISIBLE);
  561. }
  562. // startQuickSearch();
  563. } else {
  564. mGridViewFlag.setVisibility(View.GONE);
  565. mGridView.setVisibility(View.GONE);
  566. tvPlay.setVisibility(View.GONE);
  567. mEmptyPlayList.setVisibility(View.VISIBLE);
  568. }
  569. } else {
  570. showEmpty();
  571. llPlayerFragmentContainer.setVisibility(View.GONE);
  572. llPlayerFragmentContainerBlock.setVisibility(View.GONE);
  573. }
  574. }
  575. });
  576. }
  577. //画中画
  578. boolean PIP = Hawk.get(HawkConfig.PIC_IN_PIC, false);
  579. @Override
  580. public void onUserLeaveHint() {
  581. // takagen99 : Additional check for external player
  582. if (supportsPiPMode() && showPreview && !playFragment.extPlay && PIP) {
  583. List<RemoteAction> actions = new ArrayList<>();
  584. actions.add(generateRemoteAction(android.R.drawable.ic_media_previous, PIP_BOARDCAST_ACTION_PREV, "Prev", "Play Previous"));
  585. actions.add(generateRemoteAction(android.R.drawable.ic_media_play, PIP_BOARDCAST_ACTION_PLAYPAUSE, "Play", "Play/Pause"));
  586. actions.add(generateRemoteAction(android.R.drawable.ic_media_next, PIP_BOARDCAST_ACTION_NEXT, "Next", "Play Next"));
  587. PictureInPictureParams params = new PictureInPictureParams.Builder().setActions(actions).build();
  588. if (!fullWindows) {
  589. toggleFullPreview();
  590. }
  591. enterPictureInPictureMode(params);
  592. playFragment.getVodController().hideBottom();
  593. }
  594. }
  595. private String getHtml(String label, String content) {
  596. if (content == null) {
  597. content = "";
  598. }
  599. return label + "<font color=\"#FFFFFF\">" + content + "</font>";
  600. }
  601. private void initData() {
  602. Intent intent = getIntent();
  603. if (intent != null && intent.getExtras() != null) {
  604. Bundle bundle = intent.getExtras();
  605. loadDetail(bundle.getString("id", null), bundle.getString("sourceKey", ""));
  606. }
  607. }
  608. private void loadDetail(String vid, String key) {
  609. if (vid != null) {
  610. vodId = vid;
  611. sourceKey = key;
  612. showLoading();
  613. sourceViewModel.getDetail(sourceKey, vodId);
  614. boolean isVodCollect = RoomDataManger.isVodCollect(sourceKey, vodId);
  615. if (isVodCollect) {
  616. tvCollect.setText("取消收藏");
  617. } else {
  618. tvCollect.setText("加入收藏");
  619. }
  620. }
  621. }
  622. @Subscribe(threadMode = ThreadMode.MAIN)
  623. public void refresh(RefreshEvent event) {
  624. if (event.type == RefreshEvent.TYPE_REFRESH) {
  625. if (event.obj != null) {
  626. if (event.obj instanceof Integer) {
  627. int index = (int) event.obj;
  628. for (int j = 0; j < vodInfo.seriesMap.get(vodInfo.playFlag).size(); j++) {
  629. seriesAdapter.getData().get(j).selected = false;
  630. seriesAdapter.notifyItemChanged(j);
  631. }
  632. seriesAdapter.getData().get(index).selected = true;
  633. seriesAdapter.notifyItemChanged(index);
  634. mGridView.setSelection(index);
  635. vodInfo.playIndex = index;
  636. //保存历史
  637. insertVod(sourceKey, vodInfo);
  638. } else if (event.obj instanceof JSONObject) {
  639. vodInfo.playerCfg = ((JSONObject) event.obj).toString();
  640. //保存历史
  641. insertVod(sourceKey, vodInfo);
  642. }
  643. }
  644. } else if (event.type == RefreshEvent.TYPE_QUICK_SEARCH_SELECT) {
  645. if (event.obj != null) {
  646. Movie.Video video = (Movie.Video) event.obj;
  647. loadDetail(video.id, video.sourceKey);
  648. }
  649. } else if (event.type == RefreshEvent.TYPE_QUICK_SEARCH_WORD_CHANGE) {
  650. if (event.obj != null) {
  651. String word = (String) event.obj;
  652. switchSearchWord(word);
  653. }
  654. } else if (event.type == RefreshEvent.TYPE_QUICK_SEARCH_RESULT) {
  655. try {
  656. searchData(event.obj == null ? null : (AbsXml) event.obj);
  657. } catch (Exception e) {
  658. searchData(null);
  659. }
  660. }
  661. }
  662. private String searchTitle = "";
  663. private boolean hadQuickStart = false;
  664. private final List<Movie.Video> quickSearchData = new ArrayList<>();
  665. private final List<String> quickSearchWord = new ArrayList<>();
  666. private ExecutorService searchExecutorService = null;
  667. private void switchSearchWord(String word) {
  668. OkGo.getInstance().cancelTag("quick_search");
  669. quickSearchData.clear();
  670. searchTitle = word;
  671. searchResult();
  672. }
  673. private void startQuickSearch() {
  674. initCheckedSourcesForSearch();
  675. if (hadQuickStart)
  676. return;
  677. hadQuickStart = true;
  678. OkGo.getInstance().cancelTag("quick_search");
  679. quickSearchWord.clear();
  680. searchTitle = mVideo.name;
  681. quickSearchData.clear();
  682. quickSearchWord.add(searchTitle);
  683. // 分词
  684. OkGo.<String>get("http://api.pullword.com/get.php?source=" + URLEncoder.encode(searchTitle) + "&param1=0&param2=0&json=1")
  685. .tag("fenci")
  686. .execute(new AbsCallback<String>() {
  687. @Override
  688. public String convertResponse(okhttp3.Response response) throws Throwable {
  689. if (response.body() != null) {
  690. return response.body().string();
  691. } else {
  692. throw new IllegalStateException("网络请求错误");
  693. }
  694. }
  695. @Override
  696. public void onSuccess(Response<String> response) {
  697. String json = response.body();
  698. quickSearchWord.clear();
  699. try {
  700. for (JsonElement je : new Gson().fromJson(json, JsonArray.class)) {
  701. quickSearchWord.add(je.getAsJsonObject().get("t").getAsString());
  702. }
  703. } catch (Throwable th) {
  704. th.printStackTrace();
  705. }
  706. quickSearchWord.add(searchTitle);
  707. EventBus.getDefault().post(new RefreshEvent(RefreshEvent.TYPE_QUICK_SEARCH_WORD, quickSearchWord));
  708. }
  709. @Override
  710. public void onError(Response<String> response) {
  711. super.onError(response);
  712. }
  713. });
  714. searchResult();
  715. }
  716. private void searchResult() {
  717. try {
  718. if (searchExecutorService != null) {
  719. searchExecutorService.shutdownNow();
  720. searchExecutorService = null;
  721. }
  722. } catch (Throwable th) {
  723. th.printStackTrace();
  724. }
  725. searchExecutorService = Executors.newFixedThreadPool(5);
  726. List<SourceBean> searchRequestList = new ArrayList<>();
  727. searchRequestList.addAll(ApiConfig.get().getSourceBeanList());
  728. SourceBean home = ApiConfig.get().getHomeSourceBean();
  729. searchRequestList.remove(home);
  730. searchRequestList.add(0, home);
  731. ArrayList<String> siteKey = new ArrayList<>();
  732. for (SourceBean bean : searchRequestList) {
  733. if (!bean.isSearchable() || !bean.isQuickSearch()) {
  734. continue;
  735. }
  736. if (mCheckSources != null && !mCheckSources.containsKey(bean.getKey())) {
  737. continue;
  738. }
  739. siteKey.add(bean.getKey());
  740. }
  741. for (String key : siteKey) {
  742. searchExecutorService.execute(new Runnable() {
  743. @Override
  744. public void run() {
  745. sourceViewModel.getQuickSearch(key, searchTitle);
  746. }
  747. });
  748. }
  749. }
  750. private void searchData(AbsXml absXml) {
  751. if (absXml != null && absXml.movie != null && absXml.movie.videoList != null && absXml.movie.videoList.size() > 0) {
  752. List<Movie.Video> data = new ArrayList<>();
  753. for (Movie.Video video : absXml.movie.videoList) {
  754. // 去除当前相同的影片
  755. if (video.sourceKey.equals(sourceKey) && video.id.equals(vodId))
  756. continue;
  757. data.add(video);
  758. }
  759. quickSearchData.addAll(data);
  760. EventBus.getDefault().post(new RefreshEvent(RefreshEvent.TYPE_QUICK_SEARCH, data));
  761. }
  762. }
  763. private void insertVod(String sourceKey, VodInfo vodInfo) {
  764. try {
  765. vodInfo.playNote = vodInfo.seriesMap.get(vodInfo.playFlag).get(vodInfo.playIndex).name;
  766. } catch (Throwable th) {
  767. vodInfo.playNote = "";
  768. }
  769. RoomDataManger.insertVodRecord(sourceKey, vodInfo);
  770. EventBus.getDefault().post(new RefreshEvent(RefreshEvent.TYPE_HISTORY_REFRESH));
  771. }
  772. @Override
  773. protected void onDestroy() {
  774. super.onDestroy();
  775. try {
  776. if (searchExecutorService != null) {
  777. searchExecutorService.shutdownNow();
  778. searchExecutorService = null;
  779. }
  780. } catch (Throwable th) {
  781. th.printStackTrace();
  782. }
  783. OkGo.getInstance().cancelTag("fenci");
  784. OkGo.getInstance().cancelTag("detail");
  785. OkGo.getInstance().cancelTag("quick_search");
  786. EventBus.getDefault().unregister(this);
  787. }
  788. @Override
  789. public void onBackPressed() {
  790. if (fullWindows) {
  791. if (playFragment.onBackPressed())
  792. return;
  793. toggleFullPreview();
  794. mGridView.requestFocus();
  795. return;
  796. }
  797. if (seriesSelect) {
  798. if (seriesFlagFocus != null && !seriesFlagFocus.isFocused()) {
  799. seriesFlagFocus.requestFocus();
  800. return;
  801. }
  802. }
  803. super.onBackPressed();
  804. }
  805. @Override
  806. public boolean dispatchKeyEvent(KeyEvent event) {
  807. if (event != null && playFragment != null && fullWindows) {
  808. if (playFragment.dispatchKeyEvent(event)) {
  809. return true;
  810. }
  811. }
  812. return super.dispatchKeyEvent(event);
  813. }
  814. @Override
  815. public boolean dispatchTouchEvent(MotionEvent ev) {
  816. if (showPreview && !fullWindows) {
  817. Rect editTextRect = new Rect();
  818. llPlayerFragmentContainerBlock.getHitRect(editTextRect);
  819. if (editTextRect.contains((int) ev.getX(), (int) ev.getY())) {
  820. return true;
  821. }
  822. }
  823. return super.dispatchTouchEvent(ev);
  824. }
  825. // preview
  826. VodInfo previewVodInfo = null;
  827. boolean showPreview = Hawk.get(HawkConfig.SHOW_PREVIEW, true);; // true 开启 false 关闭
  828. boolean fullWindows = false;
  829. ViewGroup.LayoutParams windowsPreview = null;
  830. ViewGroup.LayoutParams windowsFull = null;
  831. void toggleFullPreview() {
  832. if (windowsPreview == null) {
  833. windowsPreview = llPlayerFragmentContainer.getLayoutParams();
  834. }
  835. if (windowsFull == null) {
  836. windowsFull = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
  837. }
  838. fullWindows = !fullWindows;
  839. llPlayerFragmentContainer.setLayoutParams(fullWindows ? windowsFull : windowsPreview);
  840. llPlayerFragmentContainerBlock.setVisibility(fullWindows ? View.GONE : View.VISIBLE);
  841. mGridView.setVisibility(fullWindows ? View.GONE : View.VISIBLE);
  842. mGridViewFlag.setVisibility(fullWindows ? View.GONE : View.VISIBLE);
  843. //全屏下禁用详情页几个按键的焦点 防止上键跑过来
  844. tvPlay.setFocusable(!fullWindows);
  845. tvSort.setFocusable(!fullWindows);
  846. tvCollect.setFocusable(!fullWindows);
  847. tvQuickSearch.setFocusable(!fullWindows);
  848. }
  849. }