返回首頁 

Greasy Fork is available in English.

Multi-OCH Helper

nopremium.pl and premiumize.me. Inserts a direct download link on several one-click-hosters and some container/folder providers.

Version au 20/12/2021. Voir la dernière version.


Installer ce script?
// ==UserScript==// @name             Multi-OCH Helper// @namespace        cuzi// @license          MIT// @description      nopremium.pl and premiumize.me. Inserts a direct download link on several one-click-hosters and some container/folder providers.// @homepageURL      https://openuserjs.org/scripts/cuzi/Multi-OCH_Helper// @contributionURL  https://buymeacoff.ee/cuzi// @contributionURL  https://ko-fi.com/cuzicvzi// @icon             https://raw.githubusercontent.com/cvzi/Userscripts/master/Multi-OCH/icons/helper.png// @version          16.17// @include          /^https:\/\/cvzi\.github\.io\/Userscripts\/index\.html\?link=.+/// @include          /^https:\/\/www\.nopremium\.pl\/files.*$/// @include          /^https:\/\/www\.premiumize\.me\/hosters\/?$/// @include          /^https:\/\/www\.premiumize\.me\/services\/?$/// @include          /^https:\/\/www\.premiumize\.me\/downloader.*$/// @include          http://download.serienjunkies.org/*// @include          /^https?:\/\/(www\.)?filecrypt.cc\/Container\/\w+\.html.*$/// @include          http*filecrypt.cc/helper.html*// @include          /^http:\/\/www\.firedrive\.com\/share\/(\w|-)+$/// @include          http://linkcrypt.ws/dir/*// @include          http://linksave.in/*// @include          /^http:\/\/ncrypt\.in\/folder\-\w+$/// @include          http*://*uploaded.net/folder/*// @include          http*://*uploaded.net/f/*// @include          http://protected.to/f-*// @include          http*://rapidgator.net/folder/*// @include          http://www.relink.us/view.php?id=*// @include          https://safelinking.net/p/*// @include          http://linkshield.org/p/*// @include          http://share-links.biz/*// @include          http*://relink.to/view.php?id=*// @include          http://extreme-protect.net/*// @include          /^https?:\/\/(www\.)?1fichier\.com\/.+$/// @include          /^https?:\/\/\w+\.1fichier\.com\/?.*$/// @include          /^http:\/\/www\.4shared\.com\/[a-z]+\/\w+\/?(.+\.html)?$/// @include          /^https?:\/\/(www\.)?alfafile\.net\/file\/.+$/// @include          /^https?:\/\/anonfiles\.com\/\w+\/?.*$/// @include          /^https?:\/\/(www\.)?bayfiles\.(net|com)\/\w+\/?.*$/// @include          /^http:\/\/billionuploads\.com\/\w+$/// @include          /^https?:\/\/(www\.)?catshare\.net\/.+$/// @include          /^https?:\/\/(www\.)?clicknupload\.(link|org|co|cc)\/\w+\/?.*$/// @include          /^https?:\/\/(www\.)?datei\.to\/\?\w+$/// @include          /^https?:\/\/dailyuploads\.net\/\w+\/?.*$/// @include          /^https?:\/\/(www\.)?ddl\.to\/\w+$/// @include          /^https?:\/\/ddownload\.com\/\w+.*$/// @include          /^https?:\/\/(www\.)?devilshare\.net\/view.+$/// @include          /^https?:\/\/(www\.)?dropapk\.to\/\w+.*$/// @include          /^https?:\/\/fastshare\.cz\/\d+\/.+$/// @include          /^https?:\/\/(www\.)?file\.al\/\w+\/?.*$/// @include          /^https?:\/\/(www\.)?filefactory\.com\/file\/.+$/// @include          /^https?:\/\/www.filemonkey.in\/file\/.+$/// @include          /^https?:\/\/www.filenext.com\/\w+\/.*$/// @include          /^https:\/\/filer\.net\/get\/\w+$/// @include          /^https?:\/\/(www\.)?fileshark\.pl\/pobierz\/\d+\/\w+\/.*$/// @include          /^https?:\/\/(www\.)?filespace\.com\/\w+\/?$/// @include          /^https?:\/\/filestore\.to\/\?d=\w+$/// @include          /^http:\/\/www\.firedrive\.com\/file\/\w+$/// @include          /^https?:\/\/fireget\.com\/\w+\/?.*$/// @include          /^https?\:\/\/(www\.)?hitfile\.net\/\w+.*$/// @include          /^https?\:\/\/(www\.)?hil\.to\/\w+.*$/// @include          /^http:\/\/hugefiles\.net\/\w+\/?.*$/// @include          /^https:\/\/www\.inclouddrive\.com\/file\/\w+\/?.*$/// @include          /^https:\/\/isra\.cloud\/\w+\/?.*$/// @include          /^https?:\/\/katfile\.com\/\w+\/?.*$/// @include          /^https?:\/\/kingfile\.pl\/download\/.+$/// @include          /^https?:\/\/lunaticfiles\.com\/\w+\/?.*$/// @include          /^https?:\/\/www\.mediafire\.com\/?\?.+$/// @include          /^https?:\/\/www\.mediafire\.com\/download\/.+$/// @include          /^https?:\/\/mega\.co\.nz\/\#\!\w+!*(\w|-)*$/// @include          /^https?:\/\/mega\.nz\/\#\!\w+!*(\w|-)*$/// @include          /^https?:\/\/megaup\.net\/\w+\/?.*$/// @include          /^https?:\/\/mixdrop\.co\/f\/\w+.*$/// @include          /^https?:\/\/modsbase\.com\/\w+\/?.*$/// @include          /^https?:\/\/nitroflare\.com\/view\/.+$/// @include          /^https?:\/\/ozofiles\.com\/\w+\/.*$/// @include          /^https?:\/\/rapidgator\.net\/file\/[^#]+$/// @include          /^https?:\/\/rg\.to\/file\/[^#]+$/// @include          /^https?:\/\/(\w+\.)?rapidu\.net\/\d+\/.*$/// @include          /^https?\:\/\/(www\.)?rockfile\.(eu|co)\/\w+.*$/// @include          /^http:\/\/www\.#####hare\.com\/file\/\w+$/// @include          /^https?:\/\/(www\.)?storbit\.net\/file\/.+$/// @include          /^https?:\/\/(www\.)?spicyfile\.com\/\w+$/// @include          /^https?:\/\/streamin\.to\/.+$/// @include          /^https?:\/\/turbobit\.net\/\w+.*\.html.*$/// @include          /^https?:\/\/turb\.to\/\w+.*\.html$/// @include          /^https?:\/\/(www\.)?tusfiles\.net\/\w+$/// @include          /^https?:\/\/ubiqfile\.com\/\w+$/// @include          /^http:\/\/www\.unibytes\.com\/\w+-\w+$/// @include          /^https?:\/\/uploadboy\.(me|com)\/\w+\/?.*$/// @include          /^https?:\/\/uploaded\.(net|to)\/file\/.+$/// @include          /^https?:\/\/ul\.to\/.+$/// @include          /^https?:\/\/uploadgig\.com\/file\/download\/\w+\/?.*$/// @include          /^http:\/\/uploading\.com\/\w+\/?.*$/// @include          /^http:\/\/(www\.)?uploading\.site\/\w+.*$/// @include          /^http:\/\/uploadrocket\.net\/\w+(\/|\w|-|\.)+(\.html)?$/// @include          /^https?:\/\/uptobox.com\/\w+(\/.*)?$/// @include          /^https?:\/\/userscloud\.com\/\w+.*$/// @include          /^https?:\/\/vidto\.me\/\w+\.?\w*$/// @include          /^https?:\/\/vidlox\.me\/\w+.*$/// @include          /^https?:\/\/vidoza\.org\/\w+.*$/// @include          /^https:\/\/(\w+.)?vishare.pl\/\w{10,}\/.*$/// @include          /^https?:\/\/www\.wdupload\.com\/file\/\w+\/?.*$/// @include          /^https?:\/\/worldbytez\.com\/\w+$/// @include          /^https?:\/\/wrzucajpliki\.pl\/\w{0,6}.*$/// @include          /^https?:\/\/(www\.)?xubster\.com\/\w+\/?.*$/// @include          /^https?:\/\/www\.youtube\.com\/watch(\?v=|\/).+$/// @include          /^https?:\/\/www\d*\.zippyshare\.com\/v\/\w+\/file\.html$/// @require          https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js// @require          https://greasyfork.org/scripts/13883-aes-js/code/aesjs.js// @grant            GM.registerMenuCommand// @grant            unsafeWindow// @grant            GM_setClipboard// @grant            GM.xmlHttpRequest// @grant            GM.openInTab// @grant            GM.setClipboard// @grant            GM.setValue// @grant            GM.getValue// @grant            GM.deleteValue// @grant            GM.listValues// ==/UserScript==/* globals confirm, alert, GM, unsafeWindow, $, atob, slowAES, cloneInto *//* eslint standard/no-callback-literal: 0 */(async function () {'use strict'// And to keep for myself whatever I may find? - Certainly. For yourself, and any friends you want to share with you.// This program inserts a download link on One-Click-Hosters and a few folder services.// If you click on the button, the current website address (or the links on the relink website) will be sent to nopremium.pl and you'll receive a nopremium.pl download link.//// Standard actions for the button are// * left mouse click:                      copy the link to the clipboard// * middle/wheel click:                    start download of the link// * right mouse click:                     open the nopremium.pl website and insert the link in the text box// * hovering the mouse over the button:    open a menu with all the above option//const scriptName = 'Multi-OCH Helper'const scriptReferer = 'multiochhelper'const scriptHightligherName = 'Multi-OCH Helper Highlight links'const chrome = ~navigator.userAgent.indexOf('Chrome')const greasemonkey = 'info' in GM && 'scriptHandler' in GM.info && GM.info.scriptHandler === 'Greasemonkey'const config = {position: [['bottom', 'top'], ['left', 'right']],position_desc: ['vertical', 'horizontal'],position_quest: 'Position of the Button. If you use "' + scriptHightligherName + '" this has to be set to bottom left',leftClick: ['clipboard', 'download', 'showLinks', 'openWebsite', 'menu', 'sendToJD', 'none'],leftClick_desc: ['Copy link to clipboard', 'Direct download', 'Show links like on website', 'Open the multihoster website', 'Show the extended menu', 'Send links to JDownloader', 'Do nothing'],leftClick_quest: 'Action on left mouse click on button',middleClick: ['download', 'clipboard', 'showLinks', 'openWebsite', 'menu', 'sendToJD', 'none'],middleClick_desc: ['Direct download', 'Copy link to clipboard', 'Show links like on website', 'Open the multihoster website', 'Show the extended menu', 'Send links to JDownloader', 'Do nothing'],middleClick_quest: 'Action on middle mouse/wheel click on button',rightClick: ['openWebsite', 'clipboard', 'showLinks', 'download', 'menu', 'sendToJD', 'none'],rightClick_desc: ['Show links like on website', 'Copy link to clipboard', 'Direct download', 'Open the multihoster website', 'Show the extended menu', 'Send links to JDownloader', 'Do nothing'],rightClick_quest: 'Action on right mouse click on button',mouseOver: ['menu', 'clipboard', 'download', 'showLinks', 'openWebsite', 'sendToJD', 'none'],mouseOver_desc: ['Show the extended menu', 'Copy link to clipboard', 'Direct download', 'Show links like on website', 'Open the multihoster website', 'Send links to JDownloader', 'Do nothing'],mouseOver_quest: 'Action on mouse hover over button',mouseOverDelay: 'int',mouseOverDelay_range: [0, 700, 3000],mouseOverDelay_quest: 'Mouse hover time before action is executed.',mouseOverDelay_suffix: 'milliseconds',newTab: 'bool',newTab_desc: ['Open in a new tab', 'Open in the same window'],newTab_quest: 'Should websites be opened in a new tab?',updateHosterStatusInterval: 'int',updateHosterStatusInterval_range: [1, 168, 9999],updateHosterStatusInterval_quest: 'How often should the status of the hosters be updated?',updateHosterStatusInterval_prefix: 'Every',updateHosterStatusInterval_suffix: 'hours',jDownloaderSupport: 'bool',jDownloaderSupport_desc: ['Show JDownloader button if JDownloader is runnning', 'Never show JDownloader button'],jDownloaderSupport_quest: ['Show a JDownloader button in the menu?']}const settings = {}// Load settingsconst savedsettings = JSON.parse(await GM.getValue('settings', '{}')) // e.g. {  position : [0,1], newTab : 1  }for (const key in config) {if (key in savedsettings) { // Savedif (config[key] === 'int') { // Intsettings[key] = parseInt(savedsettings[key], 10)} else if (config[key] === 'string') { // Stringsettings[key] = savedsettings[key].toString()} else if (config[key] === 'bool') { // Boolsettings[key] = (savedsettings[key] === 'true' || savedsettings[key] === true)} else if (Array.isArray(config[key][0])) { // Nested arrayif (!Array.isArray(savedsettings[key])) {try {const tmp = JSON.parse(savedsettings[key])if (Array.isArray(tmp)) {savedsettings[key] = tmp}} catch (e) {}}settings[key] = []for (let i = 0; i < savedsettings[key].length; i++) {settings[key].push(savedsettings[key][i])}} else { // Arraysettings[key] = savedsettings[key]}} else { // Defaultif (config[key] === 'int') { // Intsettings[key] = config[key + '_range'][1]} else if (config[key] === 'string') { // Stringsettings[key] = '' // String defaults to empty string} else if (config[key] === 'bool') { // Boolsettings[key] = true} else if (Array.isArray(config[key][0])) { // Nested array defaults to first value for each arraysettings[key] = []for (let i = 0; i < config[key].length; i++) {settings[key].push(config[key][i][0])}} else {settings[key] = config[key][0] // Array defaults to first value}}}const JDOWNLOADER = 'http://127.0.0.1:9666/'const SHAREBIZ_CNL2_URL = 'http://share-links.biz/get/cnl2/'const SHAREBIZ_RSDF_URL = 'http://share-links.biz/get/rsdf/'const SHAREBIZ_DLC_URL = 'http://share-links.biz/get/dlc/'const DCRYPTIT_UPLOAD_URL = 'http://dcrypt.it/decrypt/upload'const DCRYPTIT_CONTAINERLINK_URL = 'http://dcrypt.it/decrypt/container'const POSATIV_URL = 'http://posativ.org/decrypt/rsdf'const RELINKUS_GETFILE = 'http://www.relink.us/frame.php?'const SPINNERCSS = `/* http://www.designcouch.com/home/why/2013/05/23/dead-simple-pure-css-loading-spinner/ */.ochspinner {height:16px;width:16px;margin:0px auto;position:relative;animation: rotation .6s infinite linear;border-left:6px solid rgba(0,174,239,.15);border-right:6px solid rgba(0,174,239,.15);border-bottom:6px solid rgba(0,174,239,.15);border-top:6px solid rgba(0,174,239,.8);border-radius:100%;}@keyframes rotation {from {transform: rotate(0deg)}to {transform: rotate(359deg)}}`// const LOADINGBARBG = 'background: #b4e391;background: linear-gradient(to bottom, #b4e391 0%,#61c419 50%,#b4e391 100%);'var showOneclickButton = falsevar showOneclickLink = ''var showOneclickFromHighlighScriptAllLinks = document.location.host === 'cvzi.github.io'var showOneclickFromHighlighScriptAllLinksLoc = falsevar showOneclickFromHighlighScriptAllLinksLinks = ''var showOneclickFromHighlighScriptSelectedLinks = falsevar showOneclickFromHighlighScriptSelectedLinksLoc = falsevar showOneclickFromHighlighScriptSelectedLinksLinks = ''var linksBeforeSelection = falseconst multi = {'premiumize.me': new function () {const self = thisthis.config = {apikey: 'string',apikey_hidden: true,apikey_quest: 'Enter your premiumize.me API key',apikey_prefix: 'API key: ',apikey_suffix: ' find it under <a target="_blank" href="https://www.premiumize.me/account">https://www.premiumize.me/account</a>'}this.key = 'premiumize.me'this.name = 'premiumize'this.homepage = 'https://www.premiumize.me/'// this.updateStatusURL = 'https://www.premiumize.me/services';this.updateStatusURLpattern = /https:\/\/www\.premiumize\.me\/services\/?/this.updateDownloadProgressInterval = 5000this.updateDownloadProgressInterfaceInterval = 500this.status = {}this.init = async function () {self.status = JSON.parse(await GM.getValue(self.key + '_status', '{}'))self.lastUpdate = new Date(await GM.getValue(self.key + '_status_time', 0))}this.settings = {}this.loadSettings = async function (silent) {// Load settings, use first value as defaultconst savedsettings = JSON.parse(await GM.getValue(self.key + '_settings', '{}'))for (const key in self.config) {if (key.endsWith('desc') || key.endsWith('range') || key.endsWith('quest') || key.endsWith('prefix') || key.endsWith('suffix')) {continue}if (key in savedsettings) { // Savedif (self.config[key] === 'int') { // Intself.settings[key] = parseInt(savedsettings[key], 10)} else if (self.config[key] === 'string') { // Stringself.settings[key] = savedsettings[key].toString()} else if (config[key] === 'bool') { // Boolself.settings[key] = savedsettings[key] === 'true' || savedsettings[key] === true} else if (Array.isArray(savedsettings[key])) { // Nested arrayself.settings[key] = []for (let i = 0; i < savedsettings[key].length; i++) {self.settings[key].push(savedsettings[key][i])}} else { // Arrayself.settings[key] = savedsettings[key]}} else { // Defaultif (self.config[key] === 'int') { // Intself.settings[key] = self.config[key + '_range'][1]} else if (self.config[key] === 'string') { // Stringself.settings[key] = '' // String defaults to empty string} else if (config[key] === 'bool') { // Boolself.settings[key] = true} else if (Array.isArray(self.config[key][0])) { // Nested array defaults to first value for each arrayself.settings[key] = []for (let i = 0; i < self.config[key].length; i++) {self.settings[key].push(self.config[key][i][0])}} else {self.settings[key] = self.config[key][0] // Array defaults to first value}}}if (!self.settings.apikey && !silent) {// Try to get the apikey from the websiteGM.xmlHttpRequest({method: 'GET',url: self.homepage + 'account',onerror: function (response) {console.log(scriptName + ': premiumize.me API Key could not be loaded')setStatus('You have not set you premiumize.me Api key ')},onload: function (response) {let s = ''try {s = response.responseText.split('class="apipass"')[1].split('</')[0].split('>')[1]} catch (e) {}if (s) {self.settings.apikey = sGM.setValue(self.key + '_settings', JSON.stringify(self.settings))console.log(scriptName + ': premiumize.me API Key was loaded from account and saved!')} else {setStatus('You need to set you premiumize.me Api key')}}})}}this.updateStatus = async function () { // Update list of online hostersawait self.loadSettings()if (document.location.href.match(self.updateStatusURL)) {// Read and save current status of all hostersif ($('table.table tr>td:first-child').length) {self.status = {}await GM.setValue(self.key + '_status_time', '' + (new Date()))$('table.table tr>td:first-child').each(function () {const text = $(this).text()if (text.match(/^\s*[0-9a-z-]+\.\w{0,6}\s*$/i)) {const name = text.match(/^\s*([0-9a-z-]+)\.\w{0,6}\s*$/i)[1]self.status[name.toLowerCase()] = true}})await GM.setValue(self.key + '_status', JSON.stringify(self.status))console.log(scriptName + ': ' + self.name + ': Hosters (' + Object.keys(self.status).length + ') updated')} else if (self.settings.apikey) {GM.xmlHttpRequest({method: 'GET',url: self.homepage + 'api/services/list?apikey=' + encodeURIComponent(self.settings.apikey),onerror: function (response) {console.log(scriptName + ': GM.xmlHttpRequest error: ' + self.homepage + 'api/services/list')console.log(response)},onload: async function (response) {const r###lt = JSON.parse(response.responseText)/*{ "cache": [ "uploaded.to", "filefactory.com", ... ], "directdl": [ "uploaded.to", "filefactory.com", ... ] }*/if ('cache' in r###lt && 'directdl' in r###lt) {self.status = {}await GM.setValue(self.key + '_status_time', '' + (new Date()))r###lt.cache.forEach(function (host) {const name = host.match(/^\s*([0-9a-z-]+)\.\w{0,6}\s*$/i)[1]self.status[name.toLowerCase()] = r###lt.directdl.indexOf(host) !== -1})await GM.setValue(self.key + '_status', JSON.stringify(self.status))console.log(scriptName + ': ' + self.name + ': Hosters (' + Object.keys(self.status).length + ') updated')} else {console.log(scriptName + ': GM.xmlHttpRequest error: ' + self.homepage + 'api/services/list')console.log(response)}}})} else {console.log(scriptName + ': Cannot update hosters, no html and no api key found')}} else {alert(scriptName + '\n\nError: wrong update URL')}}this.isOnline = hostername => hostername in self.status && self.status[hostername]this.getOpenWebsiteURL = function (urls) {// Return a link to the premiumize.me website that will insert the linksconst url = this.homepage + 'downloader?link:' + encodeURIComponent(urls.join('\n'))return url}this.checkLink = function (url, cb) { // check whether the link is supported and onlineconst host = url.match(/https?:\/\/(.+?)\//)[1]let hoster = host.split('.')hoster.pop()hoster = hoster.pop().replace('-', '')cb(this.isOnline(hoster))}this.getR###lts = function (urls, cb) {// cb($node,linkNumber) -- $node contains the r###lt, linkNumber is the number of links that should be online i.e. number of hashesalert('This function does not work for ' + this.name)}this._notLoggedIn = falsethis.getLinks = async function (urls, cb) {await showConfirm('fairPointsWarning', 'You will be charged premiumize fair points for generating ' + (urls.length > 1 ? ('<b>' + urls.length + '</b> files') : ('<b>one</b> file')) + '!<br><br>Generate links?', function () { self._getLinks(urls, cb) }, function () { setStatus('Operation canceled!', 0); cb([], -1) }, self)}this._getLinks = function (urls, cb) {setTitle('✈️' + urls.length + '🔗 ')const N = urls.lengthconst downloadLinks = []const errors = []for (let i = 0; i < urls.length; i++) {this._addSingleTransfer(urls[i], function (downloadlink, originallink, message) {if (downloadlink) {downloadLinks.push(downloadlink)} else {errors.push([originallink, message])}})}const checkprogress = function () {if (self._notLoggedIn) {// Stop checking and open premiumize homepagesetTitle('🔑 ')setStatus(self.name + ' error: Not logged in!\nMaybe update your API key?', 0)GM.openInTab(self.homepage)cb([], -2)return}if (N === errors.length) { // All errorssetTitle('❌ ')cb(false, -1)if (errors.length === 1 && errors[0][1]) {setStatus(errors[0][1], 0)} else {alert('Errors occured\n' + errors.length + ' links failed:\n\n' + errors.join('\n'))}} else if (N === downloadLinks.length + errors.length) { // All finishedsetTitle(downloadLinks.length + '/' + errors.length + '✅ ')cb(downloadLinks)if (errors.length > 0) { // Errors occuredalert('Errors occured\n' + errors.length + ' links failed:\n\n' + errors.join('\n'))}} else { // not finished yetsetTitle(downloadLinks.length + '/' + N + '⏳ ')window.setTimeout(checkprogress, self.updateDownloadProgressInterfaceInterval)}}window.setTimeout(checkprogress, self.updateDownloadProgressInterfaceInterval * Math.max(5, N))}this._addSingleTransfer = function (url, cb) {GM.xmlHttpRequest({method: 'POST',url: self.homepage + 'api/transfer/create',data: 'apikey=' + encodeURIComponent(self.settings.apikey) + '&src=' + encodeURIComponent(url),headers: {'Content-Type': 'application/x-www-form-urlencoded','Cache-Control': 'no-cache'},onerror: function (response) {console.log(scriptName + ': GM.xmlHttpRequest error: ' + self.homepage + 'api/transfer/create')console.log(response)cb(false, url, 'GM.xmlHttpRequest error: api/transfer/create')},onload: function (response) {const r###lt = JSON.parse(response.responseText)/*{"status":"success","type":"savetocloud","id":"gfwRtdgd5fgdfgfhgfhf","name":"test.zip"}{"status":"error","error":"duplicate","id":"gfdgd5fgFddfgfhgfhf","message":"You already have this job added."}{"status":"error","message":"This link is not available on the file hoster website"}*/if ('id' in r###lt && r###lt.id) {window.setTimeout(function () {self._getFileFromTransfer(url, r###lt.id, cb)}, 1000)if ('message' in r###lt) {addStatus(r###lt.message, -1)}} else {if ('message' in r###lt && !self._notLoggedIn) {addStatus(r###lt.message, -1)if (~r###lt.message.indexOf('log')) {self._notLoggedIn = true}}cb(false, url, 'message' in r###lt ? r###lt.message : response.responseText)}}})}this._getFileFromTransfer = function (url, transferId, cb) {GM.xmlHttpRequest({method: 'GET',url: self.homepage + 'api/transfer/list?apikey=' + encodeURIComponent(self.settings.apikey),headers: {'Content-Type': 'application/x-www-form-urlencoded','Cache-Control': 'no-cache'},onerror: function (response) {console.log(scriptName + ': GM.xmlHttpRequest error: ' + self.homepage + 'api/transfer/list')console.log(response)cb(false, url, 'GM.xmlHttpRequest error: /api/transfer/list')},onload: function (response) {const r###lt = JSON.parse(response.responseText)/*{"status": "success","transfers": [{"id": "xXFDSXXFDSGD","name": "test.zip","message": null,"status": "finished","progress": 0,"folder_id": "gfjdfsuigjfdoikfsadf","file_id": "trhgf982u30fjklfsdag"}]}{"status": "success","transfers": [{"id":"xXFDSXXFDSGD","name":"test.zip","message":"Initializing Download...","status":"running","progress":0,"folder_id":"gfjdfsuigjfdoikfsadf","file_id":null}]}*/if (r###lt.status === 'success' && 'transfers' in r###lt) {for (let i = 0; i < r###lt.transfers.length; i++) {if (r###lt.transfers[i].id === transferId) {if (r###lt.transfers[i].file_id) {// Finishedwindow.setTimeout(function () {self._getSingleLink(url, r###lt.transfers[i].file_id, cb)}, r###lt.transfers[i].status === 'finished' ? 10 : self.updateDownloadProgressInterval)} else {// Downloadingif ('message' in r###lt.transfers[i] && r###lt.transfers[i].message) {setStatus(r###lt.transfers[i].message, -1)}window.setTimeout(function () {self._getFileFromTransfer(url, transferId, cb)}, self.updateDownloadProgressInterval)}return}}}if ('message' in r###lt && r###lt.message) {alert(scriptName + '\n\nCould not get /api/transfer/list\nError:\n' + r###lt.message)}cb(false, url, 'Could not find url in transfer list')}})}this._getSingleLink = function (url, fileId, cb) {GM.xmlHttpRequest({method: 'POST',url: self.homepage + 'api/item/details',data: 'apikey=' + encodeURIComponent(self.settings.apikey) + '&id=' + encodeURIComponent(fileId),headers: {'Content-Type': 'application/x-www-form-urlencoded','Cache-Control': 'no-cache'},onerror: function (response) {console.log(scriptName + ': GM.xmlHttpRequest error: ' + self.homepage + 'api/item/details')console.log(response)cb(false, url, 'GM.xmlHttpRequest error: /api/item/details')},onload: function (response) {const r###lt = JSON.parse(response.responseText)/*{"id": "xxXxXxxxXxxx","name": "test.zip","size": 156,"created_at": 1572458477,"transcode_status": "not_applicable","folder_id": "XxXXXxxxxxx","ip": "1.1.1.1","acodec": "","vcodec": "","mime_type": "application/zip","opensubtitles_hash": "","resx": "","resy": "","duration": "","virus_scan": "ok","type": "file","link": "https://down.host.example.com/dl/abcdefg/test.zip","stream_link": null}*/if ('link' in r###lt && r###lt.link) {cb(r###lt.link, url)} else {window.setTimeout(function () {self._getSingleLink(url, fileId, cb)}, self.updateDownloadProgressInterval)}}})}}(),'nopremium.pl': new function () {const self = thisthis.config = {mode: ['transfer', 'premium', 'none'],mode_desc: ['Transfer User (Pakiety Transferowe)', 'Premium User (Konta Premium)', 'No account'],mode_quest: 'What kind of account do you have at nopremium.pl',downloadmode: ['direct', 'server'],downloadmode_desc: ['Direct download (TRYB SZYBKIEGO POBIERANIA)', 'Downloading via NoPremium.pl server (TRYB POBIERANIA NA SERWERY)'],downloadmode_quest: ['Which download mode do you want to use?']}this.key = 'nopremium.pl'this.name = 'NoPremium.pl'this.homepage = 'https://www.nopremium.pl/'this.updateStatusURL = 'https://www.nopremium.pl/files'this.updateStatusURLpattern = /https?:\/\/www\.nopremium\.pl\/files\/?/this.updateDownloadProgressInterval = 5000const mapHosterName = name => name.replace('-', '')this.status = {}this.init = async function () {self.status = JSON.parse(await GM.getValue(self.key + '_status', '{}'))self.lastUpdate = new Date(await GM.getValue(self.key + '_status_time', 0))}this.settings = {}this.loadSettings = async function (silent) {// Load settings, use first value as defaultconst savedsettings = JSON.parse(await GM.getValue(self.key + '_settings', '{}'))for (const key in self.config) {if (key.endsWith('desc') || key.endsWith('range') || key.endsWith('quest') || key.endsWith('prefix') || key.endsWith('suffix')) {continue}if (key in savedsettings) { // Savedif (self.config[key] === 'int') { // Intself.settings[key] = parseInt(savedsettings[key], 10)} else if (self.config[key] === 'string') { // Stringself.settings[key] = savedsettings[key].toString()} else if (config[key] === 'bool') { // Boolself.settings[key] = savedsettings[key] === 'true' || savedsettings[key] === true} else if (Array.isArray(savedsettings[key])) { // Nested arrayself.settings[key] = []for (let i = 0; i < savedsettings[key].length; i++) {self.settings[key].push(savedsettings[key][i])}} else { // Arrayself.settings[key] = savedsettings[key]}} else { // Defaultif (self.config[key] === 'int') { // Intself.settings[key] = self.config[key + '_range'][1]} else if (self.config[key] === 'string') { // Stringself.settings[key] = '' // String defaults to empty string} else if (config[key] === 'bool') { // Boolself.settings[key] = true} else if (Array.isArray(self.config[key][0])) { // Nested array defaults to first value for each arrayself.settings[key] = []for (let i = 0; i < self.config[key].length; i++) {self.settings[key].push(self.config[key][i][0])}} else {self.settings[key] = self.config[key][0] // Array defaults to first value}}}}this.updateStatus = async function () { // Update list of online hostersif (document.location.href.match(self.updateStatusURL)) {// Read and save current status of all hostersawait GM.setValue(self.key + '_status_time', '' + (new Date()))self.status = {}$('#servers a[title]').each(function () {const name = mapHosterName(this.title)self.status[name] = true})await GM.setValue(self.key + '_status', JSON.stringify(self.status))console.log(scriptName + ': ' + self.name + ': Hosters (' + Object.keys(self.status).length + ') updated')} else {alert(scriptName + '\n\nError: wrong update URL')}}this.isOnline = hostername => hostername in self.status && self.status[hostername]this.getOpenWebsiteURL = function (urls) {// Return a link to the nopremium.pl website that will insert the linksconst url = this.homepage + 'files?link:' + encodeURIComponent(urls.join('\n'))return url}const getHashs = function (urls, cb, silent) {// cb(hashes,sizestring)setTitle('✈️ ')setStatus('Sending ' + (urls.length === 1 ? 'one link' : (urls.length + ' links')), -1)GM.xmlHttpRequest({method: 'POST',url: self.homepage + 'files',data: 'watchonline=&session=' + (Math.round(Math.random() * 1234567)) + '&links=' + encodeURIComponent(urls.join('\n')),headers: {'Content-Type': 'application/x-www-form-urlencoded','Cache-Control': 'no-cache'// "Referer" : "https://www.nopremium.pl/files" // FIREFOX57},onload: function (response) {if (response.responseText.indexOf('<input type="text" name="login" placeholder="Login"/>') !== -1) {setTitle('🔑 ')setStatus(self.name + ' error: Not logged in!', 0)GM.openInTab(self.homepage)return cb([], -1)}const hashes = []// Find hashesconst re = /name="hash(\d+)" value="(\w+)"/g // <input type="checkbox" id="hash0" name="hash0" value="fab3c41988" onclick="UpdateCounter();" clet ma = re.exec(response.responseText)while (ma) {hashes.push(ma[2])ma = re.exec(response.responseText)}// Find errorsma = response.responseText.match(/Pliki nieprzetworzone \((\d+)\)/)if (ma && !silent) {addStatus('Error: ' + (parseInt(ma[1], 10) === 1 ? ('One file is offline or unsupported') : (ma[1] + ' files are offline or unsupported')), 0)}// Find sizelet size = '0 Byte'if (response.responseText.indexOf('id="countSize"') !== -1) {ma = response.responseText.split('id="countSize"')[1].match(/value="(\d+.?\d*) (\w+)"/) // <input type="text" name="countSize" id="countSize" style="width:80px;" readonly="readonly" value="1.38 GB">size = ma[1] + ' ' + ma[2]}setStatus(self.name + ' identified ' + (hashes.length === 1 ? 'one online file' : (hashes.length + ' online files')), -1)setTitle(hashes.length + '🔗 ')cb(hashes, size)}})}this.checkLink = function (url, cb) { // check whether the link is supported and online// cb(boolr###lt)return getHashs([url], function (hashes, size) {cb(hashes.length === 1)}, true)}this.getR###lts = function (urls, cb, hashes) {// cb($node,linkNumber) -- $node contains the r###lt, linkNumber is the number of links that should be online i.e. number of hashes// Get download links from nopremium.pl and show the usual info about the file, that is normally shown on nopremium.plif (typeof hashes === 'undefined') {// 1. Get hashes and show transfer warninggetHashs(urls, async function (hashes, size) {if (settings.mode === 'transfer') {await showConfirm('transferWarning', 'You will be charged <b>' + size + "</b> 'Transfer' for generating " + (hashes.length > 1 ? ('<b>' + hashes.length + '</b> files') : ('<b>one</b> file')) + '!<br><br>Generate links?', function () { this.getR###lts(urls, cb, hashes) }, null, self)} else if (hashes.length > 0) {self.getR###lts(urls, cb, hashes)} else if (size === -1) { // Error was already handled (probably not logged in)console.log('getHashs->cb: Error was already handled (probably not logged in)')cb(false, -2)} else { // No files foundsetStatus('No online/available files', 0)cb(false, 0)}})return}// 2. Work with hashesconst $r###ltContainer = $('<div></div>').attr('id', 'generated-links')const mode = self.settings.downloadmode === 'direct' ? 0 : 1 // 0 -> direct , 1  ->  via serverGM.xmlHttpRequest({method: 'POST',url: self.homepage + 'files',data: 'insert=1&mode=' + mode + '&hh=0&hash[]=' + hashes.join('&hash[]=') + '&',headers: {'Content-Type': 'application/x-www-form-urlencoded','Cache-Control': 'no-cache'// "Referer" : "https://www.nopremium.pl/files"  // FIREFOX57},onload: function (response) {GM.xmlHttpRequest({method: 'POST',url: self.homepage + 'files',data: 'loadfiles=1',headers: {'Content-Type': 'application/x-www-form-urlencoded','Cache-Control': 'no-cache'// "Referer" : "https://www.nopremium.pl/files"  // FIREFOX57},onload: function (response) {if (mode === 0) {$r###ltContainer.append($('<div></div>').append(response.responseText).find('#fastFilesArea'))} else {$r###ltContainer.append($('<div></div>').append(response.responseText).find('#downloadFilesArea'))}$r###ltContainer.find('input[type=checkbox]').remove()cb($r###ltContainer, hashes.length)}})}})}this.getLinks = function (urls, cb) {// cb(downloadlinks)if (this.settings.downloadmode === 'direct') {return this._getDirectLinks(urls, cb)} else {return this._getServerLinks(urls, cb)}}this._getDirectLinks = function (urls, cb) {// Get Direct download linksthis.getR###lts(urls, async function ($node, N) {if (!$node || N < 1) {cb(false)return}const text = $node.html()/*<td>16-08-2014 20:22</td><td class="dlBox"><a href="http://direct.nopremium.pl/9091456/7895ca02bfcb2c2e43806f1079b7ff069129e/r###lt.file"><img src="https://www.nopremium.pl/images/download_ico.png" alt="Sciagnij" title="Sciagnij"></a></td>*/const files = []const re = /<td>(\d+)-(\d+)-(\d+) (\d+):(\d+)<\/td>(\s|\n)+<td class="dlBox"><a href="(.*?)"/gmlet m = re.exec(text) // wholeString, 16,08,2014,20,37,#newline#,http://direct.nopremium.pl/9091456/7895ca02bfcb2c2e43806f1079b7ff069129e/r###lt.filewhile (m) {if (m[7].indexOf('//direct.nopremium.pl') === -1) {continue // Skip files via server, only use direct download links}const d = new Date(m[3], m[2], m[1], m[4], m[5], 0, 0)files.push([d, m[7]])m = re.exec(text)}if (files.length === 0) {alert(scriptName + '\n\nAn error occured.\nCould not find download links in response.')cb(false)return}// Find youngest files by comparing their idsconst pattern = /\.pl\/(\d+)\//files.sort(function (a, b) {const x = a[1].match(pattern)[1]const y = a[1].match(pattern)[1]return x > y ? -1 : x < y ? 1 : 0})const r###lt = []for (let i = 0; i < N; i++) {r###lt.push(files[i][1])await cacheLink([urls[i]], files[i][0], [files[i][1]], self.key) // CACHE single URLs}await cacheLink(urls, new Date(), r###lt, self.key) // CACHE all URLscb(r###lt)})}this._getServerLinks = function (urls, cb) {this.getR###lts(urls, function ($node, N) {if (N === 0) {cb(false)} else {self._getProgress(cb, $node, N)}})}this._getProgress = function (cb, $node, N, ids) {GM.xmlHttpRequest({method: 'POST',url: self.homepage + 'files',data: 'downloadprogress=1',headers: {'Content-Type': 'application/x-www-form-urlencoded','Cache-Control': 'no-cache'// "Referer" : "https://www.nopremium.pl/files" // FIREFOX57},onerror: function () {self._getProgressBlocked = falsewindow.setTimeout(function () {self._getProgress(cb, $node, N, ids)}, self.updateDownloadProgressInterval)},onload: function (response) {self._getProgressBlocked = falselet datatry {data = JSON.parse(response.responseText)} catch (e) {console.log(scriptName + ': ' + e)console.log(response.responseText)if (response.responseText.indexOf('<input type="text" name="login" placeholder="Login"/>') !== -1) {setTitle('🔑 ')setStatus(self.name + ' error: Not logged in!', 0)GM.openInTab(self.homepage)cb(false, -2)} else {window.setTimeout(function () {self._getProgress(cb, $node, N, ids)}, self.updateDownloadProgressInterval)}return}data.StandardFiles.sort(function (a, b) {const x = new Date(a.insert_date.split('-').join('/'))const y = new Date(b.insert_date.split('-').join('/'))return x > y ? -1 : x < y ? 1 : 0})const r###lt = []const runnning = []let percent = 0const progess = []if (!ids) { // First run: Find the correct files: just use the first N filesids = []for (let i = 0; i < data.StandardFiles.length && i < N; i++) {ids.push(data.StandardFiles[i].id)if (data.StandardFiles[i].status === 'finish') {r###lt.push(data.StandardFiles[i].download_url)progess.push(100)percent += 100} else {runnning.push(data.StandardFiles[i])if (parseInt(data.StandardFiles[i].status, 10) > 0) {progess.push(parseInt(data.StandardFiles[i].status, 10))percent += parseInt(data.StandardFiles[i].status, 10)}}}} else { // Consecutive runs: Use the ids from first runfor (let i = 0; i < data.StandardFiles.length; i++) {if (ids.indexOf(data.StandardFiles[i].id) === -1) continueif (data.StandardFiles[i].status === 'finish') {r###lt.push(data.StandardFiles[i].download_url)progess.push(100)percent += 100} else {runnning.push(data.StandardFiles[i])if (parseInt(data.StandardFiles[i].status, 10) > 0) {progess.push(parseInt(data.StandardFiles[i].status, 10))percent += parseInt(data.StandardFiles[i].status, 10)}}}}/*Regarding caching in server mode:If you add a file, that is already on the server (or currently downloading), you will not be charged additional bandwith - therefore caching is not necessary at the moment.*/if (r###lt.length === N) {setStatus((r###lt.length === 1 ? 'One file' : (r###lt.length + ' files')) + ' downloaded to server', 1)setTitle(r###lt.length + '✅ ')cb(r###lt)} else {// Waitingpercent = percent / N// setStatus('Download '+r###lt.length+'/'+N+' ('+Math.floor(percent)+'%)\n<span title="'+round(percent,2)+'%" style="display:block; width:120px; height:18px; background:white; border:1px solid black; border-radius:5px;"><span style="display:block; border-radius:5px; height:18px; width:'+Math.ceil(percent*1.2)+'px; '+LOADINGBARBG+'"> </span></span>',-1);const dotheight = N > 2 ? 2 : 4let h = 'Download ' + r###lt.length + '/' + N + ' (' + Math.floor(percent) + '%)\n<div style="display:block; width:130px; height:auto; background:white; border:1px solid black; border-radius:5px; padding:2px; ">'for (let i = 0; i < N; i++) {if (progess[i]) {h += '<span style="display:block; width:' + Math.ceil(progess[i] * 1.2) + 'px; height:1px; background:white; border-top:' + dotheight + 'px ' + (progess[i] > 99.9 ? 'solid' : 'dotted') + ' green; margin-bottom:1px;"></span>'} else {h += '<span style="display:block; width:0x; height:1px; background:white; border-top:' + dotheight + 'px dotted silver; margin-bottom:1px;"></span>'}}h += '</div>'setTitle(Math.floor(percent) + '%⏳ ')setStatus(h)showOnlyStatus()window.setTimeout(function () {self._getProgress(cb, $node, N, ids)}, self.updateDownloadProgressInterval)}}})}}()}const debridprovider = Object.keys(multi)var currentdebrid = await GM.getValue('currentdebrid', debridprovider[0])for (const key in multi) {await multi[key].init()if (key === currentdebrid) {await multi[key].loadSettings()continue}if(!greasemonkey) {GM.registerMenuCommand(scriptName+" - Switch to "+multi[key].name, (function(key) { return async function() {if(!confirm(scriptName+"\n\nSet multi-download provider:\n"+multi[key].name)) return;await GM.setValue("currentdebrid",key);currentdebrid = key;document.location.reload();}})(key))}}if(!greasemonkey) {GM.registerMenuCommand(scriptName+" - Delete cached links", async function() {if(!confirm(scriptName+"\n\nReally delete cached links?")) return;await GM.setValue("cachedDownloadLinks","{}")alert(scriptName+"\n\nCache is empty!");})GM.registerMenuCommand(scriptName+" - Restore dialogs and warnings", async function() {if(!confirm(scriptName+"\n\nReally restore all dialogs and warnings?")) return;await GM.setValue("dialogs","[]");alert(scriptName+"\n\nDialogs and warnings restored");})}/*function round (f, p) {// Round f to p places after the commareturn parseFloat(parseFloat(f).toFixed(p))}*/const orgDocumentTitle = document.titlefunction setTitle(message) {if (window.parent.parent !== window) {window.parent.parent.postMessage({ iAm: 'Unrestrict.li', type: 'title', str: message }, '*')}if (message) {document.title = message + orgDocumentTitle} else {document.title = orgDocumentTitle}}function popUp (id, onClose, thisArg, doNotCloseOnOutsideClick) {// Remove window scrolling$(document.body).css('overflow', 'hidden')let zi = getNextZIndex()id = id || ('popup' + (new Date()).getTime())const $par = $('<div style="position:absolute; top:0px;"></div>').attr('id', id).appendTo(document.body)const $background = $('<div style="position:fixed; top:0px; left:0px; right:0px; bottom:0px; background:black; opacity:0.5; z-index:' + (zi++) + '"></div>').appendTo($par)const $div = $('<div style="position:fixed; top:50px; left:100px; overflow:auto; z-index:' + (zi++) + '; background:#E6E6E6; color:Black; border:#B555C5 2px solid;border-radius:5px; padding:10px; font-family: "Ubuntu",Arial,Sans-Serif"></div>').css('maxHeight', window.innerHeight - 100).css('maxWidth', window.innerWidth - 200).appendTo($par)const close = function () {$par.remove()if (onClose) onClose.call(thisArg)// Restore scrolling$(document.body).css('overflow', 'initial')}if (!doNotCloseOnOutsideClick) {$background.click(close)}return { node: $div, close: close }}function configForm ($form, c, s, formid) {for (const key in c) {if (key.endsWith('desc') || key.endsWith('range') || key.endsWith('quest') || key.endsWith('prefix') || key.endsWith('suffix') || key.endsWith('hidden')) {continue}const $p = $('<p>').appendTo($form)if (c[key + '_quest']) {$p.append(c[key + '_quest'])} else {$p.append(key)}$p.append('<br>')if (c[key + '_prefix']) {$p.append(c[key + '_prefix'] + ' ')}const hidden = (key + '_hidden') in c && c[key + '_hidden']if (c[key] === 'int') { // Intconst $input = $('<input type="number">').addClass('form_' + formid).data('key', key).data('parse', 'int').val(s[key]).appendTo($p)if (c[key + '_range']) {$input.prop('min', c[key + '_range'][0])$input.prop('max', c[key + '_range'][2])$input.prop('title', c[key + '_range'][0] + ' - ' + c[key + '_range'][2])}} else if (c[key] === 'string') { // Stringconst $inputText = $('<input type="text">').addClass('form_' + formid).data('key', key).data('parse', 'string').appendTo($p)if (hidden && s[key]) {$inputText.val('## HIDDEN ##')$inputText.data('hidden', '1')} else {$inputText.val(s[key])}} else if (c[key] === 'bool') { // Boolconst $select = $('<select></select>').addClass('form_' + formid).data('key', key).data('parse', 'bool').appendTo($p)const $optionYes = $('<option></option>').val('true').appendTo($select)if (c[key + '_desc']) {$optionYes.html(c[key + '_desc'][0])} else {$optionYes.html('Yes')}if (s[key]) {$optionYes[0].selected = true}const $optionNo = $('<option></option>').val('false').appendTo($select)if (c[key + '_desc']) {$optionNo.html(c[key + '_desc'][1])} else {$optionNo.html('No')}if (!s[key]) {$optionNo[0].selected = true}} else if (Array.isArray(c[key][0])) { // Nested arrayfor (let j = 0; j < c[key].length; j++) {if (c[key + '_desc'] && !Array.isArray(c[key + '_desc'][j])) {$p.append(c[key + '_desc'][j] + ': ')}const $select = $('<select></select>').addClass('form_' + formid).data('key', key).data('index', j).appendTo($p)for (let i = 0; i < c[key][j].length; i++) {const $option = $('<option></option>').val(c[key][j][i]).appendTo($select)if (c[key + '_desc'] && Array.isArray(c[key + '_desc'][0])) {$option.html(c[key + '_desc'][j][i])} else {$option.html(c[key][j][i])}if (s[key][j] === c[key][j][i]) { $option[0].selected = true }}$p.append('<br>')}} else { // Arrayconst $select = $('<select></select>').addClass('form_' + formid).data('key', key).appendTo($p)for (let i = 0; i < c[key].length; i++) {const $option = $('<option></option>').val(c[key][i]).appendTo($select)if (c[key + '_desc']) {$option.html(c[key + '_desc'][i])} else {$option.html(c[key][i])}if (s[key] === c[key][i]) { $option[0].selected = true }}}if (c[key + '_suffix']) {$p.append(' ' + c[key + '_suffix'])}}}async function saveSettings (ev) {const $body = ev.dataconst $form = $body.find('.form')// Save preferred hoster:currentdebrid = $form.find('.debridhoster').val()// Save options:const newsettings = { general: {} }for (const key in multi) {newsettings[key] = {}}$form.find('*[class^=form_]').each(function () {const $this = $(this)const namespace = $this.prop('class').split('_', 2)[1]const key = $this.data('key')const index = $this.data('index')let value = $this.val()const parse = $this.data('parse')const hiddenAndUnchanged = $this.data('hidden') && value === '## HIDDEN ##'if (typeof index !== 'undefined') { // Nested Arrayif (!(key in newsettings[namespace]) || !Array.isArray(newsettings[namespace][key])) {newsettings[namespace][key] = []}newsettings[namespace][key][index] = value} else { // Normalif (hiddenAndUnchanged) {value = multi[namespace].settings[key]} else if (parse === 'int') {value = parseInt(value, 10)} else if (parse === 'bool') {value = (value === 'true')}newsettings[namespace][key] = value}})await GM.setValue('setup', true)await GM.setValue('currentdebrid', currentdebrid)await GM.setValue('settings', JSON.stringify(newsettings.general))for (const key in multi) {await GM.setValue(key + '_settings', JSON.stringify(newsettings[key]))}alert(scriptName + '\n\nSettings were successfully saved!')document.location.reload()}async function aboutMe () {const popup = popUp('multiochhelper_about', null, null, true)const $popup = popup.nodeconst $frame = $('<iframe width="' + (window.innerWidth - 250) + '" height="' + (window.innerHeight - 150) + '" style="border:0">').appendTo($popup)$frame.bind('load', async function (e) {// Load settings for allfor (const key in multi) {await multi[key].loadSettings(true)}const $body = $($frame[0].contentDocument.getElementsByTagName('body')[0])$body.css('fontFamily', 'Ubuntu,Arial,Sans-Serif')$('<div style="position:fixed; top:0px; right:5px; cursor:pointer; color:White; background:#b555c5; border: 1px solid White; border-radius:3px; padding:0px; font-weight:bold ; " title="Close menu">X</span>').click(function () { if (confirm('Settings will NOT be saved!')) popup.close() }).appendTo($body)$body.append('<h2>' + scriptName + '</h2>')$('<a>').appendTo($body).attr('target', '_blank').css('fontSize', 'small').html('https://openuserjs.org/scripts/cuzi/Multi-OCH_Helper').attr('href', 'https://openuserjs.org/scripts/cuzi/Multi-OCH_Helper')const $form = $('<div class="form">').appendTo($body)// General options$form.append('<h3>Settings</h3>')configForm($form, config, settings, 'general')// Preferred multihosterconst $p = $('<p>').appendTo($form)$p.append('Preferred multihoster:<br>')const $select = $('<select></select>').addClass('debridhoster').appendTo($p)for (const key in multi) {const $option = $('<option></option>').val(key).appendTo($select)$option.html(multi[key].name)$option[0].selected = key === currentdebrid}// Options for multihostersfor (const key in multi) {$('<h3>').appendTo($form).html(multi[key].name)$('<a>').appendTo($form).css('fontSize', 'small').attr('target', '_blank').html(multi[key].homepage).attr('href', multi[key].homepage)if (multi[key].config) {configForm($form, multi[key].config, multi[key].settings, key)} else {$('<p>').appendTo($form).text('No settings available for this service.')}}$form.append('<br>')$('<input type="button">').val('Cancel').click(function () {if (confirm('Settings will NOT be saved!')) {popup.close()}}).appendTo($form)$('<input type="button">').val('Save').click($body, saveSettings).appendTo($form)$form.append('<h3>Other options</h3>')$('<input type="button">').val('Clear cache (' + humanBytes((await GM.getValue('cachedDownloadLinks', '{}')).length - 2) + ')').appendTo($form).click(async function () {if (!confirm(scriptName + '\n\nReally delete cached links?')) {return}await GM.setValue('cachedDownloadLinks', '{}')this.value = 'Clear cache (' + humanBytes((await GM.getValue('cachedDownloadLinks', '{}')).length - 2) + ')'alert(scriptName + '\n\nCache is empty!')})$form.append('<br>')$form.append('<br>')$('<input type="button">').val('Restore dialogs and warnings').appendTo($form).click(async function () {if (!confirm(scriptName + '\n\nReally restore all dialogs and warnings?')) {return}await GM.setValue('dialogs', '[]')alert(scriptName + '\n\nDialogs and warnings restored')})let greasemonkeyIssue = ''if (greasemonkey) {greasemonkeyIssue = `<li>In Greasymonkey it is not possible to select multiple links with the mouse and send them at once.<br>The reason is this bug: <a href="https://github.com/greasemonkey/greasemonkey/issues/2574">https://github.com/greasemonkey/greasemonkey/issues/2574</a><br>If you need this functionality, you can use Tampermonkey instead of Greasemonkey</li>`}$(`<div><br><br><h3>Known issues:</h3><ul><li>nopremium.pl sometimes omits a few links in folders</li><li>In Firefox the script sometimes does not work if the "Accept thid-parts cookies" policy is set to "Never".<br>To resolve this problem open the Firefox options and go to the tab "Privacy". Set the "Accept thid-parts cookies" to "From visited" or "Always"<br>Close and re-open Firefox. Log out and then log in your nopremium.pl account. Everything should work fine now.</li>${greasemonkeyIssue}</ul><br>\<h3>dcrypt.it</h3>This script uses an unrelated, external service to decrypt *.dlc files:<br><a href="http://dcrypt.it/">http://dcrypt.it/</a>.</div><br><br><br>`).appendTo($body)$('<input type="button">').val('Debug info').appendTo($body).click(inspectGMvalues)})if (chrome) {$frame.attr('src', 'about:blank')}}function inspectGMvalues () {let ivconst popup = popUp('multiochhelper_inspectGM', function () {clearInterval(iv)})const $popup = popup.nodeconst $frame = $('<iframe width="' + (window.innerWidth - 250) + '" height="' + (window.innerHeight - 150) + '" style="border:0">').appendTo($popup)$frame.bind('load', async function (e) {$($frame[0].contentDocument.getElementsByTagName('head')[0]).append('<style type="text/css">' + SPINNERCSS + '</style>')const $body = $($frame[0].contentDocument.getElementsByTagName('body')[0])$body.append('<h2>' + scriptName + '</h2>')let keys = await GM.listValues()if (keys.length && typeof keys[0] === 'undefined') { // Firefox 35+ workaroundkeys = cloneInto(await GM.listValues(), window)}const $table = $('<table>').appendTo($body)let $tr$tr = $('<tr>').appendTo($table)$('<th>').html('Key').appendTo($tr)$('<th>').html('Value').appendTo($tr)$('<th>').html('Type').appendTo($tr)$('<th>').html('').appendTo($tr)const deleteValue = async function (ev) {const key = $(this).data('key')await GM.deleteValue(key)$(this).parent().parent().remove()}let total = 0for (let i = 0; i < keys.length; i++) {const value = await GM.getValue(keys[i])let svalue = '' + valuelet len = 1if (typeof value === 'undefined') {svalue = 'undefined'} else if (typeof value === 'string') {len = value.length}total += len$tr = $('<tr>').appendTo($table)$('<td>').html(keys[i]).appendTo($tr)$('<td>').append($('<input type="text" style="width:600px">').val(svalue)).appendTo($tr)$('<td>').append('' + (typeof value) + (typeof value === 'string' ? ('(' + len + ')') : '')).appendTo($tr)$('<td>').append($('<input type="button">').val('Delete').data('key', keys[i]).click(deleteValue)).appendTo($tr)}$tr = $('<tr>').appendTo($table)$('<th>').html('Total').appendTo($tr)$('<th>').html(keys.length).appendTo($tr)$('<th>').html('approx. ' + humanBytes(total)).appendTo($tr)const $reload = $('<div>').appendTo($body)$('<div style="display:inline-block;width:20px; height:20px;" class="ochspinner"></div>').appendTo($reload)$reload.append(' Reload in ')const $timer = $('<span style="pointer:cursor;" title="Click to reload now"></span>').html('20 seconds').click(function () { this.innerHTML = 0 }).appendTo($reload)iv = window.setInterval(function () {let s = parseInt($timer.html(), 10)if (s === 0) {clearInterval(iv)popup.close()inspectGMvalues()} else {s--$timer.html(s + ' seconds')}}, 1000)})if (chrome) {$frame.attr('src', 'about:blank')}}function hexToBytes (s) {return s.match(/([0-9a-fA-F]{2})/g).map(v => parseInt(v, 16))}function stringToBytes (s) {return s.split('').map(v => v.charCodeAt(0))}function bytesToString (a) {return String.fromCharCode.apply(String, a)}function addCSSHead (body) {const style = document.createElement('style')style.type = 'text/css'style.innerHTML = bodydocument.head.appendChild(style)}function humanBytes (bytes, precision) {// http://stackoverflow.com/a/18650828bytes = parseInt(bytes, 10)if (bytes === 0) return '0 Byte'const k = ####const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']const i = Math.floor(Math.log(bytes) / Math.log(k))return parseFloat((bytes / Math.pow(k, i)).toPrecision(2)) + ' ' + sizes[i]}function xmlHttpRequestBinary (obj) {const sep = '-----987564176415'let res = ''const bytestring = function (s) {for (let i = 0; i < s.length; i++) {const v = s.charCodeAt(i)if (v > 255) {console.log(scriptName + ': This is strange: ' + s[i] + ' => ' + v)} else {res += s[i]}}return res}const lines = []for (const name in obj.data) {if (Object.prototype.hasOwnProperty.call(obj.data, name)) {lines.push('--' + sep)let body = 'Content-Disposition: form-data; name="' + name + '"'let valueif (typeof (obj.data[name]) === 'object') {value = bytestring(obj.data[name].value)if (obj.data[name].filename) {body += '; filename="' + obj.data[name].filename + '"'}lines.push(body)lines.push('Content-type: application/force-download')} else {value = obj.data[name]lines.push(body)}lines.push('')lines.push(value)}}lines.push('--' + sep + '--')const newdata = lines.join('\r\n')obj.binary = trueobj.headers = {'Content-Type': 'multipart/form-data; boundary=' + sep,'Content-Length': newdata.length}obj.data = newdatareturn GM.xmlHttpRequest(obj)}function getNextZIndex () {// Calculate: max(zIndex) + 1let zIndexMax = 0try {$('div').each(function () {const z = parseInt($(this).css('z-index'), 10)if (z > zIndexMax) {zIndexMax = z}})} catch (e) {} finally {if (zIndexMax < 20000) {zIndexMax = 20006}}return zIndexMax + 1}async function showConfirm (id, text, onConfirm, onNotConfirm, thisArg) {// Skipconst dialogs = JSON.parse(await GM.getValue('dialogs', '[]'))if (dialogs.indexOf(id) !== -1) {onConfirm.call(thisArg)return}const popup = popUp('confirm' + id, function () {}, thisArg)const $div = popup.node$div.append(text)$div.append('<br>')$('<input type="button" value="Yes">').click(function () {popup.close()onConfirm.call(thisArg)}).appendTo($div)$('<input type="button" value="No">').click(function () {popup.close()if (onNotConfirm) {onNotConfirm.call(thisArg)}}).appendTo($div)$div.append('<br>')$('<input type="checkbox" value="remember">').click(async function () {const dialogs = JSON.parse(await GM.getValue('dialogs', '[]'))if (this.checked) {if (dialogs.indexOf(id) === -1) {dialogs.push(id)await GM.setValue('dialogs', JSON.stringify(dialogs))}} else {if (dialogs.indexOf(id) !== -1) {dialogs.splice(dialogs.indexOf(id), 1)await GM.setValue('dialogs', JSON.stringify(dialogs))}}}).appendTo($div)$div.append(' Always "Yes". Do not show this message again!')}function setStatus (text, success) {addStatus(text, success, true)}function addStatus (text, success, clear) {if (!document.getElementById('multiochhelper')) {alert(`${scriptName}\n\n${text}`)return}let $status = $('#multiochhelper_status')if (!document.getElementById('multiochhelper_status_text')) {if (!document.getElementById('multiochhelper_status')) {const $div = $('#multiochhelper')$status = $('<div>').prependTo($div)$status.attr('id', 'multiochhelper_status')} else {$status.empty()}const $loader = $('<div>').appendTo($status)$loader.attr('id', 'multiochhelper_status_loader')const $statustext = $('<div>').appendTo($status)$statustext.attr('id', 'multiochhelper_status_text')const $statusclear = $('<div>').appendTo($status)$statusclear.attr('id', 'multiochhelper_status_clear')}const $statustext = $('#multiochhelper_status_text')if (clear) {$statustext.empty()} else if ($statustext.html().trim() != '') {$statustext.append(document.createElement('br'))}$status.show()$statustext.append(text)if (success === 1) {$statustext.css('color', '#33FF99')} else if (success === 0) {$statustext.css('color', 'orange')} else if (success === -1) {$statustext.css('color', 'cyan')} else {$statustext.css('color', 'white')}}function showOnlyStatus () {const $status = $('#multiochhelper_status')$status.siblings().not('#multiochhelper_status').remove()}function getMultiOCHWebsiteURL (links) {return multi[currentdebrid].getOpenWebsiteURL(links)}function openWebsite (links, cb) {// Call cb() and navigate to the websiteif (!links) {cb(false)return}if (cb) {cb()}const url = getMultiOCHWebsiteURL(links)if (settings.newTab) {if (typeof GM.openInTab === 'undefined') {window.open(url)} else {GM.openInTab(url)}} else {document.location.href = url}}async function useCache (urls, cb) {urls = '' + urlsconst cachedDownloadLinks = JSON.parse(await GM.getValue('cachedDownloadLinks', '{}')) // [datestring,downloadlink,multihoster]if (urls in cachedDownloadLinks) {if (confirm(scriptName + '\n\nLink was found in cache.\nUse cached link?\n\nFrom: ' + (new Date(cachedDownloadLinks[urls][0])) + '\nWith: ' + cachedDownloadLinks[urls][2] + '\n' + cachedDownloadLinks[urls][1].join('\n'))) {cb(cachedDownloadLinks[urls][1])return true}}return false}async function cacheLink (urls, datetime, downloadLinks, multihoster) {if (!Array.isArray(downloadLinks)) {const parts = downloadLinks.split('\n')downloadLinks = []for (let i = 0; i < parts.length; i++) {if ($.trim(parts[i])) {downloadLinks.push($.trim(parts[i]))}}}if (downloadLinks.length === 0) returnurls = '' + urlsconst cachedDownloadLinks = JSON.parse(await GM.getValue('cachedDownloadLinks', '{}'))cachedDownloadLinks[urls] = [datetime, downloadLinks, multihoster]await GM.setValue('cachedDownloadLinks', JSON.stringify(cachedDownloadLinks))}function showExtractedLinks (links) {if (document.querySelector('.alertlinkscont')) {alert(links.join('\n'))$('.alertlinkscont').remove()return}$('<style type="text/css">.alertlinkscont{transition: left 500ms;}.alertlinkscont a{font-size:12px;user-select:all; font-family: monospace;} .alertlinkscont a:link,.alertlinkscont a:hover{color:black; text-decoration:none;}.alertlinkscont a:visited{color:rgb(70,0,120); text-decoration:none;}</style>').appendTo('head')const $div = $('<div class="alertlinkscont"></div>')$div.appendTo(document.body)$div.css({zIndex: 10000,position: 'fixed',top: '20px',left: '20px',minWidth: '300px',minHeight: '300px',background: 'white',color: 'black',border: '2px solid black',borderRadius: '5px',padding: '20px 25px 10px',fontFamily: 'monospace',fontSize: '12px',overflow: 'auto'})for (let i = 0; i < links.length; i++) {$div[0].innerHTML += '<a target="_blank" href="' + links[i] + '">' + links[i] + '</a><br>\n'}$div[0].innerHTML += '<br><br>\n'window.setTimeout(function moveMenuIntoView () {$div.css('maxHeight', (document.documentElement.clientHeight - 100) + 'px')$div.css('maxWidth', (document.documentElement.clientWidth - 40) + 'px')$div.css('left', Math.max(20, 0.5 * (document.body.clientWidth - $div[0].clientWidth)) + 'px')}, 0)}async function generateLinks (urls, cb) {// Check cacheif (await useCache(urls, cb)) {return}await multi[currentdebrid].getLinks(urls, cb)}async function download (urls, cb) {// Get one/first download link and open it immediately/start downloadif (urls.length > 1) {alert(scriptName + '\n\nOnly the first link will be opened!')}await generateLinks(urls, function (r###lt, code) {if (cb) {cb()}if (r###lt && r###lt[0]) {addStatus('Opening download...', -1)const oldlocation = document.location.hrefdocument.location.href = r###lt[0]if (oldlocation === document.location.href) { // Changing location was blocked by sandboxed iframe// GM.openInTab(r###lt);window.top.location.href = r###lt[0]}} else if (code === -2) {// Error was already handledconsole.log('download() in generateLinks(): error already handled')} else if (!code) {addStatus('An error occured: No downloadlink to open', 0)}})}async function clipboard (urls, cb) {// Get download links and copy them into clipboardgenerateLinks(urls, function (r###lt, code) {if (r###lt) {let succeeded = falsesetStatus('Trying to set clipboard', -1)window.setTimeout(function() {if (succeeded) {return}setStatus('Trying GM_setClipboard()', -1)try {GM_setClipboard(r###lt.join('\r\n'))setStatus('Copied to clipboard', 1)} catch (e) {setStatus('Failed to access clipboard 02', 0)alert('Failed to access clipboard.\n\nLinks will appear in next dialog window')alert(r###lt.join('\r\n'))}}, 3000)try {GM.setClipboard(r###lt.join('\r\n')).then(function() {setStatus('Copied to clipboard', 1)succeeded = true}, function() {setStatus('Failed to access clipboard 01', 0)})} catch (e) {setStatus('Clipboard not supported by this browser', 0)alert(r###lt.join('\n'))};} else if (code === -2) {// Error was already handledconsole.log('clipboard() in generateLinks(): error already handled')} else {setStatus('An error occured: No downloadlinks found', 0)}if (cb) {cb()}})}async function sendToJD (urls, cb) {// Get download links and send them to JDownloadergenerateLinks(urls, function (r###lt, code) {if (r###lt) {setStatus('Waiting for JDownloader', -1)// Comment should be the original page in case of multiple linkslet comment = urls[0]if (urls.length > 1) {if (showOneclickFromHighlighScriptAllLinksLoc) {comment = showOneclickFromHighlighScriptAllLinksLoc} else if (showOneclickFromHighlighScriptSelectedLinksLoc) {comment = showOneclickFromHighlighScriptAllLinksLoc} else {comment = document.location.href}}GM.xmlHttpRequest({method: 'POST',url: JDOWNLOADER + 'flash/add',headers: {'Content-Type': 'application/x-www-form-urlencoded',Referer: scriptReferer,'User-Agent': scriptReferer},// data: "source="+encodeURIComponent(scriptReferer)+"&urls="+encodeURIComponent(r###lt.join("\r\n")), // Moved "source" to Referer// data: "comment="+encodeURIComponent(comment)+"&urls="+encodeURIComponent(r###lt.join("\r\n")), // See ExternInterfaceImpl.javadata: 'source=' + encodeURIComponent(scriptReferer) + '&comment=' + encodeURIComponent(comment) + '&urls=' + encodeURIComponent(r###lt.join('\r\n')), // See ExternInterfaceImpl.javaonload: function (resp) {if (cb) {cb()}if (resp.status === 204 || resp.responseText.startsWith('success')) {setStatus('Sent to JDownloader', 1)} else {setStatus('JDownloader rejected the request', 0)}},onerror: function (resp) {if (cb) {cb()}setStatus('JDownloader is not running', 0)}})} else if (code === -2) {// Error was already handledconsole.log('sendToJD() in generateLinks(): error already handled')if (cb) {cb()}} else {if (cb) {cb()}addStatus('No links to send', 0)}})}function showLinks (urls, cb, append, n) {const popup = popUp('showLinks')const $div = popup.nodeconst $loader = $('<div style="width:20px; height:20px;" class="ochspinner"></div>').appendTo($div)const $frame = $('<iframe width="900" height="500" style="border:0">').appendTo($div)$frame.bind('load', function (e) {$($frame[0].contentDocument.getElementsByTagName('head')[0]).append('<link rel="stylesheet" href="https://www.nopremium.pl/css/style.css" type="text/css" />')const $body = $($frame[0].contentDocument.getElementsByTagName('body')[0])multi[currentdebrid].getR###lts(urls, function ($node) {$loader.remove()$body.append($node)$body.find('a').each(function () {// Open links in new windowthis.setAttribute('target', '_blank')})if (cb) {cb()}})})if (chrome) {$frame.attr('src', 'about:blank')}}function decryptClickNLoad (cb, jk, cryptedBase64) {// Get all the links by decrypting the Click'n'Load form// return False for any error// return True, run cb() and open the menu if Click'n'Load was successfully decodedif (!cryptedBase64 && !(document.getElementsByName('crypted').length && document.getElementsByName('jk').length)) {return false // Click'n'Load not avaiblabe}setStatus("Trying to decrypt Click'n'Load", -1)try {// Key/IVif (!jk) {jk = document.getElementsByName('jk')[0].value}if (jk.indexOf('return') !== -1) {jk = eval(jk + '; f();') // eslint-disable-line no-eval}const key = hexToBytes(jk)const iv = key.slice(0)// Textif (!cryptedBase64) {cryptedBase64 = document.getElementsByName('crypted')[0].value}const cryptedString = atob(cryptedBase64)const cryptedBytes = stringToBytes(cryptedString)// Decryptconst textBytes = slowAES.decrypt(cryptedBytes, slowAES.modeOfOperation.CBC, key, iv)let text = bytesToString(textBytes)text = text.replace('\r', '')const splitted = text.split('\n')const links = []for (let i = 0; i < splitted.length; i++) {// Remove any line that is not a http linkconst t = $.trim(splitted[i])if (t && t.substring(0, 4) === 'http') {links.push(t)}}const N = links.lengthif (N === 0) {return false // Click'n'Load probably failed, try another method...}if (cb) {cb()}menu(links)setStatus('Found ' + (N === 1 ? 'one link' : (N + ' links')), 1)return true} catch (e) {alert("Click'N'Load failed:\n" + e)return false // Click'n'Load probably failed, try another method...}/*// Get all the links by decrypting the Click'n'Load formif(!document.getElementsByName('crypted').length || !document.getElementsByName('jk').length) {if(cb) {cb();}return;}setStatus("Trying linkdecrypter.com",-1);const crypted = document.getElementsByName('crypted')[0].value;const jk = document.getElementsByName('jk')[0].value;GM.xmlHttpRequest( {method: "POST",url: "http://linkdecrypter.com/api/?t=cnl2",data: 'crypted=' + encodeURIComponent(crypted) + '&jk=' + encodeURIComponent(btoa(jk)),headers: {"User-agent": "Mozilla/5.0 (X11;U;Linux i686;es-ES;rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8","Accept": "application/atom+xml,application/xml,text/xml","Content-type" : "application/x-www-form-urlencoded"},onload: function(response) {if(cb) {cb();}const N = response.responseText.split("\n").length;if(!response.responseText || response.responseText.indexOf("ERROR(CNL2)") !== -1 ||  N === 0) {setStatus("An error occurred while handling the response of linkdecrypter.com",0);} else {menu(response.responseText);setStatus("Found "+(N===1?"one link":(N+" links")),1);}}});*/}function decryptDLContainer (url, cb) {// Get all the links by decrypting the DLC container at the given URL via dcrypt.it// run cb() and open the menu if Click'n'Load was successfully decodedGM.xmlHttpRequest({method: 'GET',url: url,binary: true,overrideMimeType: 'text/plain; charset=x-user-defined',onload: function (resp) {setStatus('Decrypting dlc container via dcrypt.it', -1)xmlHttpRequestBinary({method: 'POST',url: DCRYPTIT_UPLOAD_URL,onload: function (resp) {if (cb) {cb()}try {const obj = JSON.parse(resp.responseText.replace('<textarea>', '').replace('</textarea>', ''))if (obj.success) {obj.success.links.shift() // Discard first link, it always has the same valuelet alllinks = ''for (let i = 0; i < obj.success.links.length; ++i) {alllinks += $.trim(obj.success.links[i]) + '\n'}menu(alllinks)setStatus('Found ' + (obj.success.links.length === 1 ? 'one link' : (obj.success.links.length + ' links')), 1)} else {setStatus('No links found in dlc container', 0)}} catch (e) {alert(e)setStatus('An error occurred while handling the response of dcrypt.it', 0)}},data: {dlcfile: {value: resp.responseText,filename: 'test.dlc'}}})}})}function getAllSerienjunkiesLinks (cb) {// Get all download links from a serienjunkies.org download page (i.e. the page right after the captcha)const urls = [] // [  [partnumber0,link0]  ,  [partnumber1,link1]  ,  .... ]let total = 0const rap = document.getElementById('rap')const table = rap.getElementsByTagName('table')[0]const forms = table.getElementsByTagName('form')let j = 1 // part number, in order to make sure that sorting of the links is the same as on the page.// This is only a fallback in case there is no visible part number in the actual downloadlink/filename.for (let i = 0; i < forms.length; i++) {const url = forms[i].actionif (url.indexOf('mirror') !== -1 || url.indexOf('firstload') !== -1) {continue}GM.xmlHttpRequest({method: 'GET',url: url,onload: (function (j) {return function (response) {const loc = response.finalUrl // Actual link after posible redirectionsif (response.finalUrl.match(/part*(\d+)\./)) { // Try to guess part numberconst part = response.finalUrl.match(/part*(\d+)\./)[1]urls.push([parseInt(part, 10), loc])} else { // fallback part numberurls.push([j, loc])}setStatus('Decrypting: ' + urls.length + '/' + total, total === urls.length ? 1 : -1)if (total === urls.length) {// Got all linkscb(urls)}}}(j))})j++}total = j - 1};function getSerienjunkiesLinks (cb) {// Get all the links from the pagegetAllSerienjunkiesLinks(function (urls) {if (cb) {cb()}urls = urls.sort(function (a, b) {if (a[0] > b[0]) return 1else if (a[0] < b[0]) return -1return 0})let alllinks = ''for (let i = 0; i < urls.length; ++i) {alllinks += urls[i][1] + '\n'}menu(alllinks)})}function reverseString (s) {return s.split('').reverse().join('')}function getShareBizLinks (cb, noClickNLoad) {// Decide whether to use the Click'n'Load, the dlc or the rsdf container// Try Click'n'Loadif ($('#swfcontainer') && $('#swfcontainer')[0] && !noClickNLoad) {const secret = $('#swfcontainer')[0].data.split('code=').pop()GM.xmlHttpRequest({method: 'GET',url: SHAREBIZ_CNL2_URL + secret,onload: function (resp) {const parts = resp.responseText.split(';;')const jk = 'var a;' + reverseString(atob(parts[1])) // Strict modeconst crypt = reverseString(atob(parts[2]))GM.setClipboard(resp.responseText)if (!decryptClickNLoad(cb, jk, crypt)) {// Click'n'Load did not work, try the containers:getShareBizLinks(cb, true)}}})return}let cbutton = false// Look for rsdf$('#cf img.pntr').each(function () {if ($(this).attr('onclick').indexOf("'rsdf'") !== -1) {cbutton = $(this)}})if (!cbutton) {// Now look for dlc$('#cf img.pntr').each(function () {if ($(this).attr('onclick').indexOf("'dlc'") !== -1) {cbutton = $(this)}})if (!cbutton) {if (cb) {cb()}setStatus('Could not find a container button', 0)} else {// use dlc buttongetShareBizLinksDLC(cb)}} else {// use rsdf buttongetShareBizLinksRSDF(cb)}}function getShareBizLinksRSDF (cb) {// Get all the links by decrypting the rsdf containerlet cbutton = false$('#cf img.pntr').each(function () {if ($(this).attr('onclick').indexOf("'rsdf'") !== -1) {cbutton = $(this)}})if (!cbutton) {if (cb) {cb()}setStatus('Could not find rsdf button', 0)return}const onclickstr = cbutton.attr('onclick') // javascript:_get('VXlsd3B3QU80VU13UGRCN1lSbEJrMUYzYy8wZlVLVklNVFBHTG1BWkM4bz0=', 0, 'ccf');const lnk = onclickstr.match(/get\('(\S+)'/)[1]setStatus('Retrieving rsdf container', -1)const url = SHAREBIZ_RSDF_URL + lnkGM.xmlHttpRequest({method: 'GET',url: url,onload: function (resp) {const data = resp.responseTextsetStatus('Decrypting rsdf container', -1)GM.xmlHttpRequest({method: 'POST',url: POSATIV_URL,headers: {'Content-Type': 'application/x-www-form-urlencoded'},data: 'data=' + data,onload: function (resp) {if (cb) {cb()}const urls = resp.responseText.split('\n')let alllinks = ''for (let i = 0; i < urls.length; ++i) {alllinks += $.trim(urls[i]) + '\n'}menu(alllinks)setStatus('Found ' + (urls.length === 1 ? 'one link' : (urls.length + ' links')), 1)}})}})}function getShareBizLinksDLC (cb) {// Get all the links by sending the DLC container to http://dcrypt.it/let cbutton = false$('#cf img.pntr').each(function () {if ($(this).attr('onclick').indexOf("'dlc'") !== -1) {cbutton = $(this)}})if (!cbutton) {if (cb) {cb()}setStatus('Could not find dlc button', 0)return}const onclickstr = cbutton.attr('onclick') // javascript:_get('VXlsd3B3QU80VU13UGRCN1lSbEJrMUYzYy8wZlVLVklNVFBHTG1BWkM4bz0=', 0, 'ccf');const lnk = onclickstr.match(/get\('(\S+)'/)[1]setStatus('Retrieving dlc container', -1)const url = SHAREBIZ_DLC_URL + lnkGM.xmlHttpRequest({method: 'GET',url: url,binary: true,overrideMimeType: 'text/plain; charset=x-user-defined',onload: function (resp) {setStatus('Decrypting dlc container via dcrypt.it', -1)xmlHttpRequestBinary({method: 'POST',url: DCRYPTIT_UPLOAD_URL,onload: function (resp) {if (cb) {cb()}try {const obj = JSON.parse(resp.responseText.replace('<textarea>', '').replace('</textarea>', ''))if (obj.success) {obj.success.links.shift() // Discard first link, it always has the same valuelet alllinks = ''for (let i = 0; i < obj.success.links.length; ++i) {alllinks += $.trim(obj.success.links[i]) + '\n'}menu(alllinks)setStatus('Found ' + (obj.success.links.length === 1 ? 'one link' : (obj.success.links.length + ' links')), 1)} else {setStatus('No links found in dlc container', 0)}} catch (e) {alert(e)setStatus('An error occurred while handling the response of dcrypt.it', 0)}},data: {dlcfile: {value: resp.responseText,filename: 'test.dlc'}}})}})}function getLinkSaveInLinks (cb) {// Get all the links by sending the DLC container URL to http://dcrypt.it/if ($('#container_loading').css('display') !== 'none') {if (cb) {cb()}alert(scriptName + '\n\nSorry.\nYou are too quick for this website.\n\nPlease be patient until the container has loaded.')return}const lnk = document.getElementById('dlc_link').hrefsetStatus('Decrypting dlc container via dcrypt.it', -1)GM.xmlHttpRequest({method: 'POST',url: DCRYPTIT_CONTAINERLINK_URL,headers: {'Content-Type': 'application/x-www-form-urlencoded'},data: 'link=' + encodeURIComponent(lnk),onload: function (resp) {if (cb) {cb()}try {const obj = JSON.parse(resp.responseText)if (obj.success) {obj.success.links.shift() // Discard first link, it always has the value "http://linksave.in"let alllinks = ''for (let i = 0; i < obj.success.links.length; ++i) {alllinks += $.trim(obj.success.links[i]) + '\n'}menu(alllinks)setStatus('Found ' + (obj.success.links.length === 1 ? 'one link' : (obj.success.links.length + ' links')), 1)} else {setStatus('No links found in dlc container', 0)}} catch (e) {alert(e)setStatus('An error occurred while handling the response of dcrypt.it', 0)}}})}function getRelinktoLinks (cb) {// Get all the linksif (decryptClickNLoad(cb)) { // Try Click'n'Load first, then fallback to DLCreturn}// Else: get links by sending the DLC container to http://dcrypt.it/const cbutton = $('.dlc_button')if (!cbutton) {setStatus("Could not find dlc button or Click'n'Load", -1)if (cb) {cb()}return}const url = cbutton.attr('href') // URL of .dlc filedecryptDLContainer(url, cb)}function getLinkcryptWsLinks (cb) {// Get all the links by sending the DLC container to http://dcrypt.it/if (decryptClickNLoad(cb)) { // Try Click'n'Load first, then fallback to DLCreturn}let cbutton = false$('#ad_cont a').each(function () {if ($(this).html().indexOf('dlc.png') !== -1) {cbutton = $(this)}})if (!cbutton) {setStatus("Could not find dlc button or Click'n'Load", -1)if (cb) {cb()}return}const url = cbutton.attr('href')GM.xmlHttpRequest({method: 'GET',url: url,binary: true,overrideMimeType: 'text/plain; charset=x-user-defined',onload: function (resp) {setStatus('Decrypting dlc container via dcrypt.it', -1)xmlHttpRequestBinary({method: 'POST',url: DCRYPTIT_UPLOAD_URL,onload: function (resp) {if (cb) {cb()}try {const obj = JSON.parse(resp.responseText.replace('<textarea>', '').replace('</textarea>', ''))if (obj.success) {obj.success.links.shift() // Discard first link, it always has the same valuelet alllinks = ''for (let i = 0; i < obj.success.links.length; ++i) {alllinks += $.trim(obj.success.links[i]) + '\n'}menu(alllinks)setStatus('Found ' + (obj.success.links.length === 1 ? 'one link' : (obj.success.links.length + ' links')), 1)} else {setStatus('No links found in dlc container', 0)}} catch (e) {alert(e)setStatus('An error occurred while handling the response of dcrypt.it', 0)}},data: {dlcfile: {value: resp.responseText,filename: 'test.dlc'}}})}})}function getLinkcryptWsLinks2 (cb) {// Get all the links by decrypting the Click'n'Load formconst r = decryptClickNLoad(cb)if (!r) {setStatus("Could not find Click'n'Load", -1)if (cb) {cb()}}}function getFilecryptcc (jddata, cb) {// Get all the links by decrypting the Click'n'Load formconst fieldJk = jddata[0]const fieldCrypted = jddata[1]const r = decryptClickNLoad(cb, fieldJk, fieldCrypted)if (!r) {setStatus("Could not find Click'n'Load", -1)if (cb) {cb()}}}function getNCryptLinks (cb) {// Get all the links by sending the DLC container URL to http://dcrypt.it/// Get the currently selected mirrorlet mirrorid = falsefor (let i = 0; i < 100; i++) {const div = document.getElementById('mirror_' + i)if (div && div.style.display !== 'none') {mirrorid = ibreak}}if (mirrorid === false) {if (cb) {cb()}alert(scriptName + '\n\nSorry.\nPlease select a mirror first.')return}let cbutton = false$('#mirror_' + mirrorid + '_container a').each(function () {if ($(this).html().indexOf('dlc.png') !== -1) {cbutton = $(this)}})if (!cbutton) {if (cb) {cb()}setStatus('Could not find dlc button', 0)return}const lnk = 'http://ncrypt.in' + cbutton.attr('href')setStatus('Decrypting dlc container via dcrypt.it', -1)GM.xmlHttpRequest({method: 'POST',url: DCRYPTIT_CONTAINERLINK_URL,headers: {'Content-Type': 'application/x-www-form-urlencoded'},data: 'link=' + encodeURIComponent(lnk),onload: function (resp) {if (cb) {cb()}try {const obj = JSON.parse(resp.responseText)if (obj.success) {obj.success.links.shift() // Discard first link, it always has the value "http://linksave.in"let alllinks = ''for (let i = 0; i < obj.success.links.length; ++i) {alllinks += $.trim(obj.success.links[i]) + '\n'}menu(alllinks)setStatus('Found ' + (obj.success.links.length === 1 ? 'one link' : (obj.success.links.length + ' links')), 1)} else {setStatus('No links found in dlc container', 0)}} catch (e) {alert(e)setStatus('An error occurred while handling the response of dcrypt.it', 0)}}})}function getRelinkUsLinks (cb) {// Get all the links by following each linkconst crypticUrls = []$('#links a.submit').each(function () {if (this.getAttribute('onclick')) { crypticUrls.push(RELINKUS_GETFILE + this.getAttribute('onclick').split("'")[1]) }})let captchaInfo = falseconst captchaHolder = $('<div style="position:absolute; top:10px; right:10px; overflow:auto; height:80%"></div>').appendTo(document.body)const urls = []let total = 0let j = 1for (let i = 0; i < crypticUrls.length; i++) {GM.xmlHttpRequest({method: 'GET',url: crypticUrls[i],onload: (function (j) {return function (response) {let loc = response.finalUrl // Actual link after posible redirectionsif (response.responseText.indexOf('iframe') !== -1) {loc = response.responseText.split('src="')[1].split('"')[0]urls.push(loc)} else {if (!captchaInfo) {captchaInfo = truealert(scriptName + '\n\nSorry, this page is protected with captchas.\nThe captchas will appear in the RIGHT TOP corner.')}const div = $(response.responseText).appendTo(captchaHolder)div.css('marginTop', '20px')div.css('marginLeft', 'auto')div.css('left', 'auto')div.css('top', 'auto')div.css('right', 'auto')div.css('position', 'relative')const form = $('form', div)$('input[type=image]', div).click(function (e) {e.preventDefault()const posX = $(this).offset().leftconst posY = $(this).offset().topconst x = e.pageX - posXconst y = e.pageY - posY$(this.parentNode.parentNode).remove()const data = form.serialize() + '&button.x=' + x + '&button.y=' + yGM.xmlHttpRequest({method: 'POST',url: 'http://www.relink.us/frame.php',data: data,headers: {Host: 'www.relink.us',// "Referer" : response.finalUrl,  // FIREFOX57'Content-Type': 'application/x-www-form-urlencoded','Cache-Control': 'no-cache'},onload: function (r) {if (r.responseText.indexOf('iframe') !== -1) {loc = r.responseText.split('src="')[1].split('"')[0]urls.push(loc)} else {alert(scriptName + '\n\nAn error occured:\nCould not get link.')}setStatus('Decrypting: ' + urls.length + '/' + total, -1)if (total === urls.length) {// Got all linkscb()menu(urls)setStatus('Found ' + (total === 1 ? 'one link' : (total + ' links')), 1)}}})})}setStatus('Decrypting: ' + urls.length + '/' + total, -1)if (total === urls.length) {// Got all linkscb()menu(urls)setStatus('Found ' + (total === 1 ? 'one link' : (total + ' links')), 1)}}}(j))})j++}total = j - 1};function getExtremeProtectLinks (cb) {const urls = []const a = document.querySelectorAll('.all_liens a')for (let i = 0; i < a.length; i++) {urls.push(a[i].href)}cb()menu(urls)}function getSafeLinkingNetLinks (cb) {// Get all the links by following each linkconst crypticUrls = []$('div.links-container.r###lt-form a.r###lt-a').each(function () {if (this.getAttribute('href') && this.getAttribute('href').indexOf('/d/') !== -1) { crypticUrls.push(this.getAttribute('href')) }})const urls = []let total = 0let j = 1for (let i = 0; i < crypticUrls.length; i++) {GM.xmlHttpRequest({method: 'GET',url: crypticUrls[i],onload: (function (j) {return function (response) {const loc = response.finalUrl // Actual link after posible redirectionsurls.push(loc)setStatus('Decrypting: ' + urls.length + '/' + total, -1)if (total === urls.length) {// Got all linkscb()menu(urls)setStatus('Found ' + (total === 1 ? 'one link' : (total + ' links')), 1)}}}(j))})j++}total = j - 1};const linkSelectorFilter = {_filter: function (key) {const a = Array.prototype.slice.call(arguments, 1)return function () {linkSelectorFilter[key].apply(linkSelectorFilter, a)}},all: function (trs) {for (let i = 0; i < trs.length; i++) {trs[i].$check.prop('checked', true)}},none: function (trs) {for (let i = 0; i < trs.length; i++) {trs[i].$check.prop('checked', false)}},flip: function (trs) {for (let i = 0; i < trs.length; i++) {trs[i].$check.prop('checked', !trs[i].$check.prop('checked'))}},has: function (trs, inpFilter) {const s = inpFilter.val()for (let i = 0; i < trs.length; i++) {if (trs[i].link.indexOf(s) !== -1) {trs[i].$check.prop('checked', !trs[i].$check.prop('checked'))}}},host: function (trs, $selHost) {const h = $selHost.val()for (let i = 0; i < trs.length; i++) {if (trs[i].host === h) {trs[i].$check.prop('checked', !trs[i].$check.prop('checked'))}}},fromto: function (trs, $table, $thead, $th) {const _self = thisfor (let i = 0; i < trs.length; i++) {trs[i].$check.prop('disabled', true)}$table.find('td').hover(function () {$(this).parent().find('td').each(function (i, e) {$(e).css('background', 'PaleGreen')})}, function () {$(this).parent().find('td').each(function (i, e) {$(e).css('background', '')})})$thead.find('th').css('display', 'none')$th.css('display', '')$th.html('Select from where to start')$table.find('td').click(function () {const from = $(this.parentNode).data('index')$(this).parent().find('td').css('background', 'PaleGreen')$table.find('td').unbind('click mouseenter mouseleave')$th.html('Select where to stop')$table.find('td').hover(function () {const to = $(this.parentNode).data('index')$table.find('td').each(function (i, e) {const $e = $(e)const j = $e.parent().data('index')if (j > from && j <= to) {$e.css('background', 'DarkSeaGreen')} else if (j > from && j > to) {$e.css('background', '')}})if ($(this).parent().data('index') > from) $(this).parent().find('td').css('background', 'PaleGreen')})$table.find('td').filter(function (i, e) { return $(e.parentNode).data('index') > from }).click(function () {const to = $(this.parentNode).data('index') + 1$table.find('td').unbind('click mouseenter mouseleave')$(this).parent().find('td').css('background', 'PaleGreen')$table.find('td').each(function (i, e) {const $e = $(e)const j = $e.parent().data('index')if (j < from || j >= to) {$e.css('display', 'none')}})const ntrs = trs.slice(from, to)for (let i = 0; i < ntrs.length; i++) {ntrs[i].$check.prop('disabled', false)}$th.html('Select ')$('<button>').appendTo($th).text('all').click(_self._filter('all', ntrs))$('<button>').appendTo($th).text('none').click(_self._filter('none', ntrs))$('<button>').appendTo($th).text('flip').click(_self._filter('flip', ntrs))$('<button>').appendTo($th).text('return to all links').click(function () {$table.find('td').each(function (i, e) {const $e = $(e)$e.css('display', '')$e.css('background', '')})$thead.find('th').css('display', '')$th.css('display', 'none')$th.html('')for (let i = 0; i < trs.length; i++) {trs[i].$check.prop('disabled', false)}})$th[0].scrollIntoView()return false})})},every: function (trs, $table, $thead, $th) {const _self = thisfor (let i = 0; i < trs.length; i++) {trs[i].$check.prop('disabled', true)}$table.find('td').hover(function () {$(this).parent().find('td').each(function (i, e) {$(e).css('background', 'PaleGreen')})}, function () {$(this).parent().find('td').each(function (i, e) {$(e).css('background', '')})})$thead.find('th').css('display', 'none')$th.css('display', '')$th.html('Select from where to start')$table.find('td').click(function () {const from = $(this.parentNode).data('index')$(this).parent().find('td').css('background', 'PaleGreen')$table.find('td').unbind('click mouseenter mouseleave')$th.html('Select next')$table.find('td').hover(function () {const to = $(this.parentNode).data('index')const diff = to - fromif (to < from + 2) {$table.find('td').filter(function (i, e) { return $(e.parentNode).data('index') > from + 1 }).css('background', '')} else {$table.find('td').filter(function (i, e) { return $(e.parentNode).data('index') > from + 1 }).each(function (i, e) {const j = $(this.parentNode).data('index')if ((j - from) % diff === 0 && j > from + 1) {$(this).css('background', 'PaleGreen')} else {$(this).css('background', '')}})$(this).parent().find('td').css('background', 'DarkSeaGreen')}}).click(function () {const to = $(this.parentNode).data('index')if (to < from + 2) return false$(this).parent().find('td').css('background', 'PaleGreen')const diff = to - from$table.find('td').unbind('click mouseenter mouseleave')$table.find('td').each(function (i, e) {const $e = $(e)const j = $e.parent().data('index')if ((j - from) % diff !== 0 || j < from) {$e.css('display', 'none')}})const ntrs = []for (let i = 0; i < trs.length; i++) {if ((i - from) % diff === 0 && i >= from) {trs[i].$check.prop('disabled', false)ntrs.push(trs[i])}}$th.html('Select ')$('<button>').appendTo($th).text('all').click(_self._filter('all', ntrs))$('<button>').appendTo($th).text('none').click(_self._filter('none', ntrs))$('<button>').appendTo($th).text('flip').click(_self._filter('flip', ntrs))$('<button>').appendTo($th).text('return to all links').click(function () {$table.find('td').each(function (i, e) {const $e = $(e)$e.css('display', '')$e.css('background', '')})$thead.find('th').css('display', '')$th.css('display', 'none')$th.html('')for (let i = 0; i < trs.length; i++) {trs[i].$check.prop('disabled', false)}})$th[0].scrollIntoView()return false})})}}function linkSelector (links) {const filter = function (key) {const a = Array.prototype.slice.call(arguments, 1)return function () {linkSelectorFilter[key].apply(linkSelectorFilter, a)}}const trs = []const selectedLinks = []// Coyp array and remove empty elementsfor (let i = 0; i < links.length; i++) {const t = $.trim(links[i])if (t) {selectedLinks.push(t)}}if (linksBeforeSelection === false) {linksBeforeSelection = links.slice(0) // Save all links for later selections}const allLinks = linksBeforeSelection.slice(0)const popup = popUp('linkSelector')const $div = popup.nodeconst $loader = $('<div style="width:20px; height:20px;" class="ochspinner"></div>').appendTo($div)$div.css('overflow', 'none')const $frame = $('<iframe style="border:0">').appendTo($div)$frame.attr('width', window.innerWidth - 190)$frame.attr('height', window.innerHeight - 120)$frame.bind('load', function (e) {const $body = $($frame[0].contentDocument.getElementsByTagName('body')[0])const $main = $('<div>').appendTo($body)const $table = $('<table>').appendTo($main)const $thead = $('<thead>').appendTo($table)const $tr0 = $('<tr>').appendTo($thead)const $th0 = $('<th>').appendTo($tr0).attr('colspan', 2)const $tr1 = $('<tr>').appendTo($thead)const $th1 = $('<th>').appendTo($tr1).attr('colspan', 2)const $tr2 = $('<tr>').appendTo($thead)const $th2 = $('<th>').appendTo($tr2).attr('colspan', 2)const $tr3 = $('<tr>').appendTo($thead)const $th3 = $('<th>').appendTo($tr3).attr('colspan', 2)const $tr4 = $('<tr>').appendTo($thead)const $th4 = $('<th>').appendTo($tr4).attr('colspan', 2)$('<span>Select: <span>').appendTo($th0)$('<button>').appendTo($th0).text('all').click(filter('all', trs))$('<button>').appendTo($th0).text('none').click(filter('none', trs))$('<button>').appendTo($th0).text('flip').click(filter('flip', trs))$('<button>').appendTo($th1).text('Select from ... to ...').click(filter('fromto', trs, $table, $thead, $th4))$('<button>').appendTo($th1).text('Select every ...').click(filter('every', trs, $table, $thead, $th4))$('<span> Filter:<span>').appendTo($th2)const inpFilter = $('<input>').appendTo($th2).attr('type', 'text')$('<button>').appendTo($th2).text('Flip with filter').click(filter('has', trs, inpFilter))$('<span> Host filter:<span>').appendTo($th3)const $selHost = $('<select>').appendTo($th3)$('<button>').appendTo($th3).text('Flip with host filter').click(filter('has', trs, $selHost))const allhosts = []for (let i = 0; i < allLinks.length; i++) {const $tr = $('<tr>').data('index', i).appendTo($table)const $td0 = $('<td>').appendTo($tr)const $check = $('<input>').appendTo($td0).attr('type', 'checkbox').attr('id', 'link_checkbox_' + i).prop('checked', selectedLinks.indexOf(allLinks[i]) !== -1)const $td1 = $('<td>').appendTo($tr)$('<label>').attr('for', 'link_checkbox_' + i).text(allLinks[i]).css('font-family', 'monospace').appendTo($td1)const host = allLinks[i].split('/')[2].replace(/^www\./, '')if (allhosts.indexOf(host) === -1) {allhosts.push(host)}trs.push({ $tr: $tr, $check: $check, link: allLinks[i], host: host })}for (let i = 0; i < allhosts.length; i++) {$('<option>').val(allhosts[i]).text(allhosts[i]).appendTo($selHost)}$('<button>').appendTo($main).text('Apply').click(function () {const nlinks = []for (let i = 0; i < trs.length; i++) {if (trs[i].$check.prop('checked')) {nlinks.push(trs[i].link)}}if (nlinks.length === 0) {alert('No links selected?!')return}menu(nlinks)setStatus((nlinks.length === 1 ? 'One link' : (nlinks.length + ' links')) + ' selected', 1)popup.close()})$loader.remove()})if (chrome) {$frame.attr('src', 'about:blank')}}function menu (links) {// normalize links:if (!Array.isArray(links)) {const parts = links.split('\n')links = []for (let i = 0; i < parts.length; i++) {if ($.trim(parts[i])) {links.push($.trim(parts[i]))}}}const $c = $('#multiochhelper ul')$c.html('')const $select = $('<select>')const m = links[0].match(/https?:\/\/(.+?)\//)if (!m) {console.log(scriptName + ": Not a valid link: '" + links[0] + "'")return}const host = m[1]let hoster = host.split('.')hoster.pop()hoster = hoster.pop().replace('-', '')$.each(multi, function (key, val) {const $option = $('<option></option>').val(key).html(val.name).appendTo($select)if (key === currentdebrid) {$option[0].selected = true}if (multi[key].isOnline(hoster)) {$option.css('color', 'green')} else {$option.css('color', '#F00')}})let $entry = menuentry($select)$select.bind('change', function (ev) {const $this = $(this)// Change hostercurrentdebrid = $this.val()// Check general supportif (multi[currentdebrid].isOnline(hoster)) {// Check first link for support on this multi hostermulti[currentdebrid].checkLink(links[0], function (r###lt) {if (!r###lt) {alert(scriptName + '\n\n' + host + ' is not supported by this hoster or the file is offline.\n\nChecked: ' + links[0])}})} else {alert(scriptName + '\n\n' + host + ' is not supported by ' + multi[currentdebrid].name)}// Add "Remember" checkboxif (!$this.parent().find('#remember').length) {const $div = $('<div>')const $check = $('<input id="remember" type="checkbox" value="remember" title="Remember selection">').click(async function () {if (this.checked) {currentdebrid = $select.val()await GM.setValue('currentdebrid', currentdebrid)setStatus('Switched to ' + multi[currentdebrid].name, 1)$div.remove()}})$div.append($check).append('Remember')$this.parent().append($div)}})$entry = menuentry('Direct download')$entry.click(function () { mouse('download', links) })$entry = menuentry('Copy to clipboard')$entry.click(function () { mouse('clipboard', links) })if (settings.jDownloaderSupport) {$entry = menuentry('Send to JDownloader')$entry.attr('id', 'multiochhelperjdbutton')$entry.hide()$entry.click(function () { mouse('sendToJD', links) })GM.xmlHttpRequest({method: 'GET',url: JDOWNLOADER + 'flash/',onerror: function () {},onload: function (resp) {if (resp && resp.responseText && resp.responseText.startsWith('JDownloader')) {$('#multiochhelperjdbutton').show()}}})}if (!showOneclickFromHighlighScriptAllLinks) {$entry = menuentry('Show generated links')$entry.click(function () { mouse('showLinks', links) })}$entry = menuentry('Show extracted links')$entry.click(function () {if (window.parent.parent !== window) {window.parent.parent.postMessage({ iAm: 'Unrestrict.li', type: 'alert', str: links.join('\n') }, '*')alert(links.join('\n'))} else {showExtractedLinks(links)}})if (!showOneclickFromHighlighScriptAllLinks && (links.length > 1 || linksBeforeSelection !== false)) {$entry = menuentry('Select links')$entry.click(function () { linkSelector(links) })}if (!showOneclickFromHighlighScriptAllLinks) {$entry = menuentry()$('<a style="color:white !important;">Open Website</a>').attr('href', getMultiOCHWebsiteURL(links)).appendTo($entry)}if (showOneclickFromHighlighScriptAllLinks && showOneclickFromHighlighScriptAllLinksLinks) {$entry = $(menuentry('Use all links on page...'))$entry.click(function () {// Switch to all links instead of oneconst links = showOneclickFromHighlighScriptAllLinksLinksshowOneclickFromHighlighScriptAllLinksLinks = ''menu(links)$('#multiochhelper div:empty:not(:first)').remove()setStatus('All links!', 1)})}if (showOneclickFromHighlighScriptSelectedLinks && showOneclickFromHighlighScriptSelectedLinksLinks) {$entry = $(menuentry('Use selected links...'))$entry.click(function () {// Switch to selected links instead of oneconst links = showOneclickFromHighlighScriptSelectedLinksLinksshowOneclickFromHighlighScriptSelectedLinksLinks = ''menu(links)$('#multiochhelper div:empty:not(:first)').remove()setStatus('Using selected links!', 1)})}if (!showOneclickFromHighlighScriptAllLinks) {$entry = menuentry($('<span style="cursor:default; color:silver">Userscript menu</span>').click(function (ev) { ev.stopPropagation(); aboutMe() }))$entry.css('cursor', 'default')$('<span style="cursor:pointer; color:White; border: 1px solid White; border-radius:3px; padding:0px; margin-left:20px; font-weight:bold ; " title="Close menu">X</span>').click(function () { $('#multiochhelper').remove() }).appendTo($entry)}}function loader () {// Show an animation, return function to remove the loader$('#multiochhelper_status_loader').parent().show()const $div = $('<div class="ochspinner"></div>').appendTo($('#multiochhelper_status_loader'))return function () {$div.remove()}}async function mouse (action, linkText) {// decide what to do after a mouse clickconst removeImg = loader()if (action === 'download') {await download(linkText, removeImg)} else if (action === 'showLinks') {showLinks(linkText, removeImg)} else if (action === 'openWebsite') {openWebsite(linkText)} else if (action === 'clipboard') {await clipboard(linkText, removeImg)} else if (action === 'menu') {removeImg()menu(linkText)} else if (action === 'sendToJD') {await sendToJD(linkText, removeImg)}}function menuentry (html) {const $li = $('<li>')if (html) {$li.append(html)}$li.appendTo('#multiochhelper ul')return $li}function button (label) {addCSSHead(`#multiochhelper,#multiochhelper * {font-family:Sans-Serif !important;padding:0px; margin:0px;}#multiochhelper a, #multiochhelper a:link,#multiochhelper a:visited {text-decoration:underline !important;color:#3788e8 !important;font-style:none !important;}#multiochhelper a:hover {text-decoration:none !important;color:#3788e8 !important;font-style:none !important;}#multiochhelper ul li,#multiochhelper_status {margin:1px 1px;padding:1px 5px;font-size:13px;text-shadow:0 -1px 0 #333333;color:White;border:1px solid #8B3D92;background-color:#B555C5;background:radial-gradient(ellipse at center, #B555C5, #8B3D92);list-style:none outside;}#multiochhelper div#multiochhelper_status_loader {float:left;}#multiochhelper div#multiochhelper_status_text {float:left;}#multiochhelper div#multiochhelper_status_clear {clear:left;}#multiochhelper ul li {cursor:pointer;}#multiochhelper ul li:hover {background-color:#CC6BDD;background:radial-gradient(ellipse at center, #CC6BDD, #8B3D92);}#multiochhelper select,#multiochhelper input {border-radius:0;box-shadow:none;text-shadow:none;border:none;background:white;color:black;}${SPINNERCSS}`)// div containerconst zi = getNextZIndex()const $div = $('<div>').appendTo(document.body)$div.attr('id', 'multiochhelper')$div.attr('style', 'z-index:' + zi + '; position:fixed; background:#E6E6E6; color:Black; border:#B555C5 2px solid;border-radius:5px; padding:3px;')if (settings.position[0] === 'top') {$div.css('top', '0%')} else {$div.css('bottom', '0%')}if (settings.position[1] === 'left') {$div.css('left', '0%')} else {$div.css('right', '0%')}// Statusconst $status = $('<div>').appendTo($div).hide()$status.attr('id', 'multiochhelper_status')const $loader = $('<div>').appendTo($status)$loader.attr('id', 'multiochhelper_status_loader')const $statustext = $('<div>').appendTo($status)$statustext.attr('id', 'multiochhelper_status_text')const $statusclear = $('<div>').appendTo($status)$statusclear.attr('id', 'multiochhelper_status_clear')const $ul = $('<ul>').appendTo($div)// Buttonconst $entry = menuentry(label || (multi[currentdebrid].name.charAt(0).toUpperCase() + multi[currentdebrid].name.slice(1)))$ul.append($entry)return $entry}const isSetup = await GM.getValue('setup', false)// Update hoster statuslet updatinghosters = falseif (isSetup) {for (const key in multi) {if (multi[key].updateStatusURLpattern.test(document.location.href)) { //  usually in this is true in the iframe which is defined belowmulti[key].updateStatus()updatinghosters = truebreak}}}// Create iframes to check hoster status:if (!updatinghosters && isSetup) {const now = new Date()for (const key in multi) {if ('updateStatusURL' in multi[key] && (now - multi[key].lastUpdate) > (settings.updateHosterStatusInterval * 60 * 60 * 1000)) {const $iframe = $('<embed>').appendTo(document.body)$iframe.bind('load', function () {const frame = thiswindow.setTimeout(function () { $(frame).remove() }, 3000)})$iframe.attr('src', multi[key].updateStatusURL)}}}// Setupif (!updatinghosters) {if (!isSetup) {await aboutMe()if (!confirm(scriptName + ' Setup\n\nPlease take some time to configure ' + scriptName + ' and then save the settings!\n\nPress cancel to continue with the default configuration!')) {await GM.setValue('setup', true)alert(scriptName + '\n\nDefault settings will be used.')document.location.reload()}}}if (document.location.href.indexOf('nopremium.pl') !== -1) {// nopremium.pl Websiteif (document.location.search.substring(0, 6) === '?link:') {// Insert link on nopremium.pl$('#filesList').val(decodeURIComponent(document.location.search.substring(6)))}} else if (document.location.href.indexOf('www.premiumize.me') !== -1) {// premiumize.me Websiteif (document.location.search.substring(0, 6) === '?link:') {// Insert link on nopremium.pl$('textarea').val(decodeURIComponent(document.location.search.substring(6)))}} else if (document.location.href.indexOf('download.serienjunkies.org') !== -1) {// Serienjunkiesif (!document.querySelector('.g-recaptcha')) { // if not on captcha pageconst $b = button('Decrypt links')$b.click(function (ev) {const removeImg = loader()getSerienjunkiesLinks(removeImg)})}} else if (document.location.href === 'http://filecloud.io/download.html') {// filecloud.ioif (unsafeWindow.__currentUrl) {showOneclickButton = trueshowOneclickLink = decodeURIComponent(unsafeWindow.__currentUrl)}} else if (document.location.href.indexOf('share-links.biz') !== -1) {// share-links.biz folderif (!document.getElementById('captchamap') && document.getElementById('cf')) { // if not on captcha pageconst $b = button('Decrypt links (via dcrypt.it)')$b.click(function (ev) {const removeImg = loader()getShareBizLinks(removeImg)})}} else if (document.location.href.indexOf('linksave.in') !== -1) {// linksave.in folderif (document.getElementById('dlc_link')) { // if not on captcha pageconst $b = button('Decrypt links (via dcrypt.it)')$b.click(function (ev) {const removeImg = loader()getLinkSaveInLinks(removeImg)})}} else if (document.location.href.indexOf('filecrypt.cc') !== -1) {// filecrypt.cc folderif (document.location.href.indexOf('helper.html') !== -1) { // if not on captcha pagewindow.addEventListener('message', function filecryptmessage (event) {if (event.data && typeof (event.data) === 'object') {window.opener.postMessage({ filecryptData: JSON.stringify(event.data) }, '*') // Send message back to the opening windowwindow.removeEventListener('message', filecryptmessage) // Prevent further messages from creating several buttons}}, false)} else if (document.location.href.indexOf('Container') !== -1) { // if not on captcha pageconst $b = button("Please open the Click'n'Load Popup (several times)")$b.click(function () {$('#cnl_btn').click()})window.addEventListener('message', function filecryptmessage2 (event) { // Receive messages from the popupif (event.data && typeof (event.data) === 'object' && 'filecryptData' in event.data) {window.removeEventListener('message', filecryptmessage2) // Prevent further messages from creating several buttonssetStatus('Decrypting', -1)const removeImg = loader()getFilecryptcc(JSON.parse(event.data.filecryptData), removeImg)}}, false)}} else if (document.location.href.substring(7, 19) === 'linkcrypt.ws') {// linkcrypt.ws folderif (document.getElementById('container_check') || document.getElementById('ad_cont')) { // If containers are presentconst $b = button('Decrypt links (via dcrypt.it)')$b.click(function (ev) {const removeImg = loader()getLinkcryptWsLinks(removeImg)})} else if (document.querySelector('form[id^=f]')) {const $b = button('Decrypt links (via dcrypt.it)')$b.click(function (ev) {const removeImg = loader()getLinkcryptWsLinks2(removeImg)})} else {const $b = button('Select hoster first!')$b.click(function (ev) {})}} else if (document.location.href.substring(7, 16) === 'ncrypt.in') {// nCrypt.in folderif (document.getElementById('main') && document.getElementById('main').innerHTML.indexOf('Securitycheck:') === -1) { // If not on captcha pageconst $b = button('Decrypt links (via dcrypt.it)')$b.click(function (ev) {const removeImg = loader()getNCryptLinks(removeImg)})}} else if (document.location.href.substring(7, 19) === 'protected.to') {// http://protected.to folderif (document.querySelectorAll('.links a').length > 0) { // If not on captcha pageshowOneclickButton = trueshowOneclickLink = ''$('.links a').each(function () {showOneclickLink += decodeURIComponent(this.href) + '\n'})}} else if (document.location.href.substring(7, 16) === 'relink.to') {// http://relink.to folderif (document.getElementsByClassName('cnl_form') || document.getElementsByClassName('dlc_button')) { // If not on captcha pageconst $b = button('Decrypt links (via dcrypt.it)')$b.click(function (ev) {const removeImg = loader()getRelinktoLinks(removeImg)})}} else if (document.location.href.substring(7, 20) === 'www.relink.us') {// relink.us folderif (document.getElementById('container_tabs')) {const $b = button('Decrypt links')$b.click(function (ev) {const removeImg = loader()getRelinkUsLinks(removeImg)})}} else if (document.location.href.substring(7, 26) === 'extreme-protect.net') {// extreme-protect.net folderif (document.querySelectorAll('.all_liens a').length > 0) {const $b = button('Decrypt links')$b.click(function (ev) {const removeImg = loader()getExtremeProtectLinks(removeImg)})}} else if (document.location.href.substring(8, 23) === 'safelinking.net' || document.location.host === 'linkshield.org') {// safelinking.net and linkshield.org folderif (!document.getElementById('captcha-wrapper')) {const $b = button('Decrypt links')$b.click(function (ev) {const removeImg = loader()getSafeLinkingNetLinks(removeImg)})}} else if (document.location.href.indexOf('.firedrive.com/share/') !== -1) {// firedrive.com foldershowOneclickButton = trueshowOneclickLink = ''$('a.pf_item_link:visible').each(function () {showOneclickLink += decodeURIComponent(this.href) + '\n'})} else if (document.location.href.indexOf('uploaded.net/folder/') !== -1 || document.location.href.indexOf('uploaded.net/f/') !== -1) {// Uploaded foldershowOneclickButton = trueshowOneclickLink = ''$('#fileList a.file').each(function () {showOneclickLink += decodeURIComponent(this.href) + '\n'})} else if (document.location.href.indexOf('rapidgator.net/folder/') !== -1) {// Rapidgator foldershowOneclickButton = trueshowOneclickLink = ''$('#grid tbody a').each(function () {showOneclickLink += decodeURIComponent(this.href) + '\n'})} else if (document.location.href.substring(0, 55) === 'https://cvzi.github.io/Userscripts/index.html?link=sync') {// Window opened from Helper script to sync hoster status (see postMessage events below)showOneclickButton = falseconst message = 'Updating hoster status...'const h1 = document.body.appendChild(document.createElement('h1'))h1.appendChild(document.createTextNode(scriptHightligherName + ': ' + message))setTitle("")window.setTimeout(function () {const h2 = document.body.appendChild(document.createElement('h2'))h2.appendChild(document.createTextNode('You may close this tab now'))}, 4000)} else if (document.location.href.substring(0, 51) === 'https://cvzi.github.io/Userscripts/index.html?link=') {// Iframe for a X-Frame-Options websiteshowOneclickButton = trueshowOneclickLink = decodeURIComponent(document.location.search.match(/link=(.+)/)[1])} else {// One click hoster websiteshowOneclickButton = trueshowOneclickLink = decodeURIComponent(document.location.href)}if (showOneclickButton) {let mouseOverAvailable = true// Split links into arrayconst splitted = showOneclickLink.split('\n')showOneclickLink = []for (let i = 0; i < splitted.length; i++) {if ($.trim(splitted[i])) {showOneclickLink.push($.trim(splitted[i]))}}const $b = button()$b.bind('mousedown',function (ev) {mouseOverAvailable = falseif (ev.which === 3) { // Right clickmouse(settings.rightClick, showOneclickLink)} else if (ev.which === 2) { // Middle clickmouse(settings.middleClick, showOneclickLink)} else if (ev.which === 1) { // Left click {mouse(settings.leftClick, showOneclickLink)}})if (settings.mouseOver !== 'none') {let ti = false$b.on({mouseover: function () {if (!mouseOverAvailable) { return }ti = setTimeout(function () {if (!mouseOverAvailable) { return }mouseOverAvailable = falsemouse(settings.mouseOver, showOneclickLink)}, settings.mouseOverDelay)},mouseout: function () {if (ti !== false) clearTimeout(ti)}})}// Prevent context menu on right clickif (settings.rightClick !== 'none') {$b[0].addEventListener('contextmenu', e => e.preventDefault(), false)}}// Handle messages from the highlight scriptwindow.addEventListener('message', function (e) {if (typeof e.data !== 'object' || !('iAm' in e.data) || e.data.iAm !== 'Unrestrict.li') {return}switch (e.data.type) {case 'alllinks':if (showOneclickFromHighlighScriptAllLinks) {return}showOneclickFromHighlighScriptAllLinks = trueshowOneclickFromHighlighScriptAllLinksLoc = e.data.locshowOneclickFromHighlighScriptAllLinksLinks = e.data.links.join('\n')if ($('#multiochhelper ul li').length > 1) { // Menu already openedmenu(showOneclickLink)}breakcase 'selectedlinks':if (showOneclickFromHighlighScriptSelectedLinks) {return}showOneclickFromHighlighScriptSelectedLinks = trueshowOneclickFromHighlighScriptSelectedLinksLoc = e.data.locshowOneclickFromHighlighScriptSelectedLinksLinks = e.data.links.join('\n')if ($('#multiochhelper ul li').length > 1) { // Menu already openedmenu(showOneclickLink)}breakcase 'requesthosterstatus': {window.setTimeout(function () {const h3 = document.body.appendChild(document.createElement('h3'))h3.appendChild(document.createTextNode('This will only take a few seconds'))}, 0)const o = {}for (const key in multi) {o[key] = multi[key].status}e.source.postMessage({ iAm: 'Unrestrict.li', type: 'hosterstatus', str: JSON.stringify(o) }, '*')break}}}, true)})()