// ==UserScript== // @name ficUpdate // @namespace ficscript // @version 2.3.4 // @description bulk copy-paste all the chapters from Word on ficbook // @author Dimava // @match https://ficbook.net/home/myfics/* // @grant none // @downloadURL none // ==/UserScript== var DEBUG = localStorage.ficUpdateDEBUG; if (!/\/home\/myfics\/\d+.?$/.test(location.href)) throw new Error('Для групповой загрузки перейдите на страницу редактирования фанфика!'); q('.edi') && q('.edi').remove(); var ops = document.querySelector('.myfic'); var b1 = elm('button', 'Подготовить'); b1.onclick = function() { try { prepare(); } catch (e) { err(e); } } ; 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.id = 'text'; 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; if (DEBUG) text.innerHTML = localStorage.temp; function prepare() { t = text.innerHTML; t1 = t; refs = {}; t = t.replace(/]*name="_ftn[^]*?a>/g, s=>{ refm = s.match(/_ftn(ref)?(\d+)/); refn = +refm[2]; if (refm[1]) { refs[refn] = { n: refn, t: tosupnum(refn), }; } return refm[1] ? '' : tosupnum(refn); } ); t2 = t; t = t.replace(/
/g, (s,n)=>{ refs[n].s = htext(s).trim(); return ''; } ); t3 = t; text2.innerHTML = t; if (!t.match(/

])[^>]*>/g, ''); t4 = t; // remove bad tags t = t.replace(/<(\/?)(h1|br|b|s|i|center|right)(?=[\s|>])[^>]*>/g, '<$1$2>'); t5 = t; // remove attributes parts = t.split(/]*>/).map(e=>e.split('

')).slice(1).map(e=>{ let name = htext(e[0]).replace(/\s+/g, ' ').trim() , text = tabber(e[1]); o = { name, text, com: '', comp: true, refs: [], }; text = text.replace(/\s*\/\*\s*([^]*?)\s*\*\/\s*/, (s,a,i,t)=>{ o.com = a; o.comp = i > 100; return ''; } ); let supi = 1; text = text.replace(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/g, (s,i,t)=>{ let n = fromsupnum(s); let ref = refs[n]; ref.n = supi; ref.t = tosupnum(supi); o.refs.push(ref); supi++; return ref.t; } ); o.text = text; return o; } ) text2.innerHTML = [].concat(...parts.map(p=>['

', p.name, '


', ((()=>{let t=p.text.replace(/\n/g, '\n
');if (!p.com&&!p.refs.length)return t;let com=p.com;let ref=p.refs.map(r=>r.t+htext(' ')+r.s).join('\n
');let brc=com&&ref?'

':'';return p.comp?t+'

'+ref+brc+com+'':''+com+brc+ref+'

'+t;})())])).join('\n'); prepared = true; return parts; } function tosupnum(t) { num = '⁰¹²³⁴⁵⁶⁷⁸⁹'.split(''); return (t + '').match(/\d/g).map(e=>num[e]).join(''); } function fromsupnum(t) { num = '⁰¹²³⁴⁵⁶⁷⁸⁹'.split(''); return +(t + '').match(/[⁰¹²³⁴⁵⁶⁷⁸⁹]/g).map(e=>num.indexOf(e)).join(''); } 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; q('[name=comment_direction', d).value = part.comp ? 0 : 1; let brc = part.com && part.ref.length ? '\n\n' : ''; let ref = part.refs.map(r=>r.t + htext(' ') + r.s).join('\n'); let com = part.comp ? ref + brc + part.com : part.com + brc + ref; q('[name=comment]', d).value = com; 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 unchanged = true; let brc = part.com && part.refs.length ? '\n\n' : ''; let ref = part.refs.map(r=>r.t + htext(' ') + r.s).join('\n'); let com = part.comp ? ref + brc + part.com : part.com + brc + ref; unchanged = unchanged && q('[name=title]', d).value == part.name; unchanged = unchanged && q('#content', d).value == part.text; unchanged = unchanged && q('[name=comment_direction', d).value == (part.comp ? '0' : '1'); unchanged = unchanged && q('[name=comment]', d).value == com; if (unchanged) { info('Часть не изменилась', part.name); f.remove(); return; } q('[name=title]', d).value = part.name; q('#content', d).value = part.text; q('[name=comment_direction', d).value = part.comp ? 0 : 1; q('[name=comment]', d).value = com; 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(' '); const emsp = '\u2003'; //hText(' '); const ndash = '\u2013'; //hText('–'); const replacers = [[/\n/g, ' '], [/^\s+|\s+$/gm, '\n\n\n'], [/&[^;]{2,7};/g, hText], [/
|<.div>]*>|<.div>|]*>/g, '\n'], [/]*(center|right)[^>]*>([^]*?)<\/p>/g, '\n<$1>\n$2\n\n'], [/<\/p>\s*]*>/g, '\n'], [/<\/p>\s*|\s*]*>/g, '\n'], [/