Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Kakao Saver
- // @namespace http://tampermonkey.net/
- // @version 2025-03-25
- // @description try to take over the world!
- // @author You
- // @match https://page.kakao.com/content/*/viewer/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=kakao.com
- // @grant none
- // ==/UserScript==
- (function () {
- 'use strict';
- async function delay(ms) {
- return new Promise(resolve => setTimeout(resolve, ms))
- }
- function is_cover() {
- let root = [...document.querySelectorAll('div')].filter(x => x.shadowRoot)
- if (root.length === 0) return null
- let cover = root[0].shadowRoot.firstChild.querySelector('div.cover')
- if (!cover) return false
- return true
- }
- function get_next_btn() {
- let next_btn_arr = [...document.querySelectorAll('div.cursor-pointer')].filter(x => x.firstChild.alt === "다음")
- if (next_btn_arr.length === 0) return null
- return next_btn_arr[0]
- }
- function get_next_chapter_btn() {
- return document.querySelector('div[data-test="viewer-navbar-next-button"]')
- }
- function get_paragraphs() {
- let root = [...document.querySelectorAll('div')].filter(x => x.shadowRoot)
- if (root.length === 0) return null
- let paragraphs = [...root[0].shadowRoot.firstChild.getElementsByTagName('p')]
- if (paragraphs.length === 0) return null
- return paragraphs
- }
- function allow_copy() {
- let root = [...document.querySelectorAll('div')].filter(x => x.shadowRoot)
- if (root.length === 0) return null
- root[0].shadowRoot.firstChild.style.userSelect = 'text'
- }
- function get_book_chapter() {
- let path_arr = window.location.href.split('/')
- let chapter = path_arr.pop()
- path_arr.pop()
- let book = path_arr.pop()
- return [book, chapter]
- }
- function save_paragraphs(paragraphs) {
- let [book, chapter] = get_book_chapter()
- let storage = localStorage.getItem(`kakao_saver_${book}`) || '{}'
- storage = JSON.parse(storage)
- storage[chapter] = paragraphs.map(x => x.textContent).join('\n')
- localStorage.setItem(`kakao_saver_${book}`, JSON.stringify(storage))
- console.log(`saved ${paragraphs.length} paragraphs for ${chapter} chapter`)
- }
- function save() {
- let [book, _] = get_book_chapter()
- let storage = localStorage.getItem(`kakao_saver_${book}`) || '{}'
- storage = JSON.parse(storage)
- let sorted_pairs = Object.entries(storage).sort(([, a], [, b]) => Number(b) - Number(a))
- if (sorted_pairs.length === 0) {
- console.log("nothing to print, no chapters")
- return
- }
- let chapters = []
- let chapter_rel_number = 1
- for (let [chapter_abs_number, chapter] of sorted_pairs) {
- chapters.push(`Глава ${chapter_rel_number} | ${chapter_abs_number}\n\n`)
- chapters.push(chapter)
- chapters.push("\n\n=======================\n\n")
- chapter_rel_number++;
- }
- save_to_file(chapters, book, sorted_pairs.length)
- console.log(`printed ${sorted_pairs.length} chapters`)
- console.log(`first started with ${sorted_pairs[0][1].substring(0, 10)}`)
- console.log(`last ended with ${sorted_pairs[sorted_pairs.length - 1][1].slice(-10, -1)}`)
- }
- function save_to_file(str_arr, book, length) {
- const blob = new Blob(str_arr, { type: 'text/plain;charset=utf-8' });
- const link = document.createElement('a');
- link.href = URL.createObjectURL(blob);
- link.download = `kakao-${book}_book-${length}_chapters-${Date.now()}.txt`;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- }
- let states = {
- cover: "cover",
- text: "text",
- next: "next",
- }
- async function auto() {
- window.navigation.removeEventListener("navigate", run)
- let state = states.cover
- let start = Date.now()
- let last_change = Date.now()
- const max_wait_sec = 30
- while (true) {
- switch (state) {
- case states.cover:
- if (!is_cover()) break
- let btn = get_next_btn()
- if (!btn) break
- btn.click()
- state = states.text
- last_change = Date.now()
- break;
- case states.text:
- if (is_cover()) {
- state = states.cover
- break
- }
- let paragraphs = get_paragraphs()
- if (!paragraphs) break
- save_paragraphs(paragraphs)
- state = states.next
- last_change = Date.now()
- break;
- case states.next:
- let next_chapter_btn = get_next_chapter_btn()
- if (!next_chapter_btn) break
- next_chapter_btn.click()
- state = states.cover
- last_change = Date.now()
- break;
- }
- await delay(200)
- if (Date.now() - last_change > max_wait_sec * 1000)
- break
- }
- let total_sec = Math.ceil((Date.now() - start) / 1000) - max_wait_sec
- console.log(`loaded in ${total_sec} sec`)
- }
- async function run() {
- await delay(2000) // avoid save prev. chapter data
- let paragraphs;
- while (!paragraphs || is_cover()) {
- paragraphs = get_paragraphs()
- await delay(200)
- }
- save_paragraphs(paragraphs)
- allow_copy()
- }
- run()
- window.navigation.addEventListener("navigate", run)
- // ручное управление
- Object.assign(window, {
- kk_save: save,
- kk_auto: auto,
- });
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement