├── LICENSE ├── README.md └── back2stackoverflow.user.js /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Back2stackoverflow 2 | 3 | Userscript for redirect to stackoverflow.com from machine-translated sites. 4 | 5 | [Click to install](https://raw.githubusercontent.com/Taraflex/Back2stackoverflow/master/back2stackoverflow.user.js) 6 | 7 | Required [Tampermonkey](https://tampermonkey.net/) or [Greasemonkey](https://www.greasespot.net/) or [Violentmonkey](https://violentmonkey.github.io/get-it/) or another browser extension for userscript support. 8 | 9 | Supported sites: 10 | - ~~qaru.site~~ (closed?) 11 | - fooobar.com 12 | - askdev.info 13 | - ubuntugeeks.com 14 | - programmerz.ru 15 | - ~~4answered.com~~ (closed?) 16 | - code.i-harness.com 17 | - code-examples.net 18 | - quabr.com 19 | - ~~qna.one~~ (closed?) 20 | - stackovernet.com 21 | - stackoverrun.com 22 | - qa-help.ru 23 | - exceptionshub.com 24 | - answeright.com 25 | - kotaeta.com 26 | - ciupacabra.com 27 | - de-vraag.com 28 | - switch-case.ru 29 | - *.switch-case.com 30 | - bildiredi.com 31 | - donolik.com 32 | - pytannie.com 33 | - sozdizimi.com 34 | - zapytay.com 35 | - answer-id.com 36 | - while-do.com 37 | - 365airsoft.com 38 | - codeday.me 39 | - issue.life 40 | - *.coredump.biz 41 | - code-adviser.com 42 | - ask-ubuntu.ru 43 | - stackru.com 44 | - xbuba.com 45 | - web-answers.ru 46 | - sprosi.pro 47 | - askvoprosy.com 48 | - stackanswers.net 49 | - codengineering.ru 50 | - overcoder.net 51 | - coderquestion.ru 52 | - qacode.ru 53 | - progaide.com 54 | - stackz.ru/en 55 | - stackz.ru/ru 56 | - it-swarm.(net|dev|asia|xyz) 57 | - bonprog.com 58 | - bestecode.com 59 | - progexact.com 60 | - rstopup.com 61 | - profikoder.com 62 | - itranslater.com 63 | - *.voidcc.com 64 | - v-resheno.ru 65 | - src-bin.com 66 | - intellipaat.com 67 | - oipapio.com 68 | - qarus.ru 69 | - quick-geek.github.io 70 | - *.uwenku.com 71 | - icode9.com 72 | - e-learn.cn 73 | - stackoom.com 74 | - codeindex.ru 75 | - kompsekret.ru 76 | - xszz.org 77 | - *.developreference.com 78 | - *.develop-bugs.com 79 | - thinbug.com 80 | - *.programqa.com 81 | - husl.ru 82 | - myht.ru 83 | - qarchive.ru 84 | - coderoad.ru 85 | - qastack.ru 86 | - brokencontrollers.com 87 | - ffff65535.com 88 | - itdaan.com 89 | 90 | Partially supported sites (Yandex Translate is used to find the original question - works well only in Tampermonkey) 91 | - askdev.ru 92 | - vike.io 93 | - soinside.com 94 | - qa.1r1g.com 95 | - legkovopros.ru -------------------------------------------------------------------------------- /back2stackoverflow.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Back2stackoverflow 3 | // @version 0.1.40 4 | // @description Redirect to stackoverflow.com from machine-translated sites 5 | // @namespace taraflex 6 | // @author taraflex.red@gmail.com 7 | // @run-at document-end 8 | // @downloadURL https://raw.githubusercontent.com/Taraflex/Back2stackoverflow/master/back2stackoverflow.user.js 9 | // @updateURL https://raw.githubusercontent.com/Taraflex/Back2stackoverflow/master/back2stackoverflow.user.js 10 | // @homepageURL https://github.com/Taraflex/Back2stackoverflow 11 | // @supportURL https://github.com/Taraflex/Back2stackoverflow/issues 12 | // @grant GM_xmlhttpRequest 13 | // @noframes 14 | // @match https://stackoverflow.com/search?back2stackoverflow=* 15 | // @match http://qaru.site/questions/* 16 | // @match https://qaru.site/questions/* 17 | // @match http://fooobar.com/questions/* 18 | // @match https://fooobar.com/questions/* 19 | // @match http://askdev.info/questions/* 20 | // @match https://askdev.info/questions/* 21 | // @match https://ubuntugeeks.com/questions/* 22 | // @match http://programmerz.ru/questions/* 23 | // @match https://programmerz.ru/questions/* 24 | // @match http://www.4answered.com/questions/* 25 | // @match https://www.4answered.com/questions/* 26 | // @match http://4answered.com/questions/* 27 | // @match https://4answered.com/questions/* 28 | // @match https://code-examples.net/*/q/* 29 | // @match http://code.i-harness.com/*/q/* 30 | // @match https://code.i-harness.com/*/q/* 31 | // @match http://quabr.com/*/* 32 | // @match https://quabr.com/*/* 33 | // @match https://stackovernet.com/*/q/* 34 | // @match https://*.stackovernet.com/*/q/* 35 | // @match https://stackoverrun.com/*/q/* 36 | // @match https://ffff65535.com/*/q/* 37 | // @match https://qna.one/* 38 | // @match https://qa-help.ru/questions/* 39 | // @match https://exceptionshub.com/* 40 | // @match https://kotaeta.com/* 41 | // @match https://ciupacabra.com/* 42 | // @match https://de-vraag.com/* 43 | // @match https://switch-case.ru/* 44 | // @match https://switch-case.com/* 45 | // @match https://*.switch-case.com/* 46 | // @match https://bildiredi.com/* 47 | // @match https://donolik.com/* 48 | // @match https://pytannie.com/* 49 | // @match https://sozdizimi.com/* 50 | // @match https://zapytay.com/* 51 | // @match https://answer-id.com/* 52 | // @match https://while-do.com/* 53 | // @match https://365airsoft.com/*/questions/* 54 | // @match https://codeday.me/*/* 55 | // @match https://publish.codeday.me/post/* 56 | // @match https://issue.life/questions/* 57 | // @match https://*.coredump.biz/questions/* 58 | // @match http://www.code-adviser.com/detail_* 59 | // @match https://www.code-adviser.com/detail_* 60 | // @match https://ask-ubuntu.ru/questions/* 61 | // @match https://stackru.com/questions/* 62 | // @match https://xbuba.com/questions/* 63 | // @match http://web-answers.ru/*/* 64 | // @match https://web-answers.ru/*/* 65 | // @match https://sprosi.pro/questions/* 66 | // @match https://askvoprosy.com/voprosy/* 67 | // @match https://stackanswers.net/questions/* 68 | // @match https://codengineering.ru/q/* 69 | // @match https://overcoder.net/q/* 70 | // @match https://coderquestion.ru/q/* 71 | // @match http://qacode.ru/questions/* 72 | // @match https://progaide.com/question/* 73 | // @match http://stackz.ru/en/*/* 74 | // @match http://stackz.ru/ru/*/* 75 | // @match https://www.it-swarm.xyz/*/* 76 | // @match https://www.it-swarm.asia/*/* 77 | // @match https://www.it-swarm.dev/*/* 78 | // @match https://www.it-swarm.net/*/* 79 | // @match https://bonprog.com/question/* 80 | // @match https://bestecode.com/question/* 81 | // @match https://progexact.com/question/* 82 | // @match https://rstopup.com/* 83 | // @match https://profikoder.com/question/* 84 | // @match https://itranslater.com/qa/details/* 85 | // @match https://www.itranslater.com/qa/details/* 86 | // @match http://*.voidcc.com/question/* 87 | // @match https://*.voidcc.com/question/* 88 | // @match http://v-resheno.ru/* 89 | // @match https://v-resheno.ru/* 90 | // @match https://src-bin.com/*/q/* 91 | // @match https://intellipaat.com/community/*/* 92 | // @match https://oipapio.com/question-* 93 | // @match https://www.oipapio.com/question-* 94 | // @match https://qarus.ru/* 95 | // @match https://quick-geek.github.io/answers/* 96 | // @match https://weekly-geekly.github.io/articles/* 97 | // @match https://askdev.ru/q/* 98 | // @match https://vike.io/*/*/* 99 | // @match http://uwenku.com/question/* 100 | // @match https://uwenku.com/question/* 101 | // @match http://*.uwenku.com/question/* 102 | // @match https://*.uwenku.com/question/* 103 | // @match https://www.soinside.com/question/* 104 | // @match https://qa.1r1g.com/sf/ask/* 105 | // @match https://icode9.com/* 106 | // @match https://www.icode9.com/* 107 | // @match https://e-learn.cn/topic/* 108 | // @match https://www.e-learn.cn/topic/* 109 | // @match https://stackoom.com/question/* 110 | // @match https://codeindex.ru/q/* 111 | // @match https://kompsekret.ru/q/* 112 | // @match https://xszz.org/*/question-* 113 | // @match https://www.xszz.org/*/question-* 114 | // @match https://*.developreference.com/article/* 115 | // @match https://*.develop-bugs.com/article/* 116 | // @match https://www.thinbug.com/q/* 117 | // @match https://*.programqa.com/question/* 118 | // @match https://husl.ru/questions/* 119 | // @match https://www.husl.ru/questions/* 120 | // @match https://myht.ru/question/* 121 | // @match https://www.myht.ru/question/* 122 | // @match https://qarchive.ru/* 123 | // @match https://coderoad.ru/* 124 | // @match https://qastack.ru/* 125 | // @match https://answeright.com/* 126 | // @match https://www.answeright.com/* 127 | // @match https://brokencontrollers.com/faq/* 128 | // @match https://www.brokencontrollers.com/faq/* 129 | // @match https://itdaan.com/blog/* 130 | // @match https://www.itdaan.com/blog/* 131 | // @match https://legkovopros.ru/questions/* 132 | // ==/UserScript== 133 | 134 | (async () => { 135 | 'use strict'; 136 | 137 | /** 138 | * @param {string} bgcolor 139 | * @param {string} link 140 | */ 141 | async function promtRedirect(bgcolor, link) { 142 | const dialog = document.createElement('div'); 143 | try { 144 | document.body.appendChild(dialog); 145 | const shadowRoot = dialog.attachShadow ? 146 | dialog.attachShadow({ mode: 'open' }) : 147 | //@ts-ignore 148 | dialog.createShadowRoot && dialog.createShadowRoot(); 149 | if (!shadowRoot) { 150 | throw 'Shadow dom required!'; 151 | } 152 | shadowRoot.innerHTML = ` 153 | 180 |
[ Back2stackoverflow ] Try to find the original question?`; 181 | shadowRoot.querySelector('#ok-btn').href = shadowRoot.querySelector('.search-icon').href = link; 182 | await new Promise((_, reject) => { 183 | //shadowRoot.querySelector('#ok-btn').addEventListener('click', reject); 184 | shadowRoot.querySelector('#close-btn').addEventListener('click', reject); 185 | }); 186 | } finally { 187 | document.body.removeChild(dialog); 188 | } 189 | } 190 | 191 | /** 192 | * @param {string} q 193 | * @param {string} sourceLang 194 | */ 195 | async function yaTranslate(q, sourceLang) { 196 | q = dropMarks(q); 197 | if (!q) { 198 | return null; 199 | } 200 | //todo гугл переводчик вставляет пробелы где не нужно, исследовать вокруг каких знаков стоит удалять пробелы 201 | q = q.replace(/ \/ /g, '/'); 202 | q = 'https://api.browser.yandex.ru/dictionary/translate?statLang=en&targetLang=en&text=' + encodeURIComponent(q) + (sourceLang ? '&fromLang=' + sourceLang : '') 203 | try { 204 | //dosn't work in chrome 205 | return await fetch(q, { mode: 'no-cors', credentials: 'omit' }) 206 | .then(r => r.json()) 207 | .then(r => r.text); 208 | } catch (_) { 209 | //works only in tampermonkey 210 | return new Promise((resolve, reject) => { 211 | //@ts-ignore 212 | GM_xmlhttpRequest({ 213 | url: q, 214 | responseType: 'json', 215 | anonymous: true, 216 | onload: (xhr) => { 217 | if (xhr.status === 200) { 218 | resolve(xhr.response.text) 219 | } else { 220 | reject(xhr) 221 | } 222 | }, 223 | onerror: reject 224 | }) 225 | }) 226 | } 227 | } 228 | 229 | function lastPathPart() { 230 | return location.pathname.split('/').filter(Boolean).slice(-1)[0]; 231 | } 232 | 233 | /** 234 | * @param {string} q 235 | * @param {Date} [before] 236 | * @param {Date} [after] 237 | * @param {string[]} [tags] 238 | */ 239 | function findByApi(q, before, after, tags) { 240 | q = dropMarks(q); 241 | return q && fetch( 242 | `https://api.stackexchange.com/2.2/search?page=1&pagesize=1&order=desc&sort=relevance&intitle=${encodeURIComponent(q)}&site=stackoverflow` + 243 | (after ? '&fromdate=' + (after.getTime() / 1000 - 120 | 0) : '') + 244 | (before ? '&todate=' + (before.getTime() / 1000 + 120 | 0) : '') + 245 | (Array.isArray(tags) && tags.length > 0 ? '&tagged=' + encodeURIComponent(Array.from(new Set(tags)).join(';')) : '') 246 | , { credentials: 'omit' }) 247 | .then(r => r.json()) 248 | .then(r => r.items && r.items[0] && r.items[0].link); 249 | } 250 | 251 | /** 252 | * @param {string} selector 253 | */ 254 | function textContent(selector) { 255 | const e = document.querySelector(selector); 256 | return e ? e.textContent.trim() || null : null 257 | } 258 | 259 | /** 260 | * @param {string} s 261 | * @param {boolean} [real] 262 | */ 263 | function toSearch(s, real) { 264 | s = dropMarks(s); 265 | return s ? `https://stackoverflow.com/search?back2stackoverflow=${+!!real}&q=` + encodeURIComponent(s) : null; 266 | } 267 | 268 | /** 269 | * @param {string} s 270 | * @param {number} [radix] 271 | */ 272 | function byNumber(s, radix) { 273 | const n = parseInt(s, radix); 274 | return n > 0 ? 'https://stackoverflow.com/questions/' + n : null; 275 | } 276 | 277 | /** 278 | * @param {string} s 279 | */ 280 | function dropMarks(s) { 281 | return s && s.replace(/\[(на удержании|on hold|duplikować|duplicado|duplicar|duplikat|dublicate|duplicate|дубликат|закрыто|закрытый|closed|geschlossen|zamknięte|cerrado)\]\s*$/i, '').trim(); 282 | } 283 | 284 | /** 285 | * @param {string} s 286 | */ 287 | function normalize(s) { 288 | return s && ' ' + s.toLowerCase() + ' ' 289 | } 290 | 291 | let auxiliaryRe = null; 292 | /** 293 | * @param {string} s 294 | */ 295 | function removeAuxiliary(s) { 296 | return s && s.replace(auxiliaryRe || (auxiliaryRe = new RegExp([ 297 | 'a', 'an', 'the', 298 | //Conjunctions http://englishgu.ru/soyuzyi-v-angliyskom-yazyike-tablitsa-spisok/ 299 | //https://7esl.com/english-conjunctions/ 300 | 'according to', 'after', 'against', 'also', 'although', 'and', 'as far as', 'as if', 'as long as', 'as much as', 'as soon as', 'as though', 'as well as', 'as', 'assuming that', 'at last', 'at least', 'because of', 'because', 'before', 'beyond', 'both', 'but', 'by the time', 'either', 'even if', 'even though', 'for', 'from now on', 'from time to time', 'how', 'however', 'if', 'in case', 'in order', 'in spite of', 'in terms of', 'lest', 'like', 'meanwhile', 'moreover', 'neither', 'nevertheless', 'no matter how', 'no matter what', 'no matter when', 'no matter where', 'no matter who', 'no matter why', 'nor', 'not so as', 'not yet', 'now that', 'on behalf of', 'on condition', 'on the contrary', 'on the other hand', 'once', 'only if', 'or', 'otherwise', 'owing to', 'provided that', 'rather than', 'since', 'so that', 'so', 'still', 'than', 'that is why', 'that', 'therefore', 'though', 'thus', 'till', 'unless', 'unlike', 'until', 'what', 'whatever', 'when', 'whenever', 'where', 'whereas', 'wherever', 'whether', 'which', 'whichever', 'while', 'who', 'whoever', 'whom', 'whomever', 'whose', 'with', 'within', 'without', 'yet', 301 | //some of Preposition https://www.englishclub.com/grammar/prepositions-list.htm 302 | //https://www.talkenglish.com/vocabulary/top-50-prepositions.aspx 303 | 'aboard', 'about', 'above', 'across', 'after', 'against', 'along', 'amid', 'among', 'anti', 'around', 'at', 'behind', 'below', 'beneath', 'beside', 'besides', 'beyond', 'but', 'by', 'concerning', 'considering', 'despite', 'down', 'during', 'excepting', 'excluding', 'following', 'for', 'from', 'in', 'including', 'inside', 'into', 'of', 'off', 'on', 'onto', 'opposite', 'out', 'outside', 'over', 'past', 'per', 'regarding', 'since', 'than', 'through', 'throughout', 'to', 'toward', 'towards', 'under', 'underneath', 'unlike', 'until', 'up', 'upon', 'versus', 'via', 'within', 'without', 304 | //some of https://7esl.com/interjections-exclamations/ 305 | 'aah', 'ah', 'aha', 'ahem', 'alas', 'argh', 'aw', 'aww', 'bah', 'behold', 'bingo', 'boo', 'bravo', 'brr', 'dear', 'duh', 'eek', 'eh', 'er', 'eww', 'gah', 'gee', 'grr', 'hah', 'hello', 'hey', 'hi', 'hmm', 'huh', 'hullo', 'humph', 'hurrah', 'meh', 'mhm', 'muahaha', 'nuh-uh', 'oh', 'ooh', 'ooh-la-la', 'oomph', 'oops', 'ouch', 'oww', 'oy', 'pew', 'pff', 'phew', 'psst', 'sheesh', 'shh', 'shoo', 'tsk-tsk', 'uh-hu', 'uh-oh', 'uh-uh', 'uhh', 'um', 'umm', 'wee', 'well', 'whoa', 'wow', 'yahoo', 'yay', 'yeah', 'yikes', 'yippee', 'yoo-hoo', 'yuck', 'yuh-uh', 'zing', 306 | //modals 307 | 'can', 'could', 'be able to', 'may', 'might', 'shall', 'should', 'must', 'have to', 'will', 'would', 308 | ].sort((a, b) => b.length - a.length).map(w => `\\W${w}(?!\\w)`).join('|'), 'g')), ' '); 309 | } 310 | 311 | /** 312 | * @param {string} s 313 | */ 314 | function onlyAlphanum(s) { 315 | return s && s.replace(/[^a-z0-9]+/gi, ''); 316 | } 317 | 318 | /** 319 | * @param {Function[]} fns 320 | */ 321 | function pipe(...fns) { 322 | return (v) => { 323 | for (let f of fns) { 324 | v = f(v); 325 | } 326 | return v; 327 | } 328 | } 329 | 330 | /** 331 | * @param {string} s 332 | * @return {HTMLElement[]} 333 | */ 334 | function all(s) { 335 | return Array.prototype.slice.call(document.querySelectorAll(s)); 336 | } 337 | 338 | /** 339 | * @param {string} s 340 | * @return {string[]} 341 | */ 342 | function allTexts(s) { 343 | return all(s).map(a => a.textContent.trim()) 344 | } 345 | 346 | const href = location.href; 347 | 348 | if (href.startsWith('https://stackoverflow.com/search?back2stackoverflow=')) { 349 | const searchParams = new URLSearchParams(location.search); 350 | const prepare = +searchParams.get('back2stackoverflow') ? pipe(dropMarks, normalize, onlyAlphanum) : pipe(dropMarks, normalize, removeAuxiliary, onlyAlphanum); 351 | const q = searchParams.get('q'); 352 | const preparedQ = prepare(q); 353 | if (preparedQ) { 354 | //@ts-ignore 355 | const link = all('.result-link a').find(link => link.href.indexOf('/' + q, 36) !== -1 || preparedQ.startsWith(prepare(link.textContent.replace(/^\s*(Q|A):/, '')))); 356 | if (link) { 357 | try { 358 | //@ts-ignore 359 | history.replaceState(null, null, link.href); 360 | } catch (e) { } 361 | //@ts-ignore 362 | return link.href; 363 | } else { 364 | return `https://www.google.com/search?q=${encodeURIComponent(q)}+site%3Astackoverflow.com`; 365 | } 366 | } 367 | } else if (href.startsWith('https://weekly-geekly.github.io/articles/')) { 368 | return document.querySelector('a[href^="https://habr.com/ru/post/"]'); 369 | } 370 | 371 | const host = location.hostname.split('.').slice(-2).join('.'); 372 | switch (host) { 373 | case 'legkovopros.ru': 374 | const legkovopros = await yaTranslate(textContent('h1'), 'ru'); 375 | return (await findByApi(legkovopros, null, null, allTexts('.tag'))) || promtRedirect('#55b252', toSearch(legkovopros)); 376 | case 'askdev.ru': 377 | let askdev = textContent('.block_share span') ? textContent('h1') : null; 378 | if (askdev) { 379 | askdev = await yaTranslate(askdev, 'ru'); 380 | return (await findByApi(askdev, null, null, allTexts('.block_taxonomies a'))) || promtRedirect('#970f1b', toSearch(askdev)); 381 | } 382 | return; 383 | case 'vike.io': 384 | let vike = textContent('h1'); 385 | if (vike) { 386 | vike = await yaTranslate(vike.replace(/[^–]+–\s/, ''), location.pathname.split('/', 2).find(Boolean)); 387 | const d = new Date(document.querySelector('.question-box .author__date').getAttribute('datetime')); 388 | return (await findByApi(vike, d, d, allTexts('.tags__item--blue'))) || promtRedirect('#09c199', toSearch(vike)); 389 | } 390 | return; 391 | case 'soinside.com': 392 | const soinside = await yaTranslate(textContent('h1'), 'zh'); 393 | return soinside && ((await findByApi(soinside, null, null, allTexts('.q-tag'))) || promtRedirect('#007bff', toSearch(soinside))); 394 | case '1r1g.com': 395 | const qa1r1g = await yaTranslate(textContent('h1'), 'zh'); 396 | return qa1r1g && ((await findByApi(qa1r1g, null, null, allTexts('.badge'))) || promtRedirect('#343a40', toSearch(qa1r1g))); 397 | case 'xszz.org': 398 | return findByApi( 399 | textContent('.page-title'), 400 | new Date(document.querySelector('.gp-meta-date').getAttribute('datetime')) 401 | ); 402 | case 'develop-bugs.com': 403 | case 'developreference.com': 404 | const parts = document.title.split(' - '); 405 | const tag = parts.pop(); 406 | return findByApi(parts.join(' - '), null, null, [tag]); 407 | case 'intellipaat.com': 408 | return findByApi( 409 | textContent('h1'), 410 | new Date(document.querySelector('.qa-q-view-main time').getAttribute('datetime')), 411 | null, 412 | allTexts('.qa-q-view-main .qa-tag-link') 413 | ); 414 | case 'oipapio.com': 415 | return findByApi( 416 | textContent('h1').replace(/^.*? - /, ''), 417 | new Date(textContent('.post-meta .date')), 418 | null, 419 | allTexts('.category') 420 | ); 421 | case 'icode9.com': 422 | return textContent('#paragraph > p:last-child').split('来源:', 2)[1].trim(); 423 | case 'v-resheno.ru': 424 | return textContent('.linkurl > b'); 425 | case 'stackoom.com': 426 | return byNumber(document.getElementById('question').dataset.questionid); 427 | case 'myht.ru': 428 | return byNumber(lastPathPart().split('-', 1)[0]); 429 | case 'ffff65535.com': 430 | case 'src-bin.com': 431 | case 'i-harness.com': 432 | case 'code-examples.net': 433 | return byNumber(lastPathPart(), 16); 434 | case 'coderoad.ru': 435 | case 'quabr.com': 436 | return byNumber(location.pathname.split('/', 2)[1]); 437 | case 'brokencontrollers.com': 438 | case 'programqa.com': 439 | case 'thinbug.com': 440 | case 'profikoder.com': 441 | case 'progexact.com': 442 | case 'bestecode.com': 443 | case 'bonprog.com': 444 | case 'progaide.com': 445 | case 'coderquestion.ru': 446 | case 'coredump.biz': 447 | case 'issue.life': 448 | case 'xbuba.com': 449 | return byNumber(location.pathname.split('/', 3)[2]); 450 | case 'exceptionshub.com': 451 | if (!/\.html$/.test(location.pathname)) { 452 | return; 453 | }//отсутствие break - не ошибка 454 | case 'codengineering.ru': 455 | case 'stackanswers.net': 456 | case 'askvoprosy.com': 457 | return toSearch(lastPathPart().replace(/(-closed|-duplicate)?(-\d+)?(\.html)?$/, ''), true); 458 | case 'stackz.ru': 459 | const enLink = document.querySelector('a[href^="/en/' + location.pathname.split('/', 3)[2] + '/"]'); 460 | if (enLink) { 461 | //@ts-ignore 462 | return enLink.href; 463 | } 464 | return toSearch(textContent('h1'), true); 465 | case 'codeday.me': 466 | if (location.hostname.startsWith('publish.')) { 467 | //@ts-ignore 468 | return all('.panel-body a')[1].href; 469 | } 470 | case 'itdaan.com': 471 | const uv = document.querySelector('input[name="url"]'); 472 | //@ts-ignore 473 | return uv && uv.value; 474 | default: 475 | const cssSelectors = { 476 | 'kompsekret.ru': '.question-text > .a-link', 477 | 'qaru.site': '.question-text > .aa-link', 478 | 'fooobar.com': '.question-text > .aa-link', 479 | 'askdev.info': '.question-text > .a-link', 480 | 'ubuntugeeks.com': '.question-text > .a-link', 481 | 482 | 'qa-help.ru': 'a.uncolored-text[href*="stackoverflow.com/questions/"]',//встречаются вопросы с ru.stackoverflow.com 483 | 'programmerz.ru': '.source-share-link', 484 | '4answered.com': '.view_body span a', 485 | 'qna.one': '.page-container-question .source-share-block a', 486 | '365airsoft.com': '.origin > a', 487 | 'codeday.me': '.article-es-url > a', 488 | 'code-adviser.com': '.meta_data a', 489 | 'web-answers.ru': '.source > a', 490 | 'sprosi.pro': '#qsource > a', 491 | 'overcoder.net': '.info_outlink', 492 | 'qacode.ru': '.question-info .cc-link', 493 | 'rstopup.com': '.td-post-content .origlink > a', 494 | 'itranslater.com': '.body > div:last-child > a', 495 | 'voidcc.com': '.source > a', 496 | 'qarus.ru': 'em > a', 497 | 'uwenku.com': '.post-info a', 498 | /*'quick-geek.github.io'*/ 'github.io': '.question-hyperlink', 499 | 'e-learn.cn': '.zhuanzai + div a', 500 | 'codeindex.ru': '.text-muted.small', 501 | 'husl.ru': '.source-link', 502 | 'qarchive.ru': 'cite > a', 503 | 'qastack.ru': '.text-muted > a:last-child', 504 | 'answeright.com': '.wrapper-question-card .v-card__actions > a:not(.edited-author-button):not(.category-question-button)', 505 | 506 | 'it-swarm.xyz': '.gat[data-cat="q-source"]', 507 | 'it-swarm.asia': '.gat[data-cat="q-source"]', 508 | 'it-swarm.dev': '.gat[data-cat="q-source"]', 509 | 'it-swarm.net': '.gat[data-cat="q-source"]', 510 | 511 | 'stackru.com': '.q-source', 512 | 'ask-ubuntu.ru': '.q-source', 513 | 514 | 'stackoverrun.com': '.post-meta a', 515 | 'stackovernet.com': '.post-meta a', 516 | 517 | 'kotaeta.com': '.footer_question.mt-3 > a', 518 | 'ciupacabra.com': '.footer_question.mt-3 > a', 519 | 'de-vraag.com': '.footer_question.mt-3 > a', 520 | 'switch-case.ru': '.footer_question.mt-3 > a', 521 | 'switch-case.com': '.footer_question.mt-3 > a', 522 | 'bildiredi.com': '.footer_question.mt-3 > a', 523 | 'donolik.com': '.footer_question.mt-3 > a', 524 | 'pytannie.com': '.footer_question.mt-3 > a', 525 | 'sozdizimi.com': '.footer_question.mt-3 > a', 526 | 'zapytay.com': '.footer_question.mt-3 > a', 527 | 'answer-id.com': '.footer_question.mt-3 > a', 528 | 'while-do.com': '.footer_question.mt-3 > a' 529 | }; 530 | const link = cssSelectors[host] && document.querySelector(cssSelectors[host]); 531 | return link ? link.href : null; 532 | } 533 | 534 | })().then(u => u && (location.href = u)).catch(console.error.bind(console)); --------------------------------------------------------------------------------