feat: 去除枝网查重
This commit is contained in:
parent
d3ddf23988
commit
6eef2fcf06
|
|
@ -7,14 +7,6 @@
|
|||
"author": "huanchengfly",
|
||||
"version": "1.0",
|
||||
"main_class": "com.huanchengfly.tieba.post.plugins.PluginCommentLookup"
|
||||
},
|
||||
{
|
||||
"id": "AsoulCnki",
|
||||
"name": "枝网查重",
|
||||
"desc": "调用枝网查重 API 查询重复小作文",
|
||||
"author": "huanchengfly",
|
||||
"version": "1.0",
|
||||
"main_class": "com.huanchengfly.tieba.post.plugins.asoulcnki.PluginAsoulCnki"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.huanchengfly.tieba.post.R;
|
||||
import com.huanchengfly.tieba.post.ui.common.theme.utils.ThemeUtils;
|
||||
import com.huanchengfly.tieba.post.utils.UtilsKt;
|
||||
|
||||
public class MyURLSpan extends ClickableSpan {
|
||||
public String url;
|
||||
private final Context context;
|
||||
|
||||
public MyURLSpan(Context context, String url) {
|
||||
super();
|
||||
this.url = url;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(ThemeUtils.getColorByAttr(this.context, R.attr.colorAccent));
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(@NonNull View view) {
|
||||
UtilsKt.launchUrl(context, url);
|
||||
//context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.view.View
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import com.huanchengfly.tieba.post.R
|
||||
import com.huanchengfly.tieba.post.api.models.ThreadContentBean
|
||||
import com.huanchengfly.tieba.post.components.LinkTouchMovementMethod
|
||||
import com.huanchengfly.tieba.post.components.spans.MyImageSpan
|
||||
import com.huanchengfly.tieba.post.plugins.IPlugin
|
||||
import com.huanchengfly.tieba.post.plugins.asoulcnki.api.CheckApi
|
||||
import com.huanchengfly.tieba.post.plugins.asoulcnki.models.CheckApiBody
|
||||
import com.huanchengfly.tieba.post.plugins.interfaces.IApp
|
||||
import com.huanchengfly.tieba.post.plugins.models.PluginManifest
|
||||
import com.huanchengfly.tieba.post.plugins.registerMenuItem
|
||||
import com.huanchengfly.tieba.post.toJson
|
||||
import com.huanchengfly.tieba.post.ui.common.theme.utils.ThemeUtils
|
||||
import com.huanchengfly.tieba.post.utils.DisplayUtil
|
||||
import com.huanchengfly.tieba.post.utils.Util
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.text.NumberFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class PluginAsoulCnki(app: IApp, manifest: PluginManifest) : IPlugin(app, manifest) {
|
||||
override fun onEnable() {
|
||||
super.onEnable()
|
||||
registerMenuItem<ThreadContentBean.PostListItemBean>(
|
||||
"asoul_cnki_check",
|
||||
context.getString(R.string.plugin_asoul_cnki_check)
|
||||
) { data ->
|
||||
val dialog = app.showLoadingDialog()
|
||||
val body = CheckApiBody(getPostTextContent(data)).toJson()
|
||||
launch(Dispatchers.IO + job) {
|
||||
val result =
|
||||
CheckApi.instance.checkAsync(body.toRequestBody("application/json, charset=utf-8".toMediaTypeOrNull()))
|
||||
.await()
|
||||
launch(Dispatchers.Main + job) {
|
||||
dialog.cancel()
|
||||
if (result.code == 0) {
|
||||
val numberFormatter = NumberFormat.getNumberInstance().apply {
|
||||
maximumFractionDigits = 2
|
||||
minimumFractionDigits = 2
|
||||
}
|
||||
app.showAlertDialog {
|
||||
setTitle("查重结果")
|
||||
val percent = "${numberFormatter.format(result.data.rate * 100.0)}%"
|
||||
val resultForCopy = context.getString(
|
||||
R.string.plugin_asoul_cnki_result,
|
||||
formatDateTime("yyyy-MM-dd HH:mm:ss"),
|
||||
percent,
|
||||
if (result.data.related.isNotEmpty()) {
|
||||
context.getString(
|
||||
R.string.plugin_asoul_cnki_related,
|
||||
result.data.related[0].replyUrl,
|
||||
result.data.related[0].reply.mName,
|
||||
formatDateTime(
|
||||
"yyyy-MM-dd HH:mm",
|
||||
result.data.related[0].reply.ctime * 1000L
|
||||
)
|
||||
)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
)
|
||||
val view = View.inflate(
|
||||
context,
|
||||
R.layout.plugin_asoul_cnki_dialog_check_result,
|
||||
null
|
||||
)
|
||||
val percentView = view.findViewById<TextView>(R.id.check_result_percent)
|
||||
val progress =
|
||||
view.findViewById<ProgressBar>(R.id.check_result_progress)
|
||||
val relatedView = view.findViewById<View>(R.id.check_result_related)
|
||||
val relatedTitle =
|
||||
view.findViewById<TextView>(R.id.check_result_related_title)
|
||||
val relatedContent =
|
||||
view.findViewById<TextView>(R.id.check_result_related_content)
|
||||
percentView.text = context.getString(
|
||||
R.string.plugin_asoul_cnki_check_result_percent,
|
||||
percent
|
||||
)
|
||||
progress.progress = (result.data.rate * 10000).toInt()
|
||||
if (result.data.related.isNullOrEmpty()) {
|
||||
relatedView.visibility = View.GONE
|
||||
} else {
|
||||
relatedView.visibility = View.VISIBLE
|
||||
relatedTitle.text = context.getString(
|
||||
R.string.plugin_asoul_cnki_check_result_related,
|
||||
result.data.related.size
|
||||
)
|
||||
}
|
||||
val relatedContentText = SpannableStringBuilder()
|
||||
result.data.related.forEach {
|
||||
relatedContentText.appendLink("${it.reply.mName} 的评论", it.replyUrl)
|
||||
.append("\n")
|
||||
}
|
||||
relatedContent.apply {
|
||||
text = relatedContentText
|
||||
movementMethod = LinkTouchMovementMethod.getInstance()
|
||||
}
|
||||
setView(view)
|
||||
setPositiveButton(R.string.btn_copy_check_result) { _, _ ->
|
||||
app.copyText(resultForCopy)
|
||||
}
|
||||
setNegativeButton(R.string.btn_close, null)
|
||||
}
|
||||
} else {
|
||||
app.toastShort("查重失败 ${result.code}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun SpannableStringBuilder.appendLink(
|
||||
text: CharSequence,
|
||||
url: String
|
||||
): SpannableStringBuilder {
|
||||
val spannableStringBuilder = SpannableStringBuilder()
|
||||
val size = DisplayUtil.sp2px(context, 14f)
|
||||
val bitmap = Util.tintBitmap(
|
||||
Bitmap.createScaledBitmap(
|
||||
Util.getBitmapFromVectorDrawable(
|
||||
context,
|
||||
R.drawable.ic_link
|
||||
),
|
||||
size,
|
||||
size,
|
||||
true
|
||||
),
|
||||
ThemeUtils.getColorByAttr(context, R.attr.colorAccent)
|
||||
)
|
||||
spannableStringBuilder.append(
|
||||
"[链接]",
|
||||
MyImageSpan(context, bitmap),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
spannableStringBuilder.append(" ")
|
||||
spannableStringBuilder.append(
|
||||
text,
|
||||
MyURLSpan(context, url),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
return append(spannableStringBuilder)
|
||||
}
|
||||
|
||||
fun getPostTextContent(item: ThreadContentBean.PostListItemBean): String {
|
||||
val stringBuilder = StringBuilder()
|
||||
for (contentBean in item.content ?: emptyList()) {
|
||||
when (contentBean.type) {
|
||||
"2" -> contentBean.setText("#(" + contentBean.c + ")")
|
||||
"3", "20" -> contentBean.setText("[图片]\n")
|
||||
"10" -> contentBean.setText("[语音]\n")
|
||||
}
|
||||
if (contentBean.text != null) {
|
||||
stringBuilder.append(contentBean.text)
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
private fun formatDateTime(
|
||||
pattern: String,
|
||||
timestamp: Long = System.currentTimeMillis()
|
||||
): String {
|
||||
return SimpleDateFormat(pattern, Locale.getDefault()).format(Date(timestamp))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.api
|
||||
|
||||
import com.huanchengfly.tieba.post.api.retrofit.NullOnEmptyConverterFactory
|
||||
import com.huanchengfly.tieba.post.api.retrofit.adapter.DeferredCallAdapterFactory
|
||||
import com.huanchengfly.tieba.post.api.retrofit.converter.gson.GsonConverterFactory
|
||||
import okhttp3.ConnectionPool
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
|
||||
object CheckApi {
|
||||
private val connectionPool = ConnectionPool()
|
||||
|
||||
val instance: ICheckApi by lazy {
|
||||
Retrofit.Builder()
|
||||
.baseUrl("https://asoulcnki.asia/")
|
||||
.addCallAdapterFactory(DeferredCallAdapterFactory())
|
||||
.addConverterFactory(NullOnEmptyConverterFactory())
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.client(OkHttpClient.Builder().apply {
|
||||
connectionPool(connectionPool)
|
||||
sslSocketFactory(
|
||||
SSLSocketClient.getSSLSocketFactory(),
|
||||
SSLSocketClient.getX509TrustManager()
|
||||
)
|
||||
hostnameVerifier(SSLSocketClient.getHostnameVerifier())
|
||||
}.build())
|
||||
.build()
|
||||
.create(ICheckApi::class.java)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.api
|
||||
|
||||
import com.huanchengfly.tieba.post.api.ParamExpression
|
||||
import com.huanchengfly.tieba.post.api.forEachNonNull
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
class CommonHeaderInterceptor(private vararg val additionHeaders: ParamExpression) : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
val headers = request.headers
|
||||
|
||||
return chain.proceed(request.newBuilder().apply {
|
||||
additionHeaders.forEachNonNull { name, value ->
|
||||
if (headers[name] == null) addHeader(name, value)
|
||||
}
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.api
|
||||
|
||||
import com.huanchengfly.tieba.post.plugins.asoulcnki.models.CheckResult
|
||||
import kotlinx.coroutines.Deferred
|
||||
import okhttp3.RequestBody
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.Headers
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface ICheckApi {
|
||||
@POST("/v1/api/check")
|
||||
@Headers("content-type: application/json;charset=UTF-8")
|
||||
fun checkAsync(
|
||||
@Body requestBody: RequestBody
|
||||
): Deferred<CheckResult>
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.api;
|
||||
|
||||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
|
||||
public class SSLSocketClient {
|
||||
|
||||
//获取这个SSLSocketFactory
|
||||
public static SSLSocketFactory getSSLSocketFactory() {
|
||||
try {
|
||||
SSLContext sslContext = SSLContext.getInstance("SSL");
|
||||
sslContext.init(null, getTrustManager(), new SecureRandom());
|
||||
return sslContext.getSocketFactory();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//获取TrustManager
|
||||
private static TrustManager[] getTrustManager() {
|
||||
return new TrustManager[]{
|
||||
new X509TrustManager() {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[]{};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//获取HostnameVerifier
|
||||
public static HostnameVerifier getHostnameVerifier() {
|
||||
return (s, sslSession) -> true;
|
||||
}
|
||||
|
||||
public static X509TrustManager getX509TrustManager() {
|
||||
X509TrustManager trustManager = null;
|
||||
try {
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
trustManagerFactory.init((KeyStore) null);
|
||||
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
|
||||
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
|
||||
throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
|
||||
}
|
||||
trustManager = (X509TrustManager) trustManagers[0];
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return trustManager;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.models
|
||||
|
||||
data class CheckApiBody(
|
||||
val text: String
|
||||
)
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.models
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
data class CheckResult(
|
||||
val code: Int, // 0
|
||||
val `data`: Data,
|
||||
val message: String // success
|
||||
) {
|
||||
@Keep
|
||||
data class Data(
|
||||
@SerializedName("end_time")
|
||||
val endTime: Int, // 1629010807
|
||||
val rate: Double, // 1.0
|
||||
val related: List<Related>,
|
||||
@SerializedName("start_time")
|
||||
val startTime: Int // 1606137506
|
||||
) {
|
||||
@Keep
|
||||
data class Related(
|
||||
val rate: Double, // 1.0
|
||||
val reply: Reply,
|
||||
@SerializedName("reply_url")
|
||||
val replyUrl: String // https://www.bilibili.com/video/av377092608/#reply5051494613
|
||||
) {
|
||||
@Keep
|
||||
data class Reply(
|
||||
val content: String, // 曾几何时,我也想像asoul的beeeeeeeela一样做幸福滤镜下的事至少在这层滤镜下,beeeeeeeela的一举一动都是随心所欲且浪漫真实的当我看到beeeeeeeela能像个二次元一样和弹幕大谈特谈50音,当我看到beeeeeeeela能够笑着在夜里唱着不知道练了多少遍的云烟成雨,当我看到她可以在失落后得到安抚和拥抱…以往的笑意消散殆尽,剩下的只有我对beeeeeeeela浪漫的感动和一种无中生有的失意了。我也想像她一样。但这是虚假的,每次在烂醉酩酊起来后依然会痛苦,每次在浪费时间的时候都能意识到,你不能感受到我感受到的东西。但就算是这样,没了你我可能就会完蛋了吧。因为我们需要一个梦。
|
||||
val ctime: Int, // 1627881576
|
||||
@SerializedName("dynamic_id")
|
||||
val dynamicId: String, // 553473662133564230
|
||||
@SerializedName("like_num")
|
||||
val likeNum: Int, // 9
|
||||
@SerializedName("m_name")
|
||||
val mName: String, // 走出童年
|
||||
val mid: Int, // 671239951
|
||||
val oid: String, // 377092608
|
||||
@SerializedName("origin_rpid")
|
||||
val originRpid: String, // -1
|
||||
val rpid: String, // 5051494613
|
||||
@SerializedName("similar_count")
|
||||
val similarCount: Int, // 1
|
||||
@SerializedName("similar_like_sum")
|
||||
val similarLikeSum: Int, // 424
|
||||
@SerializedName("type_id")
|
||||
val typeId: Int, // 1
|
||||
val uid: Int // 672346917
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue