Init
This commit is contained in:
52
resources/js/admin-edit.js
Normal file
52
resources/js/admin-edit.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import Tagify from '@yaireo/tagify';
|
||||
import '@yaireo/tagify/dist/tagify.css';
|
||||
|
||||
const taginput = document.querySelector("#tags");
|
||||
const studioinput = document.querySelector("#studio");
|
||||
const episode_id = document.getElementById('e_id').value;
|
||||
|
||||
// Get Tags from API
|
||||
window.axios.get('/admin/tags/' + episode_id).then(function (response) {
|
||||
if (response.status != 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tagify = new Tagify(taginput, {
|
||||
whitelist: response.data.tags,
|
||||
dropdown: {
|
||||
classname: "color-blue",
|
||||
enabled: 0, // show the dropdown immediately on focus
|
||||
maxItems: 10,
|
||||
position: "text", // place the dropdown near the typed text
|
||||
closeOnSelect: false, // keep the dropdown open after selecting a suggestion
|
||||
highlightFirst: true
|
||||
}
|
||||
});
|
||||
|
||||
tagify.addTags(response.data.episodetags);
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
// Get Studio from API
|
||||
window.axios.get('/admin/studio/' + episode_id).then(function (response) {
|
||||
if (response.status != 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tagify = new Tagify(studioinput, {
|
||||
whitelist: response.data.studios,
|
||||
dropdown: {
|
||||
classname: "color-blue",
|
||||
enabled: 0, // show the dropdown immediately on focus
|
||||
maxItems: 10,
|
||||
position: "text", // place the dropdown near the typed text
|
||||
closeOnSelect: false, // keep the dropdown open after selecting a suggestion
|
||||
highlightFirst: true
|
||||
}
|
||||
});
|
||||
|
||||
tagify.addTags(response.data.episodestudios);
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
29
resources/js/admin-subtitles.js
Normal file
29
resources/js/admin-subtitles.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import Tagify from '@yaireo/tagify';
|
||||
import '@yaireo/tagify/dist/tagify.css';
|
||||
|
||||
const taginput = document.querySelector("#subtitles");
|
||||
const episode_id = document.getElementById('e_id').value;
|
||||
|
||||
// Get Tags from API
|
||||
window.axios.get('/admin/subtitles/' + episode_id).then(function (response) {
|
||||
if (response.status != 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tagify = new Tagify(taginput, {
|
||||
whitelist: response.data.subs,
|
||||
dropdown: {
|
||||
classname: "color-blue",
|
||||
enabled: 0, // show the dropdown immediately on focus
|
||||
maxItems: 10,
|
||||
position: "text", // place the dropdown near the typed text
|
||||
closeOnSelect: false, // keep the dropdown open after selecting a suggestion
|
||||
highlightFirst: true
|
||||
}
|
||||
});
|
||||
|
||||
tagify.addTags(response.data.episodesubs);
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
|
20
resources/js/app.js
Normal file
20
resources/js/app.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import './bootstrap';
|
||||
|
||||
// import { Alpine } from '../../vendor/livewire/livewire/dist/livewire.esm';
|
||||
// Alpine.start();
|
||||
|
||||
import {
|
||||
Collapse,
|
||||
Carousel,
|
||||
Clipboard,
|
||||
Modal,
|
||||
Lightbox,
|
||||
Tooltip,
|
||||
Tab,
|
||||
Ripple,
|
||||
initTE,
|
||||
} from "tw-elements";
|
||||
|
||||
initTE({ Collapse, Carousel, Clipboard, Modal, Tab, Lightbox, Tooltip, Ripple });
|
||||
|
||||
import 'hammerjs';
|
32
resources/js/bootstrap.js
vendored
Normal file
32
resources/js/bootstrap.js
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
* to our Laravel back-end. This library automatically handles sending the
|
||||
* CSRF token as a header based on the value of the "XSRF" token cookie.
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
* allows your team to easily build robust real-time web applications.
|
||||
*/
|
||||
|
||||
// import Echo from 'laravel-echo';
|
||||
|
||||
// import Pusher from 'pusher-js';
|
||||
// window.Pusher = Pusher;
|
||||
|
||||
// window.Echo = new Echo({
|
||||
// broadcaster: 'pusher',
|
||||
// key: import.meta.env.VITE_PUSHER_APP_KEY,
|
||||
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
|
||||
// wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
|
||||
// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
|
||||
// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
|
||||
// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
|
||||
// enabledTransports: ['ws', 'wss'],
|
||||
// });
|
12
resources/js/detect-ios.js
Normal file
12
resources/js/detect-ios.js
Normal file
@@ -0,0 +1,12 @@
|
||||
export function isIOS() {
|
||||
return [
|
||||
'iPad Simulator',
|
||||
'iPhone Simulator',
|
||||
'iPod Simulator',
|
||||
'iPad',
|
||||
'iPhone',
|
||||
'iPod'
|
||||
].includes(navigator.platform)
|
||||
// iPad on iOS 13 detection
|
||||
|| (navigator.userAgent.includes("Mac") && "ontouchend" in document)
|
||||
}
|
59
resources/js/modals-playlist.js
Normal file
59
resources/js/modals-playlist.js
Normal file
@@ -0,0 +1,59 @@
|
||||
if (document.getElementById("playlist-add")) {
|
||||
function createPlaylist() {
|
||||
console.log('Adding to Playlist: ' + document.querySelector("#playlist").value)
|
||||
|
||||
window.axios.post('/hentai/add-to-playlist', {
|
||||
playlist: document.getElementById('playlist').value,
|
||||
episode_id: document.getElementById('e_id').value
|
||||
}).then(function (response) {
|
||||
if (response.status == 200) {
|
||||
document.getElementById("playlist-cancel").click();
|
||||
|
||||
if (response.data.message == 'already-added') {
|
||||
Swal.fire({
|
||||
title: "Already added!",
|
||||
text: "Episode was already added to that Playlist!",
|
||||
icon: "warning"
|
||||
});
|
||||
}
|
||||
|
||||
if (response.data.message == 'success') {
|
||||
Swal.fire({
|
||||
title: "Success!",
|
||||
text: "Added episode to the playlist!",
|
||||
icon: "success"
|
||||
});
|
||||
}
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelector("#playlist-add").addEventListener("click", createPlaylist);
|
||||
}
|
||||
|
||||
if (document.getElementById("playlist-create-and-add")) {
|
||||
function createAndAddPlaylist() {
|
||||
window.axios.post('/hentai/create-playlist', {
|
||||
name: document.getElementById('name').value,
|
||||
visiblity: document.getElementById('visiblity').value
|
||||
}).then(function (response) {
|
||||
window.axios.post('/hentai/add-to-playlist', {
|
||||
playlist: response.data.playlist_id,
|
||||
episode_id: document.getElementById('e_id').value
|
||||
}).then(function (response) {
|
||||
if (response.status == 200) {
|
||||
document.getElementById("playlist-cancel").click();
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelector("#playlist-create-and-add").addEventListener("click", createAndAddPlaylist);
|
||||
}
|
94
resources/js/player-data.js
Normal file
94
resources/js/player-data.js
Normal file
@@ -0,0 +1,94 @@
|
||||
export function addVideoTracks(streamServer, apiResponse, av1Supported, dashSupported) {
|
||||
if (dashSupported) {
|
||||
return addDashTracks(streamServer, apiResponse, av1Supported);
|
||||
}
|
||||
|
||||
return addLegacyTracks(streamServer, apiResponse, av1Supported);
|
||||
}
|
||||
|
||||
|
||||
function addDashTracks(streamServer, apiResponse, av1Supported) {
|
||||
var data = [];
|
||||
|
||||
// 720p
|
||||
data.push({
|
||||
src: streamServer + '/' + apiResponse.stream_url + '/720/manifest.mpd',
|
||||
size: 720,
|
||||
mode: 'mpd',
|
||||
});
|
||||
|
||||
if (av1Supported) {
|
||||
// 1080p
|
||||
data.push({
|
||||
src: streamServer + '/' + apiResponse.stream_url + '/1080/manifest.mpd',
|
||||
size: 1080,
|
||||
mode: 'mpd',
|
||||
});
|
||||
|
||||
// 2160p
|
||||
data.push({
|
||||
src: streamServer + '/' + apiResponse.stream_url + '/2160/manifest.mpd',
|
||||
size: 2160,
|
||||
mode: 'mpd',
|
||||
});
|
||||
|
||||
if (apiResponse.interpolated == 1) {
|
||||
// 1080p Interpolated
|
||||
data.push({
|
||||
src: streamServer + '/' + apiResponse.stream_url + '/1080i/manifest.mpd',
|
||||
size: 1081,
|
||||
mode: 'mpd',
|
||||
});
|
||||
}
|
||||
|
||||
if (apiResponse.interpolated_uhd == 1) {
|
||||
// 2160p Interpolated
|
||||
data.push({
|
||||
src: streamServer + '/' + apiResponse.stream_url + '/2160i/manifest.mpd',
|
||||
size: 2161,
|
||||
mode: 'mpd',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function addLegacyTracks(streamServer, apiResponse, av1Supported) {
|
||||
var data = [];
|
||||
|
||||
// 720p
|
||||
data.push({
|
||||
src: streamServer + '/' + apiResponse.stream_url + '/x264.720p.mp4',
|
||||
type: 'video/mp4',
|
||||
size: 720,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
export function addSubtitleTracks(streamServer, apiResponse) {
|
||||
var data = [];
|
||||
|
||||
// Default
|
||||
data.push({
|
||||
kind: 'captions',
|
||||
label: 'English',
|
||||
srclang: 'en',
|
||||
src: '',
|
||||
default: true,
|
||||
});
|
||||
|
||||
for (var key in apiResponse.extra_subtitles) {
|
||||
data.push({
|
||||
kind: 'captions',
|
||||
label: apiResponse.extra_subtitles[key] + ' (Auto Transl.)',
|
||||
srclang: key,
|
||||
src: '',
|
||||
default: false,
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
144
resources/js/player-mobile.js
Normal file
144
resources/js/player-mobile.js
Normal file
@@ -0,0 +1,144 @@
|
||||
export function initMobileWidescreen() {
|
||||
// Mobile widescreen button
|
||||
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
||||
// Add Button to fit screen
|
||||
var controls = document.getElementsByClassName('plyr__controls')[0];
|
||||
|
||||
var newButton = `
|
||||
<button class="plyr__controls__item plyr__control" id="mobile-screen" type="button" aria-pressed="false" style="padding: 5px; padding-top: 2px; padding-bottom: 2px;">
|
||||
<i class="fa-solid fa-arrows-left-right-to-line" ></i>
|
||||
</button>
|
||||
`;
|
||||
|
||||
controls.insertAdjacentHTML('beforeend', newButton);
|
||||
|
||||
// Add event listener
|
||||
var stateButton = true;
|
||||
var videoTemp = document.querySelector('video');
|
||||
const mobilebutton = document.getElementById('mobile-screen');
|
||||
mobilebutton.addEventListener('click', function() {
|
||||
if (! stateButton) {
|
||||
videoTemp.style.objectFit = 'cover';
|
||||
stateButton = true;
|
||||
} else {
|
||||
videoTemp.style.objectFit = null;
|
||||
stateButton = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Set default
|
||||
videoTemp.style.objectFit = 'cover';
|
||||
}
|
||||
}
|
||||
|
||||
export function mobileDoubleClick(player) {
|
||||
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
||||
const byClass = document.getElementsByClassName.bind(document),
|
||||
createElement = document.createElement.bind(document);
|
||||
|
||||
// Remove all dblclick stuffs
|
||||
player.eventListeners.forEach(function (eventListener) {
|
||||
if (eventListener.type === 'dblclick') {
|
||||
eventListener.element.removeEventListener(eventListener.type, eventListener.callback, eventListener.options);
|
||||
}
|
||||
});
|
||||
|
||||
// Create overlay that will show the skipped time
|
||||
const skip_ol = createElement("div");
|
||||
skip_ol.id = "plyr__time_skip"
|
||||
byClass("plyr")[0].appendChild(skip_ol)
|
||||
|
||||
// A class to manage multi click count and remember last clicked side (may cause issue otherwise)
|
||||
class multiclick_counter {
|
||||
constructor() {
|
||||
this.timers = []; // collection of timers. Important
|
||||
this.count = 0; // click count
|
||||
this.reseted = 0; // before resetting what was the count
|
||||
this.last_side = null; // L C R 3sides
|
||||
}
|
||||
|
||||
clicked() {
|
||||
this.count += 1
|
||||
var xcount = this.count; // will be checked if click count increased in the time
|
||||
this.timers.push(setTimeout(this.reset.bind(this, xcount), 500)); // wait till 500ms for next click
|
||||
return this.count
|
||||
}
|
||||
|
||||
reset_count(n) {
|
||||
// Reset count if clicked on the different side
|
||||
this.reseted = this.count
|
||||
this.count = n
|
||||
for (var i = 0; i < this.timers.length; i++) {
|
||||
clearTimeout(this.timers[i]);
|
||||
}
|
||||
this.timer = []
|
||||
}
|
||||
|
||||
reset(xcount) {
|
||||
if (this.count > xcount) { return } // return if clicked after timer started
|
||||
// Reset otherwise
|
||||
this.count = 0;
|
||||
this.last_side = null;
|
||||
this.reseted = 0;
|
||||
skip_ol.style.opacity = "0";
|
||||
this.timer = []
|
||||
}
|
||||
}
|
||||
|
||||
var counter = new multiclick_counter();
|
||||
|
||||
const poster = byClass("plyr__poster")[0]
|
||||
poster.onclick = function (e) {
|
||||
const count = counter.clicked()
|
||||
if (count < 2) { return } // if not double click
|
||||
|
||||
const rect = e.target.getBoundingClientRect();
|
||||
const x = e.clientX - rect.left; //x position within the element.
|
||||
|
||||
// The relative position of click on video
|
||||
const width = e.target.offsetWidth;
|
||||
const perc = x * 100 / width;
|
||||
|
||||
var panic = true; // panic if the side needs to be checked
|
||||
var last_click = counter.last_side
|
||||
|
||||
if (last_click == null) {
|
||||
panic = false
|
||||
}
|
||||
|
||||
if (perc < 40) {
|
||||
if (player.currentTime == 0) {
|
||||
return // won't seek beyond 0
|
||||
}
|
||||
counter.last_side = "L"
|
||||
if (panic && last_click != "L") {
|
||||
counter.reset_count(1)
|
||||
return
|
||||
}
|
||||
|
||||
skip_ol.style.opacity = "0.9";
|
||||
player.rewind()
|
||||
skip_ol.innerHTML = "<i class=\"fa-solid fa-backward\"></i> " + ((count - 1) * 10) + "s";
|
||||
}
|
||||
else if (perc > 60) {
|
||||
if (player.currentTime == player.duration) {
|
||||
return // won't seek beyond duration
|
||||
}
|
||||
counter.last_side = "R"
|
||||
if (panic && last_click != "R") {
|
||||
counter.reset_count(1)
|
||||
return
|
||||
}
|
||||
|
||||
skip_ol.style.opacity = "0.9";
|
||||
last_click = "R"
|
||||
player.forward()
|
||||
skip_ol.innerHTML = "<i class=\"fa-solid fa-forward\"></i> " + ((count - 1) * 10) + "s";
|
||||
}
|
||||
else {
|
||||
player.togglePlay()
|
||||
counter.last_click = "C"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
resources/js/player-server-select.js
Normal file
45
resources/js/player-server-select.js
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
export function serverSelectMenuItem(selectedIndex) {
|
||||
return `
|
||||
<button id="server-select" data-plyr="settings" type="button" class="plyr__control plyr__control--forward" role="menuitem" aria-haspopup="true">
|
||||
<span>Server<span class="plyr__menu__value">CDN` + (selectedIndex + 1) + `</span></span>
|
||||
</button>`;
|
||||
}
|
||||
|
||||
export function serverSelectSubmenu(selectedIndex, serverCount) {
|
||||
let htmlList = `
|
||||
<div id="server-select-list" hidden>
|
||||
<button type="button" class="plyr__control plyr__control--back" id="server-select-list-back-btn">
|
||||
<span aria-hidden="true">Server</span><span class="plyr__sr-only">Go back to previous menu</span>
|
||||
</button>
|
||||
<div role="menu">
|
||||
`;
|
||||
|
||||
for (let i = 0; i < serverCount; i++) {
|
||||
let checked = selectedIndex == i ? 'true' : 'false';
|
||||
let index = i + 1;
|
||||
htmlList += `
|
||||
<button data-plyr="server" type="button" role="menuitemradio" class="plyr__control change_server" aria-checked="` + checked + `" value="` + i +`">
|
||||
<span>Server ` + index + `<span class="plyr__menu__value"><span class="plyr__badge">CDN` + index + `</span></span></span>
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlList += `
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return htmlList;
|
||||
}
|
||||
|
||||
export function serverSelectMenuClickToggle() {
|
||||
if (document.getElementById('server-select-list').hidden) {
|
||||
document.querySelector('div[role="menu"]').hidden = true;
|
||||
document.getElementById('server-select-list').hidden = false;
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('server-select-list').hidden = true;
|
||||
document.querySelector('div[role="menu"]').hidden = false;
|
||||
}
|
462
resources/js/player.js
Normal file
462
resources/js/player.js
Normal file
@@ -0,0 +1,462 @@
|
||||
// Plyr Player
|
||||
import Plyr from 'plyr/dist/plyr.polyfilled.min.js';
|
||||
import 'plyr/dist/plyr.css';
|
||||
|
||||
// Vidstack Player
|
||||
import 'vidstack/player/styles/default/theme.css';
|
||||
import 'vidstack/player/styles/default/layouts/video.css';
|
||||
import { VidstackPlayer, VidstackPlayerLayout } from 'vidstack/global/player';
|
||||
|
||||
// Dash Support
|
||||
import dashjs from 'dashjs';
|
||||
|
||||
// Subtitle Support
|
||||
import SubtitlesOctopus from '@jellyfin/libass-wasm';
|
||||
|
||||
// Custom JS
|
||||
import { initMobileWidescreen } from './player-mobile';
|
||||
import { mobileDoubleClick } from './player-mobile'
|
||||
import { playNextPlaylistVideo } from './playlist';
|
||||
import { addVideoTracks } from './player-data';
|
||||
import { addSubtitleTracks } from './player-data';
|
||||
import { serverSelectMenuItem, serverSelectSubmenu, serverSelectMenuClickToggle } from './player-server-select';
|
||||
import { isIOS } from './detect-ios';
|
||||
|
||||
// Variables
|
||||
var player = null;
|
||||
var av1Supported = (!!document.createElement('video').canPlayType('video/webm; codecs="av01.0.05M.08, opus"'));
|
||||
var dashSupported = dashjs.supportsMediaSource();
|
||||
var apiResponse = {};
|
||||
var volume = 0.5;
|
||||
var captions = true;
|
||||
var lastTime = 0.0;
|
||||
var streamServer = '';
|
||||
var streamServers = [];
|
||||
var streamServerIndex = 0;
|
||||
var streamServerCount = 0;
|
||||
var ambientMode = true;
|
||||
var serverFallback = false;
|
||||
var saveInterval;
|
||||
|
||||
var subtitleInstance = null;
|
||||
|
||||
var controls = [
|
||||
'play-large', // The large play button in the center
|
||||
'play', // Play/pause playback
|
||||
'progress', // The progress bar and scrubber for playback and buffering
|
||||
'current-time', // The current time of playback
|
||||
'duration', // The full duration of the media
|
||||
'mute', // Toggle mute
|
||||
'volume', // Volume control
|
||||
'captions', // Toggle captions
|
||||
'settings', // Settings menu
|
||||
'fullscreen', // Toggle fullscreen
|
||||
];
|
||||
|
||||
// Load Volume from LocalStorage
|
||||
if (localStorage.hstreamVolume) {
|
||||
volume = parseFloat(localStorage.getItem('hstreamVolume')).toFixed(2);
|
||||
console.log('Loaded Audio Volume from Local Storage: ' + volume);
|
||||
}
|
||||
|
||||
// Load Captions from LocalStorage
|
||||
if (localStorage.hstreamCaptions) {
|
||||
captions = (localStorage.getItem('hstreamCaptions') == 'true');
|
||||
console.log('Loaded Captions Status from Local Storage: ' + captions);
|
||||
}
|
||||
|
||||
// Asia Server Fallback
|
||||
if (localStorage.hstreamServerFallback) {
|
||||
serverFallback = (localStorage.getItem('hstreamServerFallback') == 'true');
|
||||
console.log('Loaded Captions Status from Local Storage: ' + captions);
|
||||
}
|
||||
|
||||
// Alert User when AV1 is not supported
|
||||
if (!av1Supported) {
|
||||
document.getElementById("av1-unsupported").classList.remove("hidden");
|
||||
}
|
||||
|
||||
function initDash(data, player) {
|
||||
const video = document.querySelector('video');
|
||||
|
||||
data.forEach(function (el) {
|
||||
if (el.mode === 'mpd' && el.size === player.config.quality.selected) {
|
||||
const dash = dashjs.MediaPlayer().create();
|
||||
dash.initialize(video, el.src, true);
|
||||
// Expose player and dash so they can be used from the console
|
||||
window.player = player;
|
||||
window.dash = dash;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setCanvasDimension(canvas, video) {
|
||||
canvas.height = video.offsetHeight;
|
||||
canvas.width = video.offsetWidth;
|
||||
}
|
||||
|
||||
function paintStaticVideo(ctx, video) {
|
||||
if (localStorage.theme == 'light') {
|
||||
return;
|
||||
}
|
||||
if (!ambientMode) {
|
||||
return;
|
||||
}
|
||||
ctx.drawImage(video, 0, 0, video.offsetWidth, video.offsetHeight);
|
||||
}
|
||||
|
||||
function toggleAmbientMode() {
|
||||
let canvas = document.getElementById("ambientVideo"), ctx = canvas.getContext("2d"), video = document.getElementsByTagName('video')[0];
|
||||
if (ambientMode) {
|
||||
ambientMode = false;
|
||||
localStorage.ambientMode = 'false';
|
||||
setCanvasDimension(canvas, video);
|
||||
document.getElementById('ambient-mode-toggle').innerHTML = '<span>Ambient Mode<span class="plyr__menu__value">Off</span></span>';
|
||||
} else {
|
||||
ambientMode = true;
|
||||
localStorage.ambientMode = 'true';
|
||||
setCanvasDimension(canvas, video);
|
||||
paintStaticVideo(ctx, video);
|
||||
document.getElementById('ambient-mode-toggle').innerHTML = '<span>Ambient Mode<span class="plyr__menu__value">On</span></span>';
|
||||
}
|
||||
}
|
||||
|
||||
function toggleAsiaServer() {
|
||||
if (serverFallback) {
|
||||
serverFallback = false;
|
||||
localStorage.hstreamServerFallback = 'false';
|
||||
document.getElementById('server-fallback-toggle').innerHTML = '<span>Fallback Server<span class="plyr__menu__value">Off</span></span>';
|
||||
streamServers = apiResponse.stream_domains;
|
||||
} else {
|
||||
serverFallback = true;
|
||||
localStorage.hstreamServerFallback = 'true';
|
||||
document.getElementById('server-fallback-toggle').innerHTML = '<span>Fallback Server<span class="plyr__menu__value">On</span></span>';
|
||||
streamServers = apiResponse.asia_stream_domains;
|
||||
}
|
||||
|
||||
streamServerCount = streamServers.length;
|
||||
streamServerIndex = Math.floor(Math.random() * streamServerCount);
|
||||
streamServer = streamServers[streamServerIndex];
|
||||
console.log('Selected Server: ' + streamServer);
|
||||
|
||||
if (player) {
|
||||
clearInterval(saveInterval);
|
||||
player.destroy();
|
||||
}
|
||||
initPlayer();
|
||||
}
|
||||
|
||||
function initSubtitles(lang) {
|
||||
if (isIOS()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dispose old instance
|
||||
if (subtitleInstance != null && subtitleInstance instanceof SubtitlesOctopus) {
|
||||
subtitleInstance.dispose();
|
||||
}
|
||||
|
||||
let newSubUrl = streamServer + '/' + apiResponse.stream_url + '/';
|
||||
|
||||
if (lang != 'en') {
|
||||
newSubUrl += 'autotrans/' + lang + '.ass';
|
||||
}
|
||||
else {
|
||||
newSubUrl += 'eng.ass'
|
||||
}
|
||||
|
||||
let subFont = '/fonts/Figtree-ExtraBold.woff2';
|
||||
// Hindi font
|
||||
if (lang == 'hi') {
|
||||
subFont = '/fonts/Hind-SemiBold.ttf';
|
||||
}
|
||||
|
||||
// Subtitles
|
||||
var options = {
|
||||
video: document.getElementsByTagName('video')[0], // HTML5 video element
|
||||
subUrl: newSubUrl, // Link to subtitles
|
||||
workerUrl: '/build/js/subtitles-octopus-worker.js', // Link to WebAssembly-based file "libassjs-worker.js"
|
||||
legacyWorkerUrl: '/build/js/subtitles-octopus-worker-legacy.js', // Link to non-WebAssembly worker
|
||||
fonts: [subFont],
|
||||
renderMode: 'wasm-blend',
|
||||
};
|
||||
|
||||
subtitleInstance = new SubtitlesOctopus(options);
|
||||
}
|
||||
|
||||
function initPlayer() {
|
||||
player = new Plyr('#player', {
|
||||
controls,
|
||||
quality: {
|
||||
default: 720,
|
||||
options: [2161, 2160, 1081, 1080, 720]
|
||||
},
|
||||
i18n: {
|
||||
qualityLabel: {
|
||||
2161: "2160p48",
|
||||
2160: "2160p",
|
||||
1081: "1080p48",
|
||||
1080: "1080p",
|
||||
720: "720p"
|
||||
},
|
||||
qualityBadge: {
|
||||
2161: "UHD@48",
|
||||
1081: "FHD@48",
|
||||
1080: "FHD",
|
||||
},
|
||||
},
|
||||
fullscreen: { enabled: true, fallback: true, iosNative: true }
|
||||
});
|
||||
|
||||
// Player Track Data
|
||||
var data = addVideoTracks(streamServer, apiResponse, av1Supported, dashSupported);
|
||||
|
||||
player.source = {
|
||||
type: 'video',
|
||||
title: apiResponse.title,
|
||||
poster: apiResponse.poster,
|
||||
previewThumbnails: {
|
||||
enabled: true,
|
||||
src: streamServer + '/' + apiResponse.stream_url + '/thumbs.vtt',
|
||||
},
|
||||
sources: data,
|
||||
tracks: addSubtitleTracks(streamServer, apiResponse)
|
||||
};
|
||||
|
||||
player.volume = volume;
|
||||
//player.captions.languages = ['en'];
|
||||
player.captions.language = 'en';
|
||||
player.captions.active = captions;
|
||||
|
||||
if (dashSupported && !apiResponse.legacy) {
|
||||
player.on('qualitychange', () => {
|
||||
initDash(data, player);
|
||||
});
|
||||
|
||||
initDash(data, player);
|
||||
}
|
||||
|
||||
// Ambient Mode
|
||||
let canvas = document.getElementById("ambientVideo"), ctx = canvas.getContext("2d"), video = document.getElementsByTagName('video')[0];
|
||||
setCanvasDimension(canvas, video);
|
||||
paintStaticVideo(ctx, video);
|
||||
|
||||
var allItems = document.getElementsByClassName('plyr__control--forward');
|
||||
var lastItem = allItems[allItems.length - 1];
|
||||
lastItem.insertAdjacentHTML('afterend', '<button id="ambient-mode-toggle" type="button" class="plyr__control" role="menuitem" aria-haspopup="true"><span>Ambient Mode<span class="plyr__menu__value">On</span></span></button>');
|
||||
document.getElementById('ambient-mode-toggle').addEventListener('click', toggleAmbientMode);
|
||||
|
||||
if (localStorage.ambientMode == 'false') {
|
||||
toggleAmbientMode();
|
||||
}
|
||||
|
||||
// Server select (Asia)
|
||||
lastItem = allItems[allItems.length - 1];
|
||||
let value = 'Off';
|
||||
if (serverFallback) { value = 'On'; }
|
||||
lastItem.insertAdjacentHTML('afterend', '<button id="server-fallback-toggle" type="button" class="plyr__control" role="menuitem" aria-haspopup="true"><span>Fallback Server<span class="plyr__menu__value">' + value + '</span></span></button>');
|
||||
document.getElementById('server-fallback-toggle').addEventListener('click', toggleAsiaServer);
|
||||
|
||||
var clickedPlay = false;
|
||||
|
||||
player.on('play', () => {
|
||||
if (!clickedPlay) {
|
||||
player.stop();
|
||||
console.log("Stopped video, because user didn't click play.")
|
||||
}
|
||||
|
||||
setCanvasDimension(canvas, video);
|
||||
console.log('Play => Function Loop()');
|
||||
var $this = video;
|
||||
(function loop() {
|
||||
if (!player.paused && !player.ended && localStorage.theme == 'dark' && ambientMode) {
|
||||
ctx.drawImage($this, 0, 0, $this.offsetWidth, $this.offsetHeight);
|
||||
setTimeout(loop, 24000 / 1001); // drawing at 30fps
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
player.on('seeked', () => {
|
||||
paintStaticVideo(ctx, video);
|
||||
if (player.currentTime > 0) {
|
||||
lastTime = player.currentTime;
|
||||
}
|
||||
console.log('Seeked => paintStaticVideo() at ' + player.currentTime);
|
||||
});
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
setCanvasDimension(canvas, video);
|
||||
if (player.paused) {
|
||||
paintStaticVideo(ctx, video);
|
||||
}
|
||||
});
|
||||
|
||||
player.on('captionsenabled', () => {
|
||||
document.getElementsByClassName('libassjs-canvas-parent')[0].style.visibility = 'visible';
|
||||
localStorage.setItem('hstreamCaptions', 'true');
|
||||
console.log('Set Captions Status to Local Storage: true');
|
||||
});
|
||||
|
||||
player.on('captionsdisabled', () => {
|
||||
document.getElementsByClassName('libassjs-canvas-parent')[0].style.visibility = 'hidden';
|
||||
localStorage.setItem('hstreamCaptions', 'false');
|
||||
console.log('Set Captions Status to Local Storage: false');
|
||||
});
|
||||
|
||||
player.on('volumechange', () => {
|
||||
console.log('Saving Audio Volume to Local Storage: ' + player.volume);
|
||||
localStorage.setItem('hstreamVolume', player.volume.toString())
|
||||
});
|
||||
|
||||
player.on('ended', () => {
|
||||
playNextPlaylistVideo();
|
||||
});
|
||||
|
||||
player.on('languagechange', (event) => {
|
||||
let lang = event.detail.plyr.captions.language;
|
||||
|
||||
console.log('Subtitle Event ' + lang);
|
||||
initSubtitles(lang);
|
||||
});
|
||||
|
||||
function playerPlayTemp() {
|
||||
clickedPlay = true;
|
||||
}
|
||||
|
||||
document.querySelectorAll('[data-plyr="play"]').forEach(play =>
|
||||
play.addEventListener('click', playerPlayTemp)
|
||||
);
|
||||
|
||||
document.getElementsByClassName('plyr--video')[0].addEventListener('click', playerPlayTemp);
|
||||
|
||||
initMobileWidescreen();
|
||||
|
||||
// Start time
|
||||
setTimeout(function () {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const time = parseInt(params.get("t"));
|
||||
if (!isNaN(time)) {
|
||||
player.currentTime = time;
|
||||
console.log("Skipping to " + time)
|
||||
}
|
||||
if (lastTime > 0) {
|
||||
player.currentTime = lastTime;
|
||||
console.log("Skipping to " + lastTime)
|
||||
}
|
||||
}, 500);
|
||||
|
||||
player.on('ready', () => {
|
||||
mobileDoubleClick(player);
|
||||
});
|
||||
|
||||
// Server Select
|
||||
// I hate this...
|
||||
var settingElements = document.getElementsByClassName('plyr__control--forward');
|
||||
if (settingElements.length == 3) {
|
||||
settingElements[2].insertAdjacentHTML('afterend', serverSelectMenuItem(streamServerIndex));
|
||||
|
||||
var settingNodes = document.getElementsByClassName('plyr__menu__container')[0].childNodes[0].childNodes;
|
||||
if (settingNodes.length == 4) {
|
||||
document.getElementsByClassName('plyr__menu__container')[0].childNodes[0].childNodes[3].insertAdjacentHTML('afterend', serverSelectSubmenu(streamServerIndex, streamServerCount));
|
||||
}
|
||||
|
||||
// Event Listeners
|
||||
document.getElementById('server-select').addEventListener('click', serverSelectMenuClickToggle);
|
||||
document.getElementById('server-select-list-back-btn').addEventListener('click', serverSelectMenuClickToggle);
|
||||
let serverSelects = document.getElementsByClassName('change_server');
|
||||
for (let i = 0; i < serverSelects.length; i++) {
|
||||
serverSelects[i].addEventListener('click', function() {
|
||||
streamServerIndex = Number(this.value);
|
||||
streamServer = streamServers[streamServerIndex];
|
||||
console.log('Selected Server: ' + streamServer);
|
||||
|
||||
if (player) {
|
||||
clearInterval(saveInterval);
|
||||
player.destroy();
|
||||
}
|
||||
initPlayer();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Periodically save last timestamp
|
||||
saveInterval = setInterval(function () {
|
||||
lastTime = player.currentTime;
|
||||
console.log("Last Player Position: " + lastTime);
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
async function initVidstackPlayer() {
|
||||
const videoSource = streamServer + '/' + apiResponse.stream_url + '/x264.720p.mp4';
|
||||
const videoThumbs = streamServer + '/' + apiResponse.stream_url + '/thumbs.vtt';
|
||||
const videoCaption = streamServer + '/' + apiResponse.stream_url + '/eng.vtt';
|
||||
|
||||
player = await VidstackPlayer.create({
|
||||
target: '#player',
|
||||
title: apiResponse.title,
|
||||
src: videoSource,
|
||||
poster: apiResponse.poster,
|
||||
layout: new VidstackPlayerLayout({
|
||||
thumbnails: videoThumbs,
|
||||
}),
|
||||
tracks: [
|
||||
{
|
||||
src: videoCaption,
|
||||
label: 'English',
|
||||
language: 'en-US',
|
||||
kind: 'subtitles',
|
||||
type: 'vtt',
|
||||
default: true,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Ambient Mode
|
||||
let canvas = document.getElementById("ambientVideo"), ctx = canvas.getContext("2d"), video = document.getElementsByTagName('video')[0];
|
||||
setCanvasDimension(canvas, video);
|
||||
paintStaticVideo(ctx, video);
|
||||
|
||||
player.addEventListener('play', () => {
|
||||
setCanvasDimension(canvas, video);
|
||||
console.log('Play => Function Loop()');
|
||||
var $this = video;
|
||||
(function loop() {
|
||||
if (!player.paused && !player.ended && localStorage.theme == 'dark' && ambientMode) {
|
||||
ctx.drawImage($this, 0, 0, $this.offsetWidth, $this.offsetHeight);
|
||||
setTimeout(loop, 24000 / 1001); // drawing at 30fps
|
||||
}
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
// Get Data from API
|
||||
window.axios.post('/player/api', {
|
||||
episode_id: document.getElementById('e_id').value
|
||||
}).then(function (response) {
|
||||
if (response.status == 200) {
|
||||
apiResponse = response.data;
|
||||
streamServers = apiResponse.stream_domains;
|
||||
|
||||
if (serverFallback) {
|
||||
streamServers = apiResponse.asia_stream_domains;
|
||||
}
|
||||
|
||||
streamServerCount = streamServers.length;
|
||||
streamServerIndex = Math.floor(Math.random() * streamServerCount);
|
||||
streamServer = streamServers[streamServerIndex];
|
||||
console.log('Selected Server: ' + streamServer + ' with Index: ' + streamServerIndex);
|
||||
|
||||
if (!isIOS()) {
|
||||
initPlayer();
|
||||
}
|
||||
else {
|
||||
console.log("Detected Apple Shit. Using different player.")
|
||||
initVidstackPlayer();
|
||||
}
|
||||
|
||||
}
|
||||
}).catch(function (error) {
|
||||
var alert = document.getElementById("player-alert");
|
||||
alert.innerText = 'The player encountered a problem: ' + error;
|
||||
alert.classList.remove("hidden");
|
||||
});
|
120
resources/js/playlist.js
Normal file
120
resources/js/playlist.js
Normal file
@@ -0,0 +1,120 @@
|
||||
export function playNextPlaylistVideo() {
|
||||
console.log('Playing next episode');
|
||||
if (!document.getElementById("playlist_id")) {
|
||||
console.log('No playlist specified');
|
||||
return;
|
||||
}
|
||||
|
||||
var playlistId = document.getElementById("playlist_id").value;
|
||||
var nextEpisode = document.getElementById("playlist_next_episode_slug").value;
|
||||
|
||||
if (nextEpisode === ""){
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = '/hentai/' + nextEpisode + '?playlist=' + playlistId;
|
||||
}
|
||||
|
||||
function deleteEntry(playlistId, episodeId) {
|
||||
window.axios.post('/user/playlist-episode', {
|
||||
playlist: playlistId,
|
||||
episode: episodeId
|
||||
}).then(function (response) {
|
||||
if (response.status == 200) {
|
||||
console.log(response);
|
||||
if (response.data.message == 'success') {
|
||||
Swal.fire({
|
||||
title: "Deleted!",
|
||||
text: "Removed entry from playlist!",
|
||||
icon: "success",
|
||||
confirmButtonText: "OK",
|
||||
willClose: () => {
|
||||
location.reload();
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}).catch(function (error) {
|
||||
Swal.fire({
|
||||
title: "Error!",
|
||||
text: error,
|
||||
icon: "error"
|
||||
});
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
function addDesktopDeleteListener() {
|
||||
const deleteButtons = document.querySelectorAll('[id^="delD"]');
|
||||
|
||||
deleteButtons.forEach(button => {
|
||||
const playlist = button.id.split('-')[1];
|
||||
const episode = button.id.split('-')[2];
|
||||
console.log("Playlist: " + playlist + " Episode: " + episode);
|
||||
|
||||
button.addEventListener('click', () => deleteEntry(playlist, episode));
|
||||
});
|
||||
}
|
||||
|
||||
// Playlist Swipe (Delete)
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const swipeContainers = document.querySelectorAll('.swipe-container');
|
||||
|
||||
var swipeOptions = {
|
||||
dragLockToAxis: true,
|
||||
dragBlockHorizontal: true
|
||||
};
|
||||
|
||||
swipeContainers.forEach(container => {
|
||||
const controls = new Hammer(container, swipeOptions);
|
||||
const originalColor = container.style.backgroundColor;
|
||||
const playlistId = container.id.split('-')[0];
|
||||
const episodeId = container.id.split('-')[1];
|
||||
const delIcon = document.getElementById('del-' + container.id);
|
||||
|
||||
// Set the initial position
|
||||
let posX = 0;
|
||||
|
||||
// Listen for the pan gesture
|
||||
controls.on('pan', (event) => {
|
||||
// Update the X position based on the drag delta
|
||||
posX = event.deltaX;
|
||||
if (posX > 0) {
|
||||
// Only allow left swipe
|
||||
posX = 0;
|
||||
}
|
||||
|
||||
// Apply the translation to the element
|
||||
container.style.transform = `translateX(${posX}px)`;
|
||||
container.style.backgroundColor = "rgba(159, 18, 18, 0.3)";
|
||||
|
||||
setTimeout(() => {
|
||||
delIcon.classList.remove('fa-grip-lines-vertical');
|
||||
delIcon.classList.add('fa-trash');
|
||||
}, 300);
|
||||
});
|
||||
|
||||
controls.on('panend', () => {
|
||||
container.style.transition = 'transform 0.3s ease';
|
||||
container.style.transform = 'translateX(0)';
|
||||
setTimeout(() => {
|
||||
container.style.transition = ''; // Reset transition for next drag
|
||||
container.style.backgroundColor = originalColor;
|
||||
delIcon.classList.remove('fa-trash');
|
||||
delIcon.classList.add('fa-grip-lines-vertical');
|
||||
}, 300);
|
||||
});
|
||||
|
||||
controls.on('swipeleft', (event) => {
|
||||
container.style.display = 'none';
|
||||
console.log(playlistId, episodeId);
|
||||
deleteEntry(playlistId, episodeId);
|
||||
});
|
||||
});
|
||||
|
||||
addDesktopDeleteListener();
|
||||
});
|
56
resources/js/preview.js
Normal file
56
resources/js/preview.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const sleep = (ms = 0) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
var old_timestamp = document.getElementById('ts_reference').value;
|
||||
|
||||
function initPreviews() {
|
||||
var thumbs = document.querySelectorAll('div[data-thumbs]');
|
||||
thumbs.forEach(function (thumb) {
|
||||
var thumbsJSON = JSON.parse(thumb.dataset.thumbs);
|
||||
var originalImage = thumb.children[0].children[1].src;
|
||||
var interval;
|
||||
var i = 1;
|
||||
|
||||
function clear() {
|
||||
thumb.children[0].children[1].src = originalImage;
|
||||
i = 1;
|
||||
clearTimeout(interval);
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (i == 0) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
thumb.children[0].children[1].src = thumbsJSON[i];
|
||||
i = (i + 1) % thumbsJSON.length;
|
||||
}
|
||||
|
||||
function interval() {
|
||||
// Start Preview
|
||||
interval = setInterval(toggle, 700);
|
||||
}
|
||||
|
||||
thumb.addEventListener('mouseenter', interval);
|
||||
thumb.addEventListener('mouseleave', clear);
|
||||
});
|
||||
}
|
||||
|
||||
async function init() {
|
||||
for (let i = 0; i < 9; i++) {
|
||||
var new_timestamp = document.getElementById('ts_reference').value;
|
||||
if (new_timestamp != old_timestamp) {
|
||||
console.log('== Changed ==');
|
||||
initPreviews();
|
||||
break;
|
||||
}
|
||||
console.log('== Didnt Change ==');
|
||||
await sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('contentChanged', event => {
|
||||
console.log('== Received contentChanged Event ==');
|
||||
init();
|
||||
});
|
||||
|
||||
initPreviews();
|
22
resources/js/theme.js
Normal file
22
resources/js/theme.js
Normal file
@@ -0,0 +1,22 @@
|
||||
function darkModeListener() {
|
||||
document.querySelector("html").classList.toggle("dark");
|
||||
if (localStorage.theme == 'light') {
|
||||
localStorage.theme = 'dark';
|
||||
} else {
|
||||
localStorage.theme = 'light';
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelector("input[type='checkbox']#toogleTheme").addEventListener("click", darkModeListener);
|
||||
|
||||
if(localStorage.theme) {
|
||||
if (localStorage.theme == 'light') {
|
||||
if (document.querySelector("html").classList.contains('dark')) {
|
||||
document.querySelector("html").classList.toggle("dark");
|
||||
}
|
||||
document.getElementById("toogleTheme").checked = true;
|
||||
}
|
||||
} else {
|
||||
// Default Dark Theme
|
||||
localStorage.theme = 'dark';
|
||||
}
|
113
resources/js/upload.js
Normal file
113
resources/js/upload.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import Tagify from '@yaireo/tagify';
|
||||
import '@yaireo/tagify/dist/tagify.css';
|
||||
|
||||
const taginput = document.querySelector("#tags");
|
||||
const studioinput = document.querySelector("#studio");
|
||||
|
||||
// Get Tags from API
|
||||
window.axios.get('/admin/tags').then(function (response) {
|
||||
if (response.status != 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
new Tagify(taginput, {
|
||||
whitelist: response.data.tags,
|
||||
dropdown: {
|
||||
classname: "color-blue",
|
||||
enabled: 0, // show the dropdown immediately on focus
|
||||
maxItems: 10,
|
||||
position: "text", // place the dropdown near the typed text
|
||||
closeOnSelect: false, // keep the dropdown open after selecting a suggestion
|
||||
highlightFirst: true
|
||||
}
|
||||
});
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
// Get Studios from API
|
||||
window.axios.get('/admin/studios').then(function (response) {
|
||||
if (response.status != 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
new Tagify(studioinput, {
|
||||
whitelist: response.data.studios,
|
||||
dropdown: {
|
||||
classname: "color-blue",
|
||||
enabled: 0, // show the dropdown immediately on focus
|
||||
maxItems: 10,
|
||||
position: "text", // place the dropdown near the typed text
|
||||
closeOnSelect: false, // keep the dropdown open after selecting a suggestion
|
||||
highlightFirst: true
|
||||
}
|
||||
});
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
let eps = 1;
|
||||
|
||||
function dynEpisode() {
|
||||
let amount = this.value;
|
||||
|
||||
if (amount > eps) {
|
||||
eps += 1;
|
||||
var episodeUploads = `
|
||||
<div class="grid grid-cols-2" id="dynU` + eps + `">
|
||||
<div class="p-4">
|
||||
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="episodecover` + eps + `">Cover ` + eps + `:</label>
|
||||
<input class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900" type="file" name="episodecover` + eps + `" id="episodecover` + eps + `" required>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="episodegallery` + eps + `">Gallery ` + eps + `:</label>
|
||||
<input class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900" type="file" name="episodegallery` + eps + `[]" id="episodegallery` + eps + `" multiple="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 pt-0" id="dynB` + eps + `">
|
||||
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="description` + eps + `">Description ` + eps + `:</label>
|
||||
<textarea rows="4" cols="50" id="description` + eps + `" name="description` + eps + `" class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-neutral-900 dark:text-gray-300 focus:border-rose-500 dark:focus:border-rose-600 focus:ring-rose-500 dark:focus:ring-rose-600 rounded-md shadow-sm" required>
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<div class="p-4 pt-0" id="dynD` + eps + `">
|
||||
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="episodedlurl` + eps + `">Download 1080p ` + eps + `:</label>
|
||||
<input class="border-gray-300 dark:border-gray-700 dark:bg-neutral-900 dark:text-gray-300 focus:border-rose-500 dark:focus:border-rose-600 focus:ring-rose-500 dark:focus:ring-rose-600 rounded-md shadow-sm block w-full" id="episodedlurl` + eps + `" type="text" name="episodedlurl` + eps + `" required="required">
|
||||
</div>
|
||||
|
||||
<div class="p-4 pt-0" id="dynD48fps` + eps + `">
|
||||
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="episodedlurlinterpolated` + eps + `">Download 1080p48fps ` + eps + `:</label>
|
||||
<input class="border-gray-300 dark:border-gray-700 dark:bg-neutral-900 dark:text-gray-300 focus:border-rose-500 dark:focus:border-rose-600 focus:ring-rose-500 dark:focus:ring-rose-600 rounded-md shadow-sm block w-full" id="episodedlurlinterpolated` + eps + `" type="text" name="episodedlurlinterpolated` + eps + `">
|
||||
</div>
|
||||
|
||||
<div class="p-4 pt-0" id="dynD4k` + eps + `">
|
||||
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="episodedlurl4k` + eps + `">Download 4k ` + eps + `:</label>
|
||||
<input class="border-gray-300 dark:border-gray-700 dark:bg-neutral-900 dark:text-gray-300 focus:border-rose-500 dark:focus:border-rose-600 focus:ring-rose-500 dark:focus:ring-rose-600 rounded-md shadow-sm block w-full" id="episodedlurl4k` + eps + `" type="text" name="episodedlurl4k` + eps + `" required="required">
|
||||
</div>
|
||||
|
||||
<div class="p-4 pt-0" id="dynDUHD48fps` + eps + `">
|
||||
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="downloadUHDi` + eps + `">Download 4k 48fps ` + eps + `:</label>
|
||||
<input class="border-gray-300 dark:border-gray-700 dark:bg-neutral-900 dark:text-gray-300 focus:border-rose-500 dark:focus:border-rose-600 focus:ring-rose-500 dark:focus:ring-rose-600 rounded-md shadow-sm block w-full" id="downloadUHDi` + eps + `" type="text" name="downloadUHDi` + eps + `">
|
||||
</div>
|
||||
`;
|
||||
|
||||
var element = document.getElementById('moreEpisodes');
|
||||
element.innerHTML = element.innerHTML + episodeUploads;
|
||||
} else if (amount < eps) {
|
||||
if (amount == 0) {
|
||||
this.value = 1;
|
||||
return;
|
||||
}
|
||||
document.getElementById("dynU" + eps).remove();
|
||||
document.getElementById("dynD" + eps).remove();
|
||||
document.getElementById("dynD4k" + eps).remove();
|
||||
document.getElementById("dynD48fps" + eps).remove();
|
||||
document.getElementById("dynDUHD48fps" + eps).remove();
|
||||
document.getElementById("dynB" + eps).remove();
|
||||
eps -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
document.getElementById("episodes").addEventListener('change', dynEpisode);
|
28
resources/js/user-blacklist.js
Normal file
28
resources/js/user-blacklist.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import Tagify from '@yaireo/tagify';
|
||||
import '@yaireo/tagify/dist/tagify.css';
|
||||
|
||||
const taginput = document.querySelector("#tags");
|
||||
|
||||
// Get Tags from API
|
||||
window.axios.get('/user/blacklist').then(function (response) {
|
||||
if (response.status != 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tagify = new Tagify(taginput, {
|
||||
whitelist: response.data.tags,
|
||||
enforceWhitelist: true,
|
||||
dropdown: {
|
||||
classname: "color-blue",
|
||||
enabled: 0, // show the dropdown immediately on focus
|
||||
maxItems: 10,
|
||||
position: "text", // place the dropdown near the typed text
|
||||
closeOnSelect: false, // keep the dropdown open after selecting a suggestion
|
||||
highlightFirst: true,
|
||||
}
|
||||
});
|
||||
|
||||
tagify.addTags(response.data.usertags);
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
Reference in New Issue
Block a user