Greasy Fork

ficUpdate

bulk copy-paste all the chapters from Word on ficbook

当前为 2018-08-07 提交的版本,查看 最新版本

// ==UserScript==
// @name         ficUpdate
// @namespace    ficscript
// @version      2.1
// @description  bulk copy-paste all the chapters from Word on ficbook
// @author       Dimava
// @match        https://ficbook.net/home/myfics/*
// @grant        none
// ==/UserScript==
 
if (!/\/home\/myfics\/\d+.?$/.test(location.href))
    throw Error('Для групповой загрузки перейдите на страницу редактирования фанфика!');
 
q('.edi') && q('.edi').remove();
 
var ops = document.querySelector('.myfic');
var b1 = elm('button', 'Подготовить');
b1.onclick = prepare;
var b2 = elm('button', 'Добавить отсутствующие');
b2.onclick = addNewParts;
var b3 = elm('button', 'Обновить');
b3.onclick = updateParts;
var cb = document.createElement('input');
cb.type = 'checkbox';
cb.checked = true;
var l = elm('label', '   ', cb, ' Черновик');
var notPublishedCheckbox = cb;
var text = elm('div');
text.contentEditable = true;
text.style.cssText = 'background:white;border:1px dotted gray; width:49.5%; float:left;';
var text2 = elm('div');
text2.style.cssText = 'background:hsl(0,0%,95%);border:1px dotted gray; width:49.5%; float:right;';
ops.append(elm('div.edi', elm('div', b1, b2, b3, l), elm('br'), elm('div', text, text2)));
 
var parts, prepared;
 
//text.innerHTML = localStorage.temp;
 
function prepare() {
    let t = text.innerHTML;
    if (!t.match(/<h1/))
        return warn('В тексте нет заголовков!');
    let t2 = t.replace(/<(?!\/?(h1|br|p|b|s|i|center|right)[\s|>])[^>]*>/g, '');
    // remove bad tags
    let t3 = t2.replace(/<(\/?)(h1|br|b|s|i|center|right)(?=[\s|>])[^>]*>/g, '<$1$2>');
    // remove attributes
    parts = t3.split(/<h1[^>]*>/).map(e=>e.split('</h1>')).slice(1).map(e=>({
        name: htext(e[0]).replace(/\s+/g, ' ').trim(),
        text: tabber(e[1]),
    }))
    text2.innerHTML = [].concat(...parts.map(p=>['<br><br><h1>', p.name, '</h1><br>', p.text.replace(/\n/g, '<br>')])).join('\n');
    prepared = true;
}
async function addPart(part) {
 
    let f = elm('iframe');
    ops.prepend(f)
 
    let res;
    let p = new Promise(r=>res = r);
    f.addEventListener('load', res);
    f.addEventListener('load', (res=>console.log('loaded')));
 
    f.src = q('.add-part a').href
 
    f.style.cssText = 'height:200px;width:100%'
 
    await p;
 
    let d = f.contentWindow.document;
    q('[name=title]', d).value = part.name;
    q('#content', d).value = part.text;
    q('#not_published_chb', d).checked = notPublishedCheckbox.checked;
 
    p = new Promise(r=>res = r);
    f.addEventListener('load', res);
    f.addEventListener('load', (res=>console.log('loaded')));
    q('#savePartForm [type=submit]', d).click();
    await p;
 
    f.remove()
    done('Часть добвлена', part.name);
 
}
async function updatePart(part) {
 
    let f = elm('iframe');
    ops.prepend(f)
 
    let res;
    let p = new Promise(r=>res = r);
    f.addEventListener('load', res);
    f.addEventListener('load', (res=>console.log('loaded')));
 
    let tts = partAdded(part);
    if (!tts) {
        return err('Часть ещё не добавлена!', part.name)
    }
    f.src = tts.href;
 
    f.style.cssText = 'height:200px;width:100%'
 
    await p;
 
    let d = f.contentWindow.document;
    let changed = false;
 
    if (q('[name=title]', d).value == part.name && q('#content', d).value == part.text) {
        info('Часть не изменилась', part.name);
        f.remove();
        return;
    }
 
    q('[name=title]', d).value = part.name;
    q('#content', d).value = part.text;
 
    p = new Promise(r=>res = r);
    f.addEventListener('load', res);
    f.addEventListener('load', (res=>console.log('loaded')));
    q('#savePartForm [type=submit]', d).click();
    await p;
 
    f.remove();
    done('Часть изменена', part.name);
}
 
