From 520350f9d1beb5e2f1da96de10dd97b399fa407f Mon Sep 17 00:00:00 2001 From: lunaticbum Date: Sun, 31 Aug 2025 13:07:04 +0900 Subject: [PATCH] ... --- app/build.gradle.kts | 1 + .../bums/lunatic/launcher/LunaticLauncher.kt | 39 +++++++++--- .../lunatic/launcher/feeds/rss/RssAdapter.kt | 9 ++- .../launcher/helpers/ForeGroundService.kt | 8 +-- .../bums/lunatic/launcher/home/GeckoWeb.kt | 6 +- .../bums/lunatic/launcher/home/RssHome.kt | 63 ++++++++++++++++--- .../launcher/home/adapters/RssItemAdapter.kt | 16 ++--- .../lunatic/launcher/utils/CommonUtils.kt | 4 +- .../launcher/workers/LocationUpdateService.kt | 7 ++- 9 files changed, 113 insertions(+), 40 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7ca55c8c..a733e4f3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -149,6 +149,7 @@ dependencies { implementation("io.github.junkfood02.youtubedl-android:ffmpeg:0.17.4") implementation("io.github.junkfood02.youtubedl-android:aria2c:0.17.4") + implementation ("com.squareup.okhttp3:logging-interceptor:4.11.0") // implementation ("com.arthenica:ffmpeg-kit-full:4.5.LTS") // implementation ("com.arthenica:ffmpeg-kit-full:6.0-2") diff --git a/app/src/main/kotlin/bums/lunatic/launcher/LunaticLauncher.kt b/app/src/main/kotlin/bums/lunatic/launcher/LunaticLauncher.kt index 5782bc4b..2d9e4f2f 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/LunaticLauncher.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/LunaticLauncher.kt @@ -22,6 +22,7 @@ import android.app.Application import android.content.ComponentCallbacks2 import android.database.sqlite.SQLiteDatabase import android.net.Uri +import android.view.PixelCopy.request import bums.lunatic.launcher.helpers.HourlyLogWriter import bums.lunatic.launcher.helpers.PrefHelper import bums.lunatic.launcher.utils.Blog @@ -30,6 +31,7 @@ import com.squareup.picasso.Picasso import kr.lunaticbum.Base import okhttp3.Cache import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor import java.io.File import java.io.IOException import java.net.HttpURLConnection @@ -55,25 +57,44 @@ internal class LunaticLauncher : Application() { // dir.listFiles().forEach { Blog.LOGE("child -> ${it.absolutePath}") } } mHourlyLogWriter = HourlyLogWriter(dir) - val cacheSize = 1024L * 1024 * 1024 // 60MB + val logging = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.HEADERS + } + val cacheSize = 1024L * 1024 * 1024 * 6 // 60MB val cache = Cache(File(this.filesDir, "picasso-cache"), cacheSize) val okHttpClient = OkHttpClient.Builder() .cache(cache) + .addInterceptor(logging) .addInterceptor { chain -> - val newRequest = chain.request().newBuilder() - .addHeader("Host",chain.request().url().host()) + var request = chain.request() + val cacheControl = request.header("Cache-Control") + if (cacheControl?.contains("only-if-cached") == true) { + val newCacheControl = cacheControl.replace("only-if-cached", "") + .trim() + .ifEmpty { "max-stale=2419200" } + request = request.newBuilder() + .header("Cache-Control", newCacheControl) + .build() + } + val host = chain.request().url.host + val newRequest = chain.request().newBuilder().addHeader("authority",host) + .addHeader("Host",host) .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",chain.request().url().host()) + .addHeader("Referer",host) .build() - Blog.LOGE("chain.request().url() >>> ${chain.request().url()}") - chain.proceed(newRequest) + + Blog.LOGE("chain.request().url() >>> ${chain.request().url} : host : $host") + val response = chain.proceed(newRequest) + Blog.LOGE("응답 코드: ${response.code}:${response.message}") + response } - .connectTimeout(30, TimeUnit.SECONDS) // 연결 타임아웃 - .readTimeout(30, TimeUnit.SECONDS) // 읽기 타임아웃 - .writeTimeout(30, TimeUnit.SECONDS) // 쓰기 타임아웃 + .callTimeout(60, TimeUnit.SECONDS) + .connectTimeout(60, TimeUnit.SECONDS) // 연결 타임아웃 + .readTimeout(60, TimeUnit.SECONDS) // 읽기 타임아웃 + .writeTimeout(60, TimeUnit.SECONDS) // 쓰기 타임아웃 .build() val picasso = Picasso.Builder(this) diff --git a/app/src/main/kotlin/bums/lunatic/launcher/feeds/rss/RssAdapter.kt b/app/src/main/kotlin/bums/lunatic/launcher/feeds/rss/RssAdapter.kt index bc3d78e1..de0fd222 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/feeds/rss/RssAdapter.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/feeds/rss/RssAdapter.kt @@ -33,6 +33,7 @@ import bums.lunatic.launcher.databinding.ListItemWithBinding import bums.lunatic.launcher.home.adapters.RssItemDiffUtil import bums.lunatic.launcher.model.RssDataInterface import bums.lunatic.launcher.model.RssDataType +import com.squareup.picasso.NetworkPolicy import com.squareup.picasso.Picasso import java.net.URLEncoder import java.nio.charset.Charset @@ -81,9 +82,11 @@ internal class RssAdapter(private val context: Context) : holder.view.date.visibility = View.VISIBLE } - - if (item.thumbnailUrl().length ?: 0 > 6) { - Picasso.get().load(item.thumbnailUrl()).into(holder.view.circlePreview) + if (!item.category().equals(RssDataType.PRIVATE)) { + if (item.thumbnailUrl().length ?: 0 > 6) { + Picasso.get().load(item.thumbnailUrl()).networkPolicy(NetworkPolicy.NO_CACHE) + .into(holder.view.circlePreview) + } } holder.view.root.setOnClickListener { diff --git a/app/src/main/kotlin/bums/lunatic/launcher/helpers/ForeGroundService.kt b/app/src/main/kotlin/bums/lunatic/launcher/helpers/ForeGroundService.kt index 6e1cf360..43f38b9f 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/helpers/ForeGroundService.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/helpers/ForeGroundService.kt @@ -320,8 +320,8 @@ class ForeGroundService : Service() { .connectionPool(ConnectionPool(5, 60, TimeUnit.SECONDS)) .build().newCall(Request.Builder().url("https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/sendMessage?chat_id=${PrefString.telegramSendTarget.get()}&text=${msg}") .addHeader("Content-Type", "application/json").get().build()).execute()?.let { response -> - if (response.isSuccessful()) { - val body: ResponseBody? = response.body() + if (response.isSuccessful) { + val body: ResponseBody? = response.body if (body != null) { } } else Blog.LOGE("sendToI telegram Error Occurred") } @@ -344,9 +344,9 @@ class ForeGroundService : Service() { .connectionPool(ConnectionPool(5, 60, TimeUnit.SECONDS)) .build().newCall(Request.Builder().url(url) .addHeader("Content-Type", "application/json").get().build()).execute() - if (response.isSuccessful()) { + if (response.isSuccessful) { // 응답 받아서 처리 - val body: ResponseBody? = response.body() + val body: ResponseBody? = response.body if (body != null) { } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt index c39053e4..9334e43d 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt @@ -476,7 +476,7 @@ class GeckoWeb : BWebview { val client = OkHttpClient() val request = Request.Builder() .url(url) - .addHeader("Referer", lastedUrl) + .addHeader("Referer", lastedUrl ?: "") .addHeader("User-Agent", "Mozilla/5.0") // 필요시 Referer, 쿠키 등 헤더 추가 .build() @@ -484,7 +484,7 @@ class GeckoWeb : BWebview { Thread { // 네트워크로 인한 별도 스레드 필요(코루틴도 가능) val responseOk = client.newCall(request).execute() if (responseOk.isSuccessful) { - responseOk.body()?.byteStream()?.use { input -> + responseOk.body?.byteStream()?.use { input -> FileOutputStream(savePath).use { output -> input.copyTo(output) } @@ -496,7 +496,7 @@ class GeckoWeb : BWebview { } } else { Handler(Looper.getMainLooper()).post { - Toast.makeText(context, "다운로드 실패: ${responseOk.message()}", Toast.LENGTH_SHORT).show() + Toast.makeText(context, "다운로드 실패: ${responseOk.message}", Toast.LENGTH_SHORT).show() } } dialog?.dismiss() diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt index 2089f540..c6b9eab0 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt @@ -23,6 +23,7 @@ import android.content.Context import android.content.DialogInterface import android.content.Intent import android.content.SharedPreferences +import android.graphics.BitmapFactory import android.net.Uri import android.os.Bundle import android.os.Handler @@ -47,6 +48,7 @@ import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView +import androidx.work.NetworkType import bums.lunatic.launcher.LauncherActivity import bums.lunatic.launcher.LauncherActivity.Companion.lActivity import bums.lunatic.launcher.LunaticLauncher @@ -71,6 +73,7 @@ import bums.lunatic.launcher.workers.WorkersDb import bums.lunatic.launcher.workers.WorkersDb.getRealm import com.google.android.material.imageview.ShapeableImageView import com.google.gson.Gson +import com.squareup.picasso.NetworkPolicy import com.squareup.picasso.Picasso import io.realm.kotlin.UpdatePolicy import io.realm.kotlin.ext.query @@ -82,6 +85,12 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okio.IOException import java.text.SimpleDateFormat import java.util.Date @@ -483,17 +492,19 @@ internal class RssHome : Fragment() { Blog.LOGE(it) binding.layoutRssSummary.link.text = it } + binding.layoutRssSummary.coverLink.text = it.thumbnailUrl() binding.layoutRssSummary.cover.tag = it it.thumbnailUrl().let { Blog.LOGE(it) - loadImage(binding.layoutRssSummary.cover, it) - binding.layoutRssSummary.coverLink.text = it + loadImage(binding.layoutRssSummary.cover, it, retryCount = 3, isMain = true) + } + binding.layoutRssSummary.screenLink.text = it.getScreen() binding.layoutRssSummary.screen.tag = it it.getScreen().let { Blog.LOGE(it) - loadImage(binding.layoutRssSummary.screen, it) + loadImage(binding.layoutRssSummary.screen, it, retryCount = 2, isMain = false) binding.layoutRssSummary.screenLink.text = it } if (it.getMagnet().length < 10) { @@ -941,7 +952,7 @@ internal class RssHome : Fragment() { } } val mainHandler = Handler(Looper.getMainLooper()) - fun loadImage(imageView: ImageView, url: String?, retryCount: Int = 5) { + fun loadImage(imageView: ImageView, url: String?, retryCount: Int = 2, isMain : Boolean = false) { with(imageView) { Picasso.get().cancelRequest(this) // setOnTouchListener(null) @@ -957,6 +968,7 @@ internal class RssHome : Fragment() { Blog.LOGE("loadImage >>> $url") Picasso.get() .load(url) + .networkPolicy(NetworkPolicy.NO_CACHE) .into(imageView, object : com.squareup.picasso.Callback { override fun onSuccess() { imageView.visibility = View.VISIBLE @@ -972,14 +984,24 @@ internal class RssHome : Fragment() { if (binding.layoutRssSummary.root.isVisible) { mainHandler.postDelayed({ if (binding.layoutRssSummary.root.isVisible && imageView.visibility == View.INVISIBLE) { - loadImage(imageView, url, retryCount - 1) + loadImage(imageView, url, retryCount - 1, isMain) } - }, 3000L) + }, 6000L) } } else { - // 3회 모두 실패: 대체 이미지 표시 - imageView.setImageResource(R.drawable.ic_info) - imageView.setAlpha(1f) +// // 3회 모두 실패: 대체 이미지 표시 +// imageView.setImageResource(R.drawable.ic_info) +// imageView.setAlpha(1f) + if (isMain) { + mainHandler.postDelayed({ + binding.layoutRssSummary.root.visibility = View.GONE + currentRss?.originPage?.let { + binding.geckoWeb.loadUrl( + it + ) + } + }, 6000L) + } } } }) @@ -995,6 +1017,29 @@ internal class RssHome : Fragment() { } } fun randomOrNull() : RssData? = lasted.randomOrNull() + + fun rett(imageView: ImageView,imageUrl: String){ + // OkHttp로 직접 이미지 다운로드 후 + val request = Request.Builder().url(imageUrl).build() + val client = OkHttpClient() + client.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + // 실패 시 기본 이미지 처리 or 로깅 + mainHandler.post({ +// imageView.setImageResource(R.drawable.error_image) + }) + } + + override fun onResponse(call: Call, response: Response) { + response.body?.byteStream()?.let { inputStream -> + val bitmap = BitmapFactory.decodeStream(inputStream) + mainHandler.post({ + imageView.setImageBitmap(bitmap) + }) + } + } + }) + } } var toast: Toast? = null fun Context.toast(string: String) { diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/adapters/RssItemAdapter.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/adapters/RssItemAdapter.kt index ef43e73f..20e0b2ce 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/adapters/RssItemAdapter.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/adapters/RssItemAdapter.kt @@ -44,6 +44,7 @@ import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.SimpleFingerGestures import bums.lunatic.launcher.workers.WorkersDb import com.google.android.material.imageview.ShapeableImageView +import com.squareup.picasso.NetworkPolicy import com.squareup.picasso.Picasso import io.realm.kotlin.UpdatePolicy import kotlinx.coroutines.CoroutineScope @@ -213,14 +214,15 @@ internal class RssItemAdapter ( holder.view.circlePreview.setImageResource(rssData.category().getResId()) } - if (rssData.thumbnailUrl()?.length ?: 0 > 6) { - Blog.LOGE("rssData.thumbnailUrl() >>> ${rssData.thumbnailUrl()}") - Picasso.get().load(rssData.thumbnailUrl().replace("&", "&").toUri()) - .into(holder.view.circlePreview) + if(rssData.category().equals(RssDataType.PRIVATE) == false) { + if (rssData.thumbnailUrl()?.length ?: 0 > 6) { + Blog.LOGE("rssData.thumbnailUrl() >>> ${rssData.thumbnailUrl()}") + Picasso.get().load(rssData.thumbnailUrl().replace("&", "&").toUri()).networkPolicy( + NetworkPolicy.NO_CACHE) + .into(holder.view.circlePreview) + } } -// else { -// holder.view.circlePreview.setImageDrawable(null) -// } + holder.itemView.tag = rssData holder.itemView.setOnClickListener(dateViewClick) diff --git a/app/src/main/kotlin/bums/lunatic/launcher/utils/CommonUtils.kt b/app/src/main/kotlin/bums/lunatic/launcher/utils/CommonUtils.kt index f0c86e3f..29ee86f7 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/utils/CommonUtils.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/utils/CommonUtils.kt @@ -134,7 +134,7 @@ object CommonUtils { withContext(Dispatchers.Main) { android.widget.Toast.makeText( context, - "다운로드 실패!\n${fileUrl}\n${response.message()}", + "다운로드 실패!\n${fileUrl}\n${response.message}", android.widget.Toast.LENGTH_SHORT ).show() } @@ -162,7 +162,7 @@ object CommonUtils { }_${System.currentTimeMillis()}.$extension" val file = File(dir, fileName) - response.body()?.byteStream()?.use { input -> + response.body?.byteStream()?.use { input -> FileOutputStream(file).use { output -> input.copyTo(output) } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/workers/LocationUpdateService.kt b/app/src/main/kotlin/bums/lunatic/launcher/workers/LocationUpdateService.kt index cfb292a5..cf5606a3 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/workers/LocationUpdateService.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/workers/LocationUpdateService.kt @@ -26,6 +26,7 @@ import io.realm.kotlin.ext.query import io.realm.kotlin.query.Sort import okhttp3.ConnectionPool import okhttp3.MediaType +import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody @@ -76,7 +77,7 @@ class LocationUpdateService : Service(), LocationListener { .addHeader("Content-Type", "application/json").get() builder.method( "POST", RequestBody.create( - MediaType.parse("application/text"), + "application/text".toMediaTypeOrNull(), Base64.getEncoder().encode( Gson().toJson(loc).toByteArray() ) @@ -87,9 +88,9 @@ class LocationUpdateService : Service(), LocationListener { // Blog.LOGE("telegram before request ") // OkHttp 클라이언트로 GET 요청 객체 전송 val response: Response = client.newCall(request).execute() - if (response.isSuccessful()) { + if (response.isSuccessful) { // 응답 받아서 처리 - val body: ResponseBody? = response.body() + val body: ResponseBody? = response.body if (body != null) { }