Bump version to v0.7.0: Enhanced GDM integration, status sync, and notification system
This commit is contained in:
@@ -1,12 +1,3 @@
|
||||
/**
|
||||
* Video Modal Component JavaScript
|
||||
* Reusable video player modal for Anime Downloader
|
||||
*
|
||||
* Usage:
|
||||
* VideoModal.init({ package_name: 'anime_downloader', sub: 'ohli24' });
|
||||
* VideoModal.openWithPath('/path/to/video.mp4');
|
||||
*/
|
||||
|
||||
var VideoModal = (function() {
|
||||
'use strict';
|
||||
|
||||
@@ -15,28 +6,45 @@ var VideoModal = (function() {
|
||||
sub: 'ohli24'
|
||||
};
|
||||
|
||||
var videoPlayer = null;
|
||||
var videoPlayer = null; // Video.js instance
|
||||
var artPlayer = null; // Artplayer instance
|
||||
var plyrPlayer = null; // Plyr instance
|
||||
var currentPlayer = 'videojs'; // 'videojs', 'artplayer', 'plyr'
|
||||
var playlist = [];
|
||||
var currentPlaylistIndex = 0;
|
||||
var currentPlayingPath = '';
|
||||
var currentStreamUrl = '';
|
||||
var isVideoZoomed = false;
|
||||
|
||||
/**
|
||||
* Initialize the video modal
|
||||
* @param {Object} options - Configuration options
|
||||
* @param {string} options.package_name - Package name (default: 'anime_downloader')
|
||||
* @param {string} options.sub - Sub-module name (e.g., 'ohli24', 'linkkf')
|
||||
*/
|
||||
function init(options) {
|
||||
config = Object.assign(config, options || {});
|
||||
|
||||
// Load saved player preference
|
||||
var savedPlayer = localStorage.getItem('anime_downloader_preferred_player');
|
||||
if (savedPlayer && ['videojs', 'artplayer', 'plyr'].indexOf(savedPlayer) >= 0) {
|
||||
currentPlayer = savedPlayer;
|
||||
$('#player-select').val(currentPlayer);
|
||||
}
|
||||
|
||||
bindEvents();
|
||||
console.log('[VideoModal] Initialized with config:', config);
|
||||
console.log('[VideoModal] Initialized with player:', currentPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind all event handlers
|
||||
*/
|
||||
function bindEvents() {
|
||||
// Player selector change
|
||||
$('#player-select').off('change').on('change', function() {
|
||||
var newPlayer = $(this).val();
|
||||
if (newPlayer !== currentPlayer) {
|
||||
switchPlayer(newPlayer);
|
||||
}
|
||||
});
|
||||
|
||||
// Dropdown episode selection
|
||||
$('#episode-dropdown').off('change').on('change', function() {
|
||||
var index = parseInt($(this).val());
|
||||
@@ -50,10 +58,12 @@ var VideoModal = (function() {
|
||||
$('#btn-video-zoom').off('click').on('click', function() {
|
||||
isVideoZoomed = !isVideoZoomed;
|
||||
if (isVideoZoomed) {
|
||||
$('#video-player').addClass('vjs-zoomed');
|
||||
$('#video-player, #plyr-player').addClass('vjs-zoomed');
|
||||
$('#artplayer-container').addClass('art-zoomed');
|
||||
$(this).addClass('active').find('i').removeClass('fa-expand').addClass('fa-compress');
|
||||
} else {
|
||||
$('#video-player').removeClass('vjs-zoomed');
|
||||
$('#video-player, #plyr-player').removeClass('vjs-zoomed');
|
||||
$('#artplayer-container').removeClass('art-zoomed');
|
||||
$(this).removeClass('active').find('i').removeClass('fa-compress').addClass('fa-expand');
|
||||
}
|
||||
});
|
||||
@@ -64,87 +74,81 @@ var VideoModal = (function() {
|
||||
});
|
||||
|
||||
$('#videoModal').off('hide.bs.modal').on('hide.bs.modal', function() {
|
||||
if (videoPlayer) {
|
||||
videoPlayer.pause();
|
||||
}
|
||||
pauseAllPlayers();
|
||||
});
|
||||
|
||||
$('#videoModal').off('hidden.bs.modal').on('hidden.bs.modal', function() {
|
||||
$('body').removeClass('modal-video-open');
|
||||
if (isVideoZoomed) {
|
||||
isVideoZoomed = false;
|
||||
$('#video-player').removeClass('vjs-zoomed');
|
||||
$('#video-player, #plyr-player').removeClass('vjs-zoomed');
|
||||
$('#artplayer-container').removeClass('art-zoomed');
|
||||
$('#btn-video-zoom').removeClass('active').find('i').removeClass('fa-compress').addClass('fa-expand');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal with a file path (fetches playlist from server)
|
||||
* @param {string} filePath - Path to the video file
|
||||
* Switch between players
|
||||
*/
|
||||
function openWithPath(filePath) {
|
||||
$.ajax({
|
||||
url: '/' + config.package_name + '/ajax/' + config.sub + '/get_playlist?path=' + encodeURIComponent(filePath),
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
playlist = data.playlist || [];
|
||||
currentPlaylistIndex = data.current_index || 0;
|
||||
currentPlayingPath = filePath;
|
||||
|
||||
var streamUrl = '/' + config.package_name + '/ajax/' + config.sub + '/stream_video?path=' + encodeURIComponent(filePath);
|
||||
initPlayer(streamUrl);
|
||||
updatePlaylistUI();
|
||||
$('#videoModal').modal('show');
|
||||
},
|
||||
error: function() {
|
||||
// Fallback: single file
|
||||
playlist = [{ name: filePath.split('/').pop(), path: filePath }];
|
||||
currentPlaylistIndex = 0;
|
||||
var streamUrl = '/' + config.package_name + '/ajax/' + config.sub + '/stream_video?path=' + encodeURIComponent(filePath);
|
||||
initPlayer(streamUrl);
|
||||
updatePlaylistUI();
|
||||
$('#videoModal').modal('show');
|
||||
}
|
||||
});
|
||||
function switchPlayer(newPlayer) {
|
||||
pauseAllPlayers();
|
||||
|
||||
currentPlayer = newPlayer;
|
||||
localStorage.setItem('anime_downloader_preferred_player', newPlayer);
|
||||
|
||||
// Hide all player containers
|
||||
$('#videojs-container').hide();
|
||||
$('#artplayer-container').hide();
|
||||
$('#plyr-container').hide();
|
||||
|
||||
// Show selected player and reinitialize with current URL
|
||||
if (currentStreamUrl) {
|
||||
initPlayerWithUrl(currentStreamUrl);
|
||||
}
|
||||
|
||||
console.log('[VideoModal] Switched to:', newPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal with a direct stream URL
|
||||
* @param {string} streamUrl - Direct URL to stream
|
||||
* @param {string} title - Optional title
|
||||
* Pause all players
|
||||
*/
|
||||
function openWithUrl(streamUrl, title) {
|
||||
playlist = [{ name: title || 'Video', path: streamUrl }];
|
||||
currentPlaylistIndex = 0;
|
||||
initPlayer(streamUrl);
|
||||
updatePlaylistUI();
|
||||
$('#videoModal').modal('show');
|
||||
function pauseAllPlayers() {
|
||||
try {
|
||||
if (videoPlayer) videoPlayer.pause();
|
||||
} catch(e) {}
|
||||
try {
|
||||
if (artPlayer) artPlayer.pause();
|
||||
} catch(e) {}
|
||||
try {
|
||||
if (plyrPlayer) plyrPlayer.pause();
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal with a playlist array
|
||||
* @param {Array} playlistData - Array of {name, path} objects
|
||||
* @param {number} startIndex - Index to start playing from
|
||||
* Initialize player with URL based on current player selection
|
||||
*/
|
||||
function openWithPlaylist(playlistData, startIndex) {
|
||||
playlist = playlistData || [];
|
||||
currentPlaylistIndex = startIndex || 0;
|
||||
if (playlist.length > 0) {
|
||||
var filePath = playlist[currentPlaylistIndex].path;
|
||||
var streamUrl = '/' + config.package_name + '/ajax/' + config.sub + '/stream_video?path=' + encodeURIComponent(filePath);
|
||||
initPlayer(streamUrl);
|
||||
updatePlaylistUI();
|
||||
$('#videoModal').modal('show');
|
||||
function initPlayerWithUrl(streamUrl) {
|
||||
currentStreamUrl = streamUrl;
|
||||
|
||||
if (currentPlayer === 'videojs') {
|
||||
initVideoJS(streamUrl);
|
||||
} else if (currentPlayer === 'artplayer') {
|
||||
initArtplayer(streamUrl);
|
||||
} else if (currentPlayer === 'plyr') {
|
||||
initPlyr(streamUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize or update Video.js player
|
||||
* @param {string} streamUrl - URL to play
|
||||
* Initialize Video.js player
|
||||
*/
|
||||
function initPlayer(streamUrl) {
|
||||
function initVideoJS(streamUrl) {
|
||||
// Hide other containers
|
||||
$('#artplayer-container').hide();
|
||||
$('#plyr-container').hide();
|
||||
$('#videojs-container').show();
|
||||
|
||||
if (!videoPlayer) {
|
||||
videoPlayer = videojs('video-player', {
|
||||
controls: true,
|
||||
@@ -157,22 +161,84 @@ var VideoModal = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-next on video end
|
||||
videoPlayer.on('ended', function() {
|
||||
var autoNextEnabled = $('#auto-next-checkbox').is(':checked');
|
||||
if (autoNextEnabled && currentPlaylistIndex < playlist.length - 1) {
|
||||
currentPlaylistIndex++;
|
||||
playVideoAtIndex(currentPlaylistIndex);
|
||||
}
|
||||
});
|
||||
videoPlayer.on('ended', handleVideoEnded);
|
||||
}
|
||||
|
||||
videoPlayer.src({ type: 'video/mp4', src: streamUrl });
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Artplayer
|
||||
*/
|
||||
function initArtplayer(streamUrl) {
|
||||
// Hide other containers
|
||||
$('#videojs-container').hide();
|
||||
$('#plyr-container').hide();
|
||||
$('#artplayer-container').show().empty();
|
||||
|
||||
if (artPlayer) {
|
||||
artPlayer.destroy();
|
||||
artPlayer = null;
|
||||
}
|
||||
|
||||
artPlayer = new Artplayer({
|
||||
container: '#artplayer-container',
|
||||
url: streamUrl,
|
||||
autoplay: false,
|
||||
pip: true,
|
||||
screenshot: true,
|
||||
setting: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
theme: '#3b82f6'
|
||||
});
|
||||
|
||||
artPlayer.on('video:ended', handleVideoEnded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Plyr player
|
||||
*/
|
||||
function initPlyr(streamUrl) {
|
||||
// Hide other containers
|
||||
$('#videojs-container').hide();
|
||||
$('#artplayer-container').hide();
|
||||
$('#plyr-container').show();
|
||||
|
||||
// Set source
|
||||
$('#plyr-player').attr('src', streamUrl);
|
||||
|
||||
if (!plyrPlayer) {
|
||||
plyrPlayer = new Plyr('#plyr-player', {
|
||||
controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'settings', 'pip', 'fullscreen'],
|
||||
settings: ['quality', 'speed'],
|
||||
speed: { selected: 1, options: [0.5, 0.75, 1, 1.25, 1.5, 2] }
|
||||
});
|
||||
|
||||
plyrPlayer.on('ended', handleVideoEnded);
|
||||
} else {
|
||||
plyrPlayer.source = {
|
||||
type: 'video',
|
||||
sources: [{ src: streamUrl, type: 'video/mp4' }]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle video ended event (auto-next)
|
||||
*/
|
||||
function handleVideoEnded() {
|
||||
var autoNextEnabled = $('#auto-next-checkbox').is(':checked');
|
||||
if (autoNextEnabled && currentPlaylistIndex < playlist.length - 1) {
|
||||
currentPlaylistIndex++;
|
||||
playVideoAtIndex(currentPlaylistIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Play video at specific playlist index
|
||||
* @param {number} index - Playlist index
|
||||
*/
|
||||
function playVideoAtIndex(index) {
|
||||
if (index < 0 || index >= playlist.length) return;
|
||||
@@ -180,14 +246,73 @@ var VideoModal = (function() {
|
||||
var item = playlist[index];
|
||||
var streamUrl = '/' + config.package_name + '/ajax/' + config.sub + '/stream_video?path=' + encodeURIComponent(item.path);
|
||||
|
||||
if (videoPlayer) {
|
||||
videoPlayer.src({ type: 'video/mp4', src: streamUrl });
|
||||
videoPlayer.play();
|
||||
}
|
||||
initPlayerWithUrl(streamUrl);
|
||||
|
||||
// Try to auto-play
|
||||
setTimeout(function() {
|
||||
if (currentPlayer === 'videojs' && videoPlayer) videoPlayer.play();
|
||||
else if (currentPlayer === 'artplayer' && artPlayer) artPlayer.play = true;
|
||||
else if (currentPlayer === 'plyr' && plyrPlayer) plyrPlayer.play();
|
||||
}, 100);
|
||||
|
||||
updatePlaylistUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal with a file path (fetches playlist from server)
|
||||
*/
|
||||
function openWithPath(filePath) {
|
||||
$.ajax({
|
||||
url: '/' + config.package_name + '/ajax/' + config.sub + '/get_playlist?path=' + encodeURIComponent(filePath),
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
playlist = data.playlist || [];
|
||||
currentPlaylistIndex = data.current_index || 0;
|
||||
currentPlayingPath = filePath;
|
||||
|
||||
var streamUrl = '/' + config.package_name + '/ajax/' + config.sub + '/stream_video?path=' + encodeURIComponent(filePath);
|
||||
initPlayerWithUrl(streamUrl);
|
||||
updatePlaylistUI();
|
||||
$('#videoModal').modal('show');
|
||||
},
|
||||
error: function() {
|
||||
playlist = [{ name: filePath.split('/').pop(), path: filePath }];
|
||||
currentPlaylistIndex = 0;
|
||||
var streamUrl = '/' + config.package_name + '/ajax/' + config.sub + '/stream_video?path=' + encodeURIComponent(filePath);
|
||||
initPlayerWithUrl(streamUrl);
|
||||
updatePlaylistUI();
|
||||
$('#videoModal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal with a direct stream URL
|
||||
*/
|
||||
function openWithUrl(streamUrl, title) {
|
||||
playlist = [{ name: title || 'Video', path: streamUrl }];
|
||||
currentPlaylistIndex = 0;
|
||||
initPlayerWithUrl(streamUrl);
|
||||
updatePlaylistUI();
|
||||
$('#videoModal').modal('show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal with a playlist array
|
||||
*/
|
||||
function openWithPlaylist(playlistData, startIndex) {
|
||||
playlist = playlistData || [];
|
||||
currentPlaylistIndex = startIndex || 0;
|
||||
if (playlist.length > 0) {
|
||||
var filePath = playlist[currentPlaylistIndex].path;
|
||||
var streamUrl = '/' + config.package_name + '/ajax/' + config.sub + '/stream_video?path=' + encodeURIComponent(filePath);
|
||||
initPlayerWithUrl(streamUrl);
|
||||
updatePlaylistUI();
|
||||
$('#videoModal').modal('show');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update playlist UI (dropdown, external player buttons)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user