This commit is contained in:
lunaticbum 2025-07-24 14:54:31 +09:00
parent 668d33543c
commit 193946cadf
10 changed files with 281 additions and 115 deletions

View File

@ -13,11 +13,14 @@
},
"content_scripts": [
{
"run_at": "document_end",
"matches": ["<all_urls>"],
"js": ["messaging.js"]
}
],
"permissions": [
"cookies",
"<all_urls>",
"nativeMessaging",
"nativeMessagingFromContent",
"geckoViewAddons",

View File

@ -1,3 +1,5 @@
const port = browser.runtime.connectNative("browser");
port.onMessage.addListener(response => {
var type= response["type"];
@ -238,7 +240,13 @@ function toast(msg) {
}
var time1 = null
if (port) {
sendMessage({type: "MSG", msg:"connect prot"});
time1 = setTimeout(
function(){
if (location.hostname.search("clien") > -1 && document.querySelectorAll('[class^="view_top"]')) {
document.querySelectorAll('[class^="view_top"]').forEach(e => e.remove())
@ -323,9 +331,17 @@ if (port) {
var thumb = ""
try {
thumb = e.querySelector("td").querySelector("a").getAttribute('data-link')
}catch (e) {
try {
var sets = e.querySelector("td").querySelector("img").getAttribute('srcset')
if(sets.search(",") > -1) {
var srcSet = sets.split(",")
var newT = srcSet[srcSet.length - 1]
if (newT != null && newT.length > 5) {
thumb = newT
}
}
} catch (e) {}
}catch (e) {}
var magnet = ""
try {
e.querySelectorAll("td").forEach(function (e) {
@ -351,7 +367,6 @@ if (port) {
}
var originPage = ""
try {
originPage = location.protocol + "//" + location.hostname + e.querySelector(".name").querySelector("a").getAttribute("href");
}catch (e) {
@ -366,6 +381,7 @@ if (port) {
}catch (e) {
}
if (thumb.length > 0 || screenshots.length > 0) {}
datas.push({
"title" : title,
"description" : desc,
@ -381,57 +397,52 @@ if (port) {
sendMessage(
{
type: "PRIVATES",
privates: datas
privates: datas,
currentPage : location.href
}
);
gotoNext()
}
},1500)
}
var targetUrl = ""
var time2 = null
function gotoNext() {
clearTimeout(time1)
try{
var url = new URL(location.href);
var params = url.searchParams;
var keys = Array.from(params.keys());
console.log("targetUrl :: " + params);
console.log("targetUrl :: " + keys.length);
if (keys.length === 0 && location.href.search("page") < 0) {
targetUrl = location.protocol + "//" + location.hostname + "/?page=2"
} else {
try {
var lastValue = params.get("page");
console.log("targetUrl :: " + lastValue);
var numValue = Number(lastValue);
console.log("targetUrl :: " + numValue);
if (numValue < Number("5")) {
params.set("page", (numValue + 1).toString());
console.log("targetUrl :: " + params);
url.search = params.toString();
console.log("targetUrl :: " + url.search);
targetUrl = url.toString();
} else {
console.log("targetUrl :: ");
}
} catch (e) {
console.error(e)
}
}
console.log("targetUrl :: " + targetUrl);
time2 = setTimeout(function () {
clearTimeout(time2)
if (targetUrl.length > 5) {
console.log("targetUrl :: " + targetUrl);
location.href = targetUrl
document.querySelector('[class="btn-group"]').querySelectorAll('a').forEach(function(e){
if(e.hasAttribute("href") &&
(
(e.getAttribute("href").search("page=2") > -1 && location.href.search("page") < 0) ||
(e.getAttribute("href").search("page=3") > -1 && location.href.search("page=2") > 0)
)) {
e.click()
}
})
}, 5000);
} catch (e) {
}
}
//
// if (document.readyState === "complete" || document.readyState === "interactive") {
// reportCookiesToNative();
// } else {
// window.addEventListener("DOMContentLoaded", reportCookiesToNative);
// }
// function reportCookiesToNative() {
// // 모든 쿠키를 읽어 네이티브로 전달
// sendMessage({type: "MSG", cookies: "DOMContentLoaded try to cookies send"});
// window.cookies.getAll({url: window.location.href}).then((cookies) => {
// // 쿠키 데이터를 네이티브(Android)로 전송
// sendMessage({type: "Cookies", cookies: cookies});
// });
// }

View File

@ -731,7 +731,7 @@ internal class LauncherActivity : CommonActivity() {
when(currentFragment) {
is RssHome ->{
if (currentFragment.binding.layoutRssSummary.root.isVisible) {
currentFragment.openGecko("")
currentFragment.openGecko(rssData = currentFragment.lasted.randomOrNull())
} else {
currentFragment.doNextPage()
}

View File

@ -24,12 +24,18 @@ import android.content.Context
import android.database.sqlite.SQLiteDatabase
import bums.lunatic.launcher.helpers.PrefHelper
import bums.lunatic.launcher.utils.Blog
import com.squareup.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso
import kr.lunaticbum.Base
import okhttp3.Cache
import okhttp3.OkHttpClient
import org.json.JSONObject
import org.mozilla.geckoview.ExperimentDelegate
import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.GeckoRuntime
import org.mozilla.geckoview.GeckoRuntimeSettings
import java.io.File
import java.util.concurrent.TimeUnit
internal class LunaticLauncher : Application() {
@ -43,6 +49,33 @@ internal class LunaticLauncher : Application() {
appContext = this
Base.initialize(this)
PrefHelper.initialize(this)
val cacheSize = 1024L * 1024 * 1024 // 60MB
val cache = Cache(File(this.filesDir, "picasso-cache"), cacheSize)
val okHttpClient = OkHttpClient.Builder()
.cache(cache)
.addInterceptor { chain ->
val newRequest = chain.request().newBuilder()
.addHeader("Host","images.ijavtorrent.com")
.addHeader("User-Agent","Mozilla/5.0 (Android 15; Mobile; rv:139.0) Gecko/139.0 Firefox/139.0")
.addHeader("Accept","image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5")
.addHeader("Accept-Language","ko-KR,en-US;q=0.5")
.addHeader("Accept-Encoding","gzip, deflate, br, zstd")
.addHeader("Referer","https://ijavtorrent.com/")
.build()
chain.proceed(newRequest)
}
.connectTimeout(10, TimeUnit.SECONDS) // 연결 타임아웃
.readTimeout(30, TimeUnit.SECONDS) // 읽기 타임아웃
.writeTimeout(30, TimeUnit.SECONDS) // 쓰기 타임아웃
.build()
val picasso = Picasso.Builder(this)
.downloader(OkHttp3Downloader(okHttpClient))
.build()
// 앱 전체에 해당 인스턴스를 사용하려면
Picasso.setSingletonInstance(picasso)
}

View File

@ -482,8 +482,12 @@ class GeckoWeb : BWebview {
copyToRealm(it, UpdatePolicy.ALL)
}
}
Toast.makeText(context, "Received Msg privates form ${lPortMessage.currentPage} data => ${lPortMessage.privates?.size ?: 0}", Toast.LENGTH_SHORT).show()
}
}
"Cookies"->{
Blog.LOGE("cookies >>> ${lPortMessage.cookies}")
}
"PagerContents" -> {
if (lPortMessage.contents?.isNotEmpty() == true) {

View File

@ -19,6 +19,7 @@
package bums.lunatic.launcher.home
import android.annotation.SuppressLint
import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
@ -30,9 +31,11 @@ import android.view.LayoutInflater
import android.view.PointerIcon
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageView
import android.widget.Toast
import androidx.annotation.NonNull
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.databinding.BindingAdapter
import androidx.fragment.app.Fragment
@ -64,6 +67,7 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.google.android.material.imageview.ShapeableImageView
import com.google.gson.Gson
import com.squareup.picasso.Picasso
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query
import io.realm.kotlin.notifications.InitialResults
@ -76,6 +80,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
internal class RssHome : Fragment() {
@ -113,7 +119,7 @@ internal class RssHome : Fragment() {
): Boolean {
Blog.LOGE("")
if (imageView){
openGecko("")
openGecko(rssData = lasted.randomOrNull())
}
return true
}
@ -125,7 +131,7 @@ internal class RssHome : Fragment() {
gestureDistance: Double
): Boolean {
if (imageView){
openGecko("")
openGecko(rssData = lasted.randomOrNull())
}
Blog.LOGE("")
return true
@ -217,7 +223,7 @@ internal class RssHome : Fragment() {
RssDataType.REDDIT_NSFW,RssDataType.PRIVATE -> {
v.findViewById<ShapeableImageView>(R.id.circle_preview)?.let {
if (RssDataType.PRIVATE.equals(rss.category()) && imageView) {
openGecko("")
openGecko(rssData = lasted.randomOrNull())
} else {
if (it.visibility == View.GONE) {
it.visibility = View.VISIBLE
@ -257,8 +263,35 @@ internal class RssHome : Fragment() {
}
}
fun openGecko(originPage: String) {
fun ask() {
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
builder.setTitle("Command Line")
val viewInflated: View = LayoutInflater.from(requireContext())
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
val input = viewInflated.findViewById<View>(R.id.input) as EditText
builder.setView(viewInflated)
builder.setPositiveButton(android.R.string.ok,
DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss()
var command = input.editableText?.toString()
if (command?.length ?: 0 > 0) {
binding.geckoWeb.loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=", "/?searchTerm=${command}")
} else {
binding.geckoWeb.loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=")
}
})
builder.setNegativeButton(android.R.string.cancel,
DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
builder.show()
}
@SuppressLint("SimpleDateFormat")
fun openGecko(originPage: String? = null, rssData: RssData? = null) {
if (!imageView) {
originPage?.let {
rssId = originPage
targetList.clear()
@ -268,50 +301,49 @@ internal class RssHome : Fragment() {
targetList.addAll(setString)
binding.geckoWeb.loadUrl(rssId)
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
if (lasted.size > 0) {
lasted?.removeFirst()?.let {
rssData?.let {
Blog.LOGE("removeFirst >>> ${Gson().toJson(it)}")
binding.layoutRssSummary.title.tag = it
binding.layoutRssSummary.root.visibility = View.VISIBLE
it.title()?.let {
Blog.LOGE(it)
binding.layoutRssSummary.title.text = it
}
it.pubDate()?.let {
Blog.LOGE("")
binding.layoutRssSummary.date.text =
SimpleDateFormat("yyyy.MM.dd HH-mm").format(Date(it))
}
binding.layoutRssSummary.desc.tag = it
it.description()?.let {
Blog.LOGE(it)
binding.layoutRssSummary.desc.text = it
}
binding.layoutRssSummary.link.tag = it
it.getMagnet().let {
Blog.LOGE(it)
binding.layoutRssSummary.link.text = it
}
binding.layoutRssSummary.cover.tag = it
it.thumbnailUrl().let {
Blog.LOGE(it)
loadImage(binding.layoutRssSummary.cover, it)
binding.layoutRssSummary.coverLink.text = it
}
binding.layoutRssSummary.screen.tag = it
it.getScreen().let {
Blog.LOGE(it)
loadImage(binding.layoutRssSummary.screen, it)
binding.layoutRssSummary.screenLink.text = it
}
}
} else {
binding.home.performClick()
}
}
// targetList.clear()
// lasted?.forEach {
// it.thumbnail?.let {
// targetList.add(it)
// }
// }
// rssId = targetList.removeAt(0)
// binding.geckoWeb.loadUrl(rssId)
}
}
@SuppressLint("ClickableViewAccessibility")
override fun onCreateView(
@ -347,7 +379,7 @@ internal class RssHome : Fragment() {
}
binding.geckoWeb.visibility = View.GONE
binding.geckoWeb.loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=")
ask()
}
binding.hide.setOnClickListener {
@ -384,8 +416,19 @@ internal class RssHome : Fragment() {
binding.prv.setOnClickListener {
queryPrevate()
}
binding.layoutRssSummary.link.setOnClickListener {
(it.tag as? RssData)?.let {
appendReadCount(it, 1, true)
}
}
binding.layoutRssSummary.title.setOnClickListener {
(it.tag as? RssData)?.let {
appendReadCount(it, nomoreShowCount, false)
openGecko(rssData = lasted.randomOrNull())
}
}
binding.layoutRssSummary.close.setOnClickListener {
binding.home.performClick()
binding.layoutRssSummary.root.visibility = View.GONE
}
queryInfos()
@ -461,7 +504,7 @@ internal class RssHome : Fragment() {
delete(
query<RssData>()
.query("pubDate < $0", beforeDay(30))
// .query("category != $0 AND category != $1 ", RssDataType.GURU.name, RssDataType.MOST.name)
.query("category != $0 AND category != $1 ", RssDataType.PRIVATE.name, RssDataType.REDDIT_NSFW.name)
.query("vote != $0", true).find()
)
}
@ -554,6 +597,20 @@ internal class RssHome : Fragment() {
lasted?.let { mRssAdapter.updateData(it) }
}
fun appendReadCount(rss: RssData, appendCount : Int, vote : Boolean = false) {
WorkersDb.getRealm().apply {
writeBlocking {
var results = query<RssData>("originPage == $0", rss.originPage).find()
results.forEach { rss ->
if (false == rss.vote) {
rss.vote = vote
}
rss.read = rss.read.plus(appendCount)
}
}
}
}
private fun enableSwipeToDeleteAndUndo() {
val swipeToDeleteCallback: SwipeToDeleteCallback =
object : SwipeToDeleteCallback(requireContext()) {
@ -619,17 +676,40 @@ internal class RssHome : Fragment() {
}
@BindingAdapter("imageUrl")
fun loadImage(imageView: ImageView, url: String?) {
url?.let {
if (it.length > 4) {
Blog.LOGE("loadImage >>> $it")
Glide.with(imageView.context)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.fitCenter()
.into(imageView)
fun loadImage(imageView: ImageView, url: String?, retryCount: Int = 3) {
Picasso.get().cancelRequest(imageView)
url?.let { url ->
if (url.length > 4) {
try {
imageView.visibility = View.VISIBLE
imageView.setAlpha(0.05f)
Blog.LOGE("loadImage >>> $url")
Picasso.get()
.load(url)
.into(imageView, object : com.squareup.picasso.Callback {
override fun onSuccess() {
imageView.setAlpha(0.05f)
}
override fun onError(e: Exception?) {
e?.printStackTrace()
if (retryCount > 0) {
// 메인 스레드에서 재시도
Handler(Looper.getMainLooper()).post {
loadImage(imageView, url, retryCount - 1)
}
} else {
// 3회 모두 실패: 대체 이미지 표시
imageView.setImageResource(R.drawable.ic_info)
imageView.setAlpha(1f)
}
}
})
imageView.contentDescription = url
}catch (e: Exception){
}
} else {
imageView.visibility = View.INVISIBLE
}

View File

@ -13,6 +13,8 @@ class PortMessage {
var msg : String? = null
var contents : String? = null
var privates : ArrayList<RssData>? = null
var currentPage : String? = null
var cookies : String? = null
}
class BookContents {
var chapterTitle : String? = null

View File

@ -160,11 +160,14 @@ open class BWebview : GeckoView {
var lastDomain : String = ""
fun loadUrl(url: String) {
fun loadUrl(url: String, param : String? = null) {
var nUrl = url
Blog.LOGE("url >>>> ${url}")
if (url.endsWith("=")) {
nUrl = String(Base64.getMimeDecoder().decode(url.toByteArray()))
param?.let {
nUrl = nUrl.plus(param)
}
} else if (url.startsWith("http") == false) {
nUrl = lastDomain
}

View File

@ -224,7 +224,7 @@ object WorkersDb {
}
}
fun getPrivate() = getRealm().query<RssData>().query("category == $0 ",
RssDataType.PRIVATE.name).distinct("originPage", "title").sort("pubDate", Sort.DESCENDING)
RssDataType.PRIVATE.name).distinct("originPage", "title").query("read < $0", 5).query("vote != $0", true)
fun getVotedRss() = getRealm().query<RssData>().query("vote == $0", true).distinct("originPage", "title")

View File

@ -34,14 +34,34 @@
android:textColor="@color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ImageView
<TextView
app:layout_constraintTop_toBottomOf="@id/title"
android:alpha="0.6"
android:id="@+id/date"
android:gravity="center_vertical|right"
android:singleLine="false"
android:background="#000"
android:textSize="@dimen/_20sp"
android:textColor="@color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ImageView
app:layout_constraintTop_toBottomOf="@id/date"
android:alpha="0.05"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:id="@+id/cover"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
app:layout_constraintTop_toTopOf="@id/cover"
android:id="@+id/cover_link"
android:gravity="center_vertical|right"
android:singleLine="false"
android:background="#000"
android:textSize="@dimen/_12sp"
android:textColor="@color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
app:layout_constraintTop_toBottomOf="@id/cover"
android:id="@+id/desc"
@ -54,11 +74,21 @@
<ImageView
app:layout_constraintTop_toBottomOf="@id/desc"
android:id="@+id/screen"
android:alpha="0.6"
android:alpha="0.05"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
app:layout_constraintTop_toTopOf="@id/screen"
android:id="@+id/screen_link"
android:gravity="center_vertical|right"
android:singleLine="false"
android:background="#000"
android:textSize="@dimen/_12sp"
android:textColor="@color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
app:layout_constraintTop_toBottomOf="@id/screen"
android:id="@+id/link"