懒人听书app本地源(同人)

https://m.lrts.me/

ah-fa-fa (14292)4天前

更新tg群组链接,被盗了。懒人听书app本地源,需要自己有懒人听书会员,下载安卓8.8.03版本,登录进行抓包填入登录页信息保存,使用自己账号,听书。只有会员才能听上🔒的

二维码导入
{
    "bookSourceComment": "需要自己有懒人听书会员,下载安卓8.8.03版本,登录进行抓包填入登录页信息,使用自己账号,听书。只有会员才能听上🔒的\n1045801523群号\n纯免费,盗版源\ntg:https:\/\/t.me\/+1F9ippiIxbVmZmM1",
    "bookSourceGroup": "懒人听书,app,api",
    "bookSourceName": "懒人听书app本地源(同人)",
    "bookSourceType": 1,
    "bookSourceUrl": "https:\/\/m.lrts.me\/",
    "customButton": false,
    "customOrder": -123,
    "enabled": true,
    "enabledCookieJar": false,
    "enabledExplore": true,
    "eventListener": false,
    "exploreUrl": "@js:\n\nvar items=[];\nvar wide={layout_flexGrow:1,layout_flexBasisPercent:1};\nvar cell={layout_flexGrow:1,layout_flexBasisPercent:0.25};\nfunction add(title,url,style){items.push({title:String(title),url:url,style:style||cell});}\nfunction onePageUrl(hostKind,path,params,setup){\n  return \"@js:\\n\"+\n    \"\\n\"+\n    (setup||\"\")+\n    \"var out=null;if(Number(page||1)===1)out=\"+(hostKind===\"feed\"?\"lrtsFeedUrl\":\"lrtsUrl\")+\"(java,source,\"+JSON.stringify(path)+\",\"+JSON.stringify(params||{})+\");out;\";\n}\nfunction feedPageUrl(path,params){\n  return \"@js:\\n\"+\n    \"\\n\"+\n    \"var p=Number(page||1),refer=p===1?'':String(source.get('lrts_feed_refer')||'end');\\n\"+\n    \"if(p===1)source.put('lrts_feed_refer','');\\n\"+\n    \"var args=\"+JSON.stringify(params||{})+\";if(p>1&&\"+JSON.stringify(path)+\"==='\/lrts\/cgi\/homepage\/homePageFeedList'){args.showRankModule='0';args.size='20';}args.referId=refer;var out=null;if(refer!=='end')out=lrtsFeedUrl(java,source,\"+JSON.stringify(path)+\",args);out;\";\n}\nfunction categoryUrl(entityId){\n  return \"@js:\\n\"+\n    \"\\n\"+\n    \"var eid=\"+JSON.stringify(entityId)+\";\\n\"+\n    \"var out=null;\\n\"+\n    \"if(page==1){source.put('lrts_book_ids','');out=lrtsUrl(java,source,'\/yyting\/label\/filterResources.action',{dsize:'20',entityId:eid,entityType:'3',pageNum:'1',showFilters:'1'});}else{var ids=String(source.get('lrts_book_ids')||'').split(',').filter(function(x){return x;});var start=(page-1)*20;var part=ids.slice(start,start+20);if(part.length){out=lrtsUrl(java,source,'\/yyting\/label\/filterResources.action',{bookIds:'['+part.join(',')+']',dsize:'20',entityId:'0',entityType:'0',pageNum:'0',showFilters:'0'});}}\\n\"+\n    \"out;\";\n}\nadd(\"推荐\",feedPageUrl(\"\/lrts\/cgi\/homepage\/homePageFeedList\",{recommendedSwitch:\"0\",showRankModule:\"1\",size:\"26\"}),cell);\nadd(\"小说\",onePageUrl(\"api\",\"\/yyting\/page\/novelChannelPage\",{channelId:\"50000152\",channelShowStyle:\"5\",preferenceType:\"\",recommendedSwitch:\"0\",respType:\"0\"}),cell);\nadd(\"会员\",onePageUrl(\"feed\",\"\/lrts\/cgi\/homepage\/vipPage\",{}),cell);\nadd(\"儿童\",feedPageUrl(\"\/lrts\/cgi\/homepage\/childrenChannelPageFeedList\",{category:\"0\",channelId:\"5337203\",recommendedSwitch:\"0\",size:\"20\"}),cell);\nadd(\"音乐\",onePageUrl(\"api\",\"\/yyting\/musicradio\/channelPage\",{hv:\"1.434.0\"},\"source.put('lrts_music_tab','');\\n\"),cell);\nadd(\"榜单\",onePageUrl(\"api\",\"\/yyting\/ranking\/resList.action\",{filterType:\"0\",pageNum:\"1\",pageSize:\"100\",rangeType:\"6\",rankId:\"14680\"}),cell);\n\nadd(\"儿童分类\",null,wide);\ntry{\n  var childBody=JSON.parse(String(java.ajax(lrtsFeedUrl(java,source,\"\/lrts\/cgi\/homepage\/childrenChannelMenuList\",{channelId:\"5337203\"}))));\n  (childBody.data&&childBody.data.categoryList||[]).forEach(function(category){\n    add(category.categoryName,feedPageUrl(\"\/lrts\/cgi\/homepage\/childrenChannelPageFeedList\",{category:String(category.category),channelId:\"5337203\",recommendedSwitch:\"0\",size:\"20\"}),cell);\n  });\n}catch(e){java.log(\"懒人听书儿童分类加载失败: \"+e);}\n\nadd(\"音乐频道\",null,wide);\ntry{\n  var musicBody=JSON.parse(String(java.ajax(lrtsUrl(java,source,\"\/yyting\/musicradio\/channelPage\",{hv:\"1.434.0\"}))));\n  (musicBody.data&&musicBody.data.tabList||[]).forEach(function(tab){\n    add(tab.name,onePageUrl(\"api\",\"\/yyting\/musicradio\/recMusicService\/fetchMusicList\",{id:String(tab.id),referId:\"\",pageSize:\"20\"}),cell);\n  });\n}catch(e){java.log(\"懒人听书音乐频道加载失败: \"+e);}\n\nadd(\"榜单\",null,wide);\ntry{\n  var rankBody=JSON.parse(String(java.ajax(lrtsUrl(java,source,\"\/yyting\/ranking\/rankingsGroupList.action\",{groupId:\"0\",groupType:\"1\",recommendedSwitch:\"8\"}))));\n  (rankBody.data&&rankBody.data.list||[]).forEach(function(group){\n    var groupName=group.rankingsGroupInfoView&&group.rankingsGroupInfoView.name||\"榜单\";\n    add(groupName,null,wide);\n    (group.rankingsList||[]).forEach(function(rank){\n      var rankType=Number(rank.rankType||0);\n      var rankUrl;\n      if(rankType===10){\n        rankUrl=\"@js:\\n\"+\n          \"\\n\"+\n          \"var p=Number(page||1);lrtsUrl(java,source,'\/yyting\/music\/rankingsItemList.action',{filterType:\"+JSON.stringify(String(rank.filterType))+\",pageNum:String(p),pageSize:'100',rangeType:\"+JSON.stringify(String(rank.rangeType))+\",rankId:\"+JSON.stringify(String(rank.rankId))+\"});\";\n      }else if(rankType===2){\n        rankUrl=null;\n      }else{\n        rankUrl=\"@js:\\n\"+\n          \"\\n\"+\n          \"var p=Number(page||1);lrtsUrl(java,source,'\/yyting\/ranking\/resList.action',{filterType:\"+JSON.stringify(String(rank.filterType))+\",pageNum:String(p),pageSize:'100',rangeType:\"+JSON.stringify(String(rank.rangeType))+\",rankId:\"+JSON.stringify(String(rank.rankId))+\"});\";\n      }\n      if(rankUrl)add(rank.rankName,rankUrl,cell);\n    });\n  });\n}catch(e){java.log(\"懒人听书榜单加载失败: \"+e);}\n\n[{id:\"9011\",title:\"分类标签 · 男频\"},{id:\"9012\",title:\"分类标签 · 女频\"}].forEach(function(group){\n  add(group.title,null,wide);\n  try{\n    var body=JSON.parse(String(java.ajax(lrtsUrl(java,source,\"\/yyting\/label\/labelList.action\",{id:group.id,showLocation:\"2\"}))));\n    (body.data&&body.data.list||[]).forEach(function(label,index){\n      add(label.name,categoryUrl(group.id+\"_\"+label.id),cell);\n    });\n  }catch(e){java.log(\"懒人听书分类标签加载失败: \"+e);}\n});\nJSON.stringify(items);",
    "header": "{\"User-Agent\":\"Android16\/yyting\/Xiaomi\/2509FPN0BC\/ch_qq_appcenter\/8803\/Android\"}",
    "jsLib": "var LR_BASE=\"https:\/\/gzapi.mting.info\";\nvar LR_FEED_BASE=LR_BASE.replace(\".mting.info\",\".lanrentingshu.com\");\nvar LR_APP_BASE=\"https:\/\/shapi.mting.info\";\nvar LR_SALT=\"vYCmm+6CFVykQk5w0wiUDliCQRA=\";\nvar LR_SESSION_KEYS=[\"token\",\"imei\",\"nwt\",\"mode\",\"lrid\",\"ostar36\",\"userMode\",\"duId\"];\nfunction lrtsResolveSession(source,java) {\n  var raw=String(source.get(\"lrts_session\")||\"\").trim();\n  if(!raw){\n    throw new Error(\"本书源不含内置账号,请先在书源登录中填写本人抓包的 8 项会话参数\");\n  }\n  var custom;\n  try{\n    custom=JSON.parse(raw);\n  }catch(parseError){\n    throw new Error(\"个人抓包会话格式无效,请在书源登录中重新填写并保存\");\n  }\n  var candidate={};\n  var missing=[];\n  LR_SESSION_KEYS.forEach(function(key){\n    var value=custom[key];\n    if(value===null||value===undefined||String(value).trim()===\"\")missing.push(key);\n    else candidate[key]=String(value).trim();\n  });\n  if(missing.length){\n    throw new Error(\"个人抓包会话缺少参数:\"+missing.join(\"、\")+\",请在书源登录中补全\");\n  }\n  return candidate;\n}\nfunction lrtsSignedUrl(java, source, base, path, params) {\n  params=params||{};\n  var LR_SESSION=lrtsResolveSession(source,java);\n  Object.keys(LR_SESSION).forEach(function(key){\n    if(LR_SESSION[key]!==null&&LR_SESSION[key]!==undefined&&LR_SESSION[key]!==\"\") params[key]=String(LR_SESSION[key]);\n  });\n  var q=parseInt(String(source.get(\"lrts_q\")||\"0\"),10);\n  if(!isFinite(q)||q<0) q=0;\n  q=q+1;\n  source.put(\"lrts_q\",String(q));\n  params.q=String(q);\n  params.ts=String(Date.now());\n  var keys=Object.keys(params).filter(function(key){return params[key]!==null&&params[key]!==undefined;}).sort();\n  var canonical=path+\"?\"+keys.map(function(key){return key+\"=\"+String(params[key]);}).join(\"&\");\n  params.sc=String(java.md5Encode(canonical+LR_SALT));\n  return base+path+\"?\"+Object.keys(params).filter(function(key){return params[key]!==null&&params[key]!==undefined;}).map(function(key){return encodeURIComponent(key)+\"=\"+encodeURIComponent(String(params[key]));}).join(\"&\");\n}\nfunction lrtsUrl(java, source, path, params) { return lrtsSignedUrl(java,source,LR_BASE,path,params); }\nfunction lrtsFeedUrl(java, source, path, params) { return lrtsSignedUrl(java,source,LR_FEED_BASE,path,params); }\nfunction lrtsAppUrl(java, source, path, params) { return lrtsSignedUrl(java,source,LR_APP_BASE,path,params); }\n\/\/ QMC eKey decryption for Legado's Rhino runtime.\n\/\/ Decrypted bytes are returned through the audio player's JSON-array data source.\nfunction lrtsU8(value) {\n  return Number(value) & 255;\n}\n\nfunction lrtsSetByte(bytes, index, value) {\n  value = Number(value) & 255;\n  bytes[index] = value > 127 ? value - 256 : value;\n}\n\nfunction lrtsReadU32BE(bytes, offset) {\n  return (((lrtsU8(bytes[offset]) << 24) |\n    (lrtsU8(bytes[offset + 1]) << 16) |\n    (lrtsU8(bytes[offset + 2]) << 8) |\n    lrtsU8(bytes[offset + 3])) >>> 0);\n}\n\nfunction lrtsWriteU32BE(output, offset, value) {\n  output[offset] = (value >>> 24) & 255;\n  output[offset + 1] = (value >>> 16) & 255;\n  output[offset + 2] = (value >>> 8) & 255;\n  output[offset + 3] = value & 255;\n}\n\nfunction lrtsTeaDecryptBlock(input, key) {\n  var left = lrtsReadU32BE(input, 0);\n  var right = lrtsReadU32BE(input, 4);\n  var words = [\n    lrtsReadU32BE(key, 0),\n    lrtsReadU32BE(key, 4),\n    lrtsReadU32BE(key, 8),\n    lrtsReadU32BE(key, 12)\n  ];\n  var sum = 0xe3779b90;\n  for (var round = 0; round < 16; round++) {\n    var rightMix = ((((left << 4) + words[2]) ^\n      (left + sum) ^ ((left >>> 5) + words[3])) >>> 0);\n    right = (right - rightMix) >>> 0;\n    var leftMix = ((((right << 4) + words[0]) ^\n      (right + sum) ^ ((right >>> 5) + words[1])) >>> 0);\n    left = (left - leftMix) >>> 0;\n    sum = (sum - 0x9e3779b9) >>> 0;\n  }\n  var output = new Array(8);\n  lrtsWriteU32BE(output, 0, left);\n  lrtsWriteU32BE(output, 4, right);\n  return output;\n}\n\nfunction lrtsSliceBytes(bytes, start, end) {\n  var output = [];\n  var limit = Math.min(Number(end), bytes.length);\n  for (var index = Number(start); index < limit; index++) output.push(lrtsU8(bytes[index]));\n  return output;\n}\n\nfunction lrtsXorBlock(left, right) {\n  var output = new Array(8);\n  for (var index = 0; index < 8; index++) output[index] = lrtsU8(left[index]) ^ lrtsU8(right[index]);\n  return output;\n}\n\nfunction lrtsTencentTeaDecrypt(input, key) {\n  if (input.length < 16 || input.length % 8 !== 0) throw new Error(\"QMC TEA data length is invalid\");\n  var decrypted = lrtsTeaDecryptBlock(lrtsSliceBytes(input, 0, 8), key);\n  var padding = decrypted[0] & 7;\n  var outputLength = input.length - 1 - padding - 2 - 7;\n  if (outputLength < 0) throw new Error(\"QMC TEA padding is invalid\");\n  var output = new Array(outputLength);\n  var previousCipher = [0, 0, 0, 0, 0, 0, 0, 0];\n  var currentCipher = lrtsSliceBytes(input, 0, 8);\n  var inputOffset = 8;\n  var blockOffset = 1 + padding;\n\n  function nextBlock() {\n    previousCipher = currentCipher;\n    currentCipher = lrtsSliceBytes(input, inputOffset, inputOffset + 8);\n    decrypted = lrtsTeaDecryptBlock(lrtsXorBlock(decrypted, currentCipher), key);\n    inputOffset += 8;\n    blockOffset = 0;\n  }\n\n  for (var skipped = 0; skipped < 2;) {\n    if (blockOffset < 8) {\n      blockOffset++;\n      skipped++;\n    } else {\n      nextBlock();\n    }\n  }\n  for (var outputOffset = 0; outputOffset < outputLength;) {\n    if (blockOffset < 8) {\n      output[outputOffset++] = decrypted[blockOffset] ^ previousCipher[blockOffset];\n      blockOffset++;\n    } else {\n      nextBlock();\n    }\n  }\n  for (var zeroIndex = 0; zeroIndex < 7; zeroIndex++) {\n    if (decrypted[blockOffset] !== previousCipher[blockOffset]) {\n      throw new Error(\"QMC TEA zero check failed\");\n    }\n    blockOffset++;\n  }\n  return output;\n}\n\nfunction lrtsAsciiBytes(text) {\n  var output = new Array(String(text).length);\n  for (var index = 0; index < output.length; index++) output[index] = String(text).charCodeAt(index) & 255;\n  return output;\n}\n\nfunction lrtsBase64Bytes(java, text) {\n  var javaBytes = java.base64DecodeToByteArray(String(text));\n  var output = new Array(javaBytes.length);\n  for (var index = 0; index < javaBytes.length; index++) output[index] = lrtsU8(javaBytes[index]);\n  return output;\n}\n\nfunction lrtsBytesToAscii(bytes) {\n  var output = \"\";\n  for (var index = 0; index < bytes.length; index += 256) {\n    var part = bytes.slice(index, Math.min(index + 256, bytes.length));\n    output += String.fromCharCode.apply(String, part);\n  }\n  return output;\n}\n\nfunction lrtsStartsWithBytes(bytes, prefix) {\n  if (bytes.length < prefix.length) return false;\n  for (var index = 0; index < prefix.length; index++) {\n    if (lrtsU8(bytes[index]) !== lrtsU8(prefix[index])) return false;\n  }\n  return true;\n}\n\nfunction lrtsSimpleKey(salt, length) {\n  var output = new Array(length);\n  for (var index = 0; index < length; index++) {\n    output[index] = Math.floor(Math.abs(Math.tan(salt + index * 0.1)) * 100) & 255;\n  }\n  return output;\n}\n\nfunction lrtsDeriveQmcKey(java, eKey) {\n  var raw = lrtsBase64Bytes(java,eKey);\n  var v2Prefix = lrtsAsciiBytes(\"QQMusic EncV2,Key:\");\n  if (lrtsStartsWithBytes(raw, v2Prefix)) {\n    raw = raw.slice(v2Prefix.length);\n    raw = lrtsTencentTeaDecrypt(raw, lrtsAsciiBytes(\"386ZJY!@#*$%^&)(\"));\n    raw = lrtsTencentTeaDecrypt(raw, lrtsAsciiBytes(\"**#!(#$%&^a1cZ,T\"));\n    raw = lrtsBase64Bytes(java,lrtsBytesToAscii(raw));\n  }\n  if (raw.length < 16) throw new Error(\"QMC eKey is too short\");\n  var simpleKey = lrtsSimpleKey(106, 8);\n  var teaKey = new Array(16);\n  for (var index = 0; index < 8; index++) {\n    teaKey[index * 2] = simpleKey[index];\n    teaKey[index * 2 + 1] = raw[index];\n  }\n  return raw.slice(0, 8).concat(lrtsTencentTeaDecrypt(raw.slice(8), teaKey));\n}\n\nfunction lrtsImulU32(left, right) {\n  var low = left & 65535;\n  var high = (left >>> 16) & 65535;\n  return ((low * right + (((high * right) & 65535) << 16)) >>> 0);\n}\n\nfunction lrtsQmcDecrypt(java, bytes, eKey) {\n  var key = lrtsDeriveQmcKey(java,eKey);\n  if (key.length <= 300) {\n    for (var mapIndex = 0; mapIndex < bytes.length; mapIndex++) {\n      var mapOffset = mapIndex > 0x7fff ? mapIndex % 0x7fff : mapIndex;\n      var keyIndex = (mapOffset * mapOffset + 71214) % key.length;\n      var rotate = ((keyIndex & 7) + 4) % 8;\n      var value = key[keyIndex];\n      var mapMask = ((value << rotate) | (value >>> rotate)) & 255;\n      lrtsSetByte(bytes, mapIndex, lrtsU8(bytes[mapIndex]) ^ mapMask);\n    }\n    return key.length;\n  }\n\n  var size = key.length;\n  var box = new Array(size);\n  var cursor = 0;\n  var index;\n  for (index = 0; index < size; index++) box[index] = index & 255;\n  for (index = 0; index < size; index++) {\n    cursor = (cursor + box[index] + key[index % size]) % size;\n    var swap = box[index];\n    box[index] = box[cursor];\n    box[cursor] = swap;\n  }\n  var hash = 1;\n  for (index = 0; index < key.length; index++) {\n    if (key[index] === 0) continue;\n    var nextHash = lrtsImulU32(hash, key[index]);\n    if (nextHash === 0 || nextHash <= hash) break;\n    hash = nextHash;\n  }\n\n  function segmentSkip(id) {\n    var seed = key[id % size];\n    if (!seed) throw new Error(\"QMC RC4 seed is zero\");\n    return Math.floor((hash \/ ((id + 1) * seed)) * 100) % size;\n  }\n\n  function firstSegment(position, length, offset) {\n    for (var firstIndex = 0; firstIndex < length; firstIndex++) {\n      lrtsSetByte(bytes, position + firstIndex,\n        lrtsU8(bytes[position + firstIndex]) ^ key[segmentSkip(offset + firstIndex)]);\n    }\n  }\n\n  function segment(position, length, offset) {\n    var segmentBox = box.slice(0);\n    var left = 0;\n    var right = 0;\n    var skip = (offset % 5120) + segmentSkip(Math.floor(offset \/ 5120));\n    for (var segmentIndex = -skip; segmentIndex < length; segmentIndex++) {\n      left = (left + 1) % size;\n      right = (segmentBox[left] + right) % size;\n      var segmentSwap = segmentBox[left];\n      segmentBox[left] = segmentBox[right];\n      segmentBox[right] = segmentSwap;\n      if (segmentIndex >= 0) {\n        var mask = segmentBox[(segmentBox[left] + segmentBox[right]) % size];\n        lrtsSetByte(bytes, position + segmentIndex,\n          lrtsU8(bytes[position + segmentIndex]) ^ mask);\n      }\n    }\n  }\n\n  var offset = 0;\n  var processed = 0;\n  var remaining = bytes.length;\n  function advance(length) {\n    offset += length;\n    processed += length;\n    remaining -= length;\n  }\n  if (offset < 128) {\n    var firstLength = Math.min(remaining, 128 - offset);\n    firstSegment(0, firstLength, offset);\n    advance(firstLength);\n  }\n  if (remaining && offset % 5120 !== 0) {\n    var partialLength = Math.min(remaining, 5120 - (offset % 5120));\n    segment(processed, partialLength, offset);\n    advance(partialLength);\n  }\n  while (remaining > 5120) {\n    segment(processed, 5120, offset);\n    advance(5120);\n  }\n  if (remaining) segment(processed, remaining, offset);\n  return key.length;\n}\n\nfunction lrtsAudioFormat(bytes) {\n  var head = \"\";\n  for (var index = 0; index < Math.min(4, bytes.length); index++) head += String.fromCharCode(lrtsU8(bytes[index]));\n  if (head === \"OggS\") return { mime: \"audio\/ogg\", ext: \"ogg\" };\n  if (head === \"fLaC\") return { mime: \"audio\/flac\", ext: \"flac\" };\n  if (head.substring(0, 3) === \"ID3\" || (bytes.length > 1 && lrtsU8(bytes[0]) === 255 && (lrtsU8(bytes[1]) & 224) === 224)) {\n    return { mime: \"audio\/mpeg\", ext: \"mp3\" };\n  }\n  throw new Error(\"QMC decrypted data has an unsupported header\");\n}\n\nfunction lrtsAudioDataSource(bytes, format) {\n  var encoded = String(Packages.android.util.Base64.encodeToString(bytes, 2) || \"\");\n  if (!encoded) throw new Error(\"QMC audio Base64 encoding failed\");\n  return JSON.stringify([\"data:\" + format.mime + \";base64,\" + encoded]);\n}\n\nfunction lrtsLoadAllCatalog(java, source, marker) {\n  var bookId=String(marker.bookId||\"\");\n  var entityType=String(marker.entityType||\"1\");\n  var total=parseInt(String(marker.sections||\"0\"),10);\n  var pageSize=1000;\n  var pageCount=isFinite(total)&&total>0?Math.ceil(total\/pageSize):100;\n  var all=[];\n  if(!bookId)throw new Error(\"目录标记缺少 bookId\");\n  for(var pageNum=1;pageNum<=pageCount;pageNum++){\n    var body=null;\n    var lastError=null;\n    for(var attempt=0;attempt<2;attempt++){\n      try{\n        var pageUrl=lrtsAppUrl(java,source,\"\/yyting\/bookclient\/ClientGetBookResource.action\",{\n          bookId:bookId,\n          isUp:\"0\",\n          pageNum:String(pageNum),\n          pageSize:String(pageSize),\n          sceneId:\"B3\",\n          sortType:\"0\"\n        });\n        body=JSON.parse(String(java.ajax(pageUrl)||\"{}\"));\n        if(!body||!Array.isArray(body.list))throw new Error(String(body&&body.msg||\"目录响应缺少 list\"));\n        lastError=null;\n        break;\n      }catch(error){lastError=error;}\n    }\n    if(lastError)throw new Error(\"第\"+pageNum+\"页目录获取失败: \"+lastError);\n    var list=body.list||[];\n    if(!list.length)break;\n    for(var index=0;index<list.length;index++){\n      var item=list[index];\n      item._lrtsBookId=bookId;\n      item._lrtsEntityType=entityType;\n      all.push(item);\n    }\n    if(list.length<pageSize)break;\n  }\n  if(isFinite(total)&&total>0&&all.length<total){\n    throw new Error(\"目录不完整: \"+all.length+\"\/\"+total);\n  }\n  if(isFinite(total)&&total>0&&all.length>total)all=all.slice(0,total);\n  return all;\n}\n",
    "lastUpdateTime": "1786458192175",
    "loginUi": "@js:\nfunction lrtsSavedSession(){\n  try{return JSON.parse(String(source.get(\"lrts_session\")||\"{}\"));}catch(e){return {};}\n}\nvar saved=lrtsSavedSession();\nvar full={layout_flexGrow:1,layout_flexBasisPercent:1};\nvar half={layout_flexGrow:1,layout_flexBasisPercent:0.46};\nfunction field(name,type,style){\n  return {name:name,type:type,default:String(saved[name]||\"\"),style:style||full};\n}\nresult=JSON.stringify([\n  {name:\"请抓包懒人听书app版本为8.8.03的信息\",type:\"button\",action:\"lrtsCaptureTip()\",style:full},\n  field(\"token\",\"password\",full),\n  field(\"imei\",\"password\",full),\n  field(\"lrid\",\"password\",full),\n  field(\"duId\",\"password\",full),\n  field(\"ostar36\",\"password\",full),\n  field(\"userMode\",\"text\",full),\n  field(\"nwt\",\"text\",half),\n  field(\"mode\",\"text\",half),\n  {name:\"保存并启用\",type:\"button\",action:\"login()\",style:full},\n  {name:\"查看状态\",type:\"button\",action:\"lrtsSessionStatus()\",style:half},\n  {name:\"清除个人会话\",type:\"button\",action:\"lrtsClearSession()\",style:half}\n]);",
    "loginUrl": "var LR_LOGIN_FIELDS=[\n  {name:\"token\",key:\"token\"},\n  {name:\"imei\",key:\"imei\"},\n  {name:\"nwt\",key:\"nwt\"},\n  {name:\"mode\",key:\"mode\"},\n  {name:\"lrid\",key:\"lrid\"},\n  {name:\"ostar36\",key:\"ostar36\"},\n  {name:\"userMode\",key:\"userMode\"},\n  {name:\"duId\",key:\"duId\"}\n];\n\nfunction lrtsLoginField(name){\n  try{\n    if(result&&typeof result.get===\"function\")return String(result.get(name)||\"\").trim();\n  }catch(e1){}\n  try{\n    if(result&&result[name]!==null&&result[name]!==undefined)return String(result[name]).trim();\n  }catch(e2){}\n  return \"\";\n}\n\nfunction login(){\n  var session={};\n  var missing=[];\n  LR_LOGIN_FIELDS.forEach(function(field){\n    var value=lrtsLoginField(field.name);\n    if(!value)missing.push(field.name);\n    session[field.key]=value;\n  });\n  if(missing.length){\n    java.longToast(\"请完整填写以下参数:\\n\"+missing.join(\"、\"));\n    return;\n  }\n  source.put(\"lrts_session\",JSON.stringify(session));\n  source.put(\"lrts_q\",\"0\");\n  try{\n    var map=new Packages.java.util.HashMap();\n    LR_LOGIN_FIELDS.forEach(function(field){map.put(field.name,session[field.key]);});\n    java.upLoginData(map);\n  }catch(saveError){}\n  java.longToast(\"个人 App 会话已保存并启用\");\n}\n\nfunction lrtsCaptureTip(){\n  java.longToast(\"本书源不提供内置账号,仅支持使用你本人的抓包会话。\\n请从懒人听书 Android 客户端 8.8.03 的 HAR 请求参数中提取并填写 token、imei、lrid、duId、ostar36、userMode、nwt、mode。\\n其他版本的字段或签名可能不同,不能保证兼容;请勿填写其他 App 的参数。\");\n}\n\nfunction lrtsSessionStatus(){\n  try{\n    var saved=JSON.parse(String(source.get(\"lrts_session\")||\"{}\"));\n    var complete=LR_LOGIN_FIELDS.every(function(field){\n      return saved[field.key]!==null&&saved[field.key]!==undefined&&String(saved[field.key]).trim()!==\"\";\n    });\n    java.longToast(complete?\"个人抓包会话已配置\":\"尚未配置个人抓包会话,当前无法使用\");\n  }catch(error){\n    java.longToast(\"个人抓包会话数据无效,请清除后重新填写\");\n  }\n}\n\nfunction lrtsClearSession(){\n  source.put(\"lrts_session\",\"\");\n  source.put(\"lrts_q\",\"0\");\n  try{\n    var map=new Packages.java.util.HashMap();\n    LR_LOGIN_FIELDS.forEach(function(field){map.put(field.name,\"\");});\n    java.upLoginData(map);\n  }catch(clearError){}\n  java.longToast(\"个人抓包会话已清除;使用前请重新抓包填写\");\n  try{java.reLoginView();}catch(refreshError){}\n}",
    "respondTime": 727,
    "ruleBookInfo": {
        "author": "{{$.data.detail.author||$.data.singerName}}  演播:{{$.data.detail.announcer||$.data.singerName}}",
        "coverUrl": "$.data.detail.bestCover||$.data.detail.cover||$.data.pic",
        "intro": "🔊 播放:{{$.data.detail.play}}\n🎙 演播:{{$.data.detail.announcer||$.data.singerName}}\n💿 专辑:{{$.data.albumName}}\n🏷 标签:{{$.data.detail.labels[*].name##\n##、}}\n📖 简介:{{$.data.detail.desc}}",
        "kind": "MP3",
        "lastChapter": "@js:\nvar sections=parseInt(String(java.getString(\"$.data.detail.sections\")||\"0\"),10);\nisFinite(sections)&&sections>0?\"共\"+sections+\"集\":\"MP3\";",
        "name": "@js:\nvar name=String(java.getString(\"$.data.detail.shortName\")||java.getString(\"$.data.detail.name\")||java.getString(\"$.data.songName\")||\"\");\nname||\"MP3\";",
        "tocUrl": "@js:\nvar bookId=String(java.getString(\"$.data.detail.id\")||\"\");\nvar songMid=String(java.getString(\"$.data.songMid\")||\"\");\nif(bookId){\n  lrtsUrl(java,source,\"\/yyting\/bookclient\/ClientGetBookResource.action\",{bookId:bookId,isUp:\"0\",pageNum:\"1\",pageSize:\"50\",sceneId:\"B3\",sortType:\"0\"});\n}else if(songMid){\n  source.put(\"lrts_music_song_mid\",songMid);\n  source.put(\"lrts_music_song_name\",String(java.getString(\"$.data.songName\")||\"MP3\"));\n  var now=String(Date.now());\n  lrtsFeedUrl(java,source,\"\/lrts\/cgi\/musicradio\/tmeService\/getMediaUrl\",{costInfo:now+\"-\"+now+\"-0\",opType:\"0\",songMid:songMid});\n}else{\n  throw new Error(\"详情没有返回有声书 ID 或歌曲 ID\");\n}"
    },
    "ruleContent": {
        "content": "@js:\n\nvar raw=String(src||\"\");\nvar body;\nif(String(baseUrl||\"\").indexOf(\"data:;base64,\")===0){\n  var marker=JSON.parse(String(java.hexDecodeToString(raw)||\"{}\"));\n  if(marker.kind!==\"lrtsBookAudio\")throw new Error(\"未知的懒人听书章节标记\");\n  var now=String(Date.now());\n  var playUrl=lrtsAppUrl(java,source,\"\/yyting\/v3\/gateway\/getListenPath\",{\n    costInfo:now+\"-\"+now+\"-0\",\n    effect:\"0\",\n    entityId:String(marker.bookId||\"\"),\n    entityType:String(marker.entityType||\"1\"),\n    opType:\"0\",\n    quality:\"1\",\n    resId:String(marker.resId||\"\"),\n    section:String(marker.section||\"\"),\n    trackId:String(marker.trackId||\"\"),\n    vid:\"\"\n  });\n  body=JSON.parse(String(java.ajax(playUrl)||\"{}\"));\n}else{\n  body=JSON.parse(raw);\n}\nvar model=body.data&&body.data.length!==undefined?body.data[0]:body.data;\nmodel=model||{};\nvar path=String(model.path||model.url||\"\");\nvar eKey=String(model.key||\"\");\nvar encrypted=!!eKey||\/.mgg(?:$|[?#])\/i.test(path);\nif(encrypted){\n  if(!path)throw new Error(\"加密歌曲没有返回媒体地址\");\n  if(!eKey)throw new Error(\"加密歌曲没有返回 eKey,无法解密\");\n  var cachePath=\"\";\n  try{\n    cachePath=String(java.downloadFile(path+\", \"+JSON.stringify({type:\"mgg\"}))||\"\");\n    if(!cachePath)throw new Error(\"加密歌曲下载失败\");\n    var audioBytes=java.readFile(cachePath);\n    if(!audioBytes||!audioBytes.length)throw new Error(\"加密歌曲缓存为空\");\n    lrtsQmcDecrypt(java,audioBytes,eKey);\n    var format=lrtsAudioFormat(audioBytes);\n    path=lrtsAudioDataSource(audioBytes,format);\n  }finally{\n    if(cachePath)try{java.deleteFile(cachePath);}catch(deleteError){}\n  }\n}\nif(!path)throw new Error(String(body.msg||\"App 播放地址获取失败,请确认账号权益或更新 HAR 会话\"));\npath;"
    },
    "ruleExplore": {},
    "ruleSearch": {
        "author": "{{$.author}}  演播:{{$.announcer}}",
        "bookList": "<js>\nvar responseText=String(result==null?\"\":result).trim();\nfunction parseResponse(text){\n  text=String(text||\"\").trim();\n  if(text.charAt(0)!==\"{\"&&text.charAt(0)!==\"[\"){\n    var start=text.indexOf(\"{\");\n    var end=text.lastIndexOf(\"}\");\n    if(start>=0&&end>start)text=text.substring(start,end+1);\n  }\n  try{return JSON.parse(text);}catch(error){return null;}\n}\nvar body=parseResponse(responseText);\nif(!body&&String(baseUrl||\"\").indexOf(\"\/yyting\/musicradio\/channelPage\")>=0){\n  \n  body=parseResponse(String(java.ajax(lrtsUrl(java,source,\"\/yyting\/musicradio\/channelPage\",{hv:\"1.434.0\"}))));\n}\nif(!body){java.log(\"懒人听书发现响应不是 JSON: \"+responseText.substring(0,120));body={};}\nvar list=[];\nvar seen={};\nfunction add(raw){\n  if(!raw)return;\n  if(raw.ranking&&Array.isArray(raw.ranking.list)){raw.ranking.list.forEach(add);return;}\n  if(raw.musicList&&Array.isArray(raw.musicList.list)){raw.musicList.list.forEach(add);return;}\n  if(raw.folder&&Array.isArray(raw.folder.list)){raw.folder.list.forEach(add);return;}\n  if(raw.videoCollectionManga||raw.activity||raw.topic||raw.advert)return;\n  if(Number(raw.type)===10000)return;\n  if(raw.bookAlbum)raw=raw.bookAlbum;\n  if(raw.music)raw=raw.music;\n  if(raw.entityId&&raw.entityName)raw={id:raw.entityId,name:raw.entityName,cover:raw.cover,typeName:raw.typeName,score:raw.score,playCount:raw.playCount,recReason:raw.highlightTags||\"\",entityType:1};\n  if(raw.songMid)raw={id:String(raw.songMid),name:raw.songName,author:raw.singerName,announcer:raw.singerName,cover:raw.pic,desc:raw.albumName,entityType:99,_music:1,mediaMid:raw.mediaMid};\n  var itemType=Number(raw.type);\n  if(itemType===19||itemType===80||itemType===10||itemType===63||itemType===10000)return;\n  var id=raw.id||raw.entityId||raw.baseEntityId;\n  var displayName=raw.name||raw.entityName||raw.realName||raw.songName;\n  if(!id||!displayName||seen[String(id)])return;\n  var entityType=Number(raw.entityType||raw.baseEntityType||1);\n  if(entityType!==1&&entityType!==99)return;\n  raw.id=String(id);\n  raw.name=String(displayName);\n  raw.cover=raw.cover||raw.bestCover||raw.orignCover||raw.dynamicCover||\"\";\n  raw.announcer=raw.announcer||raw.nickName||\"\";\n  raw.author=raw.author||\"\";\n  seen[String(id)]=1;\n  list.push(raw);\n}\nif(body.data&&body.data.bookAlbums){\n  var searchBooks=body.data.bookAlbums||[];\n  var previousRefer=String(source.get(\"lrts_search_refer\")||\"\");\n  var nextRefer=String(body.data.tabInfo&&body.data.tabInfo.referId||\"\");\n  source.put(\"lrts_search_refer\",(!searchBooks.length||!nextRefer||nextRefer===previousRefer)?\"end\":nextRefer);\n  searchBooks.forEach(add);\n}else if(body.books){\n  if(body.bookIds&&body.bookIds.length>20) source.put(\"lrts_book_ids\",body.bookIds.join(\",\"));\n  body.books.concat(body.albums||[]).forEach(add);\n}else if(body.list){\n  if(String(baseUrl||\"\").indexOf(\"\/yyting\/read\/rankingsItemList.action\")>=0){\n    var rankMatch=String(baseUrl||\"\").match(\/[?&]rankId=([^&]+)\/);\n    var rankKey=\"lrts_read_rank_\"+(rankMatch?decodeURIComponent(rankMatch[1]):\"\");\n    var previous=String(source.get(rankKey)||\"0\");\n    var next=body.list.length?String(body.list[body.list.length-1].showOrder||\"\"):\"\";\n    source.put(rankKey,!next||next===previous?\"end\":next);\n  }else{\n    body.list.forEach(add);\n  }\n}else if(body.data){\n  var data=body.data;\n  if(data.recommendEntityList){\n    source.put(\"lrts_feed_refer\",String(data.referId||\"end\"));\n    data.recommendEntityList.forEach(add);\n  }\n  (data.rankListModule||[]).forEach(function(module){(module.list||[]).forEach(add);});\n  (data.ranking&&data.ranking.rankings||[]).forEach(function(rank){(rank.rankingItems||[]).forEach(add);});\n  if(data.list&&data.list.length)data.list.forEach(add);\n  function modules(groups){(groups||[]).forEach(function(group){(group.moduleList||[]).forEach(function(module){(module.entityList||[]).forEach(add);});});}\n  modules(data.moduleGroup);\n  (data.channelGroup||[]).forEach(function(channel){modules(channel.moduleGroup);});\n  var tabId=String(source.get(\"lrts_music_tab\")||\"\");\n  (data.tabList||[]).filter(function(tab){return !tabId||String(tab.id)===tabId;}).forEach(function(tab){(tab.musicList||[]).forEach(add);});\n  (data.musicList||[]).forEach(add);\n}\nresult=JSON.stringify(list);\n<\/js>\n$[*]",
        "bookUrl": "@js:\n\nif(Number(java.getString(\"$._music\"))===1){\n  var songMid=String(java.getString(\"$.id\"));\n  source.put(\"lrts_music_song_mid\",songMid);\n  source.put(\"lrts_music_song_name\",String(java.getString(\"$.name\")||\"音乐\"));\n  lrtsUrl(java,source,\"\/yyting\/musicradio\/recMusicService\/getMusicInfo\",{songMid:songMid});\n}else{\nvar id=String(java.getString(\"$.id\"));\nlrtsAppUrl(java,source,\"\/yyting\/v3\/book\/bookInfoPage\",{id:id,listenPos:\"1\",reqMask:\"31\",source:\"0\",trackSize:\"50\",type:\"1\"});}",
        "coverUrl": "$.cover",
        "intro": "{{$.recReason}}\n{{$.desc}}",
        "kind": "{{$.shortRecReason}}\n{{$.rankingInfo}}\n{{$.score}}分",
        "lastChapter": "{{$.state}}",
        "name": "$.name"
    },
    "ruleToc": {
        "chapterList": "<js>\nvar raw=String(result==null?\"\":result);\nif(String(baseUrl||\"\").indexOf(\"\/yyting\/bookclient\/ClientGetBookResource.action\")>=0){\n  var catalogBody;\n  try{catalogBody=JSON.parse(raw);}catch(error){throw new Error(\"听书目录响应不是 JSON: \"+error);}\n  if(Number(catalogBody.status)!==0||!Array.isArray(catalogBody.list)){\n    throw new Error(String(catalogBody.msg||\"听书目录响应缺少 list\"));\n  }\n  var responseBookId=String(catalogBody.bookId||\"\");\n  if(!responseBookId)throw new Error(\"听书目录响应缺少 bookId\");\n  catalogBody.list.forEach(function(item){\n    if(item&&typeof item===\"object\"){\n      item._lrtsBookId=responseBookId;\n      item._lrtsEntityType=\"1\";\n    }\n  });\n  result=JSON.stringify(catalogBody);\n}else{\n  var musicBody;\n  try{musicBody=JSON.parse(raw);}catch(error){throw new Error(\"歌曲目录响应不是 JSON: \"+error);}\n  var musicList=Array.isArray(musicBody)?musicBody:\n    (Array.isArray(musicBody.list)?musicBody.list:\n    (Array.isArray(musicBody.data)?musicBody.data:\n    (musicBody.data?[musicBody.data]:[])));\n  result=JSON.stringify({list:musicList});\n}\nresult;\n<\/js>\n$.list[*]",
        "chapterName": "@js:\nvar name=String(java.getString(\"$.name\")||\"\");\nname||String(source.get(\"lrts_music_song_name\")||\"MP3\");",
        "chapterUrl": "@js:\nif(String(baseUrl).indexOf(\"\/lrts\/cgi\/musicradio\/tmeService\/getMediaUrl\")>=0){\n  var songMid=String(source.get(\"lrts_music_song_mid\")||\"\");\n  var now=String(Date.now());\n  lrtsFeedUrl(java,source,\"\/lrts\/cgi\/musicradio\/tmeService\/getMediaUrl\",{costInfo:now+\"-\"+now+\"-0\",opType:\"0\",songMid:songMid});\n}else{\n  var bookId=String(java.getString(\"$._lrtsBookId\")||\"\");\n  if(!bookId)throw new Error(\"章节数据缺少 _lrtsBookId\");\n  var now=String(Date.now());\n  lrtsAppUrl(java,source,\"\/yyting\/v3\/gateway\/getListenPath\",{\n    costInfo:now+\"-\"+now+\"-0\",\n    effect:\"0\",\n    entityId:bookId,\n    entityType:String(java.getString(\"$._lrtsEntityType\")||\"1\"),\n    opType:\"0\",\n    quality:\"1\",\n    resId:String(java.getString(\"$.id\")||\"\"),\n    section:String(java.getString(\"$.section\")||\"\"),\n    trackId:String(java.getString(\"$.tmeId\")||\"\"),\n    vid:\"\"\n  });\n}",
        "isVip": "$.payType",
        "nextTocUrl": "@js:\nvar urls=[];\nif(String(baseUrl||\"\").indexOf(\"\/yyting\/bookclient\/ClientGetBookResource.action\")>=0){\n  var total=parseInt(String(java.getString(\"$.sections\")||\"0\"),10);\n  var bookId=String(java.getString(\"$.bookId\")||\"\");\n  var pageSize=50;\n  var pageCount=isFinite(total)&&total>0?Math.ceil(total\/pageSize):1;\n  if(!bookId)throw new Error(\"目录分页响应缺少 bookId\");\n  for(var pageNum=2;pageNum<=pageCount;pageNum++){\n    urls.push(lrtsUrl(java,source,\"\/yyting\/bookclient\/ClientGetBookResource.action\",{\n      bookId:bookId,\n      isUp:\"0\",\n      pageNum:String(pageNum),\n      pageSize:String(pageSize),\n      sceneId:\"B3\",\n      sortType:\"0\"\n    }));\n  }\n}\nurls;",
        "updateTime": "{{java.timeFormatUTC(java.getString('$.lastModify'),'yyyy-MM-dd',8)}}"
    },
    "searchUrl": "@js:\nvar p=Number(page)||1;\nvar searchId=\"\";\nvar referId=\"\";\nif(p===1){\n  searchId=\"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(\/[xy]\/g,function(ch){\n    var value=Math.floor(Math.random()*16);\n    return (ch===\"x\"?value:(value&3)|8).toString(16);\n  });\n  source.put(\"lrts_search_id\",searchId);\n  source.put(\"lrts_search_refer\",\"\");\n}else{\n  searchId=String(source.get(\"lrts_search_id\")||\"\");\n  referId=String(source.get(\"lrts_search_refer\")||\"\");\n}\nvar out=null;\nif(searchId&&(p===1||(referId&&referId!==\"end\"))){\n  out=lrtsAppUrl(java,source,\"\/yyting\/v2\/search\/searchBookAlbum\",{\n    filters:\"0,0,0,0\",\n    keyWord:String(key),\n    pageId:\"g1\",\n    searchId:searchId,\n    sort:\"1\",\n    referId:referId||undefined\n  });\n}\nout;",
    "weight": 0
}
广告