// ==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 17.1.4
// @match https://cvzi.github.io/Userscripts/index.html?link=*
// @match https://www.nopremium.pl/files*
// @match https://www.premiumize.me/hosters/*
// @match https://www.premiumize.me/services/*
// @match https://www.premiumize.me/downloader*
// @match https://*.filecrypt.cc/Container/*
// @match https://*.filecrypt.cc/helper.html*
// @match https://protected.to/*
// @match https://rapidgator.net/folder/*
// @match https://safelinking.net/p/*
// @match https://multiup.org/*
// @match https://1fichier.com/*
// @match https://*.1fichier.com/*
// @match https://www.4shared.com/*
// @match https://alfafile.net/*
// @match https://*.alfafile.net/*
// @match https://anonfiles.com/*
// @match https://bayfiles.com/*
// @match https://*.bayfiles.com/*
// @match http://clicknupload.link/*
// @match https://clicknupload.to/*
// @match https://clicknupload.org/*
// @match https://clicknupload.co/*
// @match https://clicknupload.cc/*
// @match https://clicknupload.to/*
// @match https://clicknupload.club/*
// @match https://clicknupload.click/*
// @match https://clicknupload.space/*
// @match https://dailyuploads.net/*
// @match https://ddl.to/*
// @match https://ddownload.com/*
// @match https://*.dropapk.com/*
// @match https://dropapk.com/*
// @match https://*.drop.download.com/*
// @match https://drop.download.com/*
// @match https://fastclick.to/*
// @match https://fastshare.cz/*
// @match https://fikper.com/*
// @match https://file.al/*
// @match https://www.file.al/*
// @match https://filefactory.com/*
// @match https://www.filefactory.com/*
// @match https://filenext.com/*
// @match https://www.filenext.com/*
// @match https://filer.net/*
// @match https://filerice.com/*
// @match https://filespace.com/*
// @match https://filestore.to/*
// @match http://fireget.com/*
// @match https://fireget.com/*
// @match https://hitfile.net/*
// @match https://hil.to/*
// @match https://isra.cloud/*
// @match https://katfile.com/*
// @match https://www.mediafire.com/*
// @match https://mediafire.com/*
// @match https://mega.nz/*
// @match https://megaup.net/*
// @match https://mixdrop.co/*
// @match https://modsbase.com/*
// @match https://nitroflare.com/*
// @match https://rapidgator.net/file/*
// @match https://rg.to/file/*
// @match https://spicyfile.com/*
// @match https://www.spicyfile.com/*
// @match https://turbobit.net/*
// @match https://turb.to/*
// @match https://tusfiles.net/*
// @match https://ubiqfile.com/*
// @match https://uploadboy.com/*
// @match https://uploadgig.com/*
// @match https://uptobox.com/*
// @match https://userscloud.com/*
// @match https://usersdrive.com/*
// @match https://vidoza.org/*
// @match https://worldbytez.com/*
// @match https://wrzucajpliki.pl/*
// @match https://xubster.com/*
// @match https://*.zippyshare.com/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/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
// @downloadURL https://update.greasyfork.icu/scripts/13884/Multi-OCH%20Helper.user.js
// @updateURL https://update.greasyfork.icu/scripts/13884/Multi-OCH%20Helper.meta.js
// ==/UserScript==
/* globals confirm, alert, GM, GM_setClipboard, unsafeWindow, $, atob, slowAES, cloneInto */
/* eslint n/no-callback-literal: 0 */
/* jshint asi: true, esversion: 8 */
(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 settings
const savedsettings = JSON.parse(await GM.getValue('settings', '{}')) // e.g. { position : [0,1], newTab : 1 }
for (const key in config) {
if (key in savedsettings) { // Saved
if (config[key] === 'int') { // Int
settings[key] = parseInt(savedsettings[key], 10)
} else if (config[key] === 'string') { // String
settings[key] = savedsettings[key].toString()
} else if (config[key] === 'bool') { // Bool
settings[key] = (savedsettings[key] === 'true' || savedsettings[key] === true)
} else if (Array.isArray(config[key][0])) { // Nested array
if (!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 { // Array
settings[key] = savedsettings[key]
}
} else { // Default
if (config[key] === 'int') { // Int
settings[key] = config[key + '_range'][1]
} else if (config[key] === 'string') { // String
settings[key] = '' // String defaults to empty string
} else if (config[key] === 'bool') { // Bool
settings[key] = true
} else if (Array.isArray(config[key][0])) { // Nested array defaults to first value for each array
settings[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 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%);'
let showOneclickButton = false
let showOneclickLink = ''
let showOneclickFromHighlighScriptAllLinks = document.location.host === 'cvzi.github.io'
let showOneclickFromHighlighScriptAllLinksLoc = false
let showOneclickFromHighlighScriptAllLinksLinks = ''
let showOneclickFromHighlighScriptSelectedLinks = false
let showOneclickFromHighlighScriptSelectedLinksLoc = false
let showOneclickFromHighlighScriptSelectedLinksLinks = ''
let linksBeforeSelection = false
const multi = {
'premiumize.me': new function () {
const self = this
this.config = {
apikey: 'string',
apikey_hidden: true,
apikey_quest: 'Enter your premiumize.me API key',
apikey_prefix: 'API key: ',
apikey_suffix: ' find it under https://www.premiumize.me/account'
}
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 = 5000
this.updateDownloadProgressInterfaceInterval = 500
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 default
const 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) { // Saved
if (self.config[key] === 'int') { // Int
self.settings[key] = parseInt(savedsettings[key], 10)
} else if (self.config[key] === 'string') { // String
self.settings[key] = savedsettings[key].toString()
} else if (config[key] === 'bool') { // Bool
self.settings[key] = savedsettings[key] === 'true' || savedsettings[key] === true
} else if (Array.isArray(savedsettings[key])) { // Nested array
self.settings[key] = []
for (let i = 0; i < savedsettings[key].length; i++) {
self.settings[key].push(savedsettings[key][i])
}
} else { // Array
self.settings[key] = savedsettings[key]
}
} else { // Default
if (self.config[key] === 'int') { // Int
self.settings[key] = self.config[key + '_range'][1]
} else if (self.config[key] === 'string') { // String
self.settings[key] = '' // String defaults to empty string
} else if (config[key] === 'bool') { // Bool
self.settings[key] = true
} else if (Array.isArray(self.config[key][0])) { // Nested array defaults to first value for each array
self.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 website
GM.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 = s
GM.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 hosters
await self.loadSettings()
if (document.location.href.match(self.updateStatusURL)) {
// Read and save current status of all hosters
if ($('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 result = JSON.parse(response.responseText)
/*
{ "cache": [ "uploaded.to", "filefactory.com", ... ], "directdl": [ "uploaded.to", "filefactory.com", ... ] }
*/
if ('cache' in result && 'directdl' in result) {
self.status = {}
await GM.setValue(self.key + '_status_time', '' + (new Date()))
result.cache.forEach(function (host) {
const name = host.match(/^\s*([0-9a-z-]+)\.\w{0,6}\s*$/i)[1]
self.status[name.toLowerCase()] = result.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 links
const url = this.homepage + 'downloader?link:' + encodeURIComponent(urls.join('\n'))
return url
}
this.checkLink = function (url, cb) { // check whether the link is supported and online
const host = url.match(/https?:\/\/(.+?)\//)[1]
let hoster = host.split('.')
hoster.pop()
hoster = hoster.pop().replace('-', '')
cb(this.isOnline(hoster))
}
this.getResults = function (urls, cb) {
// cb($node,linkNumber) -- $node contains the result, linkNumber is the number of links that should be online i.e. number of hashes
alert('This function does not work for ' + this.name)
}
this._notLoggedIn = false
this.getLinks = async function (urls, cb) {
await showConfirm('fairPointsWarning', 'You will be charged premiumize fair points for generating ' + (urls.length > 1 ? ('' + urls.length + ' files') : ('one file')) + '!
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.length
const 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 homepage
setTitle('🔑 ')
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 errors
setTitle('❌ ')
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 finished
setTitle(downloadLinks.length + '/' + errors.length + '✅ ')
cb(downloadLinks)
if (errors.length > 0) { // Errors occured
alert('Errors occured\n' + errors.length + ' links failed:\n\n' + errors.join('\n'))
}
} else { // not finished yet
setTitle(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 result = 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 result && result.id) {
window.setTimeout(function () {
self._getFileFromTransfer(url, result.id, cb)
}, 1000)
if ('message' in result) {
addStatus(result.message, -1)
}
} else {
if ('message' in result && !self._notLoggedIn) {
addStatus(result.message, -1)
if (~result.message.indexOf('log')) {
self._notLoggedIn = true
}
}
cb(false, url, 'message' in result ? result.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 result = 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 (result.status === 'success' && 'transfers' in result) {
for (let i = 0; i < result.transfers.length; i++) {
if (result.transfers[i].id === transferId) {
if (result.transfers[i].file_id) {
// Finished
window.setTimeout(function () {
self._getSingleLink(url, result.transfers[i].file_id, cb)
}, result.transfers[i].status === 'finished' ? 10 : self.updateDownloadProgressInterval)
} else {
// Downloading
if ('message' in result.transfers[i] && result.transfers[i].message) {
setStatus(result.transfers[i].message, -1)
}
window.setTimeout(function () {
self._getFileFromTransfer(url, transferId, cb)
}, self.updateDownloadProgressInterval)
}
return
}
}
}
if ('message' in result && result.message) {
alert(scriptName + '\n\nCould not get /api/transfer/list\nError:\n' + result.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 result = 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 result && result.link) {
cb(result.link, url)
} else {
window.setTimeout(function () {
self._getSingleLink(url, fileId, cb)
}, self.updateDownloadProgressInterval)
}
}
})
}
}(),
'nopremium.pl': new function () {
const self = this
this.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 = 5000
const 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 default
const 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) { // Saved
if (self.config[key] === 'int') { // Int
self.settings[key] = parseInt(savedsettings[key], 10)
} else if (self.config[key] === 'string') { // String
self.settings[key] = savedsettings[key].toString()
} else if (config[key] === 'bool') { // Bool
self.settings[key] = savedsettings[key] === 'true' || savedsettings[key] === true
} else if (Array.isArray(savedsettings[key])) { // Nested array
self.settings[key] = []
for (let i = 0; i < savedsettings[key].length; i++) {
self.settings[key].push(savedsettings[key][i])
}
} else { // Array
self.settings[key] = savedsettings[key]
}
} else { // Default
if (self.config[key] === 'int') { // Int
self.settings[key] = self.config[key + '_range'][1]
} else if (self.config[key] === 'string') { // String
self.settings[key] = '' // String defaults to empty string
} else if (config[key] === 'bool') { // Bool
self.settings[key] = true
} else if (Array.isArray(self.config[key][0])) { // Nested array defaults to first value for each array
self.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 hosters
if (document.location.href.match(self.updateStatusURL)) {
// Read and save current status of all hosters
await 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 links
const 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('') !== -1) {
setTitle('🔑 ')
setStatus(self.name + ' error: Not logged in!', 0)
GM.openInTab(self.homepage)
return cb([], -1)
}
const hashes = []
// Find hashes
const re = /name="hash(\d+)" value="(\w+)"/g //
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(boolresult)
return getHashs([url], function (hashes, size) {
cb(hashes.length === 1)
}, true)
}
this.getResults = function (urls, cb, hashes) {
// cb($node,linkNumber) -- $node contains the result, 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.pl
if (typeof hashes === 'undefined') {
// 1. Get hashes and show transfer warning
getHashs(urls, async function (hashes, size) {
if (settings.mode === 'transfer') {
await showConfirm('transferWarning', 'You will be charged ' + size + " 'Transfer' for generating " + (hashes.length > 1 ? ('' + hashes.length + ' files') : ('one file')) + '!
Generate links?', function () { this.getResults(urls, cb, hashes) }, null, self)
} else if (hashes.length > 0) {
self.getResults(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 found
setStatus('No online/available files', 0)
cb(false, 0)
}
})
return
}
// 2. Work with hashes
const $resultContainer = $('
').appendTo($form)
if (c[key + '_quest']) {
$p.append(c[key + '_quest'])
} else {
$p.append(key)
}
$p.append('
')
if (c[key + '_prefix']) {
$p.append(c[key + '_prefix'] + ' ')
}
const hidden = (key + '_hidden') in c && c[key + '_hidden']
if (c[key] === 'int') { // Int
const $input = $('').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') { // String
const $inputText = $('').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') { // Bool
const $select = $('').addClass('form_' + formid).data('key', key).data('parse', 'bool').appendTo($p)
const $optionYes = $('').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 = $('').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 array
for (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 = $('').addClass('form_' + formid).data('key', key).data('index', j).appendTo($p)
for (let i = 0; i < c[key][j].length; i++) {
const $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('
')
}
} else { // Array
const $select = $('').addClass('form_' + formid).data('key', key).appendTo($p)
for (let i = 0; i < c[key].length; i++) {
const $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.data
const $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 Array
if (!(key in newsettings[namespace]) || !Array.isArray(newsettings[namespace][key])) {
newsettings[namespace][key] = []
}
newsettings[namespace][key][index] = value
} else { // Normal
if (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.node
const $frame = $('