This commit is contained in:
lunaticbum 2026-03-30 14:10:05 +09:00
parent 416279a11f
commit 57039939fd
6 changed files with 36 additions and 83 deletions

View File

@ -55,6 +55,13 @@ port.onMessage.addListener(response => {
var type= response["type"]; var type= response["type"];
switch (type) { switch (type) {
case "SCROLL_TOP": {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
}
break;
case "SEEK_NEXT": // 5초 앞으로 case "SEEK_NEXT": // 5초 앞으로
{ {
let btn = let btn =

View File

@ -129,6 +129,10 @@ open class GeckoWeb @JvmOverloads constructor(
} }
} }
fun scrollTop() {
sendJsonMsg("SCROLL_TOP")
}
// UI & State // UI & State
var decoViews = arrayListOf<View>() var decoViews = arrayListOf<View>()
var progress: ProgressBar? = null var progress: ProgressBar? = null
@ -297,29 +301,6 @@ open class GeckoWeb @JvmOverloads constructor(
} }
} catch (e: Exception) { } catch (e: Exception) {
Blog.LOGE("Download Check Error", e) Blog.LOGE("Download Check Error", e)
// val msg = e.message ?: ""
// if (msg.contains("parse video information") && !lastCheckUrlS.contains(cleanUrl)) {
// CoroutineScope(Dispatchers.Main).launch {
// CoroutineScope(Dispatchers.Main).launch {
// decoViews.firstOrNull { it.id == R.id.btn_dl_video }?.let { view ->
// view.setOnClickListener {
// AlertDialog.Builder(context)
// .setTitle("음악 전용으로 재시도?")
// .setMessage("parse 에러 발생. forMusic=true로 재시도합니다.")
// .setPositiveButton("오키") { _, _ ->
// checkIfDownloadable(cleanUrl, true)
// }
// .setNegativeButton("취소", null)
// .show()
// lastCheckUrlS.add(cleanUrl)
// }
// }
// }
//
// }
// }
} }
} }
} }
@ -398,7 +379,6 @@ open class GeckoWeb @JvmOverloads constructor(
url?.let { url?.let {
if (it.contains(getFilterF()) && privateMode) this@GeckoWeb.visibility = View.INVISIBLE if (it.contains(getFilterF()) && privateMode) this@GeckoWeb.visibility = View.INVISIBLE
lastedUrl = if (it.split("//").size > 1) it.replace("//", "/").replace("https:/", "https://") else it lastedUrl = if (it.split("//").size > 1) it.replace("//", "/").replace("https:/", "https://") else it
checkIfDownloadable(it)
onLocationChangeCallback?.invoke(it) // 외부 콜백 onLocationChangeCallback?.invoke(it) // 외부 콜백
} }
@ -435,7 +415,7 @@ open class GeckoWeb @JvmOverloads constructor(
} }
override fun onCanGoBack(session: GeckoSession, canGoBack: Boolean) { override fun onCanGoBack(session: GeckoSession, canGoBack: Boolean) {
Blog.LOGE("onCanGoBack $canGoBack ${session}") // Blog.LOGE("onCanGoBack $canGoBack ${session}")
this@GeckoWeb.canGoBack = canGoBack this@GeckoWeb.canGoBack = canGoBack
} }
} }
@ -469,21 +449,19 @@ open class GeckoWeb @JvmOverloads constructor(
saveCurrentSessionState() saveCurrentSessionState()
} }
onPageStartCallback?.invoke(url) onPageStartCallback?.invoke(url)
// Blog.LOGE("onPageStart $url ${session}")
checkIfDownloadable(url)
} }
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
onPageStopCallback?.invoke(success) onPageStopCallback?.invoke(success)
if (success) { if (success) {
saveCurrentSessionState() saveCurrentSessionState()
} }
Blog.LOGE("onPageStop $success ${session}") // Blog.LOGE("onPageStop $success ${session}")
} }
override fun onSessionStateChange(session: GeckoSession, sessionState: GeckoSession.SessionState) { override fun onSessionStateChange(session: GeckoSession, sessionState: GeckoSession.SessionState) {
lastSessionState = sessionState lastSessionState = sessionState
onSessionStateChangeCallback?.invoke(sessionState) onSessionStateChangeCallback?.invoke(sessionState)
Blog.LOGE("onSessionStateChange $sessionState ${session}") // Blog.LOGE("onSessionStateChange $sessionState ${session}")
} }
} }
private var lastSessionState: GeckoSession.SessionState? = null private var lastSessionState: GeckoSession.SessionState? = null
@ -634,15 +612,16 @@ open class GeckoWeb @JvmOverloads constructor(
private fun handlePortMessage(msg: PortMessage) { private fun handlePortMessage(msg: PortMessage) {
when (msg.type) { when (msg.type) {
"COOKIES_REPORT"-> { "COOKIES_REPORT"-> {
Blog.LOGE("${msg.value} -> ${msg.url}") // Blog.LOGE("${msg.value} -> ${msg.url}")
currentCookieString = msg.value ?: "" currentCookieString = msg.value ?: ""
currentCookieUrlString = msg.url ?: "" currentCookieUrlString = msg.url ?: ""
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
saveYoutubeCookiesToFile() saveYoutubeCookiesToFile()
} }
checkIfDownloadable(currentCookieUrlString)
} }
"SCROLL_STATE" -> { "SCROLL_STATE" -> {
Blog.LOGE("${msg.type} : ${msg.value}") // Blog.LOGE("${msg.type} : ${msg.value}")
scrollState = msg.value?.toInt() ?: 0 scrollState = msg.value?.toInt() ?: 0
} }
"allImagesFound" -> lastedUrl?.let { startBookmarkSaveProcessForMultipleImages(it, msg.urls) } "allImagesFound" -> lastedUrl?.let { startBookmarkSaveProcessForMultipleImages(it, msg.urls) }

View File

@ -35,7 +35,9 @@ class LunaticBrowserLayout @JvmOverloads constructor(
context.startActivity(Intent.createChooser(intent, "공유")) context.startActivity(Intent.createChooser(intent, "공유"))
} }
} }
binding.tvTitle.setOnClickListener {
geckoWeb.scrollTop()
}
// GeckoWeb 내부에서 주소 등 업데이트 시 연동되도록 등록 // GeckoWeb 내부에서 주소 등 업데이트 시 연동되도록 등록
geckoWeb.decoViews.addAll(listOf( geckoWeb.decoViews.addAll(listOf(
binding.tvAddress, binding.btnDlVideo, binding.btnReload, binding.btnBack, binding.tvTitle binding.tvAddress, binding.btnDlVideo, binding.btnReload, binding.btnBack, binding.tvTitle

View File

@ -17,6 +17,8 @@ import java.io.File
class MyWallpaperService : WallpaperService() { class MyWallpaperService : WallpaperService() {
private val TAG = "MyWallpaperService" private val TAG = "MyWallpaperService"
override fun onCreateEngine(): Engine { override fun onCreateEngine(): Engine {
@ -187,7 +189,7 @@ class MyWallpaperService : WallpaperService() {
Log.d(TAG, "Initializing Renderer...") Log.d(TAG, "Initializing Renderer...")
nativeRenderer = NativeRenderer() nativeRenderer = NativeRenderer()
nativeRenderer?.initialize() // nativeInit() -> initialize() nativeRenderer?.initialize() // nativeInit() -> initialize()
nativeRenderer?.setFadeDuration(1500) nativeRenderer?.setFadeDuration(3000)
nativeRenderer?.setTurnPageDuration(8000) nativeRenderer?.setTurnPageDuration(8000)
nativeRenderer?.setAnimationMode(NativeRenderer.ANIMATION_MODE_PAN) nativeRenderer?.setAnimationMode(NativeRenderer.ANIMATION_MODE_PAN)
nativeRenderer?.setTransitionMode(NativeRenderer.TRANSITION_MODE_FADE) nativeRenderer?.setTransitionMode(NativeRenderer.TRANSITION_MODE_FADE)
@ -199,23 +201,22 @@ class MyWallpaperService : WallpaperService() {
handler.post { loadMediaFiles() } handler.post { loadMediaFiles() }
} }
} }
// ... loadMediaFiles, nextMediaCallback, getFdFromPath는 이전과 동일 ...
private fun loadMediaFiles() { val requiredSizeRatio = 0.5
fun loadFiles() {
if (!mediaDir.exists()) mediaDir.mkdirs() if (!mediaDir.exists()) mediaDir.mkdirs()
// mediaFiles = mediaDir.listFiles()
// ?.filter { supportedExtensions.contains(it.extension.lowercase()) }
// ?.toList() ?: emptyList()
Log.d(TAG, "Found ${mediaFiles.size} media files.") Log.d(TAG, "Found ${mediaFiles.size} media files.")
val allFiles = mediaDir.listFiles() val allFiles = mediaDir.listFiles().filter { supportedExtensions.contains(it.extension) }
val trashFolder = File(mediaDir, "low_res_backup") val trashFolder = File(mediaDir, "low_res_backup")
if (!trashFolder.exists()) trashFolder.mkdirs() if (!trashFolder.exists()) trashFolder.mkdirs()
val invalidImages = mutableListOf<File>() val invalidImages = mutableListOf<File>()
val wm = WallpaperManager.getInstance(this@MyWallpaperService) val wm = WallpaperManager.getInstance(this@MyWallpaperService)
val minWidth = wm.desiredMinimumWidth val minWidth = wm.desiredMinimumWidth
val minHeight = wm.desiredMinimumHeight val minHeight = wm.desiredMinimumHeight
val requiredSize = Math.max(minWidth, minHeight).times(0.6) val requiredSize = Math.max(minWidth, minHeight).times(requiredSizeRatio)
for (file in allFiles) { for (file in allFiles) {
if (file.isFile && (file.extension.equals("jpg", true) || if (file.isFile && (file.extension.equals("jpg", true) ||
@ -240,7 +241,10 @@ class MyWallpaperService : WallpaperService() {
val targetFile = File(trashFolder, file.name) val targetFile = File(trashFolder, file.name)
file.renameTo(targetFile) // 파일 이동 file.renameTo(targetFile) // 파일 이동
} }
}
private fun loadMediaFiles() {
loadFiles()
if (mediaFiles.isNotEmpty()) { if (mediaFiles.isNotEmpty()) {
val initialFile = mediaFiles.random() val initialFile = mediaFiles.random()
Log.d(TAG, "Attempting to load initial random media via preloader: ${initialFile.absolutePath}") Log.d(TAG, "Attempting to load initial random media via preloader: ${initialFile.absolutePath}")
@ -256,48 +260,7 @@ class MyWallpaperService : WallpaperService() {
private val nextMediaCallback = object : NativeRenderer.NextMediaCallback { private val nextMediaCallback = object : NativeRenderer.NextMediaCallback {
override fun onNextMediaRequested() { override fun onNextMediaRequested() {
loadFiles()
if (!mediaDir.exists()) mediaDir.mkdirs()
// mediaFiles = mediaDir.listFiles()
// ?.filter { supportedExtensions.contains(it.extension.lowercase()) }
// ?.toList() ?: emptyList()
val allFiles = mediaDir.listFiles()
val trashFolder = File(mediaDir, "low_res_backup")
if (!trashFolder.exists()) trashFolder.mkdirs()
// val validImages = mutableListOf<File>()
val invalidImages = mutableListOf<File>()
val wm = WallpaperManager.getInstance(this@MyWallpaperService)
val minWidth = wm.desiredMinimumWidth
val minHeight = wm.desiredMinimumHeight
val requiredSize = Math.max(minWidth, minHeight).times(0.6)
for (file in allFiles) {
if (file.isFile && (file.extension.equals("jpg", true) ||
file.extension.equals("png", true) ||
file.extension.equals("jpeg", true) ||
file.extension.equals("bmp", true) || // BMP 추가
file.extension.equals("webp", true))) {
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
BitmapFactory.decodeFile(file.absolutePath, options)
Blog.LOGE("requiredSize ${requiredSize} w :${options.outWidth} , h : ${options.outHeight}")
if (options.outWidth >= requiredSize && options.outHeight >= requiredSize) {
mediaFiles.add(file)
} else {
invalidImages.add(file) // 조건 미달
}
}
}
// 2. 부적합 이미지 이동 처리 (Job 밖에서 따로 돌려도 무방)
invalidImages.forEach { file ->
val targetFile = File(trashFolder, file.name)
file.renameTo(targetFile) // 파일 이동
}
val nextFile = mediaFiles.random() val nextFile = mediaFiles.random()
Log.d(TAG, "Callback: Preloading next random media: ${nextFile.absolutePath}") Log.d(TAG, "Callback: Preloading next random media: ${nextFile.absolutePath}")

View File

@ -96,6 +96,8 @@ open class NativeRenderer {
} }
} }
// --- Private JNI declarations --- // --- Private JNI declarations ---
private external fun nativeStartRenderLoop(nativeHandle: Long, surface: Surface) private external fun nativeStartRenderLoop(nativeHandle: Long, surface: Surface)
private external fun nativeStopRenderLoop(nativeHandle: Long) private external fun nativeStopRenderLoop(nativeHandle: Long)

View File

@ -11,7 +11,7 @@
android:layout_height="40dp" android:layout_height="40dp"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="center_vertical"
android:background="#CC000000" android:background="#D000"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<TextView android:id="@+id/btn_home" android:text="home" style="@style/MaterialIconButtonStyle" /> <TextView android:id="@+id/btn_home" android:text="home" style="@style/MaterialIconButtonStyle" />