This commit is contained in:
2025-08-01 18:36:16 +09:00
parent 2a25b49baa
commit 1272c91430
15 changed files with 1051 additions and 676 deletions
@@ -569,8 +569,11 @@ internal class LauncherActivity : CommonActivity() {
private fun initGeckoRuntime() {
if (sRuntime == null) {
try {
sRuntime = GeckoRuntime.create(this, GeckoRuntimeSettings.Builder().extensionsProcessEnabled(true)
.extensionsWebAPIEnabled(true).experimentDelegate(experimentDelegate)
sRuntime = GeckoRuntime.create(this, GeckoRuntimeSettings.Builder()
.extensionsProcessEnabled(true)
.extensionsWebAPIEnabled(true)
.experimentDelegate(experimentDelegate)
.debugLogging(false)
.remoteDebuggingEnabled(true).build())
} catch (e : Exception) {
e.printStackTrace()
@@ -717,6 +720,7 @@ internal class LauncherActivity : CommonActivity() {
}
val callBackHandler = Handler(Looper.getMainLooper())
}
@@ -73,9 +73,9 @@ class BluetoothManager : Service() {
val filter = IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)
registerReceiver(bluetoothreceiver, filter)
refreshFeeds()
// GeckoWeb(applicationContext).apply {
// loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=")
// }
GeckoWeb(applicationContext).apply {
loadUrl("https://arca.live/b/live")
}
}
override fun onBind(intent: Intent?): IBinder? {
@@ -0,0 +1,30 @@
import com.vladsch.flexmark.html2md.converter.*
import com.vladsch.flexmark.util.data.DataHolder
import org.jsoup.nodes.Element
class CustomVideoNodeRenderer(options: DataHolder?) : HtmlNodeRenderer {
override fun getHtmlNodeRendererHandlers(): Set<HtmlNodeRendererHandler<*>> {
return setOf(
HtmlNodeRendererHandler(
"video", // 처리할 태그명!
Element::class.java
) { node, context, markdown ->
// node: org.jsoup.nodes.Element 타입, 즉 <video ...> 태그
val sources = node.getElementsByTag("source")
val src = if (sources.isNotEmpty()) {
sources.first()?.attr("src")
} else {
node.attr("src")
}
// 대표 src가 있으면 단일 <video src=... controls></video>
if (src?.isNotBlank() == true) {
markdown.append("<video src=\"$src\" controls></video>\n")
} else {
// 혹시 src 속성이 없거나 source 태그가 없으면 원본 전체 남김
markdown.append(node.outerHtml() + "\n")
}
}
)
}
}
@@ -1,5 +1,6 @@
package bums.lunatic.launcher.home
import CustomVideoNodeRenderer
import android.app.DownloadManager
import android.content.Context
import android.content.DialogInterface
@@ -8,9 +9,6 @@ import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.net.Uri
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.AttributeSet
import android.util.Base64
import android.util.Log
@@ -26,36 +24,36 @@ import android.view.KeyEvent.KEYCODE_DPAD_DOWN
import android.view.KeyEvent.KEYCODE_DPAD_UP
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.EditText
import android.widget.ProgressBar
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri
import androidx.core.view.isVisible
import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime
import bums.lunatic.launcher.R
import bums.lunatic.launcher.tokiz.data.HistoryManager
import bums.lunatic.launcher.tokiz.data.model.History
import bums.lunatic.launcher.tokiz.data.model.PortMessage
import bums.lunatic.launcher.tokiz.view.BWebview
import bums.lunatic.launcher.tokiz.view.JxEvent
import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.utils.afterDay
import bums.lunatic.launcher.workers.WorkersDb
import bums.lunatic.launcher.workers.WorkersDb.getRealm
import com.google.gson.Gson
import io.realm.kotlin.UpdatePolicy
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONException
import org.json.JSONObject
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.mozilla.gecko.util.ThreadUtils
import org.mozilla.geckoview.BuildConfig
import org.mozilla.geckoview.ExperimentDelegate
import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.GeckoRuntime
import org.mozilla.geckoview.GeckoRuntimeSettings
import org.mozilla.geckoview.GeckoSession
import org.mozilla.geckoview.GeckoView
import org.mozilla.geckoview.MediaSession
import org.mozilla.geckoview.WebExtension
import org.mozilla.geckoview.WebExtension.MessageDelegate
@@ -63,7 +61,10 @@ import org.mozilla.geckoview.WebExtension.PortDelegate
import org.mozilla.geckoview.WebExtensionController.AddonManagerDelegate
import org.mozilla.geckoview.WebRequestError
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.text.SimpleDateFormat
import java.util.Date
class GeckoWeb : BWebview {
constructor(context: Context?) : super(context) {
@@ -84,6 +85,7 @@ class GeckoWeb : BWebview {
val extId = "messaging@booktoki468.com"
private fun buildWeb() {
getRuntime()?.let {
val session: GeckoSession = GeckoSession()
session.open(it)
@@ -275,30 +277,108 @@ class GeckoWeb : BWebview {
}
fun showImageDownloadDialog(context: Context, imageUrl: Uri) {
AlertDialog.Builder(context)
.setTitle("이미지 다운로드")
.setMessage("이미지를 저장하시겠습니까?")
.setPositiveButton("저장") { _, _ ->
downloadImage(context, imageUrl)
}
.setNegativeButton("취소", null)
.show()
}
fun downloadImage(context: Context, url: Uri) {
fun savePdfStreamToFile(pdfStream: InputStream?, outputFile: File) {
pdfStream?.let {
FileOutputStream(outputFile).use { output ->
val buffer = ByteArray(8 * 1024)
var bytesRead: Int
while (pdfStream.read(buffer).also { bytesRead = it } != -1) {
output.write(buffer, 0, bytesRead)
}
output.flush()
}
pdfStream.close()
}
}
// 실제 사용 예시
fun scrapWebToMd(context: Context, url: Uri?, markdownText: String) {
// 경로 선언 (예: /storage/emulated/0/fff_gg/pdfs)
val dir = File("/storage/emulated/0/bums_ob/BUM'S PACED /scraped/md")
///BUM'S PACED/pdfs
if (!dir.exists()) {
dir.mkdirs()
} else {
dir.listFiles().forEach { Blog.LOGE("child -> ${it.absolutePath}") }
}
val outputFile = File(dir, "${url?.host ?: "UnKnown"}_scraped_${SimpleDateFormat("yyyyMMdd-HHmm").format(Date())}.md")
outputFile.writeText(markdownText, Charsets.UTF_8)
// 저장 성공 알림 등 후속 처리
println("PDF 저장 완료: ${outputFile.absolutePath}")
}
fun downloadImage(context: Context, url: Uri, isGif : Boolean = false) {
Blog.LOGE("url.lastPathSegment ${url.lastPathSegment}")
val fileName = url.lastPathSegment ?: "${SimpleDateFormat("yyyyMMddHHmmsss")}.jpg"
val fileName = url.host + "_${SimpleDateFormat("yyyyMMddHHmmsss").format(Date())}.${if(isGif){"gif"}else{"jpg"}}"
val request = DownloadManager.Request(url)
request.setTitle(fileName)
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
request.setDescription("이미지 다운로드 중...")
request.setAllowedOverMetered(true) // 선택 사항 - 데이터 요금제 네트워크에서도 허용
request.setVisibleInDownloadsUi(true)
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
// 네트워크타입, 알림설정 등 옵션 추가 가능
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
val dm = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
dm.enqueue(request)
Toast.makeText(context, "다운로드 시작: $fileName", Toast.LENGTH_SHORT).show()
val downloadId = dm.enqueue(request)
monitorDownloadStatus(dm, downloadId, context)
}
fun monitorDownloadStatus(dm: DownloadManager, downloadId: Long, context: Context) {
val handler = CoroutineExceptionHandler { _, exception ->
// 에러 처리 로직 (선택)
exception.printStackTrace()
}
// 백그라운드에서 5초 간격으로 상태 체크
CoroutineScope(Dispatchers.IO + handler).launch {
while (true) {
val query = DownloadManager.Query().setFilterById(downloadId)
val cursor = dm.query(query)
var downloadFinished = false
if (cursor != null && cursor.moveToFirst()) {
val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
when (status) {
DownloadManager.STATUS_SUCCESSFUL -> {
// 다운로드 성공 처리
withContext(Dispatchers.Main) {
// UI 갱신 등 메인 스레드 작업 (필요 시)
}
downloadFinished = true
}
DownloadManager.STATUS_FAILED -> {
val reason = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_REASON))
// 여기에 reason값에 따라 적절한 처리 또는 로깅 수행
Log.e("DownloadManager", "Download failed with reason code: $reason")
// 다운로드 실패 처리
withContext(Dispatchers.Main) {
// UI 갱신 등 메인 스레드 작업 (필요 시)
}
downloadFinished = true
}
else -> {
Blog.LOGE("DownloadManager.STATUS >> ${status}")
}
// 진행 중, 대기 중 등 기타 상태는 계속 확인
}
}
cursor?.close()
if (downloadFinished) break
delay(5000L) // 5초 대기 후 다시 반복
}
}
}
fun getFilterF() = String(java.util.Base64.getMimeDecoder().decode("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=".toByteArray()))
val contentDelegate = object : GeckoSession.ContentDelegate {
override fun onTitleChange(
@@ -361,6 +441,8 @@ class GeckoWeb : BWebview {
}
override fun onPageStart(session: GeckoSession, url: String) {
super.onPageStart(session, url)
markdownContents = null
markdownUri = null
if (url.contains(getFilterF()) && privateMode) {
this@GeckoWeb.visibility = View.INVISIBLE
}
@@ -418,14 +500,17 @@ class GeckoWeb : BWebview {
loadUrl(uri)
} else {
val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder.setTitle("Move To")
builder.setTitle("Move To\n${uri}")
val viewInflated: View = LayoutInflater.from(context)
.inflate(R.layout.text_inpu_password, null, false)
val input = viewInflated.findViewById<View>(R.id.input) as EditText
(viewInflated.findViewById<CheckBox>(R.id.add_vote) as CheckBox)?.let { it.visibility = View.GONE }
(viewInflated.findViewById<CheckBox>(R.id.add_read) as CheckBox)?.let { it.visibility = View.GONE }
(viewInflated.findViewById<CheckBox>(R.id.private_mode) as CheckBox)?.let { it.visibility = View.GONE }
input.visibility = View.GONE
builder.setView(viewInflated)
builder.setPositiveButton(
android.R.string.ok,
"브라우저로 이동",
DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss()
context.startActivity(Intent().apply {
@@ -435,6 +520,12 @@ class GeckoWeb : BWebview {
data = it
})
})
builder.setNeutralButton(
"페이지 이동",
DialogInterface.OnClickListener { dialog, which ->
loadUrl(uri)
dialog.cancel()
})
builder.setNegativeButton(
android.R.string.cancel,
DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
@@ -481,6 +572,16 @@ class GeckoWeb : BWebview {
}
}
fun saveMd() {
val message: JSONObject = JSONObject()
try {
message.put("type", "saveContent")
} catch (ex: JSONException) {
throw RuntimeException(ex)
}
Blog.LOGE(Gson().toJson(message))
mPort?.postMessage(message)
}
val portDelegate: PortDelegate =
object : PortDelegate {
@@ -520,6 +621,27 @@ class GeckoWeb : BWebview {
}
}
"MainContentsEl"->{
try {
val doc: Document = Jsoup.parse(lPortMessage.contents)
val combinedHtml = doc.html()
val converter = FlexmarkHtmlConverter.builder().htmlNodeRendererFactory { options -> CustomVideoNodeRenderer(options) }.build()
markdownContents = converter.convert(combinedHtml)
markdownUri = lPortMessage.currentPage?.toUri()
markdownContents?.let {
if (it.length > 40) {
scrapWebToMd(context, markdownUri, it)
}
}
} catch (e: Exception) {
markdownContents = null
markdownUri = null
}
// scrapWepToMd(context, Uri.parse(lPortMessage.currentPage), markdown)
}
else -> {
}
@@ -542,6 +664,9 @@ class GeckoWeb : BWebview {
}
}
var markdownContents : String? = null
var markdownUri : Uri? = null
val cacheDelegate: PortDelegate =
object : PortDelegate {
override fun onPortMessage(
@@ -277,7 +277,9 @@ internal class RssHome : Fragment() {
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
val privateMode = viewInflated.findViewById<CheckBox>(R.id.parivate_mode) as CheckBox
val privateMode = viewInflated.findViewById<CheckBox>(R.id.private_mode) as CheckBox
val addVote = viewInflated.findViewById<CheckBox>(R.id.add_vote) as CheckBox
val addRead = viewInflated.findViewById<CheckBox>(R.id.add_read) as CheckBox
privateMode.setOnCheckedChangeListener { v,c->
binding.geckoWeb.privateMode = c
}
@@ -290,7 +292,7 @@ internal class RssHome : Fragment() {
dialog.dismiss()
var command = input.editableText?.toString()
if (command?.length ?: 0 > 0) {
queryInfos(keywords = command!!.split(" ")!!)
queryInfos(keywords = command!!.split(" ")!!, addVote.isChecked, addRead.isChecked)
}
})
builder.setNegativeButton(
@@ -301,13 +303,16 @@ internal class RssHome : Fragment() {
}
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
val privateMode = viewInflated.findViewById<CheckBox>(R.id.parivate_mode) as CheckBox
val privateMode = viewInflated.findViewById<CheckBox>(R.id.private_mode) as CheckBox
(viewInflated.findViewById<CheckBox>(R.id.add_vote) as CheckBox)?.let{ it.visibility = View.GONE}
(viewInflated.findViewById<CheckBox>(R.id.add_read) as CheckBox)?.let{ it.visibility = View.GONE}
privateMode.setOnCheckedChangeListener { v,c->
binding.geckoWeb.privateMode = c
}
@@ -447,6 +452,9 @@ internal class RssHome : Fragment() {
vote()
}
}
binding.share.setOnClickListener {
binding.geckoWeb.saveMd()
}
Blog.LOGE("useHiddenMenu >>> $useHiddenMenu")
if (useHiddenMenu) {
binding.search.setOnLongClickListener {
@@ -533,6 +541,7 @@ internal class RssHome : Fragment() {
}
queryInfos()
binding.geckoWeb.progress = binding.progressBar
binding.geckoWeb.jxInteface = { jxEvent ->
when (jxEvent) {
@@ -560,6 +569,7 @@ internal class RssHome : Fragment() {
}
fun vote() {
binding.geckoWeb?.saveMd()
currentRss?.originPage.let {
Blog.LOGE("Arrow Center Click")
WorkersDb.getRealm().apply {
@@ -627,6 +637,7 @@ internal class RssHome : Fragment() {
}
fun updateQuery(q: RealmQuery<RssData>) {
Blog.LOGE("updateQuery >>> ${q.description()}")
infosJob?.cancel()
commandHandler.removeCallbacks(infoUpdate)
@@ -188,59 +188,64 @@ internal class RssItemAdapter (
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
override fun onBindViewHolder(holder: RssHolder, position: Int) {
if (rssDataItemLis.isNotEmpty() && rssDataItemLis.size > position) {
val rssData = rssDataItemLis[position]
if (rssData.pubDate() > 1000L) {
holder.view.date.text = dateFormat.format(Date(rssData.pubDate()))
} else {
holder.view.date.text = emptyDate
}
holder.view.title.text = "".plus(if (rssData.vote) " * " else "")
.plus(rssData.title().plus("[R:${rssData.read}]"))
holder.view.desc.text = rssData.description()
var param = holder.view.circlePreview.layoutParams
holder.view.circlePreview.layoutParams =
ConstraintLayout.LayoutParams(rssData.category().defaultImgSize(), param.height)
holder.view.circlePreview.visibility = rssData.category().getDefaultVisibiliy()
Picasso.get().cancelRequest(holder.view.circlePreview)
if (rssData.thumbnailUrl()?.length ?: 0 > 6) {
Picasso.get().load(rssData.thumbnailUrl().replace("&amp;", "&").toUri())
.into(holder.view.circlePreview)
} else if (rssData.category().getResId() > 0) {
holder.view.circlePreview.setImageResource(rssData.category().getResId())
} else {
holder.view.circlePreview.setImageDrawable(null)
}
holder.itemView.tag = rssData
holder.itemView.setOnClickListener(dateViewClick)
holder.itemView.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(
v: View,
event: MotionEvent
): Boolean {
if (event.device != null && event.device.name != null && (event.device.name?.contains(
"JX-12",
true
) == true || event.device.name?.equals("J06", true) == true)
) {
Blog.LOGE("event.device.name >>> ${event.device.name}")
return true//mSimpleFingerGestures.onTouch(v,event)
synchronized(rssDataItemLis) {
if (rssDataItemLis.isNotEmpty() && rssDataItemLis.size > position) {
try {
val rssData = rssDataItemLis.get(position)
if (rssData.pubDate() > 1000L) {
holder.view.date.text = dateFormat.format(Date(rssData.pubDate()))
} else {
return false
holder.view.date.text = emptyDate
}
}
})
holder.view.title.text = "".plus(if (rssData.vote) " * " else "")
.plus(rssData.title().plus("[R:${rssData.read}]"))
holder.view.desc.text = rssData.description()
var param = holder.view.circlePreview.layoutParams
holder.view.circlePreview.layoutParams =
ConstraintLayout.LayoutParams(rssData.category().defaultImgSize(), param.height)
holder.view.circlePreview.visibility = rssData.category().getDefaultVisibiliy()
Picasso.get().cancelRequest(holder.view.circlePreview)
if (rssData.thumbnailUrl()?.length ?: 0 > 6) {
Picasso.get().load(rssData.thumbnailUrl().replace("&amp;", "&").toUri())
.into(holder.view.circlePreview)
} else if (rssData.category().getResId() > 0) {
holder.view.circlePreview.setImageResource(rssData.category().getResId())
} else {
holder.view.circlePreview.setImageDrawable(null)
}
holder.itemView.tag = rssData
holder.itemView.setOnClickListener(dateViewClick)
holder.itemView.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(
v: View,
event: MotionEvent
): Boolean {
if (event.device != null && event.device.name != null && (event.device.name?.contains(
"JX-12",
true
) == true || event.device.name?.equals("J06", true) == true)
) {
Blog.LOGE("event.device.name >>> ${event.device.name}")
return true//mSimpleFingerGestures.onTouch(v,event)
} else {
return false
}
}
})
// v.setOnLongClickListener {
// WorkersDb.getRealm().apply {
// copyFromRealm(rss)
// }
// }
holder.itemView.setOnLongClickListener(mLongClickListener)
holder.itemView.setOnLongClickListener(mLongClickListener)
} catch (e: Exception){}
}
}
}
@@ -268,7 +273,8 @@ internal class RssItemAdapter (
rssDataItemLis.clear()
rssDataItemLis.addAll(newList)
}
notifyDataSetChanged()
notifyDataSetChanged()
// CoroutineScope(Dispatchers.IO).launch {
// rssList.clear()
@@ -22,57 +22,57 @@ class ArcaGetter : BaseGetter {
}
override fun realWork(): Result {
RssDataType.ARCA.isOn {
try {
Blog.LOGE("realWork() ${this::class.simpleName}")
temp.clear()
val urls = arrayListOf(
"https://arca.live/b/singbung?mode=best",
// "https://arca.live/b/headline",
// "https://arca.live/b/live",
"https://arca.live/b/namuhotnow",
"https://arca.live/b/society",
// "https://arca.live/b/replay",
// "https://arca.live/b/breaking"
)
urls.forEach {
try {
Jsoup.connect(it)
.userAgent(USAGT)
.header("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
.header("accept-language", "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7")
.header("cache-control", "no-cache")
.header("pragma", "no-cache")
.ignoreContentType(true)
.timeout(5000)
.get().let { arca ->
// BLog.LOGE("url >> ${it} >> ${arca}")
arca.getElementsByClass("vrow hybrid").forEach { araca_li ->
if (araca_li.html().contains("title ") == true) {
parseArcaLi(araca_li).apply {
this.forEach {
if (it.pubDate() > commicsDateTime) {
temp.add(it.getRssData())
}
}
}
}
}
}
} catch (e : Exception) {
e.printStackTrace()
}
}
// Jsoup.connect("https://projrctjav.com").userAgent(USAGT).get().let { projectj ->
// BLog.LOGE("projectj >>>>> ${projectj}")
// RssDataType.ARCA.isOn {
// try {
// Blog.LOGE("realWork() ${this::class.simpleName}")
// temp.clear()
// val urls = arrayListOf(
// "https://arca.live/b/singbung?mode=best",
//// "https://arca.live/b/headline",
//// "https://arca.live/b/live",
// "https://arca.live/b/namuhotnow",
// "https://arca.live/b/society",
//// "https://arca.live/b/replay",
//// "https://arca.live/b/breaking"
// )
// urls.forEach {
//// try {
//// Jsoup.connect(it)
//// .userAgent(USAGT)
//// .header("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
//// .header("accept-language", "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7")
//// .header("cache-control", "no-cache")
//// .header("pragma", "no-cache")
//// .ignoreContentType(true)
//// .timeout(5000)
//// .get().let { arca ->
////// BLog.LOGE("url >> ${it} >> ${arca}")
//// arca.getElementsByClass("vrow hybrid").forEach { araca_li ->
//// if (araca_li.html().contains("title ") == true) {
//// parseArcaLi(araca_li).apply {
//// this.forEach {
//// if (it.pubDate() > commicsDateTime) {
//// temp.add(it.getRssData())
//// }
//// }
//// }
//// }
//// }
//// }
//// } catch (e : Exception) {
//// e.printStackTrace()
//// }
//
// }
//// Jsoup.connect("https://projrctjav.com").userAgent(USAGT).get().let { projectj ->
//// BLog.LOGE("projectj >>>>> ${projectj}")
//// }
// } catch (e: Exception) {
// e.printStackTrace()
// }
} catch (e: Exception) {
e.printStackTrace()
}
}
// }
return Result.success().apply {
WorkersDb.insertBulkData(temp)
// WorkersDb.insertBulkData(temp)
}
}
@@ -45,6 +45,7 @@ import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.Sort
import io.realm.kotlin.types.BaseRealmObject
import io.realm.kotlin.types.TypedRealmObject
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
@@ -104,34 +105,32 @@ object WorkersDb {
// val blockKeyword = arrayListOf<String>("붕괴 스타레일","붕괴 스타일","트릭컬 RE:VIVE","원신","메이플스토리","")
fun insertBulkData(rssDatas: Collection<RssData>) {
rssDatas.forEach {
try {
getRealm().writeBlocking {
try {
rssDatas.forEach { t ->
var results= query<RssData>("originPage == $0", t.originPage).find()
if (results.isEmpty()) {
if(it.category().equals(RssDataType.PRIVATE)) {
it.pubDate = afterDay(it.pubDate)
}
this.copyToRealm(t, UpdatePolicy.ERROR)
} else {
if(it.category().equals(RssDataType.PRIVATE)) {
it.pubDate = afterDay(it.pubDate)
it.vote = results.first().vote
it.read = results.first().read
this.copyToRealm(t, UpdatePolicy.ALL)
}
try {
getRealm().writeBlocking {
try {
rssDatas.forEach { t ->
var results= query<RssData>("originPage == $0", t.originPage).find()
if (results.isEmpty()) {
if(t.category().equals(RssDataType.PRIVATE)) {
t.pubDate = afterDay(t.pubDate)
}
this.copyToRealm(t, UpdatePolicy.ALL)
} else {
if(t.category().equals(RssDataType.PRIVATE)) {
t.pubDate = afterDay(t.pubDate)
}
t.vote = results.first().vote
t.read = results.first().read
this.copyToRealm(t, UpdatePolicy.ALL)
}
} catch (e : Exception) {
}
} catch (e : Exception) {
e.printStackTrace()
}
} catch (e : Exception) {
e.printStackTrace()
}
} catch (e : Exception) {
e.printStackTrace()
}
}