initial cbz support

This commit is contained in:
Shish 2020-03-02 16:04:29 +00:00
parent 6947b726f0
commit ca462d86f1
9 changed files with 224 additions and 0 deletions

78
ext/handle_cbz/comic.js Normal file
View file

@ -0,0 +1,78 @@
function Comic(root, comicURL) {
let self = this;
this.root = document.getElementById(root);
this.comicPages = [];
this.comicPage = 0;
this.comicZip = null;
this.setComic = function(zip) {
let self = this;
self.comicZip = zip;
// Shimmie-specific; nullify existing back / forward
$("[rel='previous']").remove();
$("[rel='next']").remove();
zip.forEach(function (relativePath, file){
self.comicPages.push(relativePath);
});
self.comicPages.sort();
for(let i=0; i<self.comicPages.length; i++) {
let op = document.createElement("OPTION");
op.value = i;
op.innerText = (i+1) + " / " + self.comicPages.length + " - " + self.comicPages[i];
document.getElementById("comicPageList").appendChild(op);
}
self.setPage(0);
};
this.setPage = function(n) {
self.comicPage = n;
self.comicZip.file(self.comicPages[n]).async("arraybuffer").then(function(arrayBufferView) {
let blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
let urlCreator = window.URL || window.webkitURL;
document.getElementById("comicPage").src = urlCreator.createObjectURL( blob );
});
document.getElementById("comicPageList").value = self.comicPage;
};
this.prev = function() {
if(self.comicPage > 0) {
self.setPage(self.comicPage-1);
}
};
this.next = function() {
if(self.comicPage < self.comicPages.length) {
self.setPage(self.comicPage+1);
}
};
this.onKeyUp = function(e) {
if ($(e.target).is('input,textarea')) { return; }
if (e.metaKey || e.ctrlKey || e.altKey || e.shiftKey) { return; }
if (e.keyCode === 37) {self.prev();}
else if (e.keyCode === 39) {self.next();}
};
this.onPageChanged = function(e) {
self.setPage(parseInt(document.getElementById("comicPageList").value));
};
JSZipUtils.getBinaryContent(comicURL, function(err, data) {
if(err) {throw err;}
JSZip.loadAsync(data).then(function (zip) {
self.setComic(zip);
});
});
document.addEventListener("keyup", this.onKeyUp);
document.getElementById("comicNext").addEventListener("click", this.next);
document.getElementById("comicPrev").addEventListener("click", this.prev);
document.getElementById("comicPageList").addEventListener("change", this.onPageChanged);
document.getElementById("comicPageList").addEventListener("keyup", function(e) {e.stopPropagation();});
return this;
}

12
ext/handle_cbz/info.php Normal file
View file

@ -0,0 +1,12 @@
<?php declare(strict_types=1);
class CBZFileHandlerInfo extends ExtensionInfo
{
public const KEY = "handle_cbz";
public $key = self::KEY;
public $name = "Handle CBZ";
public $url = self::SHIMMIE_URL;
public $authors = self::SHISH_AUTHOR;
public $description = "Handle CBZ Comic Archives.";
}

1
ext/handle_cbz/jszip-utils-ie.min.js vendored Normal file
View file

@ -0,0 +1 @@
!function i(o,a,y){function f(t,r){if(!a[t]){if(!o[t]){var n="function"==typeof require&&require;if(!r&&n)return n(t,!0);if(u)return u(t,!0);throw new Error("Cannot find module '"+t+"'")}var e=a[t]={exports:{}};o[t][0].call(e.exports,function(r){var n=o[t][1][r];return f(n||r)},e,e.exports,i,o,a,y)}return a[t].exports}for(var u="function"==typeof require&&require,r=0;r<y.length;r++)f(y[r]);return f}({1:[function(r,n,t){var e="undefined"!=typeof self?self:"undefined"!=typeof window?window:{};document.write("\x3c!-- IEBinaryToArray_ByteStr --\x3e\r\n<script type='text/vbscript'>\r\nFunction IEBinaryToArray_ByteStr(Binary)\r\n IEBinaryToArray_ByteStr = CStr(Binary)\r\nEnd Function\r\nFunction IEBinaryToArray_ByteStr_Last(Binary)\r\n Dim lastIndex\r\n lastIndex = LenB(Binary)\r\n if lastIndex mod 2 Then\r\n IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n Else\r\n IEBinaryToArray_ByteStr_Last = \"\"\r\n End If\r\nEnd Function\r\n<\/script>\r\n"),e.JSZipUtils._getBinaryFromXHR=function(r){for(var n=r.responseBody,t={},e=0;e<256;e++)for(var i=0;i<256;i++)t[String.fromCharCode(e+(i<<8))]=String.fromCharCode(e)+String.fromCharCode(i);var o=IEBinaryToArray_ByteStr(n),a=IEBinaryToArray_ByteStr_Last(n);return o.replace(/[\s\S]/g,function(r){return t[r]})+a}},{}]},{},[1]);

1
ext/handle_cbz/jszip-utils.min.js vendored Normal file
View file

