1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00
jellyfin-web/src/plugins/comicsPlayer/plugin.js

207 lines
5.7 KiB
JavaScript
Raw Normal View History

// eslint-disable-next-line import/named, import/namespace
import { Archive } from 'libarchive.js';
2020-10-18 18:58:09 +01:00
import loading from '../../components/loading/loading';
import dialogHelper from '../../components/dialogHelper/dialogHelper';
import keyboardnavigation from '../../scripts/keyboardNavigation';
import { appRouter } from '../../components/appRouter';
import ServerConnections from '../../components/ServerConnections';
2020-12-04 17:04:59 -05:00
// eslint-disable-next-line import/named, import/namespace
import { Swiper } from 'swiper/swiper-bundle.esm';
import 'swiper/swiper-bundle.css';
2020-05-29 23:32:45 +02:00
export class ComicsPlayer {
constructor() {
this.name = 'Comics Player';
this.type = 'mediaplayer';
this.id = 'comicsplayer';
this.priority = 1;
this.imageMap = new Map();
this.onDialogClosed = this.onDialogClosed.bind(this);
this.onWindowKeyUp = this.onWindowKeyUp.bind(this);
}
play(options) {
this.progress = 0;
2020-05-29 23:32:45 +02:00
2020-09-12 05:46:15 +09:00
const elem = this.createMediaElement();
2020-05-29 23:32:45 +02:00
return this.setCurrentSrc(elem, options);
}
stop() {
this.unbindEvents();
2020-12-04 17:04:59 -05:00
this.archiveSource?.release();
2020-09-12 05:46:15 +09:00
const elem = this.mediaElement;
2020-05-29 23:32:45 +02:00
if (elem) {
dialogHelper.close(elem);
2020-08-28 23:09:35 +09:00
this.mediaElement = null;
2020-05-29 23:32:45 +02:00
}
loading.hide();
}
onDialogClosed() {
this.stop();
}
onWindowKeyUp(e) {
2020-09-12 05:46:15 +09:00
const key = keyboardnavigation.getKeyName(e);
2020-05-29 23:32:45 +02:00
switch (key) {
case 'Escape':
this.stop();
break;
}
}
bindEvents() {
document.addEventListener('keyup', this.onWindowKeyUp);
}
unbindEvents() {
document.removeEventListener('keyup', this.onWindowKeyUp);
}
createMediaElement() {
2020-08-28 23:09:35 +09:00
let elem = this.mediaElement;
2020-05-29 23:32:45 +02:00
if (elem) {
return elem;
}
elem = document.getElementById('comicsPlayer');
if (!elem) {
elem = dialogHelper.createDialog({
exitAnimationDuration: 400,
size: 'fullscreen',
autoFocus: false,
scrollY: false,
exitAnimation: 'fadeout',
removeOnClose: true
});
elem.id = 'comicsPlayer';
2020-05-29 23:32:45 +02:00
elem.classList.add('slideshowDialog');
elem.innerHTML = '<div class="slideshowSwiperContainer"><div class="swiper-wrapper"></div></div>';
this.bindEvents();
dialogHelper.open(elem);
}
2020-08-28 23:09:35 +09:00
this.mediaElement = elem;
2020-05-29 23:32:45 +02:00
return elem;
}
setCurrentSrc(elem, options) {
2020-09-12 05:46:15 +09:00
const item = options.items[0];
this.currentItem = item;
2020-05-29 23:32:45 +02:00
loading.show();
2020-09-12 05:46:15 +09:00
const serverId = item.ServerId;
2020-10-18 18:58:09 +01:00
const apiClient = ServerConnections.getApiClient(serverId);
2020-05-29 23:32:45 +02:00
2020-10-18 18:58:09 +01:00
Archive.init({
2020-05-29 23:32:45 +02:00
workerUrl: appRouter.baseUrl() + '/libraries/worker-bundle.js'
});
2020-12-04 17:04:59 -05:00
const downloadUrl = apiClient.getItemDownloadUrl(item.Id);
this.archiveSource = new ArchiveSource(downloadUrl);
return this.archiveSource.load().then(() => {
loading.hide();
this.swiperInstance = new Swiper(elem.querySelector('.slideshowSwiperContainer'), {
direction: 'horizontal',
// loop is disabled due to the lack ofSwiper support in virtual slides
loop: false,
zoom: {
minRatio: 1,
toggle: true,
containerClass: 'slider-zoom-container'
},
autoplay: false,
keyboard: {
enabled: true
},
preloadImages: true,
slidesPerView: 1,
slidesPerColumn: 1,
initialSlide: 0,
// reduces memory consumption for large libraries while allowing preloading of images
virtual: {
slides: this.archiveSource.urls,
cache: true,
renderSlide: this.getImgFromUrl,
addSlidesBefore: 1,
addSlidesAfter: 1
}
2020-05-29 23:32:45 +02:00
});
});
}
getImgFromUrl(url) {
return `<div class="swiper-slide">
<div class="slider-zoom-container">
<img src="${url}" class="swiper-slide-img">
</div>
</div>`;
}
canPlayMediaType(mediaType) {
return (mediaType || '').toLowerCase() === 'book';
}
canPlayItem(item) {
if (item.Path && (item.Path.endsWith('cbz') || item.Path.endsWith('cbr'))) {
return true;
}
2020-08-28 23:09:35 +09:00
2020-05-29 23:32:45 +02:00
return false;
}
}
class ArchiveSource {
constructor(url) {
this.url = url;
this.files = [];
this.urls = [];
}
async load() {
2020-09-12 05:46:15 +09:00
const res = await fetch(this.url);
2020-05-29 23:32:45 +02:00
if (!res.ok) {
return;
}
2020-08-28 23:09:35 +09:00
2020-09-12 05:46:15 +09:00
const blob = await res.blob();
2020-10-18 18:58:09 +01:00
this.archive = await Archive.open(blob);
2020-05-29 23:32:45 +02:00
this.raw = await this.archive.getFilesArray();
await this.archive.extractFiles();
2020-09-12 05:46:15 +09:00
const files = await this.archive.getFilesArray();
2020-05-29 23:32:45 +02:00
files.sort((a, b) => {
2020-08-28 23:09:35 +09:00
if (a.file.name < b.file.name) {
2020-05-29 23:32:45 +02:00
return -1;
2020-08-28 23:09:35 +09:00
} else {
2020-05-29 23:32:45 +02:00
return 1;
2020-08-28 23:09:35 +09:00
}
2020-05-29 23:32:45 +02:00
});
2020-09-12 05:46:15 +09:00
for (const file of files) {
2020-08-30 15:11:20 +09:00
/* eslint-disable-next-line compat/compat */
2020-09-12 05:46:15 +09:00
const url = URL.createObjectURL(file.file);
2020-05-29 23:32:45 +02:00
this.urls.push(url);
}
}
2020-12-04 17:04:59 -05:00
release() {
this.files = [];
/* eslint-disable-next-line compat/compat */
this.urls.map(URL.revokeObjectURL);
this.urls = [];
2020-05-29 23:32:45 +02:00
}
}
export default ComicsPlayer;