懒人听书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&¶ms[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&¶ms[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)&§ions>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
}