@ -0,0 +1 @@
!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSZipUtils=e():"undefined"!=typeof global?global.JSZipUtils=e():"undefined"!=typeof self&&(self.JSZipUtils=e())}(function(){return function o(i,f,u){function s(n,e){if(!f[n]){if(!i[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(a)return a(n,!0);throw new Error("Cannot find module '"+n+"'")}var r=f[n]={exports:{}};i[n][0].call(r.exports,function(e){var t=i[n][1][e];return s(t||e)},r,r.exports,o,i,f,u)}return f[n].exports}for(var a="function"==typeof require&&require,e=0;e<u.length;e++)s(u[e]);return s}({1:[function(e,t,n){"use strict";var u={};function r(){try{return new window.XMLHttpRequest}catch(e){}}u._getBinaryFromXHR=function(e){return e.response||e.responseText};var s="undefined"!=typeof window&&window.ActiveXObject?function(){return r()||function(){try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(e){}}()}:r;u.getBinaryContent=function(t,n){var e,r,o,i;"function"==typeof(n=n||{})?(i=n,n={}):"function"==typeof n.callback&&(i=n.callback),i||"undefined"==typeof Promise?(r=function(e){i(null,e)},o=function(e){i(e,null)}):e=new Promise(function(e,t){r=e,o=t});try{var f=s();f.open("GET",t,!0),"responseType"in f&&(f.responseType="arraybuffer"),f.overrideMimeType&&f.overrideMimeType("text/plain; charset=x-user-defined"),f.onreadystatechange=function(e){if(4===f.readyState)if(200===f.status||0===f.status)try{r(u._getBinaryFromXHR(f))}catch(e){o(new Error(e))}else o(new Error("Ajax error for "+t+" : "+this.status+" "+this.statusText))},n.progress&&(f.onprogress=function(e){n.progress({path:t,originalEvent:e,percent:e.loaded/e.total*100,loaded:e.loaded,total:e.total})}),f.send()}catch(e){o(new Error(e),null)}return e},t.exports=u},{}]},{},[1])(1)});

13
ext/handle_cbz/jszip.min.js vendored Normal file

File diff suppressed because one or more lines are too long

66
ext/handle_cbz/main.php Normal file
View file

@ -0,0 +1,66 @@
<?php declare(strict_types=1);
class CBZFileHandler extends DataHandlerExtension
{
public $SUPPORTED_EXT = ["cbz"];
protected function media_check_properties(MediaCheckPropertiesEvent $event): void
{
$event->image->lossless = false;
$event->image->video = false;
$event->image->audio = false;
$event->image->image = false;
$tmp = $this->get_representative_image($event->file_name);
$info = getimagesize($tmp);
if ($info) {
$event->image->width = $info[0];
$event->image->height = $info[1];
}
unlink($tmp);
}
protected function create_thumb(string $hash, string $type): bool
{
$cover = $this->get_representative_image(warehouse_path(Image::IMAGE_DIR, $hash));
create_scaled_image(
$cover,
warehouse_path(Image::THUMBNAIL_DIR, $hash),
get_thumbnail_max_size_scaled(),
get_extension(getMimeType($cover)),
null
);
return true;
}
protected function check_contents(string $tmpname): bool
{
$fp = fopen($tmpname, "r");
$head = fread($fp, 4);
fclose($fp);
return $head == "PK\x03\x04";
}
private function get_representative_image(string $archive): string
{
$out = "data/comic-cover-FIXME.jpg"; // TODO: random
$za = new ZipArchive();
$za->open($archive);
$names = [];
for ($i=0; $i<$za->numFiles;$i++) {
$file = $za->statIndex($i);
$names[] = $file['name'];
}
sort($names);
$cover = $names[0];
foreach ($names as $name) {
if (strpos(strtolower($name), "cover") !== false) {
$cover = $name;
break;
}
}
file_put_contents($out, $za->getFromName($cover));
return $out;
}
}

BIN
ext/handle_cbz/spinner.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

26
ext/handle_cbz/style.css Normal file
View file

@ -0,0 +1,26 @@
#comicMain {
background: black;
color: white;
font-size: 3em;
}
#comicPageList {
width: 90%;
}
#comicView {
display: flex;
flex-flow: row;
}
#comicView #comicPage {
flex: 10 auto;
}
#comicView #comicPrev,
#comicView #comicNext {
flex: 1 auto;
padding-top: 45%;
}
#comicView .comicPager {
position: absolute;
top: 0;
margin: auto;
}

27
ext/handle_cbz/theme.php Normal file
View file

@ -0,0 +1,27 @@
<?php declare(strict_types=1);
class CBZFileHandlerTheme extends Themelet
{
public function display_image(Page $page, Image $image)
{
$data_href = get_base_href();
$ilink = $image->get_image_link();
$html = "
<div id='comicMain'>
<div class='comicPager'>
<select id='comicPageList'></select>
</div>
<div id='comicView'>
<a id='comicPrev'><span>&lt;</span></a>
<img id='comicPage' src='{$data_href}/ext/handle_cbz/spinner.gif' />
<a id='comicNext'><span>&gt;</span></a>
</div>
</div>
<script src='{$data_href}/ext/handle_cbz/jszip-utils.min.js'></script>
<script src='{$data_href}/ext/handle_cbz/jszip.min.js'></script>
<script src='{$data_href}/ext/handle_cbz/comic.js'></script>
<script>window.comic = new Comic('comicMain', '$ilink');</script>
";
$page->add_block(new Block("Comic", $html, "main", 10, "comicBlock"));
}
}