Compare commits
2 Commits
2a25b49baa
...
d1f080ded1
| Author | SHA1 | Date | |
|---|---|---|---|
| d1f080ded1 | |||
| 1272c91430 |
@ -115,8 +115,8 @@ dependencies {
|
|||||||
// implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407")
|
// implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407")
|
||||||
// https://mvnrepository.com/artifact/org.mozilla.geckoview/geckoview
|
// https://mvnrepository.com/artifact/org.mozilla.geckoview/geckoview
|
||||||
implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407")
|
implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407")
|
||||||
|
implementation("com.vladsch.flexmark:flexmark-all:0.64.0")
|
||||||
|
// implementation 'com.vladsch.flexmark:flexmark-all:0.64.8'
|
||||||
// implementation("org.opencv:opencv-android:4.11.0")
|
// implementation("org.opencv:opencv-android:4.11.0")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
couchdb:
|
||||||
|
image: couchdb:latest
|
||||||
|
container_name: couchdb
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "5984:5984" # 외부접근: 5984포트
|
||||||
|
environment:
|
||||||
|
- COUCHDB_USER=obsidian
|
||||||
|
- COUCHDB_PASSWORD=HiVi88131921
|
||||||
|
volumes:
|
||||||
|
- ./data:/opt/couchdb/data
|
||||||
@ -0,0 +1 @@
|
|||||||
|
java --telegram.bot.key=bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w --telegram.my.id=71476436 --telegram.target.id=71476436 --weather.api.key=de574a260b1f474d99955729241909 --spring.datasource.url=jdbc:mariadb://mra.sbspace.synology.me --spring.data.mongodb.uri=mongodb://lun_admin:VioPup*383@mongo.sbspace.synology.me/?wtimeoutMS=300&connectTimeoutMS=500&socketTimeoutMS=200 --spring.data.mongodb.database=lun_db --spring.datasource.username=lun_admin --spring.datasource.password=VioPup*383 --resource.handler=blog/post/image/** --resource.location=file:///usr/src/app/imgUpload --image.upload.path=/usr/src/app/imgUpload --api.gg.place=AIzaSyARLXyvmr_554tOy3UCh3naFlZQS3-qQQM
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,168 +1,168 @@
|
|||||||
//package android.print;
|
package android.print;
|
||||||
//
|
|
||||||
//import android.app.Activity;
|
import android.app.Activity;
|
||||||
//import android.content.Context;
|
import android.content.Context;
|
||||||
//import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
//import android.os.CancellationSignal;
|
import android.os.CancellationSignal;
|
||||||
//import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
//import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
//import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
//
|
|
||||||
//import java.io.File;
|
import java.io.File;
|
||||||
//import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
//import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
//import java.io.IOException;
|
import java.io.IOException;
|
||||||
//import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
//import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
//
|
|
||||||
//public class PDFPrint {
|
public class PDFPrint {
|
||||||
//
|
|
||||||
// public static void generatePDFFromHTML(final Context context, final File file, final String htmlString, final OnPDFPrintListener onPDFPrintListener) {
|
public static void generatePDFFromHTML(final Context context, final File file, final String htmlString, final OnPDFPrintListener onPDFPrintListener) {
|
||||||
// final WebView mWebView = new WebView(context);
|
final WebView mWebView = new WebView(context);
|
||||||
// mWebView.setWebViewClient(new WebViewClient() {
|
mWebView.setWebViewClient(new WebViewClient() {
|
||||||
// @Override
|
@Override
|
||||||
// public void onPageFinished(WebView view, String url) {
|
public void onPageFinished(WebView view, String url) {
|
||||||
// PrintAttributes printAttributes = new PrintAttributes.Builder()
|
PrintAttributes printAttributes = new PrintAttributes.Builder()
|
||||||
// .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
||||||
// .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
.setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
||||||
// .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
||||||
// .build();
|
.build();
|
||||||
//
|
|
||||||
// final PrintDocumentAdapter documentAdapter = mWebView.createPrintDocumentAdapter(file.getName());
|
final PrintDocumentAdapter documentAdapter = mWebView.createPrintDocumentAdapter(file.getName());
|
||||||
// documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
||||||
// @Override
|
@Override
|
||||||
// public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
||||||
// documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public void onWriteCancelled() {
|
public void onWriteCancelled() {
|
||||||
// super.onWriteCancelled();
|
super.onWriteCancelled();
|
||||||
// onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public void onWriteFailed(CharSequence error) {
|
public void onWriteFailed(CharSequence error) {
|
||||||
// super.onWriteFailed(error);
|
super.onWriteFailed(error);
|
||||||
// onPDFPrintListener.onError(new Exception(error.toString()));
|
onPDFPrintListener.onError(new Exception(error.toString()));
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public void onWriteFinished(PageRange[] pages) {
|
public void onWriteFinished(PageRange[] pages) {
|
||||||
// super.onWriteFinished(pages);
|
super.onWriteFinished(pages);
|
||||||
// onPDFPrintListener.onSuccess(file);
|
onPDFPrintListener.onSuccess(file);
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
// }, null);
|
}, null);
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
// mWebView.loadData(htmlString.replaceAll("#", "%23"), "text/HTML", "UTF-8");
|
mWebView.loadData(htmlString.replaceAll("#", "%23"), "text/HTML", "UTF-8");
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// public static void generatePDFFromWebView(final File file, final WebView webView, final OnPDFPrintListener onPDFPrintListener) {
|
public static void generatePDFFromWebView(final File file, final WebView webView, final OnPDFPrintListener onPDFPrintListener) {
|
||||||
// PrintAttributes printAttributes = new PrintAttributes.Builder()
|
PrintAttributes printAttributes = new PrintAttributes.Builder()
|
||||||
// .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
||||||
// .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
.setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
||||||
// .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
||||||
// .build();
|
.build();
|
||||||
//
|
|
||||||
// final PrintDocumentAdapter documentAdapter = webView.createPrintDocumentAdapter(file.getName());
|
final PrintDocumentAdapter documentAdapter = webView.createPrintDocumentAdapter(file.getName());
|
||||||
// documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
||||||
// @Override
|
@Override
|
||||||
// public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
||||||
// documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public void onWriteCancelled() {
|
public void onWriteCancelled() {
|
||||||
// super.onWriteCancelled();
|
super.onWriteCancelled();
|
||||||
// onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public void onWriteFailed(CharSequence error) {
|
public void onWriteFailed(CharSequence error) {
|
||||||
// super.onWriteFailed(error);
|
super.onWriteFailed(error);
|
||||||
// try {
|
try {
|
||||||
// if (error != null && error.toString().length() > 0) {
|
if (error != null && error.toString().length() > 0) {
|
||||||
// onPDFPrintListener.onError(new Exception(error.toString()));
|
onPDFPrintListener.onError(new Exception(error.toString()));
|
||||||
// } else {
|
} else {
|
||||||
// onPDFPrintListener.onError(new Exception("Empty Page"));
|
onPDFPrintListener.onError(new Exception("Empty Page"));
|
||||||
// }
|
}
|
||||||
// }catch (Exception e) {e.printStackTrace();}
|
}catch (Exception e) {e.printStackTrace();}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public void onWriteFinished(PageRange[] pages) {
|
public void onWriteFinished(PageRange[] pages) {
|
||||||
// super.onWriteFinished(pages);
|
super.onWriteFinished(pages);
|
||||||
// onPDFPrintListener.onSuccess(file);
|
onPDFPrintListener.onSuccess(file);
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
// }, null);
|
}, null);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// private static ParcelFileDescriptor getOutputFile(File file) {
|
private static ParcelFileDescriptor getOutputFile(File file) {
|
||||||
// try {
|
try {
|
||||||
// if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
// file.createNewFile();
|
file.createNewFile();
|
||||||
// }
|
}
|
||||||
// return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
|
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
|
||||||
// } catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// e.printStackTrace();
|
e.printStackTrace();
|
||||||
// }
|
}
|
||||||
// return null;
|
return null;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// public static PrintJob printPDF(final Activity activity, final File pdfFileToPrint, final PrintAttributes printAttributes) {
|
public static PrintJob printPDF(final Activity activity, final File pdfFileToPrint, final PrintAttributes printAttributes) {
|
||||||
// PrintManager printManager = (PrintManager) activity.getSystemService(Context.PRINT_SERVICE);
|
PrintManager printManager = (PrintManager) activity.getSystemService(Context.PRINT_SERVICE);
|
||||||
// String jobName = Long.valueOf(System.currentTimeMillis()).toString();
|
String jobName = Long.valueOf(System.currentTimeMillis()).toString();
|
||||||
// return printManager.print(jobName, new PrintDocumentAdapter() {
|
return printManager.print(jobName, new PrintDocumentAdapter() {
|
||||||
// @Override
|
@Override
|
||||||
// public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
|
public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
|
||||||
// InputStream input = null;
|
InputStream input = null;
|
||||||
// OutputStream output = null;
|
OutputStream output = null;
|
||||||
//
|
|
||||||
// try {
|
try {
|
||||||
//
|
|
||||||
// input = new FileInputStream(pdfFileToPrint);
|
input = new FileInputStream(pdfFileToPrint);
|
||||||
// output = new FileOutputStream(destination.getFileDescriptor());
|
output = new FileOutputStream(destination.getFileDescriptor());
|
||||||
//
|
|
||||||
// byte[] buf = new byte[1024];
|
byte[] buf = new byte[1024];
|
||||||
// int bytesRead;
|
int bytesRead;
|
||||||
//
|
|
||||||
// while ((bytesRead = input.read(buf)) > 0) {
|
while ((bytesRead = input.read(buf)) > 0) {
|
||||||
// output.write(buf, 0, bytesRead);
|
output.write(buf, 0, bytesRead);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
|
callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
|
||||||
//
|
|
||||||
// } catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// e.printStackTrace();
|
e.printStackTrace();
|
||||||
// } finally {
|
} finally {
|
||||||
// try {
|
try {
|
||||||
// input.close();
|
input.close();
|
||||||
// output.close();
|
output.close();
|
||||||
// } catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// e.printStackTrace();
|
e.printStackTrace();
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
|
public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
|
||||||
// if (cancellationSignal.isCanceled()) {
|
if (cancellationSignal.isCanceled()) {
|
||||||
// callback.onLayoutCancelled();
|
callback.onLayoutCancelled();
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(pdfFileToPrint.getName()).setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();
|
PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(pdfFileToPrint.getName()).setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();
|
||||||
// callback.onLayoutFinished(pdi, true);
|
callback.onLayoutFinished(pdi, true);
|
||||||
// }
|
}
|
||||||
// }, printAttributes);
|
}, printAttributes);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// public interface OnPDFPrintListener {
|
public interface OnPDFPrintListener {
|
||||||
// void onSuccess(File file);
|
void onSuccess(File file);
|
||||||
//
|
|
||||||
// void onError(Exception exception);
|
void onError(Exception exception);
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
@ -569,8 +569,11 @@ internal class LauncherActivity : CommonActivity() {
|
|||||||
private fun initGeckoRuntime() {
|
private fun initGeckoRuntime() {
|
||||||
if (sRuntime == null) {
|
if (sRuntime == null) {
|
||||||
try {
|
try {
|
||||||
sRuntime = GeckoRuntime.create(this, GeckoRuntimeSettings.Builder().extensionsProcessEnabled(true)
|
sRuntime = GeckoRuntime.create(this, GeckoRuntimeSettings.Builder()
|
||||||
.extensionsWebAPIEnabled(true).experimentDelegate(experimentDelegate)
|
.extensionsProcessEnabled(true)
|
||||||
|
.extensionsWebAPIEnabled(true)
|
||||||
|
.experimentDelegate(experimentDelegate)
|
||||||
|
.debugLogging(false)
|
||||||
.remoteDebuggingEnabled(true).build())
|
.remoteDebuggingEnabled(true).build())
|
||||||
} catch (e : Exception) {
|
} catch (e : Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
@ -717,6 +720,7 @@ internal class LauncherActivity : CommonActivity() {
|
|||||||
}
|
}
|
||||||
val callBackHandler = Handler(Looper.getMainLooper())
|
val callBackHandler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -73,9 +73,9 @@ class BluetoothManager : Service() {
|
|||||||
val filter = IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)
|
val filter = IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)
|
||||||
registerReceiver(bluetoothreceiver, filter)
|
registerReceiver(bluetoothreceiver, filter)
|
||||||
refreshFeeds()
|
refreshFeeds()
|
||||||
// GeckoWeb(applicationContext).apply {
|
GeckoWeb(applicationContext).apply {
|
||||||
// loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=")
|
loadUrl("https://arca.live/b/live")
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(intent: Intent?): IBinder? {
|
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
|
package bums.lunatic.launcher.home
|
||||||
|
|
||||||
|
import CustomVideoNodeRenderer
|
||||||
import android.app.DownloadManager
|
import android.app.DownloadManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
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.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.os.Message
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.util.Log
|
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.KeyEvent.KEYCODE_DPAD_UP
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.CheckBox
|
import android.widget.CheckBox
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime
|
import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime
|
||||||
import bums.lunatic.launcher.R
|
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.data.model.PortMessage
|
||||||
import bums.lunatic.launcher.tokiz.view.BWebview
|
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.Blog
|
||||||
import bums.lunatic.launcher.utils.afterDay
|
|
||||||
import bums.lunatic.launcher.workers.WorkersDb
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
import bums.lunatic.launcher.workers.WorkersDb.getRealm
|
|
||||||
import com.google.gson.Gson
|
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.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
import org.mozilla.gecko.util.ThreadUtils
|
import org.mozilla.gecko.util.ThreadUtils
|
||||||
import org.mozilla.geckoview.ExperimentDelegate
|
import org.mozilla.geckoview.ExperimentDelegate
|
||||||
import org.mozilla.geckoview.GeckoResult
|
import org.mozilla.geckoview.GeckoResult
|
||||||
import org.mozilla.geckoview.GeckoRuntime
|
|
||||||
import org.mozilla.geckoview.GeckoRuntimeSettings
|
|
||||||
import org.mozilla.geckoview.GeckoSession
|
import org.mozilla.geckoview.GeckoSession
|
||||||
import org.mozilla.geckoview.GeckoView
|
import org.mozilla.geckoview.GeckoSession.PermissionDelegate
|
||||||
import org.mozilla.geckoview.MediaSession
|
import org.mozilla.geckoview.MediaSession
|
||||||
import org.mozilla.geckoview.WebExtension
|
import org.mozilla.geckoview.WebExtension
|
||||||
import org.mozilla.geckoview.WebExtension.MessageDelegate
|
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.WebExtensionController.AddonManagerDelegate
|
||||||
import org.mozilla.geckoview.WebRequestError
|
import org.mozilla.geckoview.WebRequestError
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.InputStream
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
class GeckoWeb : BWebview {
|
class GeckoWeb : BWebview {
|
||||||
constructor(context: Context?) : super(context) {
|
constructor(context: Context?) : super(context) {
|
||||||
@ -84,6 +85,7 @@ class GeckoWeb : BWebview {
|
|||||||
val extId = "messaging@booktoki468.com"
|
val extId = "messaging@booktoki468.com"
|
||||||
|
|
||||||
private fun buildWeb() {
|
private fun buildWeb() {
|
||||||
|
|
||||||
getRuntime()?.let {
|
getRuntime()?.let {
|
||||||
val session: GeckoSession = GeckoSession()
|
val session: GeckoSession = GeckoSession()
|
||||||
session.open(it)
|
session.open(it)
|
||||||
@ -94,6 +96,38 @@ class GeckoWeb : BWebview {
|
|||||||
it.webExtensionController.setAddonManagerDelegate(addonManagerDelegate)
|
it.webExtensionController.setAddonManagerDelegate(addonManagerDelegate)
|
||||||
session.mediaDelegate = mediaDelegate
|
session.mediaDelegate = mediaDelegate
|
||||||
session.mediaSessionDelegate = mediaSessionDelegate
|
session.mediaSessionDelegate = mediaSessionDelegate
|
||||||
|
// session.permissionDelegate = (object : PermissionDelegate {
|
||||||
|
// override fun onContentPermissionRequest(
|
||||||
|
// session: GeckoSession,
|
||||||
|
// perm: PermissionDelegate.ContentPermission
|
||||||
|
// ): GeckoResult<Int?>? {
|
||||||
|
//
|
||||||
|
// return super.onContentPermissionRequest(session, perm)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onAndroidPermissionsRequest(
|
||||||
|
// session: GeckoSession,
|
||||||
|
// permissions: Array<out String?>?,
|
||||||
|
// callback: PermissionDelegate.Callback
|
||||||
|
// ) {
|
||||||
|
// super.onAndroidPermissionsRequest(session, permissions, callback)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onMediaPermissionRequest(
|
||||||
|
// session: GeckoSession,
|
||||||
|
// uri: String,
|
||||||
|
// video: Array<out PermissionDelegate.MediaSource?>?,
|
||||||
|
// audio: Array<out PermissionDelegate.MediaSource?>?,
|
||||||
|
// callback: PermissionDelegate.MediaCallback
|
||||||
|
// ) {
|
||||||
|
//
|
||||||
|
// // 첫 번째 비디오·오디오 소스를 허용
|
||||||
|
//
|
||||||
|
// callback.grant(video?.firstOrNull(), audio?.firstOrNull())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// });
|
||||||
it.webExtensionController
|
it.webExtensionController
|
||||||
.ensureBuiltIn(extPath, extId)
|
.ensureBuiltIn(extPath, extId)
|
||||||
.accept( // Register message delegate for background script
|
.accept( // Register message delegate for background script
|
||||||
@ -275,30 +309,108 @@ class GeckoWeb : BWebview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun showImageDownloadDialog(context: Context, imageUrl: Uri) {
|
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}")
|
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)
|
val request = DownloadManager.Request(url)
|
||||||
request.setTitle(fileName)
|
request.setTitle(fileName)
|
||||||
|
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
|
||||||
request.setDescription("이미지 다운로드 중...")
|
request.setDescription("이미지 다운로드 중...")
|
||||||
|
request.setAllowedOverMetered(true) // 선택 사항 - 데이터 요금제 네트워크에서도 허용
|
||||||
|
request.setVisibleInDownloadsUi(true)
|
||||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
|
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
|
||||||
// 네트워크타입, 알림설정 등 옵션 추가 가능
|
// 네트워크타입, 알림설정 등 옵션 추가 가능
|
||||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
||||||
|
|
||||||
val dm = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
val dm = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
dm.enqueue(request)
|
|
||||||
Toast.makeText(context, "다운로드 시작: $fileName", Toast.LENGTH_SHORT).show()
|
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()))
|
fun getFilterF() = String(java.util.Base64.getMimeDecoder().decode("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=".toByteArray()))
|
||||||
val contentDelegate = object : GeckoSession.ContentDelegate {
|
val contentDelegate = object : GeckoSession.ContentDelegate {
|
||||||
override fun onTitleChange(
|
override fun onTitleChange(
|
||||||
@ -361,6 +473,8 @@ class GeckoWeb : BWebview {
|
|||||||
}
|
}
|
||||||
override fun onPageStart(session: GeckoSession, url: String) {
|
override fun onPageStart(session: GeckoSession, url: String) {
|
||||||
super.onPageStart(session, url)
|
super.onPageStart(session, url)
|
||||||
|
markdownContents = null
|
||||||
|
markdownUri = null
|
||||||
if (url.contains(getFilterF()) && privateMode) {
|
if (url.contains(getFilterF()) && privateMode) {
|
||||||
this@GeckoWeb.visibility = View.INVISIBLE
|
this@GeckoWeb.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
@ -418,14 +532,17 @@ class GeckoWeb : BWebview {
|
|||||||
loadUrl(uri)
|
loadUrl(uri)
|
||||||
} else {
|
} else {
|
||||||
val builder: AlertDialog.Builder = AlertDialog.Builder(context)
|
val builder: AlertDialog.Builder = AlertDialog.Builder(context)
|
||||||
builder.setTitle("Move To")
|
builder.setTitle("Move To\n${uri}")
|
||||||
val viewInflated: View = LayoutInflater.from(context)
|
val viewInflated: View = LayoutInflater.from(context)
|
||||||
.inflate(R.layout.text_inpu_password, null, false)
|
.inflate(R.layout.text_inpu_password, null, false)
|
||||||
val input = viewInflated.findViewById<View>(R.id.input) as EditText
|
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
|
input.visibility = View.GONE
|
||||||
builder.setView(viewInflated)
|
builder.setView(viewInflated)
|
||||||
builder.setPositiveButton(
|
builder.setPositiveButton(
|
||||||
android.R.string.ok,
|
"브라우저로 이동",
|
||||||
DialogInterface.OnClickListener { dialog, which ->
|
DialogInterface.OnClickListener { dialog, which ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
context.startActivity(Intent().apply {
|
context.startActivity(Intent().apply {
|
||||||
@ -435,6 +552,12 @@ class GeckoWeb : BWebview {
|
|||||||
data = it
|
data = it
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
builder.setNeutralButton(
|
||||||
|
"페이지 이동",
|
||||||
|
DialogInterface.OnClickListener { dialog, which ->
|
||||||
|
loadUrl(uri)
|
||||||
|
dialog.cancel()
|
||||||
|
})
|
||||||
builder.setNegativeButton(
|
builder.setNegativeButton(
|
||||||
android.R.string.cancel,
|
android.R.string.cancel,
|
||||||
DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
|
DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
|
||||||
@ -481,6 +604,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 =
|
val portDelegate: PortDelegate =
|
||||||
object : PortDelegate {
|
object : PortDelegate {
|
||||||
@ -520,6 +653,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 -> {
|
else -> {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -542,6 +696,9 @@ class GeckoWeb : BWebview {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var markdownContents : String? = null
|
||||||
|
var markdownUri : Uri? = null
|
||||||
|
|
||||||
val cacheDelegate: PortDelegate =
|
val cacheDelegate: PortDelegate =
|
||||||
object : PortDelegate {
|
object : PortDelegate {
|
||||||
override fun onPortMessage(
|
override fun onPortMessage(
|
||||||
|
|||||||
@ -277,7 +277,9 @@ internal class RssHome : Fragment() {
|
|||||||
val viewInflated: View = LayoutInflater.from(requireContext())
|
val viewInflated: View = LayoutInflater.from(requireContext())
|
||||||
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
|
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
|
||||||
val input = viewInflated.findViewById<View>(R.id.input) as EditText
|
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->
|
privateMode.setOnCheckedChangeListener { v,c->
|
||||||
binding.geckoWeb.privateMode = c
|
binding.geckoWeb.privateMode = c
|
||||||
}
|
}
|
||||||
@ -290,7 +292,7 @@ internal class RssHome : Fragment() {
|
|||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
var command = input.editableText?.toString()
|
var command = input.editableText?.toString()
|
||||||
if (command?.length ?: 0 > 0) {
|
if (command?.length ?: 0 > 0) {
|
||||||
queryInfos(keywords = command!!.split(" ")!!)
|
queryInfos(keywords = command!!.split(" ")!!, addVote.isChecked, addRead.isChecked)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
builder.setNegativeButton(
|
builder.setNegativeButton(
|
||||||
@ -301,13 +303,16 @@ internal class RssHome : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun ask() {
|
fun ask() {
|
||||||
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
|
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
|
||||||
builder.setTitle("Command Line")
|
builder.setTitle("Command Line")
|
||||||
val viewInflated: View = LayoutInflater.from(requireContext())
|
val viewInflated: View = LayoutInflater.from(requireContext())
|
||||||
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
|
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
|
||||||
val input = viewInflated.findViewById<View>(R.id.input) as EditText
|
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->
|
privateMode.setOnCheckedChangeListener { v,c->
|
||||||
binding.geckoWeb.privateMode = c
|
binding.geckoWeb.privateMode = c
|
||||||
}
|
}
|
||||||
@ -447,6 +452,9 @@ internal class RssHome : Fragment() {
|
|||||||
vote()
|
vote()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
binding.share.setOnClickListener {
|
||||||
|
binding.geckoWeb.saveMd()
|
||||||
|
}
|
||||||
Blog.LOGE("useHiddenMenu >>> $useHiddenMenu")
|
Blog.LOGE("useHiddenMenu >>> $useHiddenMenu")
|
||||||
if (useHiddenMenu) {
|
if (useHiddenMenu) {
|
||||||
binding.search.setOnLongClickListener {
|
binding.search.setOnLongClickListener {
|
||||||
@ -533,6 +541,7 @@ internal class RssHome : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
queryInfos()
|
queryInfos()
|
||||||
|
|
||||||
binding.geckoWeb.progress = binding.progressBar
|
binding.geckoWeb.progress = binding.progressBar
|
||||||
binding.geckoWeb.jxInteface = { jxEvent ->
|
binding.geckoWeb.jxInteface = { jxEvent ->
|
||||||
when (jxEvent) {
|
when (jxEvent) {
|
||||||
@ -560,6 +569,7 @@ internal class RssHome : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun vote() {
|
fun vote() {
|
||||||
|
binding.geckoWeb?.saveMd()
|
||||||
currentRss?.originPage.let {
|
currentRss?.originPage.let {
|
||||||
Blog.LOGE("Arrow Center Click")
|
Blog.LOGE("Arrow Center Click")
|
||||||
WorkersDb.getRealm().apply {
|
WorkersDb.getRealm().apply {
|
||||||
@ -627,6 +637,7 @@ internal class RssHome : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateQuery(q: RealmQuery<RssData>) {
|
fun updateQuery(q: RealmQuery<RssData>) {
|
||||||
|
Blog.LOGE("updateQuery >>> ${q.description()}")
|
||||||
infosJob?.cancel()
|
infosJob?.cancel()
|
||||||
commandHandler.removeCallbacks(infoUpdate)
|
commandHandler.removeCallbacks(infoUpdate)
|
||||||
|
|
||||||
|
|||||||
@ -188,59 +188,64 @@ internal class RssItemAdapter (
|
|||||||
|
|
||||||
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
||||||
override fun onBindViewHolder(holder: RssHolder, position: Int) {
|
override fun onBindViewHolder(holder: RssHolder, position: Int) {
|
||||||
if (rssDataItemLis.isNotEmpty() && rssDataItemLis.size > position) {
|
synchronized(rssDataItemLis) {
|
||||||
val rssData = rssDataItemLis[position]
|
if (rssDataItemLis.isNotEmpty() && rssDataItemLis.size > position) {
|
||||||
if (rssData.pubDate() > 1000L) {
|
try {
|
||||||
holder.view.date.text = dateFormat.format(Date(rssData.pubDate()))
|
val rssData = rssDataItemLis.get(position)
|
||||||
} else {
|
if (rssData.pubDate() > 1000L) {
|
||||||
holder.view.date.text = emptyDate
|
holder.view.date.text = dateFormat.format(Date(rssData.pubDate()))
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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("&", "&").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 {
|
} 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("&", "&").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 {
|
// v.setOnLongClickListener {
|
||||||
// WorkersDb.getRealm().apply {
|
// WorkersDb.getRealm().apply {
|
||||||
// copyFromRealm(rss)
|
// copyFromRealm(rss)
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
holder.itemView.setOnLongClickListener(mLongClickListener)
|
holder.itemView.setOnLongClickListener(mLongClickListener)
|
||||||
|
} catch (e: Exception){}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +273,8 @@ internal class RssItemAdapter (
|
|||||||
rssDataItemLis.clear()
|
rssDataItemLis.clear()
|
||||||
rssDataItemLis.addAll(newList)
|
rssDataItemLis.addAll(newList)
|
||||||
}
|
}
|
||||||
notifyDataSetChanged()
|
|
||||||
|
notifyDataSetChanged()
|
||||||
|
|
||||||
// CoroutineScope(Dispatchers.IO).launch {
|
// CoroutineScope(Dispatchers.IO).launch {
|
||||||
// rssList.clear()
|
// rssList.clear()
|
||||||
|
|||||||
@ -22,57 +22,57 @@ class ArcaGetter : BaseGetter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun realWork(): Result {
|
override fun realWork(): Result {
|
||||||
RssDataType.ARCA.isOn {
|
// RssDataType.ARCA.isOn {
|
||||||
try {
|
// try {
|
||||||
Blog.LOGE("realWork() ${this::class.simpleName}")
|
// Blog.LOGE("realWork() ${this::class.simpleName}")
|
||||||
temp.clear()
|
// temp.clear()
|
||||||
val urls = arrayListOf(
|
// val urls = arrayListOf(
|
||||||
"https://arca.live/b/singbung?mode=best",
|
// "https://arca.live/b/singbung?mode=best",
|
||||||
// "https://arca.live/b/headline",
|
//// "https://arca.live/b/headline",
|
||||||
// "https://arca.live/b/live",
|
//// "https://arca.live/b/live",
|
||||||
"https://arca.live/b/namuhotnow",
|
// "https://arca.live/b/namuhotnow",
|
||||||
"https://arca.live/b/society",
|
// "https://arca.live/b/society",
|
||||||
// "https://arca.live/b/replay",
|
//// "https://arca.live/b/replay",
|
||||||
// "https://arca.live/b/breaking"
|
//// "https://arca.live/b/breaking"
|
||||||
)
|
// )
|
||||||
urls.forEach {
|
// urls.forEach {
|
||||||
try {
|
//// try {
|
||||||
Jsoup.connect(it)
|
//// Jsoup.connect(it)
|
||||||
.userAgent(USAGT)
|
//// .userAgent(USAGT)
|
||||||
.header("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
|
//// .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("accept-language", "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7")
|
||||||
.header("cache-control", "no-cache")
|
//// .header("cache-control", "no-cache")
|
||||||
.header("pragma", "no-cache")
|
//// .header("pragma", "no-cache")
|
||||||
.ignoreContentType(true)
|
//// .ignoreContentType(true)
|
||||||
.timeout(5000)
|
//// .timeout(5000)
|
||||||
.get().let { arca ->
|
//// .get().let { arca ->
|
||||||
// BLog.LOGE("url >> ${it} >> ${arca}")
|
////// BLog.LOGE("url >> ${it} >> ${arca}")
|
||||||
arca.getElementsByClass("vrow hybrid").forEach { araca_li ->
|
//// arca.getElementsByClass("vrow hybrid").forEach { araca_li ->
|
||||||
if (araca_li.html().contains("title ") == true) {
|
//// if (araca_li.html().contains("title ") == true) {
|
||||||
parseArcaLi(araca_li).apply {
|
//// parseArcaLi(araca_li).apply {
|
||||||
this.forEach {
|
//// this.forEach {
|
||||||
if (it.pubDate() > commicsDateTime) {
|
//// if (it.pubDate() > commicsDateTime) {
|
||||||
temp.add(it.getRssData())
|
//// temp.add(it.getRssData())
|
||||||
}
|
//// }
|
||||||
}
|
//// }
|
||||||
}
|
//// }
|
||||||
}
|
//// }
|
||||||
}
|
//// }
|
||||||
}
|
//// }
|
||||||
} catch (e : Exception) {
|
//// } catch (e : Exception) {
|
||||||
e.printStackTrace()
|
//// e.printStackTrace()
|
||||||
}
|
//// }
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
// Jsoup.connect("https://projrctjav.com").userAgent(USAGT).get().let { projectj ->
|
//// Jsoup.connect("https://projrctjav.com").userAgent(USAGT).get().let { projectj ->
|
||||||
// BLog.LOGE("projectj >>>>> ${projectj}")
|
//// BLog.LOGE("projectj >>>>> ${projectj}")
|
||||||
|
//// }
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// e.printStackTrace()
|
||||||
// }
|
// }
|
||||||
} catch (e: Exception) {
|
// }
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Result.success().apply {
|
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.query.Sort
|
||||||
import io.realm.kotlin.types.BaseRealmObject
|
import io.realm.kotlin.types.BaseRealmObject
|
||||||
import io.realm.kotlin.types.TypedRealmObject
|
import io.realm.kotlin.types.TypedRealmObject
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@ -104,34 +105,32 @@ object WorkersDb {
|
|||||||
|
|
||||||
// val blockKeyword = arrayListOf<String>("붕괴 스타레일","붕괴 스타일","트릭컬 RE:VIVE","원신","메이플스토리","")
|
// val blockKeyword = arrayListOf<String>("붕괴 스타레일","붕괴 스타일","트릭컬 RE:VIVE","원신","메이플스토리","")
|
||||||
fun insertBulkData(rssDatas: Collection<RssData>) {
|
fun insertBulkData(rssDatas: Collection<RssData>) {
|
||||||
rssDatas.forEach {
|
try {
|
||||||
try {
|
getRealm().writeBlocking {
|
||||||
getRealm().writeBlocking {
|
try {
|
||||||
try {
|
rssDatas.forEach { t ->
|
||||||
rssDatas.forEach { t ->
|
var results= query<RssData>("originPage == $0", t.originPage).find()
|
||||||
var results= query<RssData>("originPage == $0", t.originPage).find()
|
if (results.isEmpty()) {
|
||||||
if (results.isEmpty()) {
|
if(t.category().equals(RssDataType.PRIVATE)) {
|
||||||
if(it.category().equals(RssDataType.PRIVATE)) {
|
t.pubDate = afterDay(t.pubDate)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,20 @@
|
|||||||
tools:ignore="ContentDescription"
|
tools:ignore="ContentDescription"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
/>
|
/>
|
||||||
|
<ImageButton
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/hide"
|
||||||
|
android:id="@+id/share"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:visibility="visible"
|
||||||
|
android:background="@null"
|
||||||
|
android:tint="@color/white"
|
||||||
|
android:foregroundTint="@color/white"
|
||||||
|
android:src="@drawable/ic_share"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
android:layout_height="40dp" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/home"
|
android:id="@+id/home"
|
||||||
|
|||||||
@ -54,7 +54,7 @@
|
|||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:id="@+id/parivate_mode"
|
android:id="@+id/private_mode"
|
||||||
android:checked="true"
|
android:checked="true"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user