Last active
September 15, 2022 16:19
-
-
Save luiseok/c22c7a67c2311fa8d19c2268667df8e7 to your computer and use it in GitHub Desktop.
Scriptable-Dogdripnet-notification
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Variables used by Scriptable. | |
// These must be at the very top of the file. Do not edit. | |
// icon-color: deep-gray; icon-glyph: bone; | |
/** | |
* @author 어그로학교수 | |
* released at 2022.09.15 | |
* use as your own risk | |
*/ | |
const CONSTANTS = { | |
LOG_LEVEL: 'debug', | |
USER_AGENT: 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/105.0.5195.100 Mobile/15E148 Safari/604.1', | |
BASE_DOGDRIP_HOST: 'https://dogdrip.net', | |
ALERT_CHOICES: { | |
CANCEL: -1, | |
GO_SETTINGS: 0, | |
SET_COOKIES: 1 | |
} | |
} | |
const unreadCount = await main() | |
if (config.runsInWidget) { | |
let widget = dogdripWidget(unreadCount) | |
Script.setWidget(widget) | |
widget.presentSmall() | |
} | |
Script.complete() | |
function getRandomInt(min, max) { | |
min = Math.ceil(min); | |
max = Math.floor(max); | |
return Math.floor(Math.random() * (max - min + 1)) + min; | |
} | |
function dogdripWidget(count) { | |
let w = new ListWidget() | |
w.setPadding(10, 10, 10, 10) | |
let nextRefresh = Date.now() + 1000 * getRandomInt(60 * 5, 60 * 5 * 5) // Tries between 5 mins and 25mins | |
w.refreshAfterDate = new Date(nextRefresh) | |
let myGradient = new LinearGradient() | |
w.backgroundColor = new Color("#2e4361") | |
myGradient.colors = [new Color('#44444466'), new Color('#88888855'), new Color("#66666655")] | |
myGradient.locations = [0, 0.8, 1] | |
w.backgroundGradient = myGradient | |
let title = w.addText("Dogdrip") | |
title.textColor = Color.white() | |
title.font = Font.largeTitle() | |
if (count >= 0) { | |
let content = w.addText(`${count}개의 읽지않은 알림이 있습니다.`) | |
content.textColor = Color.white() | |
content.font = Font.headline() | |
} else { | |
let warning = w.addText(`아직 로그인 하지 않았습니다.`) | |
warning.textColor = Color.red() | |
warning.font = Font.headline() | |
let guide = w.addText('여기를 눌러 로그인 해주세요') | |
guide.textColor = Color.white() | |
guide.font = Font.regularSystemFont(10) | |
} | |
return w | |
} | |
function log(msg) { | |
if (config.runsInApp) { | |
console.log(msg); | |
} | |
let oldData = '' | |
let logManager = FileManager.iCloud() | |
const logPath = logManager.joinPath(logManager.documentsDirectory(), `${Script.name()}.txt`) | |
if (logManager.fileExists(logPath)) { | |
oldData = logManager.readString(logPath) + "\n" | |
} | |
let time = new Date() | |
oldData += `[${time.toISOString()}] ${Script.name()} : ${msg}` | |
logManager.writeString(logPath, oldData) | |
return time.toLocaleTimeString() | |
} | |
function sendNotification({ | |
title, | |
from, | |
comment, | |
link, | |
subtitle, | |
groupId | |
}) { | |
let n = new Notification() | |
n.title = title | |
n.subtitle = subtitle | |
n.body = `[${from}] ${comment}` | |
n.openURL = link | |
if (groupId) n.threadIdentifier = groupId | |
n.schedule() | |
} | |
/* | |
Cookie Handling | |
*/ | |
function resetCookie() { | |
Keychain.set(`${Script.name().toLowerCase()}-cookie`, "") | |
} | |
function setCookie(response) { | |
const next = response.cookies?.filter(({ | |
name | |
}) => name.includes('rx_') || name.includes('PHPSESSID')) | |
.map(({ | |
name, | |
value | |
}) => `${name}=${value}`)?.join("; ") ?? ''; | |
log(next) | |
if (CONSTANTS.LOG_LEVEL === 'info') console.log(`setting new cookie with ${next}`) | |
if (next) { | |
Keychain.set(`${Script.name().toLowerCase()}-cookie`, next) | |
} | |
} | |
function getCookie() { | |
return Keychain.contains(`${Script.name().toLowerCase()}-cookie`) ? Keychain.get(`${Script.name().toLowerCase()}-cookie`) : "" | |
} | |
/** | |
* Dogdrip | |
*/ | |
async function getLatestNotification() { | |
log(`Attempting getLatestNotification`) | |
if (CONSTANTS.LOG_LEVEL === 'info') log(`cookie: ${getCookie()}`) | |
const pageReq = new Request("https://www.dogdrip.net/index.php?mid=intro&act=dispNcenterliteNotifyList"); | |
pageReq.headers = { | |
'Cookie': getCookie(), | |
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/105.0.5195.100 Mobile/15E148 Safari/604.1' | |
} | |
// Slower way, but reliable. | |
const wv = new WebView(); | |
await wv.loadRequest(pageReq); | |
// Faster way, but not reliable. | |
// const result = await pageReq.loadString(); | |
// await wv.loadHTML(result); | |
try { | |
const isloggedOut = await wv.evaluateJavaScript(`document.body.contains(document.getElementById("access"))`) | |
log(`isLogout: ${isloggedOut}`) | |
if (isloggedOut) { | |
const msg = '쿠키가 올바르지 않거나 로그인이 해제되었습니다. 다시 쿠키를 설정해주세요.'; | |
if (config.runsInApp) { | |
const alert = new Alert(); | |
alert.title = '오류 발생'; | |
alert.message = msg | |
alert.addCancelAction("종료"); | |
const canceled = await alert.presentAlert() === -1; | |
if (canceled) resetCookie(); | |
Script.complete(); | |
return [ | |
[], 0 | |
]; | |
} | |
sendNotification({ | |
title: "개드립 새 댓글 알림", | |
subtitle: "오류 발생", | |
from: "시스템", | |
link: "https://www.dogdrip.net/computer/432206629#user_content_help-how-to", | |
comment: msg | |
}) | |
Script.complete(); | |
return [ | |
[], 0 | |
]; | |
} | |
// Server does not response well as you think. | |
// this can broke authenticated user | |
// else { | |
// setCookie(pageReq.response); | |
// } | |
} catch (error) { | |
log(error) | |
} | |
try { | |
const getNotiData = await wv.evaluateJavaScript(` | |
const href = Array.from(document.querySelectorAll("tbody > tr td a")??[]).map(a=>a.href); | |
const writer = Array.from(document.querySelectorAll("tbody > tr td a strong:first-of-type")??[]).map(w=>w.innerText); | |
const comment = Array.from(document.querySelectorAll("tbody > tr td a strong:last-of-type")??[]).map(c=>c.innerText); | |
const time = Array.from(document.querySelectorAll("tbody > tr td:last-of-type")??[]).map(nt=>(new Date(nt.innerText.replaceAll('\\n', '')))); | |
const result = href.map((link, index) => { | |
const fullUrl = new URL(link); | |
const commentId = fullUrl.searchParams.get("comment_srl") ?? null; | |
return { | |
href: link, | |
writer: writer[index], | |
comment: comment[index], | |
time: time[index], | |
commentId | |
} | |
}).sort((a, b) => a.time - b.time); | |
result; | |
`); | |
const getNotiCount = wv.evaluateJavaScript(`document.querySelector(".eq.badge.badge-primary.count")?.innerText`); | |
return Promise.all([getNotiData, getNotiCount]) | |
} catch (error) { | |
log(error) | |
} | |
} | |
/** | |
* Send Notification | |
*/ | |
function handleNewComments(comments = []) { | |
const now = new Date() | |
const uid = UUID.string() | |
for (const comment of comments) { | |
const createdAt = new Date(comment.time) | |
const timeDiff = Math.floor((now.getTime() - createdAt.getTime()) / 1000) | |
sendNotification({ | |
title: '개드립 새 댓글 알림', | |
from: comment.writer, | |
subtitle: `${timeDiff}초 전`, | |
comment: comment.comment, | |
link: comment.href, | |
groupId: comments.length > 1 ? uid : null | |
}) | |
} | |
} | |
async function checkCookieExists() { | |
if (config.runsInApp && !getCookie()) { | |
const alert = new Alert(); | |
alert.title = '초기 설정 필요'; | |
alert.message = '개드립 글을 참고하여 쿠키값을 세팅해주세요.'; | |
alert.addAction("설정 방법 보기"); | |
alert.addAction("쿠키값 붙여넣기"); | |
alert.addCancelAction("종료"); | |
const select = await alert.presentAlert(); | |
switch (select) { | |
case CONSTANTS.ALERT_CHOICES.GO_SETTINGS: { | |
await Safari.openInApp("https://www.dogdrip.net/computer/432206629#user_content_help-how-to"); | |
break; | |
} | |
case CONSTANTS.ALERT_CHOICES.SET_COOKIES: { | |
const prompt = new Alert(); | |
prompt.title = '쿠키값 설정'; | |
prompt.message = '가이드를 통해 확인하신 쿠키 String을 붙여넣으세요'; | |
prompt.addSecureTextField("rx_autologin=....;rx_sesskey1=....;rx_sesskey2=....;", ""); | |
prompt.addAction("확인"); | |
prompt.addCancelAction("취소"); | |
await prompt.presentAlert(); | |
const cookieInput = prompt.textFieldValue(0); | |
const VALID_COOKIE_KEYS = ['rx_autologin', 'rx_sesskey1', 'rx_sesskey2']; | |
const IS_VALID = VALID_COOKIE_KEYS.filter(k => cookieInput.includes(k)).length === VALID_COOKIE_KEYS.length; | |
if (!cookieInput || !IS_VALID) { | |
const a = new Alert(); | |
a.title = '오류'; | |
a.message = IS_VALID ? '쿠키가 입력되지 않았습니다. 다시 확인해주세요' : '"로그인 상태 유지" 옵션이 포함되지 않은 쿠키입니다. 로그인 상태 유지 옵션을 눌러 로그인 한 후, 다시 시도해주세요.'; | |
a.addCancelAction('닫기') | |
await a.presentAlert(); | |
break; | |
} | |
Keychain.set(`${Script.name().toLowerCase()}-cookie`, prompt.textFieldValue(0)) | |
} | |
case CONSTANTS.ALERT_CHOICES.CANCEL: { | |
break; | |
} | |
} | |
if (CONSTANTS.LOG_LEVEL === 'debug') log('not logged in!') | |
return false; | |
} | |
return true | |
} | |
async function main() { | |
const loggedIn = await checkCookieExists(); | |
if (!loggedIn) { | |
return -1 | |
} | |
try { | |
const [notificationData, unreadCount] = await getLatestNotification(); | |
if (Array.isArray(notificationData) && notificationData.length > 0) { | |
let oldData = ''; | |
let newComments = []; | |
const fileManager = FileManager.iCloud(); | |
const dbFile = fileManager.joinPath(fileManager.documentsDirectory(), `dogdripCommentDB.txt`); | |
if (fileManager.fileExists(dbFile)) { | |
await fileManager.downloadFileFromiCloud(dbFile) | |
let commentHistory = fileManager.readString(dbFile).split(',').filter(s => s); | |
newComments = notificationData.filter(n => { | |
return !commentHistory.includes(n.commentId) | |
}) | |
oldData = commentHistory.join(",") | |
if (newComments.length > 0) { | |
fileManager.writeString(dbFile, `${oldData},${newComments.map(n=>n.commentId).join(",")}`) | |
} | |
} else { | |
newComments = notificationData | |
fileManager.writeString(dbFile, newComments.map(n => n.commentId).join(",")) | |
} | |
log(`Found ${newComments.length}`) | |
log(`UnreadCount: ${unreadCount ?? 0}`) | |
handleNewComments(newComments) | |
return unreadCount ?? 0 | |
} | |
} catch (error) { | |
log(error) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment