This commit is contained in:
lunaticbum 2025-08-31 13:07:04 +09:00
parent 32e38fda59
commit 520350f9d1
9 changed files with 113 additions and 40 deletions

View File

@ -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")

View File

@ -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)

View File

@ -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<T : RssDataInterface>(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 {

View File

@ -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) {
}

View File

@ -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()

View File

@ -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) {

View File

@ -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("&amp;", "&").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("&amp;", "&").toUri()).networkPolicy(
NetworkPolicy.NO_CACHE)
.into(holder.view.circlePreview)
}
}
// else {
// holder.view.circlePreview.setImageDrawable(null)
// }
holder.itemView.tag = rssData
holder.itemView.setOnClickListener(dateViewClick)

View File

@ -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)
}

View File

@ -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) {
}