"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const axios_1 = require("axios"); const fetchCookie = require("fetch-cookie"); const fs_1 = require("fs"); const mediawiki2_1 = require("mediawiki2"); const node_fetch_1 = require("node-fetch"); const playwright_1 = require("playwright"); const gifski_1 = require("./gifski"); const loggers_1 = require("./loggers"); const twitter_1 = require("./twitter"); const logger = (0, loggers_1.getLogger)('wiki'); const baseUrl = 'https://wiki.biligame.com/idolypride'; class default_1 { constructor(lock) { this.login = (sessdata) => playwright_1.firefox.launch().then(browser => { const jar = this.bot.cookieJar; return browser.newPage().then(page => page.context().addCookies([{ name: 'SESSDATA', value: sessdata, domain: '.biligame.com', path: '/', }]) .then(() => page.route('**/*.{png,jpg,jpeg,gif}', route => route.abort())) .then(() => page.route('*://*.baidu.com/**', route => route.abort())) .then(() => page.goto(`${baseUrl}/index.php?curid=2`, { waitUntil: 'networkidle' })) .then(() => { logger.info('logging in via browser...'); return page.context().cookies(); }) .then(cookies => { const uidIndex = cookies.findIndex(cookie => cookie.name === 'gamecenter_wiki_UserName'); if (!uidIndex) throw new Error('auth error'); return Promise.all(cookies.map(({ name, value, domain, path }) => jar.setCookie(`${name}=${value}; Domain=${domain}; Path=${path}`, baseUrl))).then(() => cookies[uidIndex].value); }) .then(uid => { logger.info(`finished logging in via browser, wiki username: ${uid}`); this.bot.fetch = fetchCookie(node_fetch_1.default, jar); return browser.close(); }) .catch((err) => browser.close().then(() => { logger.fatal(`error logging in via browser, error: ${err}`); process.exit(0); }))); }); this.fetchMedia = (url) => new Promise((resolve, reject) => { logger.info(`fetching ${url}`); const fetch = () => (0, axios_1.default)({ method: 'get', url, responseType: 'arraybuffer', timeout: 150000, }).then(res => { if (res.status === 200) { logger.info(`successfully fetched ${url}`); resolve(res.data); } else { logger.error(`failed to fetch ${url}: ${res.status}`); reject(); } }).catch(err => { logger.error(`failed to fetch ${url}: ${err instanceof Error ? err.message : err}`); logger.info(`trying to fetch ${url} again...`); fetch(); }); fetch(); }).then(data => { var _a; return (([_, filename, ext]) => { if (ext) { const mediaFileName = `${filename}.${ext}`; (0, fs_1.writeFileSync)(mediaFileName, Buffer.from(data)); return (ext === 'mp4' ? (0, gifski_1.default)(mediaFileName, 320) : Promise.resolve(mediaFileName)); } logger.warn('unable to find MIME type of fetched media, failing this fetch'); throw Error(); })((_a = /([^/]*)\?format=([a-z]+)&/.exec(url)) !== null && _a !== void 0 ? _a : /.*\/([^/]*)\.([^?]+)/.exec(url)); }); this.uploadMediaItems = (tweet, fileNamePrefix, indexOffset = 0) => { const mediaItems = []; if (tweet.extended_entities) { tweet.extended_entities.media.forEach((media, index) => { let url; if (media.type === 'photo') { url = media.media_url_https.replace(/\.([a-z]+)$/, '?format=$1') + '&name=orig'; } else { url = media.video_info.variants .filter(variant => variant.bitrate !== undefined) .sort((var1, var2) => var2.bitrate - var1.bitrate) .map(variant => variant.url)[0]; } const mediaPromise = this.fetchMedia(url) .then(mediaFileName => { const filename = `${fileNamePrefix}${indexOffset + index + 1}.${mediaFileName.split('.')[1]}`; logger.info(`uploading ${mediaFileName} as ${filename}...`); return this.bot.simpleUpload({ file: mediaFileName, filename, }) .then(() => filename) .catch(error => { if (error instanceof mediawiki2_1.WikiError && error.data.result === 'Warning') { const { duplicate } = error.data.warnings; if (duplicate) return duplicate[0]; } else throw error; }); }); mediaItems.push(mediaPromise); }); } return Promise.all(mediaItems); }; this.appendMedia = (tweet, genre, indexOffset) => { const { pageTitle } = (0, twitter_1.processTweetBody)(tweet); const pageLongTitle = `公告/${pageTitle}`; const mediaFilePrefix = `公告-${genre}-${pageTitle}-`; return this.uploadMediaItems(tweet, mediaFilePrefix, indexOffset) .then(fileNames => { logger.info(`updating page ${pageLongTitle}...`); return this.bot.edit({ title: pageLongTitle, appendtext: `${fileNames.map(fileName => `[[文件:${fileName}|无框|左]]\n`).join('')}`, bot: true, notminor: true, nocreate: true, }) .then(({ new: isNewPost, newtimestamp, pageid, result, title }) => ({ pageid, title, new: isNewPost, mediafiles: fileNames, result, timestamp: new Date(newtimestamp).toString(), })); }) .catch(error => { logger.error(`error updating page, error: ${error}`); return { pageid: undefined, title: pageLongTitle, new: undefined, mediafiles: [], result: 'Failed', timestamp: undefined, }; }); }; this.post = (tweet, genre) => { const { title, body, pageTitle, date } = (0, twitter_1.processTweetBody)(tweet); const pageLongTitle = `公告/${pageTitle}`; const mediaFilePrefix = `公告-${genre}-${pageTitle}-`; const sameTitleAction = this.lock.lastActions.find(action => action.title === pageLongTitle); if (sameTitleAction) return this.appendMedia(tweet, genre, sameTitleAction.mediafiles.length); return this.uploadMediaItems(tweet, mediaFilePrefix) .then(fileNames => { logger.info(`creating page ${pageLongTitle}`); return this.bot.edit({ title: pageLongTitle, basetimestamp: new Date(), text: `{{文章戳 |文章上级页面=公告 |子类别=${genre} |时间=${date} |作者=IDOLY PRIDE |是否原创=否 |来源=[https://twitter.com/idolypride IDOLY PRIDE] |原文地址=[https://twitter.com/idolypride/status/${tweet.id_str} ${pageTitle}] }} ====${title.replace('\n', '
')}==== ${body} ${fileNames.map(fileName => `[[文件:${fileName}|无框|左]]`).join('\n')} `, bot: true, notminor: true, createonly: true, }) .then(({ new: isNewPost, newtimestamp, pageid, result, title }) => ({ pageid, title, new: isNewPost, mediafiles: fileNames, result, timestamp: new Date(newtimestamp).toString(), })); }) .catch(error => { logger.error(`error creating page, error: ${error}`); return { pageid: undefined, title: pageLongTitle, new: undefined, mediafiles: [], result: 'Failed', timestamp: undefined, }; }); }; this.bot = new mediawiki2_1.MWBot(`${baseUrl}/api.php`); this.lock = lock; const updateCsrfToken = this.bot.updateCsrfToken.bind(this.bot); this.bot.updateCsrfToken = (function () { setTimeout(() => { this.lastCsrfToken = undefined; }, 7200000); return updateCsrfToken(); }).bind(this.bot); } } exports.default = default_1;