diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4c9a6a1..55982c4a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -100,6 +100,7 @@ + @@ -130,14 +131,14 @@ - - - - - - + - + diff --git a/app/src/main/assets/extensions/my_extension/messaging.js b/app/src/main/assets/extensions/my_extension/messaging.js index c8099bdc..3e092ce3 100644 --- a/app/src/main/assets/extensions/my_extension/messaging.js +++ b/app/src/main/assets/extensions/my_extension/messaging.js @@ -5,6 +5,27 @@ port.onMessage.addListener(response => { var type= response["type"]; switch (type) { + case "search" : { + var keyword = response["keyword"]; + if (location.href.search("bigkinds.or.kr") > -1) { + document.querySelector('input[id^="total-search-key"]').value = keyword + } else if (location.href.search("www.google") > -1) { + document.querySelector('form[action^="/search"]').querySelector("textarea").value = keyword + } else if(location.href.search("naver.com") > -1) { + document.querySelector('input[id^="query"]').value = keyword + } else if(location.href.search("namu.wiki") > -1) { + document.querySelector('input[type^="search"]').value = keyword + } + } + case "searchDo" : { + if (location.href.search("bigkinds.or.kr") > -1) { + document.querySelector('a[class^="bk_keywordSearchBtn"]').click() + } else if (location.href.search("www.google") > -1) { + document.querySelector('form[action^="/search"]').submit() + } else if(location.href.search("naver.com") > -1) { + document.querySelector('[class^="sch_btn_search"]').click() + } + } case "getList": { try { // var listBody = null @@ -39,6 +60,7 @@ port.onMessage.addListener(response => { }break; case "scrollDown":{ + autoScrollAndSave() var max = response["max"] var current = response["current"] var isUpDown = response["isUpDown"] @@ -74,7 +96,7 @@ port.onMessage.addListener(response => { } break; case "saveContent":{ - scrollToLazyImg() + scrollToLazyImg(true === response["fast"]) } default: port.postMessage(`Received: ${JSON.stringify(response)}`); @@ -235,12 +257,12 @@ document.addEventListener('DOMContentLoaded', function () { }) -function scrollToLazyImg() { +function scrollToLazyImg(fastMode) { (function(autoScrollAndSave){ // 한 번에 이동할 픽셀 - const step = 200; + const step = fastMode ? 600 : 200; // 반복 간격(ms) (느릴수록 로딩에 더 여유 생김) - const delay = 600; + const delay = fastMode ? 200 : 600; // 스크롤 현재 위치 추적 let currentY = window.scrollY; let maxY = Math.max( @@ -322,357 +344,62 @@ function isNewerThanOneDay(dateStr) { return (now - date) < oneDayMs; } function autoScrollAndSave(senContents) { - if (location.href.search("nate.com") > -1 && document.querySelectorAll("#ad_sponsorBar")) { - if (location.href.startsWith("https://news.nate.com")) { - var string = location.href.toString() - string = string.replace("https://","https://m."); - location.href = string - } - document.querySelectorAll('[class^="float-adv-wrap"]').forEach(e => e.remove()) - document.querySelectorAll('[id^="ad_"]').forEach(e => e.remove()) - document.querySelectorAll("#ad_sponsorBar").forEach((element) => {element.remove();}); - document.querySelectorAll("#newsSidebar").forEach((element) => {element.remove();}); - document.querySelectorAll("#header").forEach((element) => {element.remove();}); - document.querySelectorAll('iframe[id^="ad"]').forEach(e => e.remove()) - document.querySelectorAll("#module_ssul").forEach((element) => {element.remove();}); - document.querySelectorAll('[class^="boxtype1 thisTimeNews"]').forEach(e => e.remove()) - document.querySelectorAll("#mediaFooter").forEach((element) => {element.remove();}); - document.querySelectorAll('[class^="news_cmt"]').forEach(e => e.remove()) - document.querySelectorAll('section[class^="rwd_right"]').forEach(e => e.remove()) + // 도메인에 맞는 handler 실행 + const matchedRule = domainRules.find(rule => rule.test(location.href)); + if (matchedRule) { + matchedRule.handler(); + } + // 공통 광고 요소 제거는 항상 실행 + handleCommon(); + window.scrollTo({ top: 2, behavior: 'smooth' }); + if (mainContentsEl == null) { + mainContentsEl = document.body.outerHTML + } + if (senContents) { + sendMessage({type: "MainContentsEl", contents: mainContentsEl.outerHTML, currentPage: location.href}); + } +} - } +// 도메인 규칙 배열 +const domainRules = [ + { test: url => url.includes("nate.com") && document.querySelectorAll("#ad_sponsorBar").length > 0, handler: handleNate }, + { test: url => url.includes("zdnet.co.kr"), handler: handleZdnet }, + { test: url => url.includes("inews24"), handler: handleInews24 }, + { test: url => url.includes("starnewskorea"), handler: handleStarnewsKorea }, + { test: url => url.includes("khan.co.kr"), handler: handleKhan }, + { test: url => url.includes("m.health.chosun.com"), handler: handleHealthChosun }, + { test: url => url.includes("betanews"), handler: handleBetanews }, + { test: url => url.includes("newsis.com"), handler: handleNewsis }, + { test: url => url.includes("seoul.co.kr"), handler: handleSeoul }, + { test: url => url.includes("ytn.co.kr"), handler: handleYtn }, + { test: url => url.includes("nocutnews.co.kr"), handler: handleNocutnews }, + { test: url => url.includes("sedaily.com"), handler: handleSedaily }, + { test: url => url.includes("digitaltoday"), handler: handleDigitaltoday }, + { test: url => url.includes("kormedi"), handler: handleKormedi }, + { test: url => url.includes("chosun.com"), handler: handleChosun }, + { test: url => url.includes("traveltimes"), handler: handleTraveltimes }, + { test: url => url.includes("theqoo.net") && document.querySelectorAll('[class^="m-list m-element"]').length > 0, handler: handleTheqoo }, + { test: url => url.includes("doctorsnews"), handler: handleDoctorsnews }, + { test: url => url.includes("dcinside.com") && document.querySelectorAll('[class^="container"]').length > 0, handler: handleDcinside }, + { test: url => url.includes("fmkorea.com") && document.querySelectorAll('[class^="bd bd_mobile"]').length > 0, handler: handleFmkorea }, + { test: url => url.includes("torrentzota"), handler: handleToreentZota}, + { test: url => url.includes("acrofan.com") && document.querySelectorAll('[id^="wide"]').length > 0, handler: handleAcrofan }, + { test: url => url.includes("yna.co.kr") && document.querySelectorAll('[class^="wrapper"]').length > 0, handler: handleYna }, + { test: url => url.includes("clien") && document.querySelectorAll('[class^="content_view"]').length > 0, handler: handleClien }, + { test: url => url.includes("toki") && (document.querySelectorAll('[id^="id_mbv"]').length > 0 || document.querySelectorAll('[class^="basic-banner"]').length > 0), handler: handleToki }, +]; - if (location.href.search("khan.co.kr") > -1) { - document.querySelectorAll('[class^="banner-"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="google-auto-placed"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="relationList"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="reporter_news"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="box"]').forEach(e => e.remove()) - document.querySelectorAll('footer').forEach(e => e.remove()) - document.querySelectorAll('iframe').forEach(e => e.remove()) - document.querySelectorAll('[class^="bottom-wrap"]').forEach(e => e.remove()) - document.querySelectorAll('aside[class^="list-wrap"]').forEach(e => e.remove()) - document.querySelectorAll('div[style^="width:100%;height:250px;text-align:center;margin-bottom:20px;overflow:hidden;"]').forEach(e => e.remove()) +function handleCommon() { + // 공통 광고 제거 + if (document.querySelector(".top_google_ad_space")) document.querySelector(".top_google_ad_space").remove(); + document.querySelectorAll(".adv-group, [id^='div-gpt-ad'], [id^='div_adnmore_area'], [class^='adv-groupno'], [class^='code-block'], .ad-template").forEach(e => e.remove()); + if (document.querySelector('#xpromo-bottom-sheet')) document.querySelector('#xpromo-bottom-sheet').remove(); - - } - if (location.href.search("betanews") > -1) { - document.querySelectorAll('[class^="banner"]').forEach(e => e.remove()) - document.querySelectorAll('aside[class^="list-wrap"]').forEach(e => e.remove()) - document.querySelectorAll('section[class^="bottom"]').forEach(e => e.remove()) - document.querySelectorAll('footer').forEach(e => e.remove()) - } - if (location.href.search("newsis.com") > -1) { - document.querySelectorAll('div[style^="width: 300px; margin: 0 auto 25px;"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="listStyle"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="headtopBanner"]').forEach(e => e.remove()) - document.querySelectorAll('div[id^="ad_"]').forEach(e => e.remove()) - document.querySelectorAll('div[id^="adbay"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="article"]').forEach(function (e) { - e.querySelectorAll("iframe").forEach(e => e.remove()) - }) - document.querySelectorAll('div[class^="Float"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="bxcn"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="A1"]').forEach(e => e.remove()) - document.querySelectorAll('div[id^="news_body_end"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="linkNews"]').forEach(e => e.remove()) - document.querySelectorAll('div[id^="footer"]').forEach(e => e.remove()) - } - - if (location.href.search("seoul.co.kr") > -1) { - document.querySelectorAll('div[class^="rowAd"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="ad"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="articleBottomNews"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="sub-layoutBorder"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="m-sectionLayout"]').forEach(e => e.remove()) - document.querySelectorAll('[id^="rollingAdDiv"]').forEach(e => e.remove()) - document.querySelectorAll('footer').forEach(e => e.remove()) - document.querySelectorAll('[class^="banner"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="joinPopup"]').forEach(e => e.remove()) - } - - - if (location.href.search("ytn.co.kr") > -1) { - - document.querySelectorAll('div[class^="footer"]').forEach(e => e.remove()) - document.querySelectorAll('div[style^="width: 100%; background-color: rgb(255, 255, 255); display: flex; justify-content: center;"]').forEach(e => e.remove()) - document.querySelectorAll('div[style^="width:100%"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="ad_"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="bx_hot"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="bx_ad"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="bx_pro"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="bx_main"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="bx_sns"]').forEach(e => e.remove()) - document.querySelectorAll('div[id^="popularArea"]').forEach(e => e.remove()) - } - if (location.href.search("nocutnews.co.kr")> -1) { - document.querySelectorAll('div[style^="width:300px; margin:0 auto 25px;"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="ct2"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="footer"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="con_b"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="v_like"]').forEach(e => e.remove()) - document.querySelectorAll('div[id^="divCommonRelated"]').forEach(e => e.remove()) - document.querySelectorAll('iframe').forEach(e => e.remove()) - } - if (location.href.search("sedaily.com") > -1) { - document.querySelectorAll('div[class^="article"]').forEach(function (e) { - e.querySelectorAll("iframe").forEach(e => e.remove()) - }) - document.querySelectorAll('div[class^="banner"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^=" banner"]').forEach(e => e.remove()) - document.querySelectorAll('div[class^="col-right"]').forEach(e => e.remove()) - document.querySelectorAll('footer[class^="footer"]').forEach(e => e.remove()) - } - if (location.href.search("digitaltoday") > -1) { - document.querySelectorAll('[class^="aedi"]').forEach(e => e.remove()) - document.querySelectorAll('[id^="layer-popups"]').forEach(e => e.remove()) - document.querySelectorAll('[id^="enters"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="view-toast"]').forEach(e => e.remove()) - document.querySelectorAll('footer[id^="user"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="clearfix"]').forEach(e => e.remove()) - document.querySelectorAll('[id^="bottom-sticky"]').forEach(e => e.remove()) - - if (location.href.search("kormedi") > -1) { - document.querySelectorAll('[class^="entry-content-after"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="code-block"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="post-featured"]').forEach(e => e.remove()) - document.querySelectorAll('footer[class^="cs"]').forEach(e => e.remove()) - document.querySelectorAll('ins[class^="adsbygoogle"]').forEach(e => e.remove()) - - } - } - - if (location.href.search("chosun.com") > -1) { - document.querySelectorAll('[class^="arcad-wrapper"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="flex-chain-wrapper"]').forEach(e => e.remove()) - document.querySelectorAll('footer[class^="layout"]').forEach(e => e.remove()) - document.querySelectorAll('aside[class^="layout"]').forEach(e => e.remove()) - document.querySelectorAll('ins').forEach(e => e.remove()) - } - if (location.href.search("traveltimes") > -1) { - document.querySelectorAll('ins').forEach(e => e.remove()) - document.querySelectorAll('[class^="teads"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="tdn"]').forEach(e => e.remove()) - document.querySelectorAll('aside[class^="grid"]').forEach(e => e.remove()) - document.querySelectorAll('footer[id^="user"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="clearfix"]').forEach(e => e.remove()) - } - if (location.href.search("theqoo.net") > -1 && document.querySelectorAll('[class^="m-list m-element"]')) { - document.querySelectorAll('[class^="m-list m-element"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="button_area"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="board_content_google_ad"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="clearfix list-header"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="clearfix list-footer"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="main-footer"]').forEach(e => e.remove()) - document.querySelectorAll('ins[class^="adsbygoogle"]').forEach(e => e.remove()) - mainContentsEl = document.querySelector('div[id="grid-content"]') - } - if(location.href.search("doctorsnews") > -1) { - document.querySelectorAll('[class^="clearfix"]').forEach(e => e.remove()) - document.querySelectorAll('aside').forEach(e => e.remove()) - document.querySelectorAll('[class^="banner_"]').forEach(e => e.remove()) - } - if (location.href.search("dcinside.com") > -1 && document.querySelectorAll('[class^="container"]')) { - document.querySelectorAll('[id^="view_btn_area"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="trend-rank"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="view-btm-con"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="md-tit-box"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="gall-detail-lst"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="outside-search-box"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="footer ftlong"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="adv-group"]').forEach(e => e.remove()) - document.querySelectorAll('li[style^="cursor:default;"]').forEach(e => e.remove()) - mainContentsEl = document.querySelector('div[class="container"]') - } - - if (location.href.search("fmkorea.com") > -1 && document.querySelectorAll('[class^="bd bd_mobile"]')) { - document.querySelectorAll('[class^="fmad_wrapper fmad_naver_power_link"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="ad ad_wrapper"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="bd_lst_wrp"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="m_top_hotdeal"]').forEach(e => e.remove()) - document.querySelectorAll('[style^="margin-top:2px;line-height:0;"]').forEach(e => e.remove()) - mainContentsEl = document.querySelector('div[class="bd bd_mobile"]') - } - - if (location.hostname.search("acrofan.com") > -1 && document.querySelectorAll('[id^="wide"]')) { - document.querySelectorAll('[class^="header"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="footer"]').forEach(e => e.remove()) - document.querySelectorAll('[id^="tabmenu"]').forEach(e => e.remove()) - mainContentsEl = document.querySelector('div[class="wide"]') - } - - if (location.hostname.search("yna.co.kr") > -1 && document.querySelectorAll('[class^="wrapper"]')) { - document.querySelectorAll('[class^="aside-box426 sticky"]').forEach(e => e.remove()) - document.querySelectorAll('aside[class^="aside-box"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="section02"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="content03 wide"]').forEach(e => e.remove()) - document.querySelectorAll('[id="footer"]').forEach(e => e.remove()) - mainContentsEl = document.querySelector('div[id="container"]') - } - - if (location.hostname.search("clien") > -1 && document.querySelectorAll('[class^="content_view"]')) { - document.querySelectorAll('[class^="view_top"]').forEach(e => e.remove()) - document.querySelectorAll('[id^="naverAd"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="content_view_list"]').forEach(e => e.remove()) - document.querySelectorAll('[class^="footer_wrap"]').forEach(e => e.remove()) - mainContentsEl = document.querySelector('div[id="content_view"]') - } - - if (location.hostname.search("toki") > -1 && document.querySelectorAll('[id^="id_mbv"]')) { - document.querySelectorAll('[id^="id_mbv"]').forEach(e => e.remove()) - } - if (location.hostname.search("toki") > -1 && document.querySelectorAll('[class^="basic-banner"]')) { - document.querySelectorAll('[class^="basic-banner"]').forEach(e => e.remove()) - } - if (document.querySelector(".top_google_ad_space")) { - document.querySelector(".top_google_ad_space").remove() - } - if (document.querySelectorAll(".adv-group")) { - document.querySelectorAll(".adv-group").forEach(e => - e.remove() - ) - } - if (document.querySelectorAll('[id^="div-gpt-ad"]')) { - document.querySelectorAll('[id^="div-gpt-ad"]').forEach(e => - e.remove() - ) - } - if (document.location.href.search("reddit") > -1) { - if (document.querySelector('#xpromo-bottom-sheet')) { - document.querySelector('#xpromo-bottom-sheet').remove() - } - } - if (document.querySelectorAll('[id^="div_adnmore_area"]')) { - document.querySelectorAll('[id^="div_adnmore_area"]').forEach(e => - e.remove() - ) - } - if (document.querySelectorAll('[id^="div_adnmore_area"]')) { - document.querySelectorAll('[id^="div_adnmore_area"]').forEach(e => - e.remove() - ) - } - if (document.querySelectorAll('[class^="adv-groupno"]')) { - document.querySelectorAll('[class^="adv-groupno"]').forEach(e => - e.remove() - ) - } - if (document.querySelectorAll('[class^="code-block"]')) { - document.querySelectorAll('[class^="code-block"]').forEach(e => e.remove()) - } - if (document.querySelectorAll('.ad-template')) { - document.querySelectorAll('.ad-template').forEach(function (e) { - e.remove() - }) - } - if (location.href.search("arca.live") > -1 && document.querySelectorAll('[class^="vrow hybrid"]')) { - const tempArray = []; - document.querySelectorAll('[class^="vrow hybrid"]').forEach(function (aracaLi) { - if (aracaLi.innerHTML.search("title ") > -1) { - // title.hybrid-title 클래스가 붙은 첫 번째 요소 텍스트 추출 - let titleEl = aracaLi.querySelector('.title.hybrid-title'); - let title = titleEl ? titleEl.textContent.trim() : ''; - - // badge 클래스 텍스트와 user-info 클래스 텍스트 합치기 - let descBadge = aracaLi.querySelector('.badge'); - let descUserInfo = aracaLi.querySelector('.user-info'); - let desc = (descBadge ? descBadge.textContent.trim() : '') - if (desc.length > 0) { - desc = desc + "," - } - desc = desc + (descUserInfo ? descUserInfo.textContent.trim() : ''); - if (descUserInfo) { - desc = desc + "," - } - - // time 태그 datetime 속성 값 - let timeEl = aracaLi.querySelector('time'); - - let dateTime = timeEl ? timeEl.getAttribute('datetime') : ''; - // console.log("dateTime >>> "+ dateTime) - // const dateObj = new Date(dateTime); - // console.log(dateObj.getFullYear()); // 2025 - // console.log(dateObj.getMonth() + 1); // 7 (월은 0부터 시작하므로 +1) - // console.log(dateObj.getDate()); // 30 - // console.log(dateObj.getHours()); // 13 (현지 시간 기준) - // console.log(dateObj.getMinutes()); // 45 - // console.log(dateObj.getSeconds()); - // console.log(dateObj); - // img 태그 src 값 - let imgEl = aracaLi.querySelector('img'); - let thumbnail = imgEl ? imgEl.getAttribute('src') : ''; - - // 링크 만들기 - let link = 'https://arca.live'; - if (titleEl && titleEl.getAttribute('href')) { - link += titleEl.getAttribute('href'); - } else { - let aEl = aracaLi.querySelector('a'); - if (aEl && aEl.getAttribute('href')) { - link += aEl.getAttribute('href'); - } - } - - if (title.length > 0 && link.length > 20) { - // thumbnail 절대경로 처리 (프로토콜이 없는 경우 https: 붙이기) - if (thumbnail.startsWith('//')) { - thumbnail = 'https:' + thumbnail; - } - - // 날짜가 하루 이내인지 확인하는 함수 사용 - - tempArray.push({ - title: title.replace(/\s+/g, ' ').trim(), - description: desc.replace(/\s+/g, ' ').trim() + "ARCA", - pubDate: new Date(dateTime).getTime(), - originPage: link, - "category": "ARCA", - thumbnail: thumbnail - }); - - } - } - - }) - if (tempArray.length > 0) { - console.log(tempArray); - sendMessage( - { - type: "PRIVATES", - privates: tempArray, - currentPage: location.href - } - ); - location.href = "about:blank;" - } - } - if (document.querySelectorAll('[class^="popupBanner_w popupOpen"]')) { - document.querySelectorAll('[class^="popupBanner_w popupOpen"]').forEach(function (e) { - e.remove() - }) - } - - if (document.querySelectorAll('iframe')) { - document.querySelectorAll('iframe').forEach(function (e) { - if (e.getAttribute("src") != null && (e.getAttribute("src").search("ads") > -1 || e.getAttribute("src").search("coupang") > -1)) { - e.remove() - } - }) - } - if (location.href.search("x.com") > -1) { - var mainClass = document.querySelector('section').className - - document.querySelector('section').querySelectorAll('div[class="' + mainClass + '"]').forEach(function (e) { - if (e.hasAttribute("data-testid") && e.querySelector('video')) { - e.querySelectorAll('[poster]').forEach(function (e) { - - }) - console.log(e.innerHTML) - } - }) - - } + document.querySelectorAll('iframe').forEach(e => { + const src = e.getAttribute("src"); + if (src != null && (src.includes("ads") || src.includes("coupang"))) e.remove(); + }); if (document.querySelectorAll('[data-banner^="coupang-"]')) { document.querySelectorAll('[data-banner^="coupang-"]').forEach(e => e.remove()) @@ -690,6 +417,127 @@ function autoScrollAndSave(senContents) { if (document.querySelectorAll('[class^="science-banner-area"]')) { document.querySelectorAll('[class^="science-banner-area"]').forEach(e => e.remove()) } + + + if (document.querySelectorAll('[class^="col-md-4 mb-4 video-item"]').length > 1) { + var datas = [] + document.querySelectorAll('[class^="col-md-4 mb-4 video-item"]').forEach(function (e) { + var date = 0 + try { + const dateString = e.querySelector('[class^="mb-2"]').querySelector("a").textContent.trim(); + + const [day, month, year] = dateString.split("/").map(Number); + date = new Date(year, month - 1, day).getTime(); + } catch (e) { + + } + var actor = "" + try { + actor = e.querySelector('[class^="mb-1"]').getAttribute("alt").trim() + } catch (e) { + + } + var desc = "" + try { + e.querySelectorAll('[class^="badge badge-"]').forEach(function (e) { + try { + if (Number(e.textContent) > 0) { + + } else { + if (desc.length > 0) { + desc += "," + } + desc += e.textContent.trim() + } + } catch (e) { + } + } + ) + } catch (e) { + + } + var thumb = "" + try { + thumb = e.querySelector("td").querySelector("a").getAttribute('data-link') + try { + var sets = e.querySelector("td").querySelector("img").getAttribute('srcset') + if (sets.search(",") > -1) { + var srcSet = sets.split(",") + var newT = srcSet[srcSet.length - 1] + if (newT != null && newT.length > 5) { + thumb = newT + } + } + } catch (e) { + } + } catch (e) { + } + var magnet = "" + try { + e.querySelectorAll("td").forEach(function (e) { + e.querySelectorAll("a").forEach(function (e) { + if (e.getAttribute("href").startsWith("magnet")) { + magnet = e.getAttribute("href").replaceAll("&", "&"); + } + }) + }) + } catch (e) { + + } + + var title = ""; + try { + e.querySelector(".name").querySelector("a").querySelectorAll("span").forEach(function (e) { + if (e.hasAttribute("class") == false) { + title = e.textContent.trim(); + } + }) + } catch (e) { + + } + var originPage = "" + try { + originPage = location.protocol + "//" + location.hostname + e.querySelector(".name").querySelector("a").getAttribute("href"); + } catch (e) { + + } + var screenshots = "" + try { + e.querySelectorAll("a").forEach(function (e) { + if (e.getAttribute("href").search("screenshots") > -1) { + screenshots = e.getAttribute("href"); + } + }) + } catch (e) { + + } + if (thumb.length > 0 || screenshots.length > 0) { + } + datas.push({ + "title": title, + "description": desc, + "originPage": originPage, + "magnet_link": magnet, + "thumbnail": thumb, + "pubDate": date, + "screenshotsUrl": screenshots, + "chosung": "", + "category": "PRIVATE" + }); + }) + sendMessage( + { + type: "PRIVATES", + privates: datas, + currentPage: location.href + } + ); + + gotoNext() + } + window.scrollTo({ top: 2, behavior: 'smooth' }); +} +function handleToreentZota() { if (location.href.search("torrentzota") > -1 && document.querySelectorAll('a')) { document.querySelectorAll('a').forEach(function (e) { if (e.getAttribute('href') != null && e.getAttribute('href').startsWith("/adver-")) { @@ -812,125 +660,122 @@ function autoScrollAndSave(senContents) { } } - - if (document.querySelectorAll('[class^="col-md-4 mb-4 video-item"]').length > 1) { - var datas = [] - document.querySelectorAll('[class^="col-md-4 mb-4 video-item"]').forEach(function (e) { - var date = 0 - try { - const dateString = e.querySelector('[class^="mb-2"]').querySelector("a").textContent.trim(); - - const [day, month, year] = dateString.split("/").map(Number); - date = new Date(year, month - 1, day).getTime(); - } catch (e) { - - } - var actor = "" - try { - actor = e.querySelector('[class^="mb-1"]').getAttribute("alt").trim() - } catch (e) { - - } - var desc = "" - try { - e.querySelectorAll('[class^="badge badge-"]').forEach(function (e) { - try { - if (Number(e.textContent) > 0) { - - } else { - if (desc.length > 0) { - desc += "," - } - desc += e.textContent.trim() - } - } catch (e) { - } - } - ) - } catch (e) { - - } - var thumb = "" - try { - thumb = e.querySelector("td").querySelector("a").getAttribute('data-link') - try { - var sets = e.querySelector("td").querySelector("img").getAttribute('srcset') - if (sets.search(",") > -1) { - var srcSet = sets.split(",") - var newT = srcSet[srcSet.length - 1] - if (newT != null && newT.length > 5) { - thumb = newT - } - } - } catch (e) { - } - } catch (e) { - } - var magnet = "" - try { - e.querySelectorAll("td").forEach(function (e) { - e.querySelectorAll("a").forEach(function (e) { - if (e.getAttribute("href").startsWith("magnet")) { - magnet = e.getAttribute("href").replaceAll("&", "&"); - } - }) - }) - } catch (e) { - - } - - var title = ""; - try { - e.querySelector(".name").querySelector("a").querySelectorAll("span").forEach(function (e) { - if (e.hasAttribute("class") == false) { - title = e.textContent.trim(); - } - }) - } catch (e) { - - } - var originPage = "" - try { - originPage = location.protocol + "//" + location.hostname + e.querySelector(".name").querySelector("a").getAttribute("href"); - } catch (e) { - - } - var screenshots = "" - try { - e.querySelectorAll("a").forEach(function (e) { - if (e.getAttribute("href").search("screenshots") > -1) { - screenshots = e.getAttribute("href"); - } - }) - } catch (e) { - - } - if (thumb.length > 0 || screenshots.length > 0) { - } - datas.push({ - "title": title, - "description": desc, - "originPage": originPage, - "magnet_link": magnet, - "thumbnail": thumb, - "pubDate": date, - "screenshotsUrl": screenshots, - "chosung": "", - "category": "PRIVATE" - }); - }) - sendMessage( - { - type: "PRIVATES", - privates: datas, - currentPage: location.href - } - ); - - gotoNext() - } - window.scrollTo({ top: 2, behavior: 'smooth' }); - if (senContents) { - sendMessage({type: "MainContentsEl", contents: mainContentsEl.outerHTML, currentPage: location.href}); +} +// 도메인별 처리 함수 모음 +function handleNate() { + if (location.href.startsWith("https://news.nate.com")) { + location.href = location.href.replace("https://", "https://m."); } + document.querySelectorAll('[class^="float-adv-wrap"]').forEach(e => e.remove()); + document.querySelectorAll('[id^="ad_"]').forEach(e => e.remove()); + document.querySelectorAll("#ad_sponsorBar, #newsSidebar, #header, #module_ssul, #mediaFooter").forEach(e => e.remove()); + document.querySelectorAll('iframe[id^="ad"]').forEach(e => e.remove()); + document.querySelectorAll('[class^="boxtype1 thisTimeNews"], [class^="news_cmt"], section[class^="rwd_right"]').forEach(e => e.remove()); +} + +function handleZdnet() { + document.querySelectorAll('div[id*="FloatCon"]').forEach(e => e.remove()); +} + +function handleInews24() { + document.querySelectorAll('ad[alt^="a"], div[class^="topnews"], form[class^="talkplus"], form[class^="timeline"], form[class^="photo"], ins[class^="adsbygoogle"], footer[class^="footer"], ad, footer').forEach(e => e.remove()); +} + +function handleStarnewsKorea() { + document.querySelectorAll('div[class^="floating-top-ad"], div[class^="fixed bottom"], section[class^="mt-4"], div[id^="dablewidget_"], footer[class^="footer"]').forEach(e => e.remove()); +} + +function handleKhan() { + document.querySelectorAll('[class^="banner-"], [class^="google-auto-placed"], [class^="relationList"], [class^="reporter_news"], [class^="box"], footer, iframe, [class^="bottom-wrap"], aside[class^="list-wrap"], div[style^="width:100%;height:250px"]').forEach(e => e.remove()); +} + +function handleHealthChosun() { + document.querySelectorAll('ins, iframe, footer, div[class^="google-"], div[id^="banner-"], section[class^="hranking"], section[class^="related-articles"], div[class^="separator-container"], div[class^="raw-html"]').forEach(e => e.remove()); + mainContentsEl = document.querySelectorAll('article[class^="layout_"]'); +} + +function handleBetanews() { + document.querySelectorAll('[class^="banner"], aside[class^="list-wrap"], section[class^="bottom"], footer').forEach(e => e.remove()); +} + +function handleNewsis() { + document.querySelectorAll('div[style^="width: 300px; margin: 0 auto 25px;"], div[class^="listStyle"], div[class^="headtopBanner"], div[id^="ad_"], div[id^="adbay"], div[class^="article"], div[class^="Float"], div[class^="bxcn"], div[class^="A1"], div[id^="news_body_end"], div[class^="linkNews"], div[id^="footer"]').forEach(e => e.remove()); + document.querySelectorAll('div[class^="article"]').forEach(e => e.querySelectorAll("iframe").forEach(i => i.remove())); +} + +function handleSeoul() { + document.querySelectorAll('div[class^="rowAd"], div[class^="ad"], [class^="articleBottomNews"], [class^="sub-layoutBorder"], [class^="m-sectionLayout"], [id^="rollingAdDiv"], footer, [class^="banner"], [class^="joinPopup"]').forEach(e => e.remove()); +} + +function handleYtn() { + document.querySelectorAll( + 'div[class^="footer"], div[style^="width: 100%; background-color: rgb(255, 255, 255); display: flex; justify-content: center;"], div[style^="width:100%"], ' + + 'div[class^="ad_"], div[class^="bx_hot"], div[class^="bx_ad"], div[class^="bx_pro"], div[class^="bx_main"], div[class^="bx_sns"], div[id^="popularArea"]' + ).forEach(e => e.remove()); +} + +function handleNocutnews() { + document.querySelectorAll('div[style^="width:300px; margin:0 auto 25px;"], div[class^="ct2"], div[class^="footer"], div[class^="con_b"], div[class^="v_like"], div[id^="divCommonRelated"], iframe').forEach(e => e.remove()); +} + +function handleSedaily() { + document.querySelectorAll('div[class^="article"]').forEach(e => e.querySelectorAll("iframe").forEach(i => i.remove())); + document.querySelectorAll('div[class^="banner"], div[class^=" banner"], div[class^="col-right"], footer[class^="footer"]').forEach(e => e.remove()); +} + +function handleDigitaltoday() { + document.querySelectorAll('[class^="aedi"], [id^="layer-popups"], [id^="enters"], [class^="view-toast"], footer[id^="user"], [class^="clearfix"], [id^="bottom-sticky"]').forEach(e => e.remove()); +} + +function handleKormedi() { + document.querySelectorAll('[class^="entry-content-after"], [class^="code-block"], [class^="post-featured"], footer[class^="cs"], ins[class^="adsbygoogle"]').forEach(e => e.remove()); +} + +function handleChosun() { + document.querySelectorAll('[class^="arcad-wrapper"], [class^="flex-chain-wrapper"], footer[class^="layout"], aside[class^="layout"], ins, div[id^="paywallCont"], div[class^="paywall--bg"]').forEach(e => e.remove()); +} + +function handleTraveltimes() { + document.querySelectorAll('ins, [class^="teads"], [class^="tdn"], aside[class^="grid"], footer[id^="user"], [class^="clearfix"]').forEach(e => e.remove()); +} + +function handleTheqoo() { + document.querySelectorAll('[class^="m-list m-element"], [class^="button_area"], [class^="board_content_google_ad"], [class^="clearfix list-header"], [class^="clearfix list-footer"], [class^="main-footer"], ins[class^="adsbygoogle"]').forEach(e => e.remove()); + mainContentsEl = document.querySelector('div[id="grid-content"]'); +} + +function handleDoctorsnews() { + document.querySelectorAll('[class^="clearfix"], aside, [class^="banner_"]').forEach(e => e.remove()); +} + +function handleDcinside() { + document.querySelectorAll( + '[id^="view_btn_area"], [class^="trend-rank"], [class^="view-btm-con"], [class^="md-tit-box"], [class^="gall-detail-lst"], [class^="outside-search-box"], [class^="footer ftlong"], [class^="adv-group"], li[style^="cursor:default;"], [id^="div_adnmore_area"]' + ).forEach(e => e.remove()); + document.querySelectorAll('div[class="container"]').forEach(e => e.remove()); // just in case + mainContentsEl = document.querySelector('div[class="container"]'); +} + +function handleFmkorea() { + document.querySelectorAll('[class^="fmad_wrapper fmad_naver_power_link"], [class^="ad ad_wrapper"], [class^="bd_lst_wrp"], [class^="m_top_hotdeal"], [style^="margin-top:2px;line-height:0;"]').forEach(e => e.remove()); + mainContentsEl = document.querySelector('div[class="bd bd_mobile"]'); +} + +function handleAcrofan() { + document.querySelectorAll('[class^="header"], [class^="footer"], [id^="tabmenu"]').forEach(e => e.remove()); + mainContentsEl = document.querySelector('div[class="wide"]'); +} + +function handleYna() { + document.querySelectorAll('[class^="aside-box426 sticky"], aside[class^="aside-box"], [class^="section02"], [class^="content03 wide"], [id="footer"]').forEach(e => e.remove()); + mainContentsEl = document.querySelector('div[id="container"]'); +} + +function handleClien() { + document.querySelectorAll('[class^="view_top"], [id^="naverAd"], [class^="content_view_list"], [class^="footer_wrap"]').forEach(e => e.remove()); + mainContentsEl = document.querySelector('div[id="content_view"]'); +} + +function handleToki() { + document.querySelectorAll('[id^="id_mbv"], [class^="basic-banner"]').forEach(e => e.remove()); } \ No newline at end of file diff --git a/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt b/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt index 5331bc6d..7ce4c0da 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt @@ -79,6 +79,8 @@ import bums.lunatic.launcher.home.RssViewBuilder import bums.lunatic.launcher.model.RssData import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.tokiz.Comics +import bums.lunatic.launcher.tokiz.Magnet +import bums.lunatic.launcher.tokiz.Perplexity import bums.lunatic.launcher.tokiz.Twitter import bums.lunatic.launcher.tokiz.Webtoons import bums.lunatic.launcher.tokiz.Zota @@ -518,15 +520,6 @@ internal class LauncherActivity : CommonActivity() { binding.tabs.setOnCheckedChangeListener { g, id -> showContents(id) } - binding.hidden.setOnLongClickListener { - supportFragmentManager.beginTransaction() - .replace(R.id.fragment_container, RssHome().apply { - arguments = Bundle().apply { - putBoolean("HIDDEN", true) - }} - ).commit() - true - } /* handle navigation back events */ handleBackPress() @@ -559,6 +552,11 @@ internal class LauncherActivity : CommonActivity() { .replace(R.id.fragment_container, Comics()) .commit() } + R.id.perplexity ->{ + supportFragmentManager.beginTransaction() + .replace(R.id.fragment_container, Perplexity()) + .commit() + } R.id.zota ->{ supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, Zota()) @@ -569,6 +567,11 @@ internal class LauncherActivity : CommonActivity() { .replace(R.id.fragment_container, Twitter()) .commit() } + R.id.magnet ->{ + supportFragmentManager.beginTransaction() + .replace(R.id.fragment_container, Magnet()) + .commit() + } else -> {} } } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt index 2437beee..9c5bcefa 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt @@ -75,7 +75,10 @@ class GeckoWeb : BWebview { super.setVisibility(visibility) decoViews.forEach { it.visibility = visibility } } - + interface OnSave { + fun saved() + } + var mOnSave : OnSave? = null constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { buildWeb() } @@ -173,6 +176,28 @@ class GeckoWeb : BWebview { Blog.LOGE(Gson().toJson(message)) mPort?.postMessage(message) } + fun sendSearch(keyword: String) { + val message: JSONObject = JSONObject() + try { + message.put("type", "search") + message.put("keyword", keyword) + } catch (ex: JSONException) { + throw RuntimeException(ex) + } + Blog.LOGE(Gson().toJson(message)) + mPort?.postMessage(message) + } + + fun sendSearchDo() { + val message: JSONObject = JSONObject() + try { + message.put("type", "searchDo") + } catch (ex: JSONException) { + throw RuntimeException(ex) + } + Blog.LOGE(Gson().toJson(message)) + mPort?.postMessage(message) + } var mExtension: WebExtension? = null var mSession: GeckoSession? = null @@ -342,6 +367,7 @@ class GeckoWeb : BWebview { // 저장 성공 알림 등 후속 처리 println("PDF 저장 완료: ${outputFile.absolutePath}") + mOnSave?.saved() } fun downloadImage(context: Context, url: Uri, isGif : Boolean = false) { @@ -604,10 +630,11 @@ class GeckoWeb : BWebview { } } - fun saveMd() { + fun saveMd(fast : Boolean? = false) { val message: JSONObject = JSONObject() try { message.put("type", "saveContent") + message.put("fast", fast) } catch (ex: JSONException) { throw RuntimeException(ex) } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt index 246af4d4..b3636c9c 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt @@ -103,7 +103,7 @@ internal class RssHome : Fragment() { var infosJob: Job? = null // var rssId = "" lateinit var mRssAdapter: RssItemAdapter - + var mLastedQuery: RealmQuery? = null var mRssDataResult: RealmResults? = null val mSimpleFingerGestures = @@ -199,7 +199,7 @@ internal class RssHome : Fragment() { return false } }) - var useHiddenMenu = false + var useHiddenMenu = true override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { @@ -319,39 +319,72 @@ 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(R.id.input) as EditText - val privateMode = viewInflated.findViewById(R.id.private_mode) as CheckBox - (viewInflated.findViewById(R.id.add_vote) as CheckBox)?.let{ it.visibility = View.GONE} - (viewInflated.findViewById(R.id.add_read) as CheckBox)?.let{ it.visibility = View.GONE} - privateMode.setOnCheckedChangeListener { v,c-> - binding.geckoWeb.privateMode = c - } - privateMode.isChecked = true - binding.geckoWeb.privateMode = true - builder.setView(viewInflated) - builder.setPositiveButton( - android.R.string.ok, - DialogInterface.OnClickListener { dialog, which -> - dialog.dismiss() - var command = input.editableText?.toString() - if (command?.length ?: 0 > 0) { - binding.geckoWeb.loadUrl( - "aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=", - "/?searchTerm=${command}" - ) - } else { - binding.geckoWeb.loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=") - } - }) - builder.setNegativeButton( - android.R.string.cancel, - DialogInterface.OnClickListener { dialog, which -> dialog.cancel() }) + val bottomSheet = WebBottomSheet() + bottomSheet.listener = object : WebBottomSheet.OnGoToWebListener{ + override fun enterSearch() { + binding.geckoWeb.sendSearchDo() + } + override fun onGotoWeb( + keyword: String, + category: RssDataType, + privateMode: Boolean + ) { + when (category) { + RssDataType.GOOGLE -> { + if (binding.geckoWeb.lastedUrl?.contains("www.google") == true) { + binding.geckoWeb.sendSearch(keyword) + } else { + binding.geckoWeb.loadUrl("https://www.google.com/", if (keyword.length ?: 0 > 0) { "/?q=${keyword}" } else { null }) + } + binding.geckoWeb.privateMode = false + } + RssDataType.NAMU -> { + if (binding.geckoWeb.lastedUrl?.contains("namu.wiki") == true) { + binding.geckoWeb.sendSearch(keyword) + } else { + binding.geckoWeb.loadUrl("https://namu.wiki", if (keyword.length ?: 0 > 0) {"/Search?q=${keyword}"} else {null}) + } + binding.geckoWeb.privateMode = false + } + RssDataType.NAVER -> { + if (binding.geckoWeb.lastedUrl?.contains("naver") == true) { + binding.geckoWeb.sendSearch(keyword) + } else { + binding.geckoWeb.loadUrl("https://search.naver.com/", if (keyword.length ?: 0 > 0) {"search.naver?where=nexearch&query==${keyword}"} else {null}) + } + binding.geckoWeb.privateMode = false + } + RssDataType.NEWSFEED -> { + if (binding.geckoWeb.lastedUrl?.contains("news.google") == true) { + binding.geckoWeb.sendSearch(keyword) + } else { + binding.geckoWeb.loadUrl("https://news.google.com/", if (keyword.length ?: 0 > 0) {"search?q=${keyword}&hl=ko&gl=KR&ceid=KR%3Ako"} else {null}) + } + binding.geckoWeb.privateMode = false + } + RssDataType.NEWS -> { + if (binding.geckoWeb.lastedUrl?.contains("bigkinds") == true) { + binding.geckoWeb.sendSearch(keyword) + } else { + binding.geckoWeb.loadUrl("https://www.bigkinds.or.kr/", if (keyword.length ?: 0 > 0) {"search?q=${keyword}&hl=ko&gl=KR&ceid=KR%3Ako"} else {null}) + } + binding.geckoWeb.privateMode = false + } + RssDataType.PRIVATE -> { +// if (binding.geckoWeb.lastedUrl?.contains("naver") == true) { +// +// } else { + binding.geckoWeb.privateMode = privateMode + binding.geckoWeb.loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=", if (keyword.length ?: 0 > 0) {"/?searchTerm=${keyword}"} else {null}) +// } + } + else -> { - builder.show() + } + } + } + } + bottomSheet.show(childFragmentManager, "SearchBottomSheet") } var currentRss : RssData? = null @@ -500,7 +533,25 @@ internal class RssHome : Fragment() { binding.privateBtn.visibility = View.GONE binding.search.visibility = View.GONE } - + binding.geckoWeb?.mOnSave = object : GeckoWeb.OnSave{ + override fun saved() { + currentRss?.originPage.let { + Blog.LOGE("Arrow Center Click") + WorkersDb.getRealm().apply { + writeBlocking { + val result = query().query( + if (imageView) "thumbnail == $0" else "originPage == $0", + it + ).find() + if (result.size > 0) { + result.forEach { it.vote = true } + } + } + } + doNextPage() + } + } + } binding.hide.setOnClickListener { if (binding.geckoWeb.isVisible) { WorkersDb.getRealm().apply { @@ -583,22 +634,7 @@ internal class RssHome : Fragment() { } fun vote() { - binding.geckoWeb?.saveMd() - currentRss?.originPage.let { - Blog.LOGE("Arrow Center Click") - WorkersDb.getRealm().apply { - writeBlocking { - val result = query().query( - if (imageView) "thumbnail == $0" else "originPage == $0", - it - ).find() - if (result.size > 0) { - result.forEach { it.vote = true } - } - } - } - doNextPage() - } + binding.geckoWeb?.saveMd(true) } @@ -654,14 +690,11 @@ internal class RssHome : Fragment() { Blog.LOGE("updateQuery >>> ${q.description()}") infosJob?.cancel() commandHandler.removeCallbacks(infoUpdate) - - mRssDataResult = - q.sort("pubDate ", Sort.DESCENDING).limit(300).distinct("originPage", "title").find() + mLastedQuery = q.sort("pubDate ", Sort.DESCENDING).limit(300).distinct("originPage", "title") + mRssDataResult = mLastedQuery?.find() mRssDataResult?.asFlow()?.let { flow -> infosJob = CoroutineScope(Dispatchers.IO).launch { flow.collect { changes: ResultsChange -> -// when (changes) { -// is InitialResults -> { synchronized(lasted) { commandHandler.removeCallbacks(infoUpdate) WorkersDb.getRealm().apply { @@ -670,17 +703,6 @@ internal class RssHome : Fragment() { } commandHandler.post(infoUpdate) } -// } -// -// is UpdatedResults -> { -// CoroutineScope(Dispatchers.Main).launch { -// changes.changeRanges.forEach { -// mRssAdapter.notifyItemRangeChanged(it.startIndex, it.length) -// } -// } -// } -// -// } } } infosJob?.start() @@ -771,18 +793,7 @@ internal class RssHome : Fragment() { Blog.LOGE("onViewCreated()") - -// fragManager.addOnBackStackChangedListener { -// Blog.LOGE("addOnBackStackChangedListener()") -// shouldResume = if (fragManager.backStackEntryCount == 0) { -// binding.root.visibility = View.VISIBLE -// true -// } else { -// binding.root.visibility = View.GONE -// false -// } -// } - enableSwipeToDeleteAndUndo() +// enableSwipeToDeleteAndUndo() } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/SearchBottomSheet.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/SearchBottomSheet.kt index 5f3c8c1c..419c649a 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/SearchBottomSheet.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/SearchBottomSheet.kt @@ -64,17 +64,12 @@ class SearchBottomSheet : BottomSheetDialogFragment() { text = category.name isAllCaps = false setBackgroundResource(android.R.drawable.btn_default) - - // 초기 색상(활성 상태 색 표시) - updateButtonStyle(this, true) - + setTextColor(Color.WHITE) + setBackgroundResource(R.color.tabs_black) setOnClickListener { - // 상태 반전 val current = categoryStates[category.name] ?: true categoryStates[category.name] = !current - - // 스타일 업데이트 - updateButtonStyle(this, !current) + this.isSelected = !this.isSelected triggerSearchWithDebounce(inputKeyword.text.toString()) } } @@ -113,15 +108,6 @@ class SearchBottomSheet : BottomSheetDialogFragment() { } } - private fun updateButtonStyle(button: Button, isActive: Boolean) { - if (isActive) { - button.setBackgroundColor(Color.parseColor("#FF9800")) // 활성화 색상 - button.setTextColor(Color.WHITE) - } else { - button.setBackgroundColor(Color.LTGRAY) // 비활성화 색상 - button.setTextColor(Color.DKGRAY) - } - } private fun triggerSearchWithDebounce(keyword: String) { searchRunnable?.let { debounceHandler.removeCallbacks(it) } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/WebBottomSheet.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/WebBottomSheet.kt new file mode 100644 index 00000000..0f946350 --- /dev/null +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/WebBottomSheet.kt @@ -0,0 +1,136 @@ +package bums.lunatic.launcher.home + +import android.content.Context +import android.graphics.Color +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.text.Editable +import android.text.TextWatcher +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.view.inputmethod.EditorInfo +import android.view.inputmethod.InputMethodManager +import android.widget.Button +import android.widget.CheckBox +import android.widget.EditText +import android.widget.LinearLayout +import android.widget.RadioButton +import android.widget.RadioGroup +import android.widget.Toast +import androidx.core.view.children +import bums.lunatic.launcher.R +import bums.lunatic.launcher.model.RssDataType +import com.google.android.material.bottomsheet.BottomSheetDialogFragment + +class WebBottomSheet : BottomSheetDialogFragment() { + + private val debounceHandler = Handler(Looper.getMainLooper()) + private var searchRunnable: Runnable? = null + private val debounceDelay = 300L // 0.3초 지연 + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.bottom_sheet_web, container, false) + } + + interface OnGoToWebListener { + fun onGotoWeb(keyword: String, category: RssDataType, privateMode : Boolean) + fun enterSearch() + } + + var listener: OnGoToWebListener? = null + + var selectedRssType : RssDataType = RssDataType.GOOGLE + lateinit var privateMode : CheckBox + lateinit var inputKeyword : EditText + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + inputKeyword = view.findViewById(R.id.inputKeyword) + val categoryContainer = view.findViewById(R.id.categoryContainer) + privateMode = view.findViewById(R.id.check_private) as CheckBox + privateMode.setOnCheckedChangeListener {v,b->triggerSearchWithDebounce(inputKeyword.text.toString())} + // 카테고리 목록 + val categories = listOf(RssDataType.GOOGLE, RssDataType.NAVER,RssDataType.NEWS,RssDataType.NEWSFEED,RssDataType.NAMU,RssDataType.PRIVATE) + + // 버튼 동적 생성 + categoryContainer.removeAllViews() + + categoryContainer.setOnCheckedChangeListener { g,checked -> + ((g.findViewById(checked))?.tag as? RssDataType)?.let { + selectedRssType = it + } + } + + for (category in categories) { + val btn = RadioButton(requireContext()).apply { + layoutParams = RadioGroup.LayoutParams(RadioGroup.LayoutParams.WRAP_CONTENT,RadioGroup.LayoutParams.MATCH_PARENT) + setPadding(50,2,50,2) + tag = category + text = category.name + isAllCaps = false + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + setButtonIcon(null) + } + setTextColor(Color.WHITE) + setBackgroundResource(R.color.tabs_black) + setOnClickListener { + triggerSearchWithDebounce(inputKeyword.text.toString()) + } + } + categoryContainer.addView(btn) + } + + (categoryContainer.getChildAt(0) as? RadioButton)?.let { it.isChecked = true } + + inputKeyword.requestFocus() + // 키보드 강제 오픈 + inputKeyword.postDelayed( { + val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput(inputKeyword, InputMethodManager.SHOW_IMPLICIT) + },150L) + +// EditText 입력 실시간 감지 + debounce + inputKeyword.addTextChangedListener(object : TextWatcher { + override fun afterTextChanged(s: Editable?) { + triggerSearchWithDebounce(s.toString()) + } + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} + }) + // 키보드 "검색" 액션 처리 + inputKeyword.setOnEditorActionListener { _, actionId, _ -> + if (actionId == EditorInfo.IME_ACTION_SEARCH) { + val keyword = inputKeyword.text.toString() + if (keyword.isNotEmpty()) { + triggerSearchWithDebounce(keyword) + dismiss() // 필요 시 닫기 + } + true + } else { + false + } + } + } + + private fun triggerSearchWithDebounce(keyword: String) { + searchRunnable?.let { debounceHandler.removeCallbacks(it) } + searchRunnable = Runnable { + listener?.onGotoWeb(keyword, selectedRssType, privateMode.isChecked) + } + debounceHandler.postDelayed(searchRunnable!!, debounceDelay) + } + + override fun onStart() { + super.onStart() + // 전체 창 높이를 키보드에 맞게 조정 + dialog?.window?.setSoftInputMode( + WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE or + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE + ) + } +} diff --git a/app/src/main/kotlin/bums/lunatic/launcher/model/RssDataInterface.kt b/app/src/main/kotlin/bums/lunatic/launcher/model/RssDataInterface.kt index 84eb92ff..5d0a6ce3 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/model/RssDataInterface.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/model/RssDataInterface.kt @@ -10,6 +10,7 @@ enum class RssDataType { TORRENT, YOUTUBE, NEWSFEED, + NEWS, TAGS, REDDIT, REDDIT_NSFW, @@ -19,6 +20,9 @@ enum class RssDataType { RULIWEB, CLIEN, THEQOO, + NAVER, + GOOGLE, + NAMU, ARCA; fun getResId() = when (this) { diff --git a/app/src/main/kotlin/bums/lunatic/launcher/tokiz/Magnet.kt b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/Magnet.kt new file mode 100644 index 00000000..cf736900 --- /dev/null +++ b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/Magnet.kt @@ -0,0 +1,185 @@ +package bums.lunatic.launcher.tokiz + +import android.content.DialogInterface +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.res.Configuration +import android.graphics.Bitmap +import android.graphics.Color +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.os.Message +import android.text.InputType +import android.text.SpannableStringBuilder +import android.text.style.RelativeSizeSpan +import android.util.Log +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.View.GONE +import android.view.View.OnTouchListener +import android.view.View.VISIBLE +import android.view.View.inflate +import android.view.ViewGroup +import android.webkit.WebView +import android.webkit.WebViewClient +import android.widget.ArrayAdapter +import android.widget.EditText +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.net.toUri +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime +import bums.lunatic.launcher.R +import bums.lunatic.launcher.tokiz.common.PairArray +import bums.lunatic.launcher.tokiz.common.TouchArea +import bums.lunatic.launcher.tokiz.common.colorz +import bums.lunatic.launcher.tokiz.common.getIndex +import bums.lunatic.launcher.tokiz.common.typesfacez +import bums.lunatic.launcher.tokiz.data.HistoryManager +import bums.lunatic.launcher.tokiz.data.model.ContentsPageInfo +import bums.lunatic.launcher.tokiz.data.model.ContentsCollection +import bums.lunatic.launcher.tokiz.data.model.PageInfosJ +import bums.lunatic.launcher.tokiz.data.model.HistoryItem +import bums.lunatic.launcher.tokiz.data.model.LastInfo +import bums.lunatic.launcher.tokiz.data.model.PortMessage +import bums.lunatic.launcher.tokiz.data.model.ReaderConfig +import bums.lunatic.launcher.tokiz.dialog.DefaultList +import bums.lunatic.launcher.tokiz.view.JxEvent +import bums.lunatic.launcher.tokiz.view.PagedTextLayout +import bums.lunatic.launcher.tokiz.view.PagedTextViewInterface +import bums.lunatic.launcher.databinding.BooktokiBinding +import bums.lunatic.launcher.utils.Blog +import com.google.gson.Gson +import io.realm.kotlin.Realm +import io.realm.kotlin.UpdatePolicy +import io.realm.kotlin.ext.copyFromRealm +import io.realm.kotlin.ext.query +import org.json.JSONException +import org.json.JSONObject +import org.mozilla.gecko.util.ThreadUtils +import org.mozilla.geckoview.GeckoResult +import org.mozilla.geckoview.GeckoSession +import org.mozilla.geckoview.MediaSession +import org.mozilla.geckoview.WebExtension +import org.mozilla.geckoview.WebExtension.MessageDelegate +import org.mozilla.geckoview.WebExtension.PortDelegate +import org.mozilla.geckoview.WebExtensionController.AddonManagerDelegate +import org.mozilla.geckoview.WebRequestError +import java.lang.System.currentTimeMillis +import java.text.SimpleDateFormat +import java.util.Date +import kotlin.collections.ArrayList +import kotlin.collections.List +import kotlin.collections.MutableList +import kotlin.collections.arrayListOf +import kotlin.collections.first +import kotlin.collections.isNotEmpty +import kotlin.collections.last +import kotlin.collections.sortBy +import kotlin.random.Random +import kotlin.text.contains +import kotlin.text.endsWith +import kotlin.text.equals +import kotlin.text.replace +import kotlin.text.split +import kotlin.text.startsWith +import kotlin.text.toInt +import kotlin.text.toRegex +import kotlin.text.trim + + +class Magnet : BaseToki(), PagedTextViewInterface { +// "https://btsearch.love/ + override val contentsType = "btsearch" + override var lastNumber : Int = 143 + override val webcontentsName : String = "btsearch" + override val afterDot = "love" + override fun getLastedDoamin(): String { + return String.format("https://%s.%s", webcontentsName, afterDot) + } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + super.onCreateView(inflater, container, savedInstanceState) + return binding.root + } + + override fun onStart() { + super.onStart() + } + + override fun onResume() { + super.onResume() + loadLastInfo() + } + + override fun onTouch(touchArea: TouchArea) { + Blog.LOGD(log = "onTouch ${touchArea}") + when (touchArea) { + TouchArea.Center -> { + + } + + TouchArea.Right -> { + actionNextEvent() + } + + TouchArea.Left -> { + actionPrevEvent() + } + + TouchArea.DoubleRight -> { + actionNextEvent(true) + } + + TouchArea.DoubleLeft -> { + actionPrevEvent(true) + } + else -> { + + } + } + + + } + + override fun onLongClick() { + Blog.LOGD(log = "onLongClick") + + } + + override fun onSwipeLeft(count: Int) { + Blog.LOGD(log = "onSwipeLeft ${count}") + actionNextEvent(count > 1) + + } + + override fun onSwipeRight(count: Int) { + Blog.LOGD(log = "onSwipeRight ${count}") + actionPrevEvent(count > 1) + } + + override fun onSwipeUp(touchCount: Int) { + + } + + override fun onSwipeDown(touchCount: Int) { + if (touchCount == 2) { + if (binding.pagedLayer.isVisible) { + binding.pagedLayer.visibility = GONE + } + } + } + + override fun onTimeoverTouch() { + + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/bums/lunatic/launcher/tokiz/Perplexity.kt b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/Perplexity.kt new file mode 100644 index 00000000..f1dc5c21 --- /dev/null +++ b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/Perplexity.kt @@ -0,0 +1,185 @@ +package bums.lunatic.launcher.tokiz + +import android.content.DialogInterface +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.res.Configuration +import android.graphics.Bitmap +import android.graphics.Color +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.os.Message +import android.text.InputType +import android.text.SpannableStringBuilder +import android.text.style.RelativeSizeSpan +import android.util.Log +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.View.GONE +import android.view.View.OnTouchListener +import android.view.View.VISIBLE +import android.view.View.inflate +import android.view.ViewGroup +import android.webkit.WebView +import android.webkit.WebViewClient +import android.widget.ArrayAdapter +import android.widget.EditText +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.net.toUri +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime +import bums.lunatic.launcher.R +import bums.lunatic.launcher.tokiz.common.PairArray +import bums.lunatic.launcher.tokiz.common.TouchArea +import bums.lunatic.launcher.tokiz.common.colorz +import bums.lunatic.launcher.tokiz.common.getIndex +import bums.lunatic.launcher.tokiz.common.typesfacez +import bums.lunatic.launcher.tokiz.data.HistoryManager +import bums.lunatic.launcher.tokiz.data.model.ContentsPageInfo +import bums.lunatic.launcher.tokiz.data.model.ContentsCollection +import bums.lunatic.launcher.tokiz.data.model.PageInfosJ +import bums.lunatic.launcher.tokiz.data.model.HistoryItem +import bums.lunatic.launcher.tokiz.data.model.LastInfo +import bums.lunatic.launcher.tokiz.data.model.PortMessage +import bums.lunatic.launcher.tokiz.data.model.ReaderConfig +import bums.lunatic.launcher.tokiz.dialog.DefaultList +import bums.lunatic.launcher.tokiz.view.JxEvent +import bums.lunatic.launcher.tokiz.view.PagedTextLayout +import bums.lunatic.launcher.tokiz.view.PagedTextViewInterface +import bums.lunatic.launcher.databinding.BooktokiBinding +import bums.lunatic.launcher.utils.Blog +import com.google.gson.Gson +import io.realm.kotlin.Realm +import io.realm.kotlin.UpdatePolicy +import io.realm.kotlin.ext.copyFromRealm +import io.realm.kotlin.ext.query +import org.json.JSONException +import org.json.JSONObject +import org.mozilla.gecko.util.ThreadUtils +import org.mozilla.geckoview.GeckoResult +import org.mozilla.geckoview.GeckoSession +import org.mozilla.geckoview.MediaSession +import org.mozilla.geckoview.WebExtension +import org.mozilla.geckoview.WebExtension.MessageDelegate +import org.mozilla.geckoview.WebExtension.PortDelegate +import org.mozilla.geckoview.WebExtensionController.AddonManagerDelegate +import org.mozilla.geckoview.WebRequestError +import java.lang.System.currentTimeMillis +import java.text.SimpleDateFormat +import java.util.Date +import kotlin.collections.ArrayList +import kotlin.collections.List +import kotlin.collections.MutableList +import kotlin.collections.arrayListOf +import kotlin.collections.first +import kotlin.collections.isNotEmpty +import kotlin.collections.last +import kotlin.collections.sortBy +import kotlin.random.Random +import kotlin.text.contains +import kotlin.text.endsWith +import kotlin.text.equals +import kotlin.text.replace +import kotlin.text.split +import kotlin.text.startsWith +import kotlin.text.toInt +import kotlin.text.toRegex +import kotlin.text.trim + + +class Perplexity : BaseToki(), PagedTextViewInterface { +// "https://btsearch.love/ + override val contentsType = "perplexity" + override var lastNumber : Int = 143 + override val webcontentsName : String = "www.perplexity" + override val afterDot = "ai" + override fun getLastedDoamin(): String { + return String.format("https://%s.%s", webcontentsName, afterDot) + } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + super.onCreateView(inflater, container, savedInstanceState) + return binding.root + } + + override fun onStart() { + super.onStart() + } + + override fun onResume() { + super.onResume() + loadLastInfo() + } + + override fun onTouch(touchArea: TouchArea) { + Blog.LOGD(log = "onTouch ${touchArea}") + when (touchArea) { + TouchArea.Center -> { + + } + + TouchArea.Right -> { + actionNextEvent() + } + + TouchArea.Left -> { + actionPrevEvent() + } + + TouchArea.DoubleRight -> { + actionNextEvent(true) + } + + TouchArea.DoubleLeft -> { + actionPrevEvent(true) + } + else -> { + + } + } + + + } + + override fun onLongClick() { + Blog.LOGD(log = "onLongClick") + + } + + override fun onSwipeLeft(count: Int) { + Blog.LOGD(log = "onSwipeLeft ${count}") + actionNextEvent(count > 1) + + } + + override fun onSwipeRight(count: Int) { + Blog.LOGD(log = "onSwipeRight ${count}") + actionPrevEvent(count > 1) + } + + override fun onSwipeUp(touchCount: Int) { + + } + + override fun onSwipeDown(touchCount: Int) { + if (touchCount == 2) { + if (binding.pagedLayer.isVisible) { + binding.pagedLayer.visibility = GONE + } + } + } + + override fun onTimeoverTouch() { + + } +} \ No newline at end of file diff --git a/app/src/main/res/color/tabs_black.xml b/app/src/main/res/color/tabs_black.xml index 5642ec02..5505df03 100644 --- a/app/src/main/res/color/tabs_black.xml +++ b/app/src/main/res/color/tabs_black.xml @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/app/src/main/res/drawable/h_divider.xml b/app/src/main/res/drawable/h_divider.xml new file mode 100644 index 00000000..1ec7437d --- /dev/null +++ b/app/src/main/res/drawable/h_divider.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/bottom_sheet_search.xml b/app/src/main/res/layout/bottom_sheet_search.xml index 1d6589f6..d55b3d72 100644 --- a/app/src/main/res/layout/bottom_sheet_search.xml +++ b/app/src/main/res/layout/bottom_sheet_search.xml @@ -1,46 +1,57 @@ - - - - - + + + + - + diff --git a/app/src/main/res/layout/bottom_sheet_web.xml b/app/src/main/res/layout/bottom_sheet_web.xml new file mode 100644 index 00000000..5ba7760d --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_web.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/launcher_activity.xml b/app/src/main/res/layout/launcher_activity.xml index 0528f900..55cb16bb 100644 --- a/app/src/main/res/layout/launcher_activity.xml +++ b/app/src/main/res/layout/launcher_activity.xml @@ -59,6 +59,11 @@ android:id="@+id/comics" style="@style/tabItem" android:layout_height="match_parent"/> + -