fix lanzou api

pull/28/head
fengyuecanzhu 2 years ago
parent 1c99b3ee76
commit 0b739766fa
No known key found for this signature in database
GPG Key ID: 04B78AD06A9D6E6C
  1. 29
      app/src/main/java/xyz/fycz/myreader/webapi/LanZouApi.kt
  2. 103
      dynamic/build.gradle
  3. 5
      dynamic/src/main/java/xyz/fycz/dynamic/AppLoadImpl.kt
  4. 60
      dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix4.kt
  5. 62
      dynamic/src/main/java/xyz/fycz/dynamic/fix/AppSubSourceFix.kt
  6. 138
      dynamic/src/main/java/xyz/fycz/dynamic/utils/LanZouUtils.kt

@ -158,12 +158,13 @@ object LanZouApi {
* @param url * @param url
* @param password * @param password
*/ */
private fun getFileUrl(url: String, password: String = ""): Observable<String> { fun getFileUrl(url: String, password: String = ""): Observable<String> {
return Observable.create { return Observable.create {
val html = OkHttpUtils.getHtml(url) val html = OkHttpUtils.getHtml(url)
val url2 = if (password.isEmpty()) { val url2 = if (password.isEmpty()) {
val url1 = getUrl1(html) val url1 = getUrl1(html)
val key = getKey(OkHttpUtils.getHtml(url1)) val data = StringUtils.getSubString(OkHttpUtils.getHtml(url1), "},", "},")
val key = getKeyValueByKey(data, "sign") + "&" + getKeyValueByKey(data, "websignkey")
getUrl2(key, url1) getUrl2(key, url1)
} else { } else {
getUrl2(StringHelper.getSubString(html, "sign=", "&"), url, password) getUrl2(StringHelper.getSubString(html, "sign=", "&"), url, password)
@ -177,27 +178,25 @@ object LanZouApi {
} }
} }
private fun getUrl1(html: String): String { fun getUrl1(html: String): String {
val doc = Jsoup.parse(html) val doc = Jsoup.parse(html)
return URLCONST.LAN_ZOU_URL + doc.getElementsByTag("iframe").attr("src") return URLCONST.LAN_ZOU_URL + doc.getElementsByTag("iframe").attr("src")
} }
private fun getKey(html: String): String { fun getKeyValueByKey(html: String, key: String): String {
var lanzousKeyStart = "var pposturl = '" val keyName = StringHelper.getSubString(html, "'$key':", ",")
val keyName = StringHelper.getSubString(html, "'sign':", ",") return if (keyName.endsWith("'")) {
lanzousKeyStart = if (keyName.endsWith("'")) { key + "=" + keyName.replace("'", "")
"'sign':'"
} else { } else {
"var $keyName = '" val lanzousKeyStart = "var $keyName = '"
key + "=" + StringHelper.getSubString(html, lanzousKeyStart, "'")
} }
return StringHelper.getSubString(html, lanzousKeyStart, "'")
} }
fun getUrl2(key: String, referer: String, password: String = ""): String {
private fun getUrl2(key: String, referer: String, password: String = ""): String {
val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull() val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull()
val body = if (password.isEmpty()) { val body = if (password.isEmpty()) {
"action=downprocess&sign=$key&ves=1" "action=downprocess&signs=?ctdf&websign=&ves=1&$key"
} else { } else {
"action=downprocess&sign=$key&p=$password" "action=downprocess&sign=$key&p=$password"
} }
@ -213,7 +212,7 @@ object LanZouApi {
return getUrl2(html) return getUrl2(html)
} }
private fun getUrl2(o: String): String { fun getUrl2(o: String): String {
/*val info = o.split(",").toTypedArray() /*val info = o.split(",").toTypedArray()
val zt = info[0].substring(info[0].indexOf(":") + 1) val zt = info[0].substring(info[0].indexOf(":") + 1)
if (!"1".endsWith(zt)) { if (!"1".endsWith(zt)) {
@ -239,7 +238,7 @@ object LanZouApi {
* *
* @param path * @param path
*/ */
private fun getRedirectUrl(path: String): String { fun getRedirectUrl(path: String): String {
val conn = URL(path) val conn = URL(path)
.openConnection() as HttpURLConnection .openConnection() as HttpURLConnection
conn.instanceFollowRedirects = false conn.instanceFollowRedirects = false

@ -48,14 +48,111 @@ android {
} }
dependencies { dependencies {
compileOnly("androidx.core:core-ktx:$kotlin_version")
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
compileOnly("me.fycz.maple:maple:1.9") // androidx
compileOnly 'org.greenrobot:greendao:3.3.0' compileOnly "androidx.core:core-ktx:$kotlin_version"
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compileOnly 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
compileOnly 'androidx.appcompat:appcompat:1.3.1' compileOnly 'androidx.appcompat:appcompat:1.3.1'
compileOnly 'androidx.constraintlayout:constraintlayout:2.1.3'
//anko
def anko_version = '0.10.8'
compileOnly "org.jetbrains.anko:anko-sdk27:$anko_version"
compileOnly "org.jetbrains.anko:anko-sdk27-listeners:$anko_version"
//Glide
compileOnly 'com.github.bumptech.glide:glide:4.13.1'
compileOnly 'com.squareup.okhttp3:okhttp:4.9.3'
compileOnly 'com.google.code.gson:gson:2.9.0' compileOnly 'com.google.code.gson:gson:2.9.0'
compileOnly 'com.journeyapps:zxing-android-embedded:3.5.0'
compileOnly 'org.greenrobot:greendao:3.3.0'
compileOnly 'com.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1'
//JSoup
compileOnly 'org.jsoup:jsoup:1.14.3'
compileOnly 'cn.wanghaomiao:JsoupXpath:2.5.1'
compileOnly 'com.jayway.jsonpath:json-path:2.7.0'
//SmartRefreshLayout
compileOnly 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.2'
compileOnly 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.2'
compileOnly 'com.google.android.material:material:1.4.0'
//Scroller
compileOnly 'com.futuremind.recyclerfastscroll:fastscroll:0.2.5'
//Toasty
compileOnly 'com.github.GrenderG:Toasty:1.5.0'
//
compileOnly 'net.ricecode:string-similarity:1.0.0'
compileOnly 'com.jayway.jsonpath:json-path:2.7.0'
//RxAndroid
compileOnly 'io.reactivex.rxjava2:rxjava:2.2.19'
compileOnly 'io.reactivex.rxjava2:rxandroid:2.1.1'
//ImmersionBar
compileOnly 'com.gyf.immersionbar:immersionbar:3.0.0'
//
compileOnly 'com.luhuiguo:chinese-utils:1.0'
//
compileOnly 'com.jaredrummler:colorpicker:1.1.0'
//
compileOnly 'cn.bingoogolapple:bga-qrcode-zxing:1.3.7'
//
compileOnly 'com.github.albfernandez:juniversalchardet:2.4.0'
// https://github.com/hongyangAndroid/FlowLayout
compileOnly 'com.hyman:flowlayout-lib:1.1.2'
compileOnly 'com.liulishuo.filedownloader:library:1.7.7'
//SwipeBackLayout
compileOnly 'me.imid.swipebacklayout.lib:library:1.1.0'
//JS
//noinspection GradleDependency
compileOnly 'com.github.gedoor:rhino-android:1.6'
//XXPermissions
compileOnly 'com.github.getActivity:XXPermissions:11.2'
//epub
compileOnly('com.positiondev.epublib:epublib-core:3.1') {
exclude group: 'org.slf4j'
exclude group: 'xmlpull'
}
compileOnly 'com.nshmura:recyclertablayout:1.5.0'
// https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j
compileOnly group: 'net.lingala.zip4j', name: 'zip4j', version: '2.9.1'
//
def coroutines_version = '1.5.1'
compileOnly("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
compileOnly("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version")
//apache
compileOnly('org.apache.commons:commons-text:1.9')
//https://github.com/fengyuecanzhu/Maple
compileOnly("me.fycz.maple:maple:1.9")
compileOnly project(":app") compileOnly project(":app")
compileOnly project(":DialogX") compileOnly project(":DialogX")
} }

@ -48,9 +48,10 @@ class AppLoadImpl : IAppLoader {
App244Fix::class.java, App244Fix::class.java,
App244Fix2::class.java, App244Fix2::class.java,
App246Fix::class.java, App246Fix::class.java,
App246Fix2::class.java,
//AppSubSourceFix::class.java, //AppSubSourceFix::class.java,
App246Fix2::class.java,
App246Fix3::class.java, App246Fix3::class.java,
App246Fix4::class.java,
) )
override fun onLoad(appParam: AppParam) { override fun onLoad(appParam: AppParam) {
@ -70,7 +71,7 @@ class AppLoadImpl : IAppLoader {
} }
if (sb.isNotEmpty()) { if (sb.isNotEmpty()) {
if (sb.endsWith("\n")) sb.substring(0, sb.length - 1) if (sb.endsWith("\n")) sb.substring(0, sb.length - 1)
val key = "fix2022-06-28" val key = "fix2022-06-30"
val hasRead = spu.getBoolean(key, false) val hasRead = spu.getBoolean(key, false)
if (!hasRead) { if (!hasRead) {
announce("插件更新", "更新内容:\n$sb") announce("插件更新", "更新内容:\n$sb")

@ -0,0 +1,60 @@
/*
* This file is part of FYReader.
* FYReader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FYReader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FYReader. If not, see <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 - 2022 fengyuecanzhu
*/
package xyz.fycz.dynamic.fix
import me.fycz.maple.MapleBridge
import me.fycz.maple.MapleUtils
import me.fycz.maple.MethodReplacement
import xyz.fycz.dynamic.utils.LanZouUtils
import xyz.fycz.myreader.webapi.LanZouApi
/**
* @author fengyue
* @date 2022/6/30 20:40
*/
@AppFix([243, 244, 245, 246], ["修复书源订阅失败的问题"], "2022-06-30")
class App246Fix4: AppFixHandle {
override fun onFix(key: String): BooleanArray {
val result = try {
fxLanZouApi()
true
} catch (e: Exception) {
MapleUtils.log(e)
false
}
fixResult(key, "lanZouApi", result)
return booleanArrayOf(result)
}
private fun fxLanZouApi() {
MapleUtils.findAndHookMethod(
LanZouApi::class.java,
"getFileUrl",
String::class.java,
String::class.java,
object : MethodReplacement(){
override fun replaceHookedMethod(param: MapleBridge.MethodHookParam): Any {
return LanZouUtils.getFileUrl(param.args[0] as String, param.args[1] as String)
}
}
)
}
}

@ -0,0 +1,62 @@
/*
* This file is part of FYReader.
* FYReader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FYReader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FYReader. If not, see <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 - 2022 fengyuecanzhu
*/
package xyz.fycz.dynamic.fix
import me.fycz.maple.MapleBridge
import me.fycz.maple.MapleUtils
import me.fycz.maple.MethodHook
import xyz.fycz.myreader.common.URLCONST
import xyz.fycz.myreader.webapi.LanZouApi
/**
* @author fengyue
* @date 2022/6/21 18:30
*/
@AppFix([], ["更新订阅书源链接,仅支持v2.4.3版本及以上版本"], "2022-06-21")
class AppSubSourceFix : AppFixHandle{
override fun onFix(key: String): BooleanArray {
val result = try {
fxSubSource()
true
} catch (e: Exception) {
MapleUtils.log(e)
false
}
fixResult(key, "subSource", result)
return booleanArrayOf(result)
}
private fun fxSubSource() {
MapleUtils.findAndHookMethod(
LanZouApi::class.java,
"getFoldFiles",
String::class.java,
Int::class.java,
String::class.java,
object : MethodHook(){
override fun beforeHookedMethod(param: MapleBridge.MethodHookParam) {
if (param.args[0] == URLCONST.SUB_SOURCE_URL){
param.args[0] = "https://fycz.lanzoum.com/b00pucrch"
param.args[2] = "b0ox"
}
}
}
)
}
}

@ -0,0 +1,138 @@
/*
* This file is part of FYReader.
* FYReader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FYReader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FYReader. If not, see <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 - 2022 fengyuecanzhu
*/
package xyz.fycz.dynamic.utils
import io.reactivex.Observable
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import org.jsoup.Jsoup
import xyz.fycz.myreader.common.URLCONST
import xyz.fycz.myreader.entity.lanzou.LanZouParseBean
import xyz.fycz.myreader.util.help.StringHelper
import xyz.fycz.myreader.util.utils.GSON
import xyz.fycz.myreader.util.utils.OkHttpUtils
import xyz.fycz.myreader.util.utils.StringUtils
import xyz.fycz.myreader.util.utils.fromJsonObject
import java.net.HttpURLConnection
import java.net.URL
/**
* @author fengyue
* @date 2022/1/22 18:50
*/
object LanZouUtils {
/**
* 通过api获取蓝奏云可下载直链
*
* @param url
* @param password
*/
fun getFileUrl(url: String, password: String = ""): Observable<String> {
return Observable.create {
val html = OkHttpUtils.getHtml(url)
val url2 = if (password.isEmpty()) {
val url1 = getUrl1(html)
val data = StringUtils.getSubString(OkHttpUtils.getHtml(url1), "},", "},")
val key = getKeyValueByKey(data, "sign") + "&" + getKeyValueByKey(data, "websignkey")
getUrl2(key, url1)
} else {
getUrl2(StringHelper.getSubString(html, "sign=", "&"), url, password)
}
if (url2.contains("file")) {
it.onNext(getRedirectUrl(url2))
} else {
it.onError(Throwable(url2))
}
it.onComplete()
}
}
fun getUrl1(html: String): String {
val doc = Jsoup.parse(html)
return URLCONST.LAN_ZOU_URL + doc.getElementsByTag("iframe").attr("src")
}
fun getKeyValueByKey(html: String, key: String): String {
val keyName = StringHelper.getSubString(html, "'$key':", ",")
return if (keyName.endsWith("'")) {
key + "=" + keyName.replace("'", "")
} else {
val lanzousKeyStart = "var $keyName = '"
key + "=" + StringHelper.getSubString(html, lanzousKeyStart, "'")
}
}
fun getUrl2(key: String, referer: String, password: String = ""): String {
val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull()
val body = if (password.isEmpty()) {
"action=downprocess&signs=?ctdf&websign=&ves=1&$key"
} else {
"action=downprocess&sign=$key&p=$password"
}
val requestBody = body.toRequestBody(mediaType)
val headers = HashMap<String, String>()
headers["Referer"] = referer
val html = OkHttpUtils.getHtml(
URLCONST.LAN_ZOU_URL + "/ajaxm.php", requestBody,
"UTF-8", headers
)
return getUrl2(html)
}
private fun getUrl2(o: String): String {
val lanZouBean = GSON.fromJsonObject<LanZouParseBean>(o)
lanZouBean?.run {
return if (zt == 1) {
"$dom/file/$url"
} else {
"解析失败\n信息:$inf"
}
}
return ""
}
/**
* 获取重定向地址
*
* @param path
*/
fun getRedirectUrl(path: String): String {
val conn = URL(path)
.openConnection() as HttpURLConnection
conn.instanceFollowRedirects = false
conn.connectTimeout = 5000
conn.setRequestProperty(
"User-Agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"
)
conn.setRequestProperty("Accept-Language", "zh-cn")
conn.setRequestProperty("Connection", "Keep-Alive")
conn.setRequestProperty(
"Accept",
"image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, */*"
)
conn.connect()
val redirectUrl = conn.getHeaderField("Location")
conn.disconnect()
return redirectUrl
}
}
Loading…
Cancel
Save