Vision TV+

https://www.visiontv.club/

Simwoodone (12535)06/08 15:26

该用户很懒,什么介绍也没有写!
二维码导入(APP尚未完成该功能)
{
    "bookSourceUrl": "https:\/\/www.visiontv.club\/",
    "bookSourceName": "Vision TV+",
    "enabledExplore": true,
    "enabled": true,
    "bookSourceGroup": "有声漫画",
    "author": "",
    "help": true,
    "html": "<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Vision TV+ - 轻悦时光书源<\/title>\n<\/head>\n<body>\n<\/body>\n\n<script src=\"https:\/\/vc.jd.com\/web\/js\/jquery-3.1.1.min.js\"><\/script>\n<script>\n  var isCookieJar = true;\n  class FlutterJSBridge {\n    constructor() { this.init(); }\n    init() {\n      if (window.flutter_inappwebview) { this.isReady = true; this.CookieJar(); }\n      else { window.addEventListener('flutterInAppWebViewPlatformReady', () => { this.isReady = true; this.CookieJar(); }); }\n    }\n    async CookieJar() { try { await window.flutter_inappwebview.callHandler('CookieJar', isCookieJar); } catch (e) {} }\n    async getDeviceid() { try { return await window.flutter_inappwebview.callHandler('id'); } catch (e) { return \"\"; } }\n    async log(str) { try { return await window.flutter_inappwebview.callHandler('log', str); } catch (e) { return false; } }\n    async showToast(str) { try { return await window.flutter_inappwebview.callHandler('showToast', str); } catch (e) { return false; } }\n    async showLongToast(str) { try { return await window.flutter_inappwebview.callHandler('showLongToast', str); } catch (e) { return false; } }\n    async openurl(url) { try { return await window.flutter_inappwebview.callHandler('openurl', url, \"\"); } catch (e) { return false; } }\n    async startBrowser(url, title, header) { try { return await window.flutter_inappwebview.callHandler('startBrowser', url, title, header); } catch (e) { return \"\"; } }\n    async showvideoplay(url, title, key) { try { return await window.flutter_inappwebview.callHandler('showvideoplay', url, title, key); } catch (e) { return \"\"; } }\n    async webview(url, js, html, body, header) {\n      try { return await window.flutter_inappwebview.callHandler('webview', url, js, html, body, header, \"\", \"\"); }\n      catch (e) { return \"\"; }\n    }\n  }\n\n  class Http {\n    constructor() { this.open = false; this.requestTimestamps = []; this.rateLimit = 5; this.rateLimitWindow = 1000; }\n    async checkRateLimit() {\n      if (!this.open) return;\n      const now = Date.now();\n      this.requestTimestamps = this.requestTimestamps.filter(t => now - t < this.rateLimitWindow);\n      if (this.requestTimestamps.length >= this.rateLimit) {\n        await new Promise(r => setTimeout(r, this.rateLimitWindow - (now - this.requestTimestamps[0])));\n        return this.checkRateLimit();\n      }\n      this.requestTimestamps.push(now);\n    }\n    async Get(url, headers, followRedirects) {\n      try { await this.checkRateLimit(); return await window.flutter_inappwebview.callHandler('http', \"get\", url, \"\", JSON.stringify(headers), followRedirects, \"\"); }\n      catch (e) { return null; }\n    }\n  }\n\n  class Cache {\n    constructor() {}\n    async get(key) { try { return await window.flutter_inappwebview.callHandler('cache.get', key); } catch (e) { return null; } }\n    async set(key, value) { try { return await window.flutter_inappwebview.callHandler('cache.set', key, value); } catch (e) { return null; } }\n    async getLoginInfo() { return await this.get(\"LoginInfo\"); }\n  }\n\n  const flutterBridge = new FlutterJSBridge();\n  const cache = new Cache();\n  const http = new Http();\n\n  const BASE_URL = 'https:\/\/www.visiontv.club';\n  const UA = { 'User-Agent': 'Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/120.0.0.0 Safari\/537.36' };\n\n  function pick() {\n    for (let i = 0; i < arguments.length; i++) {\n      const v = arguments[i];\n      if (v !== undefined && v !== null && String(v) !== '' && String(v) !== 'null') return v;\n    }\n    return '';\n  }\n\n  function asText(res) {\n    if (!res) return '';\n    if (typeof res === 'string') return res;\n    if (typeof res.data === 'string') return res.data;\n    if (typeof res.body === 'string') return res.body;\n    try { return JSON.stringify(res.data); } catch (e) { return ''; }\n  }\n\n  function safeJson(text, fallback) { try { return JSON.parse(text); } catch (e) { return fallback; } }\n\n  async function fetchHtml(url) {\n    var res = await http.Get(url, UA, true);\n    return asText(res);\n  }\n\n  \/\/ All pages need WebView to pass Cloudflare. Use webview() for all data extraction.\n\n  function encodeUrl(type, url) {\n    return 'vistv:\/\/' + type + '?url=' + encodeURIComponent(url);\n  }\n  function decodeUrl(s) {\n    var m = String(s || '').indexOf('url=');\n    if (m < 0) return s;\n    return decodeURIComponent(String(s).slice(m + 4));\n  }\n\n  \/\/ ==================== 搜索 ====================\n  async function search(key, page) {\n    page = page || 1;\n    var keyword = String(key || '').trim();\n    if (!keyword || page > 1) return '[]';\n\n    var url = BASE_URL + '\/index.php\/vod\/search.html?wd=' + encodeURIComponent(keyword);\n    var js = \"(function(){\" +\n      \"var items=document.querySelectorAll('[class*=public-list-box]');\" +\n      \"var r=[];\" +\n      \"for(var i=0;i<items.length;i++){\" +\n      \"var box=items[i];\" +\n      \"var a=box.querySelector('a[href*=\\\"\/detail\/\\\"]');\" +\n      \"var img=box.querySelector('img');\" +\n      \"var btn=box.querySelector('[class*=button]');\" +\n      \"if(a){r.push({\" +\n      \"\\\"href\\\":a.getAttribute('href')||'',\" +\n      \"\\\"title\\\":a.getAttribute('title')||a.textContent.trim().slice(0,30),\" +\n      \"\\\"img\\\":img?(img.getAttribute('src')||''):'',\" +\n      \"\\\"status\\\":btn?btn.textContent.trim():''\" +\n      \"});}\" +\n      \"}\" +\n      \"return JSON.stringify(r);\" +\n      \"})()\";\n\n    var data = await flutterBridge.webview(url, js, '', '', '{}');\n    var list = safeJson(data, []);\n    var result = [];\n    for (var i = 0; i < list.length; i++) {\n      var item = list[i];\n      if (!item.href || !item.title) continue;\n      result.push({\n        bookUrl: encodeUrl('detail', item.href),\n        name: item.title,\n        author: '',\n        kind: '',\n        coverUrl: item.img.indexOf('http') === 0 ? item.img : '',\n        intro: '',\n        tocUrl: encodeUrl('detail', item.href),\n        wordCount: '',\n        type: 0,\n        latestChapterTitle: item.status\n      });\n    }\n    return JSON.stringify(result);\n  }\n\n  \/\/ ==================== 详情 ====================\n  async function info(bookurl) {\n    var detailUrl = decodeUrl(bookurl);\n    if (detailUrl.indexOf('http') !== 0) detailUrl = BASE_URL + detailUrl;\n\n    var js = \"(function(){\" +\n      \"var t=document.title||'';t=t.replace(\/[-_].*Vision.*$\/i,'').trim();\" +\n      \"var c=document.querySelector('img[src*=\\\".jpg\\\"],img[src*=\\\".png\\\"],img[src*=\\\".webp\\\"]');\" +\n      \"var cover=c?c.getAttribute('src'):'';\" +\n      \"var ogd=document.querySelector('meta[property=\\\"og:description\\\"]');\" +\n      \"var intro=ogd?ogd.getAttribute('content'):'';\" +\n      \"var ogt=document.querySelector('meta[property=\\\"og:title\\\"]');\" +\n      \"if(ogt)t=ogt.getAttribute('content');\" +\n      \"return JSON.stringify({name:t,cover:cover,intro:intro});\" +\n      \"})()\";\n\n    var data = await flutterBridge.webview(detailUrl, js, '', '', '{}');\n    var info = safeJson(data, {});\n    return JSON.stringify({\n      bookUrl: bookurl,\n      name: pick(info.name, '未知'),\n      author: '',\n      kind: '',\n      coverUrl: pick(info.cover, ''),\n      intro: pick(info.intro, ''),\n      tocUrl: encodeUrl('detail', detailUrl),\n      wordCount: '',\n      type: 0,\n      latestChapterTitle: ''\n    });\n  }\n\n  \/\/ ==================== 目录 ====================\n  async function chapter(tocUrl, bookurl) {\n    var detailUrl = decodeUrl(tocUrl || bookurl);\n    if (detailUrl.indexOf('http') !== 0) detailUrl = BASE_URL + detailUrl;\n\n    \/\/ Extract play lines and episodes grouped by line\n    var js = \"(function(){\" +\n      \/\/ First, try to find line\/source tabs and their names\n      \"var lineNames={};\" +\n      \"var sourceTabs=document.querySelectorAll('[class*=source] a,[class*=play-source] a,[class*=tab] a,.source-list a,.play-source-tab a');\" +\n      \"for(var i=0;i<sourceTabs.length;i++){\" +\n      \"var tab=sourceTabs[i];\" +\n      \"var sid=tab.getAttribute('data-sid')||tab.getAttribute('data-id')||tab.getAttribute('href');\" +\n      \"if(sid&&sid.match(\/sid[=\/](\\\\d+)\/)){sid=sid.match(\/sid[=\/](\\\\d+)\/)[1];}\" +\n      \"if(!sid)continue;\" +\n      \"var name=tab.textContent.trim();\" +\n      \"if(name&&name.length<20)lineNames[sid]=name;}\" +\n      \/\/ If no tabs found, try to extract sid from episode URLs\n      \"var allLinks=document.querySelectorAll('a[href*=\\\"\/play\/\\\"]');\" +\n      \"var lines={};var allSids={};\" +\n      \"for(var j=0;j<allLinks.length;j++){\" +\n      \"var a=allLinks[j];\" +\n      \"var t=a.textContent.trim();\" +\n      \"var h=a.getAttribute('href');\" +\n      \"if(!h||!t||t.length>50)continue;\" +\n      \"var sidMatch=h.match(\/sid[=\/](\\\\d+)\/);\" +\n      \"var sid=sidMatch?sidMatch[1]:'1';\" +\n      \"allSids[sid]=1;\" +\n      \"if(!lines[sid])lines[sid]=[];\" +\n      \"lines[sid].push({name:t,url:h});}\" +\n      \/\/ Build result with line names as volumes\n      \"var result=[];var sids=Object.keys(allSids).sort();\" +\n      \"for(var k=0;k<sids.length;k++){\" +\n      \"var sid=sids[k];\" +\n      \"var lineName=lineNames[sid]||('播放线路'+sid);\" +\n      \"result.push({name:lineName,url:'',isVolume:true});\" +\n      \"var eps=lines[sid]||[];\" +\n      \"for(var e=0;e<eps.length;e++){\" +\n      \"result.push({name:eps[e].name,url:eps[e].url,isVolume:false});}\" +\n      \"}\" +\n      \"return JSON.stringify(result);\" +\n      \"})()\";\n\n    var data = await flutterBridge.webview(detailUrl, js, '', '', '{}');\n    var eps = safeJson(data, []);\n    var result = [];\n    for (var i = 0; i < eps.length; i++) {\n      if (eps[i].isVolume) {\n        result.push({\n          name: eps[i].name,\n          chapterId: '',\n          index: i,\n          isPay: false, isVip: false, isVolume: true, tag: ''\n        });\n      } else {\n        result.push({\n          name: eps[i].name || ('第' + (i + 1) + '集'),\n          chapterId: encodeUrl('play', eps[i].url),\n          index: i,\n          isPay: false, isVip: false, isVolume: false, tag: ''\n        });\n      }\n    }\n    return JSON.stringify(result);\n  }\n\n  \/\/ ==================== 正文 ====================\n  async function content(url, bookurl) {\n    var playUrl = decodeUrl(url);\n    if (playUrl.indexOf('http') !== 0) playUrl = BASE_URL + playUrl;\n\n    var js = \"(function(){\" +\n      \"var scripts=document.querySelectorAll('script');\" +\n      \"for(var i=0;i<scripts.length;i++){\" +\n      \"var t=scripts[i].textContent||'';\" +\n      \"var m=t.match(\/player_\\\\w+\\\\s*=\\\\s*(\\\\{[^;]+\\\\});?\/);\" +\n      \"if(m){\" +\n      \"try{var d=JSON.parse(m[1]);if(d.url)return d.url.replace(\/\\\\\\\\\\\\\/\/g,'\/');}catch(e){}\" +\n      \"}\" +\n      \"m=t.match(\/thisUrl\\\\s*=\\\\s*\\\"([^\\\"]+?)\\\"\/);\" +\n      \"if(m)return m[1];\" +\n      \"}\" +\n      \"var iframes=document.querySelectorAll('iframe');\" +\n      \"for(var j=0;j<iframes.length;j++){\" +\n      \"var s=iframes[j].getAttribute('src');\" +\n      \"if(s&&(s.indexOf('m3u8')>-1||s.indexOf('.mp4')>-1))return s;}\" +\n      \"return '';\" +\n      \"})()\";\n\n    try {\n      var videoUrl = await flutterBridge.webview(playUrl, js, '', '', '{}');\n      videoUrl = (videoUrl || '').trim();\n      if (videoUrl) {\n        return '<img src=\"data:image\/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIiB2aWV3Qm94PSIwIDAgMjMgMjgiPjxkZWZzPjxmaWx0ZXIgaWQ9InMiPjxmZURyb3BTaGFkb3cgZHg9IjAiIGR5PSIwLjYiIHN0ZERldmlhdGlvbj0iMC43IiBmbG9vZC1jb2xvcj0iIzAwMCIgZmxvb2Qtb3BhY2l0eT0iMC4zNSIvPjwvZmlsdGVyPjwvZGVmcz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0LjUsNCkiPjxwYXRoIGQ9Ik0wIDBoMTR2MTRIMHoiIGZpbGw9Im5vbmUiLz48ZyBmaWxsPSJub25lIj48cGF0aCBmaWxsPSIjMjg1OWM1IiBkPSJNNC41IDguODgyVjUuMTE4YTEgMSAwIDAgMSAxLjQ0Ny0uODk0bDMuNzY0IDEuODgyYTEgMSAwIDAgMSAwIDEuNzg4TDUuOTQ3IDkuNzc2QTEgMSAwIDAgMSA0LjUgOC44ODIiLz48cGF0aCBmaWxsPSIjOGZiZmZhIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik04LjA5LjA4NGEuNzUuNzUgMCAwIDAtLjIzMiAxLjQ4MkE1LjUwMiA1LjUwMiAwIDAgMSA3IDEyLjVhNS41IDUuNSAwIDAgMS01LjExNi0zLjQ3NWEuNzUuNzUgMCAwIDAtMS4zOTQuNTUyQTcuMDAyIDcuMDAyIDAgMCAwIDE0IDdBNyA3IDAgMCAwIDguMDkuMDg0bS0yLjQ2NiAxLjQ5QS43NS43NSAwIDAgMCA1LjI1MS4xMjNhNyA3IDAgMCAwLS45MzguMzE0YS43NS43NSAwIDAgMCAuNTc2IDEuMzg1cS4zNTYtLjE0OC43MzUtLjI0Nk0zLjE3IDIuOTU1YS43NS43NSAwIDAgMC0xLjA0NC0xLjA3NkE3IDcgMCAwIDAgLjkxNyAzLjQzNWEuNzUuNzUgMCAxIDAgMS4zMDMuNzQ0Yy4yNTgtLjQ1Mi41NzgtLjg2NC45NS0xLjIyNE0xLjU1NCA2LjEyN2EuNzUuNzUgMCAxIDAtMS40ODUtLjIxQTcgNyAwIDAgMCAwIDYuOTAzYS43NS43NSAwIDEgMCAxLjUgMHEwLS4zOTYuMDU0LS43NzYiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvZz48L2c+PHRleHQgeD0iMTEuNSIgeT0iMjUuNSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1zaXplPSIxLjMiIGZvbnQtZmFtaWx5PSJzeXN0ZW0tdWksLWFwcGxlLXN5c3RlbSxQaW5nRmFuZyBTQyxNaWNyb3NvZnQgWWFIZWksc2Fucy1zZXJpZiIgZmlsbD0iIzI4NTljNSIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbHRlcj0idXJsKCNzKSI+54K55Ye75pKt5pS+PC90ZXh0Pjwvc3ZnPg==,{&quot;js&quot;:&quot;flutterBridge.showvideoplay(\\''+videoUrl+'\\',\\'Vision TV+\\',\\''+videoUrl+'\\')&quot;}\"\/>';\n      }\n      return '未找到视频地址\\n' + playUrl;\n    } catch (e) {\n      return '加载失败: ' + e.message;\n    }\n  }\n\n  \/\/ ==================== 发现 ====================\n  async function getfinds() {\n    var finds = [];\n\n    function addSection(title) {\n      finds.push({ title: title, url: '', width: 3 });\n    }\n    function addItem(title, url) {\n      finds.push({ title: title, url: url, type: 0, width: 0 });\n    }\n\n    \/\/ === 频道 ===\n    addSection('📺 频道');\n    var channels = [\n      ['电影', '\/index.php\/vod\/type\/id\/1.html'],\n      ['电视剧', '\/index.php\/vod\/type\/id\/2.html'],\n      ['综艺', '\/index.php\/vod\/type\/id\/3.html'],\n      ['动漫', '\/index.php\/vod\/type\/id\/4.html'],\n      ['纪录片', '\/index.php\/vod\/type\/id\/5.html'],\n      ['短剧', '\/index.php\/vod\/type\/id\/6.html'],\n    ];\n    for (var i = 0; i < channels.length; i++) {\n      addItem(channels[i][0], BASE_URL + channels[i][1] + '?page={{page}}');\n    }\n\n    \/\/ === 类型 ===\n    addSection('🏷️ 类型');\n    var types = ['动作', '喜剧', '爱情', '科幻', '恐怖', '剧情', '战争', '动画', '纪录', '犯罪', '悬疑', '奇幻', '冒险'];\n    for (var j = 0; j < types.length; j++) {\n      addItem(types[j], BASE_URL + '\/index.php\/vod\/search.html?class=' + encodeURIComponent(types[j]) + '&page={{page}}');\n    }\n\n    \/\/ === 地区 ===\n    addSection('🌍 地区');\n    var areas = ['中国大陆', '中国香港', '中国台湾', '日本', '韩国', '美国', '英国', '法国', '德国', '泰国', '印度', '其他'];\n    for (var k = 0; k < areas.length; k++) {\n      addItem(areas[k], BASE_URL + '\/index.php\/vod\/search.html?area=' + encodeURIComponent(areas[k]) + '&page={{page}}');\n    }\n\n    \/\/ === 年份 ===\n    addSection('📅 年份');\n    var years = ['2026', '2025', '2024', '2023', '2022', '2021', '2020', '2019', '2018', '2017', '2016', '2015', '更早'];\n    for (var y = 0; y < years.length; y++) {\n      addItem(years[y], BASE_URL + '\/index.php\/vod\/search.html?year=' + years[y] + '&page={{page}}');\n    }\n\n    \/\/ === 语言 ===\n    addSection('🔊 语言');\n    var langs = ['国语', '英语', '日语', '韩语', '粤语', '法语', '德语', '泰语', '西班牙语', '其他'];\n    for (var l = 0; l < langs.length; l++) {\n      addItem(langs[l], BASE_URL + '\/index.php\/vod\/search.html?lang=' + encodeURIComponent(langs[l]) + '&page={{page}}');\n    }\n\n    \/\/ === 字母 ===\n    addSection('🔤 字母');\n    var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');\n    for (var a = 0; a < letters.length; a++) {\n      addItem(letters[a], BASE_URL + '\/index.php\/vod\/search.html?letter=' + letters[a] + '&page={{page}}');\n    }\n\n    finds.push({ title: '', url: '', width: 0 });\n    finds.push({ title: '🔍 首次使用请先登录过CF', url: '', width: 3 });\n\n    return JSON.stringify(finds);\n  }\n\n  \/\/ ==================== 发现搜索 ====================\n  async function find(url, page) {\n    page = page || 1;\n    var realUrl = String(url || '').replace(\/\\{\\{page\\}\\}\/g, String(page));\n    if (!realUrl) return '[]';\n\n    var js = \"(function(){\" +\n      \"var items=document.querySelectorAll('[class*=public-list-box]');\" +\n      \"var r=[];\" +\n      \"for(var i=0;i<items.length;i++){\" +\n      \"var box=items[i];\" +\n      \"var a=box.querySelector('a[href*=\\\"\/detail\/\\\"]');\" +\n      \"var img=box.querySelector('img');\" +\n      \"var btn=box.querySelector('[class*=button]');\" +\n      \"if(a){r.push({\" +\n      \"\\\"href\\\":a.getAttribute('href')||'',\" +\n      \"\\\"title\\\":a.getAttribute('title')||a.textContent.trim().slice(0,30),\" +\n      \"\\\"img\\\":img?(img.getAttribute('src')||''):'',\" +\n      \"\\\"status\\\":btn?btn.textContent.trim():''\" +\n      \"});}\" +\n      \"}\" +\n      \"return JSON.stringify(r);\" +\n      \"})()\";\n\n    var data = await flutterBridge.webview(realUrl, js, '', '', '{}');\n    var list = safeJson(data, []);\n    var result = [];\n    for (var i = 0; i < list.length; i++) {\n      var item = list[i];\n      if (!item.href || !item.title) continue;\n      result.push({\n        bookUrl: encodeUrl('detail', item.href),\n        name: item.title, author: '', kind: '',\n        coverUrl: item.img.indexOf('http') === 0 ? item.img : '',\n        intro: '', tocUrl: encodeUrl('detail', item.href),\n        wordCount: '', type: 0, latestChapterTitle: item.status\n      });\n    }\n    return JSON.stringify(result);\n  }\n\n  async function getloginurl() {\n    \/\/ 通过搜索页过CF验证(默认搜索词\"我的\")\n    return BASE_URL + '\/index.php\/vod\/search.html?wd=' + encodeURIComponent('我的');\n  }\n  async function login() {\n    await flutterBridge.showToast('CF 验证完成,可以正常使用了');\n  }\n  async function pay(bookurl, url) {}\n  async function imagedecrypt(url, image) { return []; }\n  async function shouldOverrideUrlLoading(url) { return true; }\n  async function gethelp() {\n    return 'Vision TV+ v1.2 轻悦时光版(内置播放器)\\n\\n所有页面通过WebView过CF\\n正文调用内置播放器播放\\n搜索\/发现\/正文全覆盖';\n  }\n<\/script>\n<\/html>\n",
    "login": true,
    "lastUpdateTime": "1780903584517"
}
广告