Recaptcha Skipper

Try to skip google recaptcha error page automatically through reloading the page. If not, redirect to configurable url

目前為 2021-09-14 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Recaptcha Skipper
// @namespace    c4ca4238a0b923820dcc509a6f75849b
// @version      0.3
// @description  Try to skip google recaptcha error page automatically through reloading the page. If not, redirect to configurable url
// @author       _SUDO
// @match        https://www.google.com/sorry/*
// @grant        GM_addStyle
// @compatible      chrome Chrome + Tampermonkey or Violentmonkey
// @compatible      firefox Firefox + Greasemonkey or Tampermonkey or Violentmonkey
// @compatible      opera Opera + Tampermonkey or Violentmonkey
// @compatible      edge Edge + Tampermonkey or Violentmonkey
// @compatible      safari Safari + Tampermonkey or Violentmonkey
// ==/UserScript==
/* jshint esversion: 6 */

(function (){
    'use strict';
    const config = {
        redirect_to: true, // Will redirect the actual searched query to the defined url (from ?q=[terms])
        redirect_to_url: 'https://duckduckgo.com/?q=', // if you like DuckDuckGo for example... https://duckduckgo.com/?q=
        promp_redirect: true, // Create UI to cancel redirection
        verbose_logging: false
    }

    const logger = (...args) => {
        if (!config.verbose_logging) {
            return;
        }
        console.log(...args)
    }


    class SkipCaptcha {
        constructor() {
            this.url = false
            this.tries = 1
        }

        // Create a 3sec counter to allow the user to cancel automatic redirection
        create_Redirect_UI () {
            if (!config.promp_redirect) return this; // Will automatically allow

            let redirect_allowed = true // By default it's automatically allowed redirect

            // Add progress bar style

            GM_addStyle(`
        #UIcounter {
         box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset;
        }
        #UIcounter[value] {
  /* Reset the default appearance */
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;

  /* Get rid of default border in Firefox. */
  border: none;

  /* Dimensions */
  width: 100%;
  height: 20px;
}

#UIcounter[value]::-moz-progress-bar {
  background-color: #09c;
background-image:
  /* the stripe layer */linear-gradient(45deg, rgba(255, 255, 255, 0.16) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.16) 50%, rgba(255, 255, 255, 0.16) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0)), linear-gradient(to right, #09c, #f44);

/* we also need background-size, because the stripe must repeat every 20 pixels */
  background-size: 60px 50px, 100%;
}`)

            document.body.innerHTML += `
<div id="userUI" style="position: fixed; bottom: 5px; right: 5px; background: #f9f9f9; z-index: 999999;border-radius: 5px; box-shadow: 0 0 5px -1px;border: 1px solid gray;display: grid;grid-template-columns: 0.3fr 1.6fr;">
 <a id="redirect" style="cursor: pointer; text-align: center;font-size: 24px;box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset;margin: 0;padding-top: 21px;border-radius: 5px 0 0 5px;text-decoration: none;color: black;">►</a>
 <div>
  <p style="margin: 15px;">You will be automatically redirected...</p>
  <progress id="UIcounter" max="${100}" value="0" style="width: 100%; height: 15px;"></progress>
 <div>
</div>`
            const UI = document.getElementById('userUI')
            const UI_skipBTN = document.getElementById('redirect')
            const UI_Counter = document.getElementById('UIcounter')
            let counter = 0

            logger('Started countdown')
            const processBar = setInterval(() => {
                if (counter >= 100) {
                    logger('Ended countdown')
                    remove_event()
                    clearInterval(processBar)
                }
                counter = counter >= 100 ? 100 : counter+5
                UI_Counter.value = counter
            }, 135)

            // This event will allows us to just force skip
            const event_skip = UI_skipBTN.addEventListener('click', () => {
                logger('User clicked, cancelled redirect.')
                clearInterval(processBar)

                this.handle_redirects()
            }, {once: true})

            const event = UI.addEventListener('click', () => {
                if (counter != 100) {
                    redirect_allowed = false
                    logger('User clicked, cancelled redirect.')
                    clearInterval(processBar)
                }
            }, {once: true})

            const remove_event = () => {
                logger('Removed Event Listener')
                UI.removeEventListener('click', event, true)
            }

            return new Promise(resolve => {
                setTimeout(() => {
                    logger('Redirect Status:', redirect_allowed)
                    resolve(redirect_allowed)
                }, 3000)
            })
        }

        checkAttemps () {
            // Will check if there's a value of previous retries on the sesion storage, if not create one
            const storage = sessionStorage
            const storage_name = 'Captch_Retries'

            // Check if it's already a value
            if (storage.getItem(storage_name)) {
                this.tries = storage.getItem(storage_name)
                logger('Retries saved:', this.tries)
                if (!typeof this.tries === 'number') {
                    logger('Value not a number, parsing to integer...')
                    this.tries = parseInt(this.tries)
                }
                logger('Adding an attemt to saved retries...')
                this.tries++
                storage.setItem(storage_name, this.tries)

                logger('New set value stored:', this.tries)
            }
            else {
                logger('Any previous retries saved, creating a new storage item with value of', this.tries)
                storage.setItem(storage_name, this.tries)
            }

            logger('checkAttemps', this.tries)

            return this
        }

        async redirectURL_to_Google () {
            // Forced await
            const response = await this.create_Redirect_UI()
            if (!response) {
                logger('User cancelled redirect')
                return;
            }
            this.handle_redirects()

            return this
        }

        handle_redirects () {
            if (this.url) {
                if (this.tries < 3) {
                    window.location = this.url
                } else {
                    if (config.redirect_to) {
                        this.redirect_to_user_defined_url()
                    } else {
                        logger('Not redirecting, too many retries:', this.url, this.tries)
                    }
                }
            } else {
                logger('ERROR: no url finded!')
            }

            return this
        }

        redirect_to_user_defined_url () {
            logger(`Redirecting to "${config.redirect_to_url}"`)

            // this.url is the <title> string and we have to convert to an URL to use URLSearchParams constructor
            const gen_URL_to_search = new URL(this.url)
            const getSearchedParams = new URLSearchParams(gen_URL_to_search.search).get('q') // Only get que Query searched
            const newURL = config.redirect_to_url + getSearchedParams
            logger('Google search params:', getSearchedParams)
            logger('New URL generated to redirect:', newURL)

            // Send to the new url formated
            window.location = newURL

            // If works properly, a return isn't necesary
            // return this
        }

        getURL () {
            // The search url/terms are in the page url and body,
            // because I'am lazy I will get it from the title element
            const url = document.getElementsByTagName('title')[0].textContent
            if (url.lenght != 0) {
                this.url = url
            }
            logger('URL:', this.url)

            return this
        }

        init () {
            logger('Initilizing...')
            this.getURL().checkAttemps().redirectURL_to_Google()
        }
    }

    const init = new SkipCaptcha().init()

    if (document.readyState === 'complete') {
        init
    } else {
        document.addEventListener('readystatechange', function () {
            if (document.readyState === 'complete') {
                init
            }
        })
    }
})()