From ca1c968f568ad58f9a16aa0fa933c3dbfa7081c6 Mon Sep 17 00:00:00 2001 From: d1y Date: Fri, 28 Jun 2024 02:23:40 +0800 Subject: [PATCH] fix: miss maccms json reponse parse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Release Notes: - fix: 修复部分 maccms 源返回 json 解析失败 --- lib/app/modules/play/views/play_view.dart | 55 +--- packages/xi/lib/adapters/mac_cms.dart | 331 ++++++++++++++++------ packages/xi/lib/utils/maccms.dart | 63 ++++ packages/xi/lib/utils/utils.dart | 1 + 4 files changed, 307 insertions(+), 143 deletions(-) create mode 100644 packages/xi/lib/utils/maccms.dart diff --git a/lib/app/modules/play/views/play_view.dart b/lib/app/modules/play/views/play_view.dart index 162645a..af556fe 100644 --- a/lib/app/modules/play/views/play_view.dart +++ b/lib/app/modules/play/views/play_view.dart @@ -10,7 +10,6 @@ import 'package:movie/app/widget/helper.dart'; import 'package:movie/app/widget/window_appbar.dart'; import 'package:movie/widget/simple_html/flutter_html.dart'; import 'package:simple/x.dart'; -import 'package:xi/adapters/mac_cms.dart'; import 'package:xi/xi.dart'; import '../controllers/play_controller.dart'; @@ -21,17 +20,6 @@ class PlayState { final int index; } -class PlayListData { - final String title; - - final List datas; - - PlayListData({ - required this.title, - required this.datas, - }); -} - class PlayView extends StatefulWidget { const PlayView({super.key}); @@ -59,48 +47,7 @@ class _PlayViewState extends State { } List get playlist { - List result = []; - var v = play.movieItem.videos; - for (var element in v) { - var url = element.url; - var hasUrl = isURL(url); - if (hasUrl) { - var output = [element]; - result.add(PlayListData(title: element.name, datas: [])); - var urls = url.split("#"); - if (urls.length >= 2) { - output = urls - .map( - (e) => VideoInfo( - url: e, - type: MacCMSSpider.easyGetVideoType(e), - ), - ) - .toList(); - } - result.last.datas.addAll(output); - } else { - var movies = url.split("#"); - var cache = PlayListData(title: element.name, datas: []); - for (var e in movies) { - var subItem = e.split("\$"); - if (subItem.length <= 1) continue; - var title = subItem[0]; - var url = subItem[1]; - // var subType = subItem[2]; - cache.datas.add(VideoInfo( - name: title, - url: url, - type: MacCMSSpider.easyGetVideoType(url), - )); - } - result.add(cache); - } - } - result = result.where((element) { - return element.datas.isNotEmpty; - }).toList(); - return result; + return videoInfo2PlayListData(play.movieItem.videos); } get tabviewData { diff --git a/packages/xi/lib/adapters/mac_cms.dart b/packages/xi/lib/adapters/mac_cms.dart index d275587..53c7161 100644 --- a/packages/xi/lib/adapters/mac_cms.dart +++ b/packages/xi/lib/adapters/mac_cms.dart @@ -50,9 +50,7 @@ class MacCMSSpider extends ISpiderAdapter { return root_url + suffix; } - Options ops = Options( - responseType: ResponseType.plain, - ); + Options ops = Options(responseType: ResponseType.plain); bool get hasJiexiUrl { return jiexiUrl.isNotEmpty; @@ -92,18 +90,18 @@ class MacCMSSpider extends ISpiderAdapter { String get _responseParseFail => "接口返回值解析错误 :("; - /// 检测一下请求之后返回的内容 + /// 获取结构类型并且检测一下请求之后返回的内容 /// /// 如果是内容为 [ResponseCustomType.unknow] 则抛出异常 - void beforeTestResponseData(dynamic data) { + ResponseCustomType getResponseTypeAndCheck(dynamic data) { ResponseCustomType _type = getResponseType(data); if (_type == ResponseCustomType.unknow) { throw AsyncError( _responseParseFail, StackTrace.fromString(_responseParseFail), ); - // return Future.error('解析失败'); } + return _type; } @override @@ -116,36 +114,11 @@ class MacCMSSpider extends ISpiderAdapter { }, options: ops, ); - var x2j = Xml2Json(); - x2j.parse(resp.data); - var _json = x2j.toBadgerfish(); - var _ = json.decode(_json); - KBaseMovieXmlData xml = KBaseMovieXmlData.fromJson(_); - var video = xml.rss.list.video; - var cards = video.map( - (e) { - var __dd = e.dl.dd; - List videos = __dd.map((item) { - return VideoInfo( - url: easyGetVideoURL(item.cData), - name: item.flag, - type: easyGetVideoType(item.cData), - ); - }).toList(); - var pic = normalizeCoverImage(e.pic); - return VideoDetail( - id: e.id, - smallCoverImage: pic, - title: e.name, - videos: videos, - desc: e.des, - ); - }, - ).toList(); - if (cards.isEmpty) { - throw UnimplementedError(); + var _type = getResponseTypeAndCheck(resp.data); + if (_type == ResponseCustomType.json) { + return _parseDetailJSON(resp.data); } - return cards[0]; + return _parseDetailXML(resp.data); } @override @@ -167,33 +140,11 @@ class MacCMSSpider extends ISpiderAdapter { options: ops, ); dynamic data = resp.data; - beforeTestResponseData(data); - var x2j = Xml2Json(); - x2j.parse(data); - var _json = x2j.toBadgerfish(); - var _ = json.decode(_json); - KBaseMovieXmlData xml = KBaseMovieXmlData.fromJson(_); - var cards = xml.rss.list.video.map( - (e) { - var __dd = e.dl.dd; - List videos = __dd.map((item) { - return VideoInfo( - url: easyGetVideoURL(item.cData), - name: item.flag, - type: easyGetVideoType(item.cData), - ); - }).toList(); - var pic = normalizeCoverImage(e.pic); - return VideoDetail( - id: e.id, - smallCoverImage: pic, - title: e.name, - videos: videos, - desc: e.des, - ); - }, - ).toList(); - return cards; + var _type = getResponseTypeAndCheck(data); + if (_type == ResponseCustomType.json) { + return _parseHomeJSON(data); + } + return _parseHomeXML(data); } /// 匹配的规则: @@ -239,15 +190,6 @@ class MacCMSSpider extends ISpiderAdapter { } return ResponseCustomType.unknow; - - // String attrText = checkText.substring(0, 2); - // String jsonSyb = "{\""; - // String xmlSyb = " result = searchData.rss?.list?.video! - .map( - (e) => VideoDetail( - id: e.id ?? "", - smallCoverImage: defaultCoverImage, - title: e.name?.cdata ?? "", - ), - ) - .toList() ?? - []; - return result; + var _type = getResponseTypeAndCheck(data); + if (_type == ResponseCustomType.json) { + return _parseSearchJSON(data); + } + return _parseSearchXML(data); } @override @@ -304,7 +234,117 @@ class MacCMSSpider extends ISpiderAdapter { var path = createUrl(suffix: api_path); var resp = await XHttp.dio.get(path); dynamic data = resp.data; - beforeTestResponseData(data); + var _type = getResponseTypeAndCheck(data); + if (_type == ResponseCustomType.json) { + return _parseCategoryJSON(data); + } + return _parseCategoryXML(data); + } + + _parseDetailJSON(dynamic data) { + if (data is! String) { + throw AsyncError( + _responseParseFail, + StackTrace.fromString(_responseParseFail), + ); + } + var list = _getJSONList(data); + if (list.isEmpty) { + throw AsyncError( + _responseParseFail, + StackTrace.fromString(_responseParseFail), + ); + } + return list[0]; + } + + _parseDetailXML(dynamic data) { + var x2j = Xml2Json(); + x2j.parse(data); + var _json = x2j.toBadgerfish(); + var _ = json.decode(_json); + KBaseMovieXmlData xml = KBaseMovieXmlData.fromJson(_); + var video = xml.rss.list.video; + var cards = video.map( + (e) { + var __dd = e.dl.dd; + List videos = __dd.map((item) { + return VideoInfo( + url: easyGetVideoURL(item.cData), + name: item.flag, + type: easyGetVideoType(item.cData), + ); + }).toList(); + var pic = normalizeCoverImage(e.pic); + return VideoDetail( + id: e.id, + smallCoverImage: pic, + title: e.name, + videos: videos, + desc: e.des, + ); + }, + ).toList(); + if (cards.isEmpty) { + throw UnimplementedError(); + } + return cards[0]; + } + + _parseSearchJSON(dynamic data) { + if (data is! String) { + throw AsyncError( + _responseParseFail, + StackTrace.fromString(_responseParseFail), + ); + } + return _getJSONList(data); + } + + _parseSearchXML(dynamic data) { + var x2j = Xml2Json(); + x2j.parse(data); + var _json = x2j.toBadgerfish(); + KBaseMovieSearchXmlData searchData = kBaseMovieSearchXmlDataFromJson(_json); + var defaultCoverImage = meta.logo; + List result = searchData.rss?.list?.video! + .map( + (e) => VideoDetail( + id: e.id ?? "", + smallCoverImage: defaultCoverImage, + title: e.name?.cdata ?? "", + ), + ) + .toList() ?? + []; + return result; + } + + List _parseCategoryJSON(dynamic data) { + if (data is! String) { + throw AsyncError( + _responseParseFail, + StackTrace.fromString(_responseParseFail), + ); + } + var json = jsonDecode(data); + List> cx = json['class'].cast>(); + var result = []; + for (var item in cx) { + var name = item['type_name'] ?? ""; + var _id = item['type_id']; + late String id; + if (_id is int) { + id = _id.toString(); + } else { + id = _id; + } + result.add(SourceSpiderQueryCategory(name, id)); + } + return result; + } + + List _parseCategoryXML(dynamic data) { var x2j = Xml2Json(); x2j.parse(data); var _json = x2j.toBadgerfish(); @@ -313,6 +353,119 @@ class MacCMSSpider extends ISpiderAdapter { return xml.rss.category; } + List _parseHomeXML(dynamic data) { + var x2j = Xml2Json(); + x2j.parse(data); + var _json = x2j.toBadgerfish(); + var _ = json.decode(_json); + KBaseMovieXmlData xml = KBaseMovieXmlData.fromJson(_); + return xml.rss.list.video.map( + (e) { + var __dd = e.dl.dd; + List videos = __dd.map((item) { + return VideoInfo( + url: easyGetVideoURL(item.cData), + name: item.flag, + type: easyGetVideoType(item.cData), + ); + }).toList(); + var pic = normalizeCoverImage(e.pic); + return VideoDetail( + id: e.id, + smallCoverImage: pic, + title: e.name, + videos: videos, + desc: e.des, + ); + }, + ).toList(); + } + + List _parseHomeJSON(dynamic data) { + if (data is! String) { + throw AsyncError( + _responseParseFail, + StackTrace.fromString(_responseParseFail), + ); + } + return _getJSONList(data); + } + + _getJSONList(dynamic jsonData) { + var json = jsonDecode(jsonData); + var list = json['list']; //; + var result = []; + if (list is Map) { + var cx = list as Map; + result.add(__parseListItem(cx)); + } else if (list is List) { + for (var item in list.cast>()) { + result.add(__parseListItem(item)); + } + } + return result; + } + + __parseListItem(dynamic item) { + var videos = []; + // 参考格式: vod_play_from":"ukyun$$$ukm3u8","vod_play_server":"no$$$no","vod_play_note":"$$$","vod_play_url": "xxxx$$$xxxxx" + String vodFrom = item["vod_play_from"]; + String vodNote = item['vod_play_note']; + String _vodURL = (item['vod_play_url'] ?? ""); + late List tags; + if (vodNote.isNotEmpty) { + tags = vodFrom.split(vodNote /* $$$ */); + } else { + tags = [vodFrom]; + } + String vodURL = _vodURL.replaceAll(RegExp(r'#$'), ''); + List _t = vodURL.split(vodNote /* $$$ */); + if (tags.length >= 2) { + Map> _cx = {}; + for (final (index, subItem) in _t.indexed) { + var _nameKey = tags[index]; + List _map = + subItem.split("#").where((e) => e.trim().isNotEmpty).map((item) { + List items = item.split("\$"); + return VideoInfo( + name: items[0], + url: items[1], + type: easyGetVideoType(items[1]), + ); + }).toList(); + _cx[_nameKey] = _map; + } + _cx.forEach((key, value) { + var url = value + .map((item) { + /// 这里转成 [videoInfo2PlayListData] 需要的格式 + return "${item.name}\$${item.url}"; + }) + .toList() + .join("#"); + var video = VideoInfo(name: key, url: url); + videos.add(video); + }); + } else if (tags.length == 1) { + videos.add(VideoInfo(name: tags[0], url: _vodURL)); + } + var _id = item['vod_id']; + late String id; + if (_id is int) { + id = _id.toString(); + } else { + id = _id; + } + var detail = VideoDetail( + id: id, + title: item['vod_name'] ?? "", + desc: item['vod_blurb'] ?? "", + smallCoverImage: item['vod_pic'] ?? "", + videos: videos, + ); + return detail; + } + @override String toString() { var output = "\n"; diff --git a/packages/xi/lib/utils/maccms.dart b/packages/xi/lib/utils/maccms.dart new file mode 100644 index 0000000..8deb770 --- /dev/null +++ b/packages/xi/lib/utils/maccms.dart @@ -0,0 +1,63 @@ +import '../adapters/mac_cms.dart'; +import '../interface.dart'; +import 'helper.dart'; + +class PlayListData { + final String title; + + final List datas; + + PlayListData({ + required this.title, + required this.datas, + }); +} + +/// 将 [VideoInfo] 转换为 [PlayListData] +/// 单个 [VideoInfo] 格式参考: +/// - name: 源分类集合 +/// - url: 多个视频播放地址, 通过 `.split("#").split("$")` +/// > 其中 [0] 为名称, [1] 为视频地址 +videoInfo2PlayListData(List cx) { + List result = []; + for (var element in cx) { + var url = element.url; + var hasUrl = isURL(url); + if (hasUrl) { + var output = [element]; + result.add(PlayListData(title: element.name, datas: [])); + var urls = url.split("#"); + if (urls.length >= 2) { + output = urls + .map( + (e) => VideoInfo( + url: e, + type: MacCMSSpider.easyGetVideoType(e), + ), + ) + .toList(); + } + result.last.datas.addAll(output); + } else { + var movies = url.split("#"); + var cache = PlayListData(title: element.name, datas: []); + for (var e in movies) { + var subItem = e.split("\$"); + if (subItem.length <= 1) continue; + var title = subItem[0]; + var url = subItem[1]; + // var subType = subItem[2]; + cache.datas.add(VideoInfo( + name: title, + url: url, + type: MacCMSSpider.easyGetVideoType(url), + )); + } + result.add(cache); + } + } + result = result.where((element) { + return element.datas.isNotEmpty; + }).toList(); + return result; +} diff --git a/packages/xi/lib/utils/utils.dart b/packages/xi/lib/utils/utils.dart index f627777..7f37189 100644 --- a/packages/xi/lib/utils/utils.dart +++ b/packages/xi/lib/utils/utils.dart @@ -4,3 +4,4 @@ export 'json.dart'; export 'path.dart'; export 'source.dart'; export 'xid.dart'; +export 'maccms.dart';