// ==UserScript==
// @icon https://bs.to/favicon.ico
// @name DEV burning series enhancer
// @name:en DEV burning series enhancer
// @author xtrars
// @description Wechselt automatisch zum Vivo-Tab auf burning series enhancer und öffnet Vivo oder Vupload. Das Tool startet das nächste Video und falls nötig die nächste Staffel, wenn eine Episode beendet wurde. Burning series enhancer bietet eine Downloadfunktion.
// @description:en Automatically switches to the Vivo tab on burning series enhancer and opens Vivo or Vupload. The tool starts the next video and if necessary the next season when an episode is finished. Burning series enhancer provides a download function.
// @version 6.0
// @run-at document-body
// @license GPL-3.0-or-later
// @namespace https://greasyforks.org/users/140785
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addValueChangeListener
// @grant GM_removeValueChangeListener
// @grant GM_download
// @grant GM_info
// @grant GM_addStyle
// @grant GM_getResourceText
// @grant window.close
// @grant window.focus
// @include https://bs.to/*
// @include https://burningseries.co/*
// @include https://burningseries.sx/*
// @include https://burningseries.vc/*
// @include https://burningseries.ac/*
// @include https://burningseries.cx/*
// @include https://burningseries.nz/*
// @include https://burningseries.se/*
// @include https://vivo.sx/*
// @include https://vivo.st/*
// @include https://vupload.com/*
// @include https://*.vivo.sx/*
// @include https://*.vivo.st/*
// @include https://*.megaupload.to/*
// @require https://unpkg.com/video.js/dist/video.min.js
// ==/UserScript==
class BaseHandler {
waitForElement(sSelector, bWaitUnlimited = true) {
return new Promise(async resolve => {
if (document.querySelector(sSelector)) {
return resolve(document.querySelector(sSelector));
}
const observer = new MutationObserver(() => {
if (document.querySelector(sSelector)) {
resolve(document.querySelector(sSelector));
observer.disconnect();
}
});
let waitForElementInterval = setInterval(() => {
if (document.body) {
observer.observe(document.body, {
childList: true,
subtree: true,
});
clearInterval(waitForElementInterval);
}
}, 20);
if (!bWaitUnlimited) {
setTimeout(() => {
resolve(document.querySelector(sSelector));
observer.disconnect();
}, 3000);
}
});
}
hasUrl(aSelector) {
let isAvailable = true;
for (let selector of aSelector) {
isAvailable = document['location']['href'].search(selector) !== -1;
if (!isAvailable) {
return false;
}
}
return true;
}
reload(iDelay = 300) {
setTimeout(() => {
window.location.reload();
}, iDelay);
}
}
class BurningSeriesHandler extends BaseHandler {
initGMVariables() {
if (typeof GM_getValue('bActivateEnhancer') === "undefined") {
GM_setValue('bActivateEnhancer', false);
}
if (typeof GM_getValue('bAutoplayNextEpisode') === "undefined") {
GM_setValue('bAutoplayNextEpisode', true);
}
if (typeof GM_getValue('bAutoplayVideo') === "undefined") {
GM_setValue('bAutoplayVideo', true);
}
if (typeof GM_getValue('bAutoplayNextSeason') === "undefined") {
GM_setValue('bAutoplayNextSeason', true);
}
if (typeof GM_getValue('bAutoplayRandomEpisode') === "undefined") {
GM_setValue('bAutoplayRandomEpisode', false);
}
if (typeof GM_getValue('bDownloadVideo') === "undefined") {
GM_setValue('bDownloadVideo', false);
}
if (typeof GM_getValue('bExtraSettings') === "undefined") {
GM_setValue('bExtraSettings', false);
}
if (typeof GM_getValue('bDownloadType') === "undefined") {
GM_setValue('bDownloadType', true);
}
if (typeof GM_getValue('bFirstStart') === "undefined") {
GM_setValue('bDownloadType', true);
}
if (typeof GM_getValue('bActivateVivo') === "undefined") {
GM_setValue('bActivateVivo', true);
}
}
hasAnotherHoster() {
return this.hasUrl([/^https:\/\/(bs.to|burningseries.[a-z]{2,3})\/.*[0-9]{1,2}\/[0-9]{1,2}-.*\/[a-z]*\/(?!Vivo|Vupload).*/g]);
}
isEpisode() {
return this.hasUrl([/^https:\/\/(bs.to|burningseries.[a-z]{2,3})/g, /[0-9]{1,2}\/[0-9]{1,2}-/g]);
}
async clickPlay() {
let playerElem = await this.waitForElement('section.serie .hoster-player').catch(() => {
});
let iNumberOfClicks = 0;
let clickInterval = setInterval(() => {
if (playerElem) {
if (document.querySelector('section.serie .hoster-player > a') ||
document.querySelector('iframe[title="recaptcha challenge"]') ||
iNumberOfClicks > 120) {
clearInterval(clickInterval);
}
iNumberOfClicks++;
let clickEvent = new Event('click');
clickEvent.which = 1;
clickEvent.pageX = 6;
clickEvent.pageY = 1;
playerElem.dispatchEvent(clickEvent);
}
}, 500);
}
playNextEpisodeIfVideoEnded(bSetEvent = true) {
if (!bSetEvent) {
GM_removeValueChangeListener('isLocalVideoEnded');
GM_setValue('isLocalVideoEnded', false);
return;
}
GM_addValueChangeListener('isLocalVideoEnded', () => {
if (GM_getValue('isLocalVideoEnded')) {
GM_setValue('isLocalVideoEnded', false);
window.focus();
if (GM_getValue('bAutoplayRandomEpisode')) {
let oRandomEpisode = document.querySelector('#sp_right > a');
document['location'].replace(oRandomEpisode.href);
} else {
let oNextEpisode = document.querySelector('.serie .frame ul li[class^="e"].active ~ li:not(.disabled) a');
if (oNextEpisode) {
document['location'].replace(oNextEpisode.href);
} else if (GM_getValue('bAutoplayNextSeason')) {
let oNextSeason = document.querySelector('.serie .frame ul li[class^="s"].active ~ li:not(.disabled) a');
if (oNextSeason) {
GM_setValue('clickFirstSeason', true);
document.location.replace(oNextSeason);
}
}
}
}
});
}
appendOwnStyle() {
const style = document.createElement('style');
style.innerHTML = `
:root {
--inner-pl: 14px;
--inner-bc-before: #2FB536;
--inner-bc-after: #12A6F6;
--color: white;
}
button.tab {
background-color: transparent;
color: white;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 10px;
padding-top: 7px;
user-select: none;
}
@keyframes shake {
10%, 90% {transform: translate3d(-.5px, 0, 0);}
20%, 80% {transform: translate3d(1px, 0, 0);}
30%, 50%, 70% {transform: translate3d(-2px, 0, 0);}
40%, 60% {transform: translate3d(2px, 0, 0);}
}
.onoffswitch {
z-index: 161;
position: relative; width: 100%;
}
.onoffswitch-label {
width: calc(100% - 20px);
display: block;
overflow: hidden;
float: left;
}
.onoffswitch-inner {
display: inline-block; width: 200%; margin-left: -100%;
transition: margin 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
margin-left: 0;
}
.onoffswitch-checkbox.disabled {
pointer-events: none;
-webkit-user-select: none; /* Safari */
user-select: none; /* Standard syntax */
}
.onoffswitch-inner:before, .onoffswitch-inner:after {
display: block;
float: left;
width: 50%;
padding-left: 10px;
font-size: 10px;
font-family: Trebuchet, Arial, sans-serif;
box-sizing: border-box;
}
#xtrars-btn {
position: absolute;
bottom: 70px;
right: 18px;
background: #12a6f6;
border-radius: 50%;
width: 70px;
height: 70px;
line-height: 81px;
text-align: center;
cursor: pointer;
animation: shake 1s ease 1s 1 normal;
}
#xtrars-menu {
right: 4;
}
#xtrars-btn-icon {
color: var(--color);
}
.onoffswitch-checkbox {
float: left;
margin-top: 3px;
cursor: pointer;
}
.onoffswitch.disabled {
color: grey;
}
.xtrars-switch {
position: relative;
display: inline-block;
width: 30px;
height: 17px;
margin-top: 6px;
margin-left: 10px;
}
.xtrars-switch input {
opacity: 0;
width: 0;
height: 0;
}
.xtrars-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.xtrars-slider:before {
position: absolute;
content: "";
height: 13px;
width: 15px;
left: 2px;
bottom: 2.5px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .xtrars-slider {
background-color: #669900;
}
input:focus + .xtrars-slider {
box-shadow: 0 0 1px #669900;
}
input:checked + .xtrars-slider:before {
-webkit-transform: translateX(11px);
transform: translateX(11px);
}
.onoffswitch-inner.autoplay:before {
content: "Video-Autoplay aktiviert";
}
.onoffswitch-inner.autoplay:after {
content: "Video-Autoplay deaktiviert";
}
.onoffswitch-inner.auto-next-episode:before {
content: "Nächste Episode wird automatisch abgespielt";
}
.onoffswitch-inner.auto-next-episode:after {
content: "Nächste Episode wird manuell abgespielt";
}
.onoffswitch-inner.enable-enhancer:before {
content: "burning series enhancer aktiviert";
}
.onoffswitch-inner.enable-enhancer:after {
content: "burning series enhancer deaktiviert";
}
.onoffswitch-inner.auto-next-season:before {
content: "Nächste Staffel wird automatisch abgespielt";
}
.onoffswitch-inner.auto-next-season:after {
content: "Nächste Staffel wird manuell abgespielt";
}
.onoffswitch-inner.auto-random-episode:before {
content: "Nächste folgende Episode wird abgespielt";
}
.onoffswitch-inner.auto-random-episode:after {
content: "Nächste Episode wird zufällig abgespielt";
}
.onoffswitch-inner.download:before {
content: "Downloadfunktion aktiviert";
}
.onoffswitch-inner.download:after {
content: "Downloadfunktion deaktiviert";
}
.onoffswitch-inner.extra-settings:before {
content: "Erweiterte Einstellungen eingeblendet";
}
.onoffswitch-inner.extra-settings:after {
content: "Erweiterte Einstellungen ausgeblendet";
}
.onoffswitch-inner.download-type:before {
content: "Video wird heruntergeladen & Stream angeschaut";
}
.onoffswitch-inner.download-type:after {
content: "Video wird heruntergeladen & Stream geschlossen";
}
.onoffswitch-inner.activate-vivo:before {
content: "Wechselt zum Vivo-Tab";
}
.onoffswitch-inner.activate-vivo:after {
content: "Wechselt zum Vupload-Tab";
}
.disabled:after {
background-color: darkgrey !important;
}
.disabled:before {
background-color: darkgrey !important;
}
.hidden {
visibility: hidden !important;
}
.xtrars-tabcontent::-webkit-scrollbar {
width: 10px;
}
.xtrars-tabcontent::-webkit-scrollbar-track {
background: #fdfdfd;
}
.xtrars-tabcontent::-webkit-scrollbar-thumb {
background: #12a6f6;
}
.xtrars-tabcontent::-webkit-scrollbar-thumb:hover {
background: #0296d6;
}
.xtrars-tabcontent {
display: none;
padding: 10px;
width: 100%;
height: calc(100% - 60px);
overflow: auto;
}
.xtrars-active {
text-shadow: -0.3px 0 #12a6f6, 0.3px 0 #12a6f6 !important;
color: #12a6f6 !important;
background-color: rgb(253, 253, 253) !important;
}
`;
document.head.appendChild(style);
}
async buildButton() {
const button = document.createElement("div");
button.innerHTML = `
<div id="xtrars-btn" style="cursor: pointer;">
<i id="xtrars-btn-icon" class="fas fa-cogs fa-2x"></i>
</div>`;
button.style.cssText = 'position: relative;';
await this.waitForElement('.infos').catch(() => {
});
document.getElementsByClassName('infos')[0].appendChild(button);
}
buildSettingsWindow() {
const settingsWindow = document.createElement("div");
settingsWindow.innerHTML = `
<div id="xtrars-settings-toolbar"
style="height: 30px; width: 100%; background-color: #12a6f6; color: white; line-height: 30px;">
<span style="margin-left: 10px; user-select: none; cursor: auto;">burning series enhancer - Settings</span>
<button id="xtrars-settings-close-btn" style="user-select: none; float: right; margin-top: 6px; background-color: transparent; border: none;
margin-right: 10px; cursor: pointer; font-weight: bolder; color: white;" onclick="closeSettingsWindow">✕</button>
</div>
<div id="xtrars-settings-tabs"
style="height: 30px; width: 100%; background-color: #12a6f6; color: white; line-height: 30px">
<button class="tab xtrars-settings-tabs xtrars-active" data-tab="BS">BS</button>
<button class="tab xtrars-settings-tabs" data-tab="Streaming">Streaming</button>
<button class="tab xtrars-settings-tabs" data-tab="Download">Download</button>
<button class="tab xtrars-settings-tabs" data-tab="Info">Info</button>
<label class="xtrars-switch">
<input type="checkbox" class="xtrars-onoffswitch">
<span class="xtrars-slider"></span>
</label>
</div>
<!-- Tab content -->
<div id="BS" class="xtrars-tabcontent" style="display: block; overflow: auto;">
<div class="onoffswitch">
<input type="checkbox" name="xtrars-onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch">
<label class="onoffswitch-label" for="xtrars-onoffswitch">
<span class="onoffswitch-inner auto-next-episode switch"></span>
</label>
</div>
<div class="onoffswitch">
<input type="checkbox" name="xtrars-onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch">
<label class="onoffswitch-label" for="xtrars-onoffswitch">
<span class="onoffswitch-inner auto-random-episode switch"></span>
</label>
</div>
<div class="onoffswitch">
<input type="checkbox" name="xtrars-onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch">
<label class="onoffswitch-label" for="xtrars-onoffswitch">
<span class="onoffswitch-inner auto-next-season switch"></span>
</label>
</div>
<div class="onoffswitch">
<input type="checkbox" name="xtrars-onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch">
<label class="onoffswitch-label" for="xtrars-onoffswitch">
<span class="onoffswitch-inner activate-vivo switch"></span>
</label>
</div>
</div>
<div id="Streaming" class="xtrars-tabcontent">
<div class="onoffswitch">
<input type="checkbox" name="xtrars-onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch">
<label class="onoffswitch-label" for="xtrars-onoffswitch">
<span class="onoffswitch-inner autoplay switch"></span>
</label>
</div>
</div>
<div id="Download" class="xtrars-tabcontent">
<div class="onoffswitch">
<input type="checkbox" name="xtrars-onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch">
<label class="onoffswitch-label" for="xtrars-onoffswitch">
<span class="onoffswitch-inner download switch"></span>
</label>
</div>
<div class="onoffswitch">
<input type="checkbox" name="xtrars-onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch">
<label class="onoffswitch-label" for="xtrars-onoffswitch">
<span class="onoffswitch-inner download-type switch"></span>
</label>
</div>
</div>
<div id="Info" class="xtrars-tabcontent" style="font-size: 10px;">
burning series enhancer by xtrars
</div>
`;
settingsWindow.style.cssText = 'display: none;';
settingsWindow.id = 'xtrars-settingsWindow';
document.body.appendChild(settingsWindow);
}
dragStart(e) {
let eSettingsWindow = document.getElementById('xtrars-settingsWindow');
let iSettingsWindowLeft = parseInt(window.getComputedStyle(eSettingsWindow).left);
let iSettingsWindowTop = parseInt(window.getComputedStyle(eSettingsWindow).top);
e.preventDefault();
if (e.type === "touchstart") {
document['settingsWindowInitialX'] = e.x - iSettingsWindowLeft;
document['settingsWindowInitialY'] = e.y - iSettingsWindowTop;
} else {
document['settingsWindowInitialX'] = e.x - iSettingsWindowLeft;
document['settingsWindowInitialY'] = e.y - iSettingsWindowTop;
}
document['settingsWindowActive'] = true;
}
dragEnd() {
document['settingsWindowActive'] = false;
}
drag(e) {
if (!document['settingsWindowActive']) {
return;
}
e.preventDefault();
let eSettingsWindow = document.getElementById('xtrars-settingsWindow');
let currentX;
let currentY;
if (e.type === "touchmove") {
currentX = (e.touches[0].x - document['settingsWindowInitialX']);
currentY = (e.touches[0].y - document['settingsWindowInitialY']);
} else {
currentX = (e.x - document['settingsWindowInitialX']);
currentY = (e.y - document['settingsWindowInitialY']);
}
eSettingsWindow.style.top = currentY + 'px';
eSettingsWindow.style.left = currentX + 'px';
while (parseInt(window.getComputedStyle(eSettingsWindow).left) <= 0) {
eSettingsWindow.style.left = parseInt(eSettingsWindow.style.left) + 1 + 'px';
}
while (parseInt(window.getComputedStyle(eSettingsWindow).top) <= 0) {
eSettingsWindow.style.top = parseInt(eSettingsWindow.style.top) + 1 + 'px';
}
while (parseInt(window.getComputedStyle(eSettingsWindow).right) <= 0) {
eSettingsWindow.style.left = parseInt(eSettingsWindow.style.left) - 1 + 'px';
}
while (parseInt(window.getComputedStyle(eSettingsWindow).bottom) <= 0) {
eSettingsWindow.style.top = parseInt(eSettingsWindow.style.top) - 1 + 'px';
}
}
showSettingsWindow() {
let eSettingsWindow = document.getElementById('xtrars-settingsWindow');
// Vorher schonmal setzen, damit korrekte Breite und Höhe berechnet werden kann
eSettingsWindow.style.cssText = `height: 160px; width: 500px; max-width: calc(100% - 4px); max-height: calc(100% - 4px); display: block; position: fixed;`;
eSettingsWindow.style.cssText = `height: 160px; width: 500px; max-width: calc(100% - 4px); max-height: calc(100% - 4px); display: block; position: fixed;
top: calc(50% - ${(parseInt(window.getComputedStyle(eSettingsWindow).height) / 2) + 'px'});
left: calc(50% - ${(parseInt(window.getComputedStyle(eSettingsWindow).width) / 2) + 'px'});
background-color: #fdfdfd; box-shadow: rgba(0, 0, 0, .05) 1px 1px 10px 5px; z-index: 2147483640;`
}
showTabContent(sTab) {
let eTabContent = document.querySelectorAll('.xtrars-tabcontent');
eTabContent.forEach(item => {
item.style.display = 'none';
});
document.getElementById(sTab).style.display = 'block';
}
initEvents() {
let eButton = document.getElementById('xtrars-btn');
let eToolbar = document.getElementById('xtrars-settings-toolbar');
let eSettingsWindow = document.getElementById('xtrars-settingsWindow');
let eTabs = document.querySelectorAll('.xtrars-settings-tabs');
let activateEnhancer = document.querySelector('#xtrars-settings-tabs .xtrars-onoffswitch');
let bsCheckboxes = document.querySelectorAll('#BS .xtrars-onoffswitch');
let streamingCheckboxes = document.querySelectorAll('#Streaming .xtrars-onoffswitch');
let downloadCheckboxes = document.querySelectorAll('#Download .xtrars-onoffswitch');
let autoplayNextEpisode = bsCheckboxes[0]; //auto-next-episode
let autoplayRandomEpisode = bsCheckboxes[1]; //auto-random-episode
let autoplayNextSeason = bsCheckboxes[2]; //auto-next-season
let activateVivo = bsCheckboxes[3]; //enable-vivo
let autoplayVideo = streamingCheckboxes[0]; //autoplay
let downloadVideo = downloadCheckboxes[0]; //download
let downloadType = downloadCheckboxes[1]; //download-type
eTabs.forEach(item => {
item.addEventListener('click', e => {
eTabs.forEach(tab => {
tab.classList.remove('xtrars-active');
});
e.target.classList.add('xtrars-active');
this.showTabContent(e.target.dataset.tab);
});
});
eButton.addEventListener('click', () => {
this.showSettingsWindow();
if (GM_getValue('bFirstStart')) {
GM_setValue('bFirstStart', false);
document.getElementsByClassName('xtrars-switch')[0].style.animation = 'shake 1s ease 1s 1 normal;'
}
document.addEventListener("touchmove", this.drag, {passive: false});
document.addEventListener("mousemove", this.drag, {passive: false});
});
eToolbar.addEventListener("touchstart", this.dragStart, {passive: false});
eToolbar.addEventListener("mousedown", this.dragStart, {passive: false});
document.addEventListener("touchend", this.dragEnd, {passive: false});
document.addEventListener("mouseup", this.dragEnd, {passive: false});
document.getElementById('xtrars-settings-close-btn').addEventListener('click', () => {
document.removeEventListener("touchmove", this.drag, {passive: false});
document.removeEventListener("mousemove", this.drag, {passive: false});
eSettingsWindow.style.cssText = 'display: none;';
});
let oManagedButtons = {
'activateEnhancer': activateEnhancer,
'autoplayNextEpisode': autoplayNextEpisode,
'autoplayRandomEpisode': autoplayRandomEpisode,
'autoplayNextSeason': autoplayNextSeason,
'autoplayVideo': autoplayVideo,
'downloadVideo': downloadVideo,
'downloadType': downloadType,
'activateVivo': activateVivo,
};
this.manageButtonState(oManagedButtons);
activateEnhancer.addEventListener('change', () => {
GM_setValue('bActivateEnhancer', activateEnhancer.checked);
this.manageButtonState(oManagedButtons);
this.reload();
});
autoplayNextEpisode.addEventListener('change', () => {
GM_setValue('bAutoplayNextEpisode', autoplayNextEpisode.checked);
this.manageButtonState(oManagedButtons);
});
autoplayRandomEpisode.addEventListener('change', () => {
GM_setValue('bAutoplayRandomEpisode', !autoplayRandomEpisode.checked);
this.manageButtonState(oManagedButtons);
});
autoplayNextSeason.addEventListener('change', () => {
GM_setValue('bAutoplayNextSeason', autoplayNextSeason.checked);
});
autoplayVideo.addEventListener('change', () => {
GM_setValue('bAutoplayVideo', autoplayVideo.checked);
});
activateVivo.addEventListener('change', () => {
GM_setValue('bActivateVivo', activateVivo.checked);
});
downloadVideo.addEventListener('change', () => {
GM_setValue('bDownloadVideo', downloadVideo.checked);
this.manageButtonState(oManagedButtons);
if (GM_info['downloadMode'] !== 'browser' && downloadVideo.checked) {
alert('Downloadfunktion nicht im Userscript-Manager aktiviert!');
}
});
downloadType.addEventListener('change', () => {
GM_setValue('bDownloadType', downloadType.checked);
this.manageButtonState(oManagedButtons);
});
window.addEventListener('resize', () => {
while (parseInt(window.getComputedStyle(eSettingsWindow).left) <= 0) {
eSettingsWindow.style.left = parseInt(eSettingsWindow.style.left) + 1 + 'px';
}
while (parseInt(window.getComputedStyle(eSettingsWindow).top) <= 0) {
eSettingsWindow.style.top = parseInt(eSettingsWindow.style.top) + 1 + 'px';
}
while (parseInt(window.getComputedStyle(eSettingsWindow).right) <= 0) {
eSettingsWindow.style.left = parseInt(eSettingsWindow.style.left) - 1 + 'px';
}
while (parseInt(window.getComputedStyle(eSettingsWindow).bottom) <= 0) {
eSettingsWindow.style.top = parseInt(eSettingsWindow.style.top) - 1 + 'px';
}
});
}
manageButtonState(oManagedButtons) {
let activateEnhancer = oManagedButtons['activateEnhancer'];
let autoplayNextEpisode = oManagedButtons['autoplayNextEpisode'];
let autoplayRandomEpisode = oManagedButtons['autoplayRandomEpisode'];
let autoplayNextSeason = oManagedButtons['autoplayNextSeason'];
let autoplayVideo = oManagedButtons['autoplayVideo'];
let downloadVideo = oManagedButtons['downloadVideo'];
let downloadType = oManagedButtons['downloadType'];
let activateVivo = oManagedButtons['activateVivo'];
activateEnhancer.checked = GM_getValue('bActivateEnhancer');
autoplayNextEpisode.checked = GM_getValue('bAutoplayNextEpisode');
autoplayRandomEpisode.checked = !GM_getValue('bAutoplayRandomEpisode');
autoplayNextSeason.checked = GM_getValue('bAutoplayNextSeason');
autoplayVideo.checked = GM_getValue('bAutoplayVideo');
downloadVideo.checked = GM_getValue('bDownloadVideo');
downloadType.checked = GM_getValue('bDownloadType');
activateVivo.checked = GM_getValue('bActivateVivo');
if (!activateEnhancer.checked) {
this.disableButton(autoplayVideo);
this.disableButton(autoplayNextEpisode);
this.disableButton(autoplayNextSeason);
this.disableButton(autoplayRandomEpisode);
this.disableButton(downloadVideo);
this.disableButton(downloadType);
this.disableButton(activateVivo);
} else {
this.enableButton(autoplayNextEpisode);
this.enableButton(downloadVideo);
this.enableButton(activateVivo);
if (autoplayNextEpisode.checked) {
this.enableButton(autoplayRandomEpisode);
this.enableButton(activateVivo);
this.disableButton(autoplayVideo);
if (!autoplayRandomEpisode.checked) {
this.disableButton(autoplayNextSeason);
} else {
this.enableButton(autoplayNextSeason);
}
} else {
this.disableButton(autoplayRandomEpisode);
this.disableButton(autoplayNextSeason);
this.disableButton(activateVivo);
this.enableButton(autoplayVideo);
}
if (downloadVideo.checked) {
this.enableButton(downloadType);
} else {
this.disableButton(downloadType);
}
}
}
hideButton(oElement) {
oElement.parentElement.style.visibility = 'hidden';
}
showButton(oElement) {
oElement.parentElement.style.visibility = 'visible';
}
disableButton(oElement) {
if (oElement.parentElement.childNodes[3].childNodes[1].classList.contains('auto-next-episode')) {
this.playNextEpisodeIfVideoEnded(false);
}
oElement.classList.add('disabled');
oElement.parentElement.classList.add('disabled');
oElement.disabled = true;
}
enableButton(oElement) {
oElement.classList.remove('disabled');
oElement.parentElement.classList.remove('disabled');
oElement.disabled = false;
}
}
class StreamingHandler extends BaseHandler {
applyShortcuts() {
document.addEventListener('keydown', this.shortcuts);
}
shortcuts(e) {
if (!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
switch (e.keyCode) {
case 37: // Left
e.preventDefault();
document['localVideo'].currentTime -= 10;
break;
case 38: // Up
e.preventDefault();
if (document['localVideo'].volume < 0.9) {
document['localVideo'].volume += 0.1;
} else {
document['localVideo'].volume = 1;
}
break;
case 39: // Right
e.preventDefault();
document['localVideo'].currentTime += 10;
break;
case 40: // Down
e.preventDefault();
if (document['localVideo'].volume > 0.1) {
document['localVideo'].volume -= 0.1;
} else {
document['localVideo'].volume = 0;
}
break;
case 70: // F
if (!document.fullscreenElement) {
document['localVideo'].requestFullscreen().catch(() => {
document['localVideo'].style.width = "100%";
document['localVideo'].style.height = "100%";
document.body.style.margin = "0px";
});
} else {
document.exitFullscreen().catch(() => {
});
}
break;
case 75: // K
if (document['localVideo'].paused) {
document['localVideo'].play();
} else {
document['localVideo'].pause();
}
break;
case 77: // M
document['localVideo'].muted = !document['localVideo'].muted;
break;
}
}
}
async handleStreamBehavior(oHoster, video) {
let match = video['src'].match(/^blob:https:\/\//g)
if (oHoster['hoster'] === 'vupload' && match !== null) {
let m3u8Regex = /(?<=sources.*)https:\/\/.*\.m3u8(?=",[ ]+type)/g;
// Extract m3u8 video url and then
video['src'] = Array.from(document.querySelectorAll('script')).filter(item => {
let match = item.text.match(m3u8Regex);
return match && match.length;
}).map(item => {
return item.text.match(m3u8Regex)[0];
});
document.body.innerHTML = `
<video id="xtrars-video" preload="true" controls="true" autoplay>
<source src="${video['src']}" type="application/x-mpegURL">
</video>
`;
return;
}
if (GM_getValue('bDownloadVideo') && GM_info['downloadMode'] === 'browser' && match === null) {
GM_download(video['src'], GM_getValue('sEpisodeName') + '.mp4');
if (!GM_getValue('bDownloadType')) {
setTimeout(() => {
GM_setValue('isLocalVideoEnded', true);
window.close();
}, 3000);
return;
}
}
if ((GM_getValue('bAutoplayVideo') || GM_getValue('bAutoplayNextEpisode')) && (!GM_getValue('bDownloadVideo') || GM_getValue('bDownloadType'))) {
window['location'].replace(video['src']);
}
}
async isStreamingHoster(regex, selector) {
return this.hasUrl([regex]) && await this.waitForElement(selector).catch(() => {
});
}
async handleStreamingHoster(aHoster) {
for (let oHoster of aHoster) {
if (await this.isStreamingHoster(oHoster['regex'], oHoster['selector'])) {
let video = await this.waitForElement(oHoster['selector'] + oHoster['detailSelector']).catch(() => {
});
await this.handleStreamBehavior(oHoster, video);
}
}
await this.handleLocalVideo();
}
async handleLocalVideo() {
let video = await this.waitForElement('html head ~ body video').catch(() => {
});
if (this.hasUrl(['vupload.com'])) {
let player = videojs('xtrars-video', {
autoSetup: 'false',
preload: 'true',
controls: true,
});
player.play();
video.controls = 'controls';
document.body.style.backgroundColor = 'black';
document.querySelector('#xtrars-video').style.cssText = 'width: 100%; height: 100%';
document.querySelector('#xtrars-video').childNodes.forEach((item, key) => {
if (key) {
item.style.display = 'none';
}
});
}
document['localVideo'] = video;
video.addEventListener('loadeddata', () => {
this.applyShortcuts();
});
video.style.width = "100%";
video.style.height = "100%";
document.body.style.margin = "0px";
video.requestFullscreen().catch(() => {
});
video.onended = () => {
GM_setValue('isLocalVideoEnded', true);
window.close();
}
}
}
(async function () {
'use strict';
let bsHandler = new BurningSeriesHandler();
let streamingHandler = new StreamingHandler();
if (GM_getValue('clickFirstSeason')) {
GM_setValue('clickFirstSeason', false);
let sSelector = '.serie > .episodes > tbody > tr:first-child > td:first-child > a:first-child';
await bsHandler.waitForElement(sSelector);
document['location'].replace(document.querySelector(sSelector));
}
bsHandler.initGMVariables();
if (bsHandler.isEpisode()) {
if (GM_getValue('bActivateEnhancer') && !bsHandler.hasAnotherHoster() && !bsHandler.hasUrl(['/Vivo']) &&
!bsHandler.hasUrl(['/Vupload'])) {
if (GM_getValue('bActivateVivo')) {
// TODO Drag im Touch
let hoster = await bsHandler.waitForElement('.hoster.VIVO', false);
if (hoster !== null) {
document['location'].replace(document['location']['href'] + '/Vivo');
} else {
document['location'].replace(document['location']['href'] + '/Vupload');
}
} else {
let hoster = await bsHandler.waitForElement('.hoster.Vupload', false);
if (hoster !== null) {
document['location'].replace(document['location']['href'] + '/Vupload');
} else {
document['location'].replace(document['location']['href'] + '/Vivo');
}
}
}
bsHandler.appendOwnStyle();
await bsHandler.buildButton();
bsHandler.buildSettingsWindow();
bsHandler.initEvents();
if (GM_getValue('bActivateEnhancer') && !bsHandler.hasAnotherHoster() && (bsHandler.hasUrl(['/Vivo']) || bsHandler.hasUrl(['/Vupload']))) {
if (GM_getValue('bAutoplayNextEpisode')) {
bsHandler.playNextEpisodeIfVideoEnded();
}
let oName = await bsHandler.waitForElement('.episode > h2');
GM_setValue('sEpisodeName', oName['outerText']);
await bsHandler.clickPlay();
}
}
if (GM_getValue('bActivateEnhancer')) {
// add new hoster here
let aHoster = [
{
selector: 'video:not(#player)',
regex: /^https:\/\/vivo.[a-z]{2,3}\//g,
detailSelector: ' > source',
hoster: 'vivo',
},
{
selector: '#vjsplayer_html5_api',
regex: /^https:\/\/vupload.[a-z]{2,3}\//g,
detailSelector: '[src]',
hoster: 'vupload',
},
];
await streamingHandler.handleStreamingHoster(aHoster);
}
})();