[{"bookSourceComment":"版本：20261026\n作者：知秋\n反馈群：766236637\ntg群：https:\/\/t.me\/+dcNnFFZv5KtmYjIx\n注意：快速下载建议在登录界面的全本下载先进行缓存\n1.请登录自己号看自己订阅的书籍\n2. 内置了一个号，部分资源免费阅读，但是不支持下载，只支持在线观看\n4. 登录账密请不要多次输入错误，会出现验证码，遇到这种情况等待一会重新登录\n介绍：\n1. 使用服务器进行中转，有请求速率限制，小说为一秒3次。\n2. 临时token口令为 天一团队是倒狗(qq为1070240776和845646066和1484608559)请勿相信任何需要付费的说法欢迎来官方反馈群举报\n3. 获取token请点击登录界面，获取token按钮，点击测试\/修改token可查询日下载量，切记获取token后请保存，最后选择√存储成功，token为3日有效期，到期请重新获取，切记token变为明文，请勿外泄，异地登录多次会封禁token，如封禁请等过期重新获取。(token改为明文存源变量中防止丢失)\n4. 共享数据库如有，则优先使用数据库，共享章节开头的图标为🍅\n5. 章节目录前有图标🎉，即为共享章节\n6. 支持下载，请把预下载改成0-3之间，请求有超限拉黑，请勿大规模批量下载\n7. 支持订阅接口，但是不要重复点击\n8. 反馈q群：755947375，token问题群里找我，或者社区找也行(社区不经常在线，上线看到会回)\n9. 接口请求速率存在限制，请不要大规模下载，耐心等待。","bookSourceGroup":"少年梦,api,优质,禁止外传","bookSourceName":"✿少年梦（知秋）✿","bookSourceType":0,"bookSourceUrl":"少年梦＃知秋","concurrentRate":"1000","customButton":false,"customOrder":-1,"enabled":true,"enabledCookieJar":true,"enabledExplore":true,"eventListener":false,"exploreUrl":"@js:\nlet token = String(source.getVariable())\nif (token == '') {\n  java.longToast('\\n❌未获取共享Token，请于登录界面获取共享Token后使用')\n}\nlet data = requestApiUrl('\/novel\/explore\/init', {})\n\/\/小说·共享更新时间::@js:getApiUrl('\/novel\/novels', {page})\n\/\/我的书架::@js:getApiUrl('\/console\/bookrack', {page})\nJSON.stringify(data)","jsLib":"const host = '少年梦'\nconst branch = 'temp'\nconst version = '1.0.0'\nconst api = 'https:\/\/snd.vv9v.cn'\nconst apiAdmin = 'https:\/\/zqmy.vv9v.cn'\n\nfunction releasePage() {\n  this.java.startBrowser(`${apiAdmin}\/source\/release\/?host=${host}&branch=${branch}&version=${version}&lastUpdateTime=${this.source.lastUpdateTime}`, '发布页')\n}\n\nfunction checkUpdate() {\n  let lastCheckUpdateTime = Number(this.source.get('lastCheckUpdateTime')) || 0\n  let now = Date.now()\n  if (now - lastCheckUpdateTime < 12 * 3600 * 1000) return\n  this.source.put('lastCheckUpdateTime', String(now))\n  let data = requestApiUrl.call(this, '\/source\/sources', { host, branch, version }, apiAdmin)\n  if (!data) return\n  if (data.history[0].version != version) {\n    releasePage.call(this)\n  }\n}\n\nfunction getApiUrl(path, data, host = api) {\n  const { source } = this\n  data = Object.entries(data).map(v => v.join('=')).join('&')\n  const option = {\n    method: \"GET\",\n    headers: {\n      'authorization': `Bearer ${source.getVariable()}`\n    }\n  }\n  const url = host + path + '?' + data + ',' + JSON.stringify(option)\n  return url\n}\n\nfunction requestApiUrl(path, data, host = api) {\n  const url = getApiUrl.call(this, path, data, host)\n  try {\n    let res = this.java.ajax(url)\n    res = JSON.parse(res)\n    if (res.code != 0) {\n      this.java.longToast(`\\n❌操作失败，code${res.code}：\\n${res.msg}`)\n    } else {\n      return res.data\n    }\n  } catch (e) {\n    this.java.log(`请求共享接口${path}异常：` + e.message)\n  }\n  return null\n}\n\nfunction getCNTimeString(time, format = 'YYYY\/MM\/DD HH:mm:ss') {\n  const date = time ? new Date(time) : new Date()\n  const year = date.getFullYear()\n  const month = String(date.getMonth() + 1).padStart(2, '0')\n  const day = String(date.getDate()).padStart(2, '0')\n  const hours = String(date.getHours()).padStart(2, '0')\n  const minutes = String(date.getMinutes()).padStart(2, '0')\n  const seconds = String(date.getSeconds()).padStart(2, '0')\n  return format.replace('YYYY', String(year))\n    .replace('MM', month)\n    .replace('DD', day)\n    .replace('HH', hours)\n    .replace('mm', minutes)\n    .replace('ss', seconds)\n}","lastUpdateTime":"1792975903295","loginUi":"[\n  {\n    \"name\": \"源作者\",\n    \"type\": \"text\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  },\n  {\n    \"name\": \"官方反馈群\",\n    \"type\": \"text\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  },\n  {\n    \"name\": \"临时Token口令\",\n    \"type\": \"text\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  },\n  {\n    \"name\": \"查询Token\",\n    \"type\": \"button\",\n    \"action\": \"queryToken()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 0.4\n    }\n  },\n  {\n    \"name\": \"获取Token\",\n    \"type\": \"button\",\n    \"action\": \"getTempToken()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 0.4\n    }\n  },\n  {\n    \"name\": \"检查更新\",\n    \"type\": \"button\",\n    \"action\": \"releasePage()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 0.4\n    }\n  },\n  {\n    \"name\": \"数据库统计\",\n    \"type\": \"button\",\n    \"action\": \"showDb()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 0.4\n    }\n  },\n  {\n    \"name\": \"账号\",\n    \"type\": \"text\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  },\n  {\n    \"name\": \"密码\",\n    \"type\": \"password\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  },\n  {\n    \"name\": \"登录\",\n    \"type\": \"button\",\n    \"action\": \"_login()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 0.27\n    }\n  },\n  {\n    \"name\": \"退出登录\",\n    \"type\": \"button\",\n    \"action\": \"logout()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 0.27\n    }\n  },\n  {\n    \"name\": \"账号信息\",\n    \"type\": \"button\",\n    \"action\": \"showUserInfo()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 0.27\n    }\n  },\n  {\n    \"name\": \"开关自动订阅未购章节\",\n    \"type\": \"button\",\n    \"action\": \"toggleAutoBuy()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  },\n  {\n    \"name\": \"书籍ID\",\n    \"type\": \"text\"\n  },\n  {\n    \"name\": \"全本后台下载\",\n    \"type\": \"button\",\n    \"action\": \"downloadNovel()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  },\n  {\n    \"name\": \"🛒购买全本🛒\",\n    \"type\": \"button\",\n    \"action\": \"buy(true)\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  },\n  {\n    \"name\": \"购买数量\",\n    \"type\": \"text\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  },\n  {\n    \"name\": \"🛒购买指定数量章节（默认5）🛒\",\n    \"type\": \"button\",\n    \"action\": \"buy(false)\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 1\n    }\n  }\n]","loginUrl":"function login() {\n  let info = JSON.parse(String(source.getLoginInfo()))\n  _login(info)\n}\n\nfunction _login(info) {\n  info = info || result\n  let username = info['账号']\n  let password = info['密码']\n  if (username == '' || password == '') {\n    return java.longToast('\\n❌登录失败，用户名或密码不能为空')\n  }\n  let data = requestApiUrl('\/console\/login', { username, password })\n  if (!data || !data.id) return\n  source.putLoginInfo(JSON.stringify(info))\n  showUserInfo()\n}\n\nfunction logout() {\n  let data = requestApiUrl('\/console\/logout', {})\n  if (!data || !data.msg) return\n  let { msg } = data\n  java.longToast(`\\n✅${msg}`)\n}\n\nfunction showUserInfo() {\n  let data = requestApiUrl('\/console\/info', {})\n  if (!data || !data.msg) return\n  let { msg } = data\n  java.longToast(`\\n✅${msg}`)\n}\n\nfunction toggleAutoBuy() {\n  let auto = source.get('autoBuy') == '1'\n  source.put('autoBuy', auto ? '0' : '1')\n  java.longToast(`\\n✅自动订阅未购章节已${auto ? '关闭' : '开启\\n阅读时将自动订阅未购买章节'}`)\n}\n\nfunction queryToken() {\n  let token = String(source.getVariable())\n  if (token.length <= 60) {\n    java.toast('请输入有效token')\n  } else {\n    let info = requestApiUrl('\/user\/test', { token })\n    if (!info) return\n    java.longToast(`\\n✅查询成功\\n用户：${info.id}${info.max ? `\\n日下载上限：${info.max}` : ''}\\n今日已下载：${info.used}\\n日下载剩余：${info.left}\\n创建时间：${info.createTime}${info.ddl ? `\\n到期时间：${info.ddlTime}` : ''}`)\n  }\n}\n\nfunction getTempToken() {\n  let pw1 = String(result['源作者'])\n  if (pw1 == '') {\n    return java.longToast('请输入源作者')\n  }\n  let pw2 = String(result['官方反馈群'])\n  if (pw2 == '') {\n    return java.longToast('请输入官方反馈群')\n  }\n  let pw3 = String(result['临时Token口令'])\n  if (pw3 == '') {\n    return java.longToast('请输入临时Token口令')\n  }\n  let info = requestApiUrl('\/user\/temp', { id: java.androidId(), pw1, pw2, pw3 })\n  if (!info) return\n  let token = info.token\n  source.setVariable(token)\n  java.longToast(`\\n✅获取临时token成功\\n用户：${info.id}\\n日下载剩余：${info.left}\\n创建时间：${info.createTime}\\n到期时间：${info.ddlTime}`)\n  source.putLoginInfo(JSON.stringify(result))\n}\n\nfunction showDb() {\n  let data = requestApiUrl('\/system\/dbinfo', {})\n  if (!data) return\n  let { msg } = data\n  java.longToast(`\\n✅${msg}`)\n}\n\nfunction downloadNovel() {\n  let novelId = +String(result['书籍ID'])\n  if (!novelId) {\n    return java.longToast('\\n❌请输入有效书籍ID')\n  }\n  let data = requestApiUrl('\/novel\/download', { novelId })\n  if (!data) return\n  let { msg } = data\n  java.longToast(`\\n✅${msg}`)\n}\n\nfunction buy(all) {\n  let novelId = +String(result['书籍ID'])\n  if (!novelId) {\n    return java.longToast('\\n❌请输入有效书籍ID')\n  }\n  let data\n  if (all) {\n    data = requestApiUrl('\/console\/subscribe', { novelId, num: -1 })\n  } else {\n    let num = +String(result['购买数量'])\n    if (!num || num <= 0) {\n      num = 5\n    }\n    data = requestApiUrl('\/console\/subscribe', { novelId, num })\n  }\n  if (!data) return\n  java.longToast('\\n✅' + data.msg)\n}","respondTime":180000,"ruleBookInfo":{"author":"penName","coverUrl":"https:\/\/aliossouterendtest.shaoniandream.com{{$.picture}}","init":"data","intro":"&nbsp;{{$.jianjie}}","kind":"{{java.getString('$.isUpdate') == '0' ? '完本' : '连载'}}\n{{java.getString('$.sortName')}}\n{{java.getString('$.booklabel')}}","lastChapter":"ChapterName\n@js:\nif (result != '') {\n  result = String(result).replace('连载至', '')\n}\nresult","name":"title","tocUrl":"id||BookID\n@js:\n`data:;base64,${java.base64Encode(result)},{\"type\":\"SNDapi\"}`","wordCount":"FontCount"},"ruleContent":{"content":"@js:\ncheckUpdate()\nlet chapId = java.hexDecodeToString(result)\nlet info = JSON.parse(baseUrl.slice(baseUrl.indexOf('{')))\nlet novelId = info.novelId\nlet autoBuy = source.get('autoBuy') == '1'\nlet data = requestApiUrl('\/novel\/chap', { novelId, chapId, autoBuy })\ndata.content\n","payAction":"\/\/ java.log('章节url：' + chapter.url)\nlet novelId = chapter.url.match(\/\"novelId\":\\s*\"(\\d+)\"\/)[1]\nlet chapId = java.base64Decode(chapter.url.match(\/base64,(.*?),\/)[1])\nlet data = requestApiUrl('\/console\/subscribe', { novelId, chapId })\nif (data.msg) {\n  java.longToast('\\n✅' + data.msg)\n  true\n} else {\n  false\n}"},"ruleExplore":[],"ruleSearch":{"author":"penName","bookList":"data[*]","bookUrl":"BookID||BooksID||id\n@js:\ngetApiUrl('\/novel\/info', { novelId: result  })","checkKeyWord":"","coverUrl":"https:\/\/aliossouterendtest.shaoniandream.com{{$.picture}}","intro":"jianjie","kind":"{{java.getString('$.isUpdate') == '0' ? '完本' : '连载'}}\n{{java.getString('$.cname')}}\n{{java.getString('$.sortName')}}\n{{java.getString('$.booklabel')}}","name":"title||BookName","wordCount":"FontCount"},"ruleToc":{"chapterList":"@js:\nlet novelId = java.hexDecodeToString(result)\nlet vols = requestApiUrl('\/novel\/catalog', { novelId })\n\nlet cache = requestApiUrl('\/novel\/cache', { novelId }) || []\ncache = cache.reduce((acc, d) => {\n  acc[d.chapId] = d\n  return acc\n}, {})\n\nlet loginInfo = JSON.parse(source.getLoginInfo() || '{}')\nloginInfo.书籍ID = novelId\nsource.putLoginInfo(JSON.stringify(loginInfo))\n\nlet chaps = []\n\nfor (let v of vols) {\n  chaps.push({\n    title: v.title,\n    voltype: true\n  })\n  for (let c of v.chapterList) {\n    let cacheChap = cache[c.id]\n    let isShare = !!cacheChap\n    let isBuy = c.lock == 1\n    let isVip = !!c.isFree\n    let tag = isBuy ? '🔑' : isShare ? cacheChap.s ? '🍎' : '🎉' : ''\n    if (tag) tag += '  '\n    let onlineTime = (cacheChap ? cacheChap.onlineTime : getCNTimeString(c.release_time_now * 1000)) || getCNTimeString(c.release_time_now * 1000) || ''\n    let info = `${onlineTime} ┃ 字数：${c.FontCount || 0}`\n    chaps.push({\n      title: (isVip ? tag : '') + c.title,\n      info: info + (isShare ? (cacheChap.s ? '🍎' : '🎉') : tag),\n      isVip,\n      isBuy: isBuy || (cacheChap && cacheChap.s),\n      url: `data:;base64,${java.base64Encode(c.id)},{\"type\":\"SNDapi\",\"novelId\":\"${novelId}\"}`\n    })\n  }\n}\n\nchaps","chapterName":"title","chapterUrl":"url","isPay":"isBuy","isVip":"isVip","isVolume":"voltype","updateTime":"info"},"searchUrl":"@js:\ngetApiUrl('\/novel\/search', { keyword: key, page })","weight":0}]