function htext(h) {
    let a = document.createElement('a');
    a.innerHTML = h;
    return a.innerText;
}
 
function elm(sel, ...childs) {
    let el = document.createElement(sel.match(/^[a-zA-Z\-_]+/)[0]);
    (sel.match(/\.[a-zA-Z\-_]+/) || []).forEach(c=>el.classList.add(c.replace(/\./, '')));
    if (childs.length)
        el.append(...childs);
    return el;
}
 
function tabber(s) {
    let hTexts = {};
 
    function hText(s) {
        if (hTexts[s])
            return hTexts[s];
        let a = document.createElement('a');
        a.innerHTML = s;
        return hTexts[s] = a.innerText;
    }
    const nbsp = '\xa0';
    //hText('&nbsp;');
    const emsp = '\u2003';
    //hText('&emsp;');
    const ndash = '\u2013';
    //hText('&ndash;');
    const replacers = [[/\n/g, ' '], [/^\s+|\s+$/gm, '\n\n\n'], [/&[^;]{2,7};/g, hText], [/<br>|<.div><div[^>]*>|<.div>|<div[^>]*>/g, '\n'], [/<p[^>]*(center|right)[^>]*>([^]*?)<\/p>/g, '\n<$1>\n$2\n</$1>\n'], [/<\/p>\s*<p[^>]*>/g, '\n'], [/<\/p>\s*|\s*<p[^>]*>/g, '\n'], [/<script>[^]*?<.script>/, ''], [/\s*\n{4,}/g, '\n\n\n'], [/(\s*)(<(b|i|s)>)/g, '$2$1'], [/(^|[^\.])(…|\.{2,4}(?!\.))(?!\n\s)? /gm, '$1… '], [/(–|—|―)/gm, ' - '], [/--?(?![\-\wа-яёА-ЯЁ])|([^\-\wа-яёА-ЯЁ])-(?![\->\w])/g, `$1 - `], [/^((?=.)\s)*/gm, emsp + emsp], [/((?!\n)\s)+-\s+/gm, ' ' + ndash + nbsp], [/^\s*–/gm, emsp + nbsp + ndash], [/\n<center>\n([^]*?)\n<\/center>\n/g, s=>s.replace(/^\s*/gm, '')], [/\n<right>\n([^]*?)\n<\/right>\n/g, s=>s.replace(/^\s*/gm, '')], [/\s*<center>\s*([*][\s*]*[*])\s*<\/center>\n*|\n+\s*([*][\s*]*[*])\s*\n+/g, '\n\n\n<center>\n$1$2\n</center>\n\n'], [/\n(<.?(center|right)>)\n/g, '$1'], [/(<(b|i|s)>)(\s*)/g, '$3$1'], [/<(?!\/?(b|i|s|center|right))/g, '&lt;'], [/^\s*\n|\n\s*$/g, '']];
    replacers.forEach(rpl=>{
        s = s.replace(rpl[0], rpl[1]);
    }
    );
    return s;
}
function partAdded(part) {
    return qq('.part .title a').find(e=>e.innerText.replace(/\s/g, '') == part.name.replace(/\s/g, ''));
}
 
function q(a, b=document) {
    return b.querySelector(a);
}
function qq(a, b=document) {
    return [...b.querySelectorAll(a)];
}
 
function done(...a) {
    console.log(...a),
    toastr.success(...a);
    return a[0];
}
function info(...a) {
    console.log(...a),
    toastr.info(...a);
    return a[0];
}
function warn(...a) {
    console.warn(...a),
    toastr.warning(...a);
    return a[0];
}
function err(...a) {
    console.error(...a),
    toastr.error(...a);
    return a[0];
}
 
async function addNewParts() {
    parts || prepare();
    let toAdd = parts.filter(p=>!partAdded(p));
    for (let i = 0; i < toAdd.length; i++) {
        await addPart(toAdd[i]);
    }
    info('Все части добавлены')
}
 
async function updateParts() {
    parts || prepare();
    let toUpd = parts.filter(partAdded);
    for (let i = 0; i < toUpd.length; i++) {
        await updatePart(toUpd[i]);
    }
    info('Все части обновлены')
}