Initial Commit
28
.gitignore
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Trashes
|
||||
Thumbs.db
|
||||
|
||||
# Ignore temporary office docs
|
||||
~$*
|
||||
|
||||
# The active config file copied from config-dist.php
|
||||
variables.php
|
||||
|
||||
# Vim
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# sass generated files
|
||||
.sass-cache/
|
||||
install/.sass-cache/
|
||||
compressed
|
||||
*.map
|
||||
|
||||
# IDE generated
|
||||
.idea/
|
||||
|
||||
comics/
|
||||
thumbs/
|
15
README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Comics Viewer
|
||||
|
||||
This small project provides a web based viewer for comics in the CBZ and CBR formats.
|
||||
|
||||
## This project requires
|
||||
|
||||
* PHP ImageMagick
|
||||
* PHP RAR (PECL)
|
||||
|
||||
## Don't forget to:
|
||||
|
||||
* Create a MySQL/MariaDB database for the app with privileges granted to a user
|
||||
* Import the `install/initial_db_mysql.sql` database structure
|
||||
* Change the ownership of the `comics/` and `thumbs/` folders to the web server user
|
||||
* Copy the `variables-dist.php` file to `variables.php` and edit that file appropriately
|
11
ajax/sess.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
require '../header.php';
|
||||
|
||||
require_login();
|
||||
|
||||
$data = $_SESSION;
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data);
|
||||
exit();
|
28
ajax/setpage.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
require '../header.php';
|
||||
require_login();
|
||||
|
||||
$data = array();
|
||||
|
||||
if ( !isset($_REQUEST['page']) ) {
|
||||
exit();
|
||||
}
|
||||
$page = intval($_REQUEST['page']);
|
||||
|
||||
$query = "INSERT INTO pagetracker (username, comic, issue, currentpage, lastupdate) ";
|
||||
$query .= "VALUES(:username, :comic, :issue, :currentpage, NOW()) ";
|
||||
$query .= "ON DUPLICATE KEY UPDATE currentpage=:currentpage, lastupdate=NOW()";
|
||||
$fields = array();
|
||||
$fields[':username'] = $_SESSION['username'];
|
||||
$fields[':comic'] = str_replace("/", "", $_SESSION['compath']);
|
||||
$fields[':issue'] = $_SESSION['comfile'];
|
||||
$fields[':currentpage'] = $page;
|
||||
$sth = $globaldbh->prepare($query);
|
||||
$sth->execute($fields);
|
||||
|
||||
$data['message'] = "Page set to $page for {$_SESSION['username']} reading {$_SESSION['comfile']}";
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data);
|
||||
exit();
|
91
ajax/showcomic.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
require '../header.php';
|
||||
|
||||
require_login();
|
||||
|
||||
if ( isset($_REQUEST['comic']) ) {
|
||||
$comic = makePathSafe(base64_decode(urldecode(($_REQUEST['comic']))));
|
||||
$comicfull = COMICSDIR . $comic;
|
||||
$comicoutputurl = "comics" . str_replace("#", "", $comic) . "/";
|
||||
$comicoutputfull = "../" . EXTRACTSDIR . str_replace("#", "", $comic) . "/";
|
||||
} else {
|
||||
exit();
|
||||
}
|
||||
|
||||
$ext = strtolower(substr($comic, -3));
|
||||
$_SESSION['comfile'] = basename($comic);
|
||||
|
||||
$data = array();
|
||||
|
||||
// Get the current page for this comic or 0 (zero) if never opened
|
||||
$query = "SELECT currentpage FROM pagetracker WHERE username=:username AND issue=:issue";
|
||||
$fields = array();
|
||||
$fields[':username'] = $_SESSION['username'];
|
||||
$fields[':issue'] = $_SESSION['comfile'];
|
||||
$sth = $globaldbh->prepare($query);
|
||||
$sth->execute($fields);
|
||||
if ( $row = $sth->fetch(PDO::FETCH_ASSOC) ) {
|
||||
$currentpage = intval($row['currentpage']);
|
||||
} else {
|
||||
$currentpage = 0;
|
||||
}
|
||||
$data["startindex"] = $currentpage;
|
||||
|
||||
if ( !is_dir($comicoutputfull) ) {
|
||||
mkdir($comicoutputfull, 0755, true);
|
||||
}
|
||||
|
||||
$files = array();
|
||||
if ( $ext == "cbz" ) {
|
||||
$zip = new ZipArchive();
|
||||
$opened = $zip->open($comicfull);
|
||||
for ( $i=0; $i<$zip->numFiles; $i++ ) {
|
||||
$imgname = basename($zip->getNameIndex($i));
|
||||
$myext = substr($imgname, -3);
|
||||
if ( ($myext == "jpg") || ($myext == "png") ) {
|
||||
$imgname = str_replace("#", "", $imgname);
|
||||
$imgcontents = $zip->getFromIndex($i);
|
||||
$written = file_put_contents($comicoutputfull . $imgname, $imgcontents);
|
||||
if ( $written ) $files[] = $imgname;
|
||||
}
|
||||
}
|
||||
} elseif ( $ext == "cbr" ) {
|
||||
$junk = `/usr/local/bin/rar e -ep -o+ "$comicfull" "$comicoutputfull"`;
|
||||
$fh = opendir($comicoutputfull);
|
||||
while ( false !== ($file = readdir($fh)) ) {
|
||||
$myfile = $comicoutputfull . $file;
|
||||
$mynewfile = $comicoutputfull . str_replace("#", "", $file);
|
||||
$myext = strtolower(substr($file, -3));
|
||||
if ( ($myext == "jpg") || ($myext == "png") ) {
|
||||
rename($myfile, $mynewfile);
|
||||
$files[] = basename($mynewfile);
|
||||
}
|
||||
}
|
||||
closedir($fh);
|
||||
} else {
|
||||
exit();
|
||||
}
|
||||
|
||||
natsort($files);
|
||||
|
||||
$images = array();
|
||||
$captions = array();
|
||||
|
||||
$last = count($files);
|
||||
$count = 0;
|
||||
foreach ( $files as $file ) {
|
||||
$count++;
|
||||
$images[] = $comicoutputurl . $file;
|
||||
$captions[] = substr(basename($comicoutputurl), 0, -4) . ": {$count} of {$last}";
|
||||
}
|
||||
$debug = (DEBUG_SHOWCOMICAJAX || DEBUG_ALL);
|
||||
|
||||
$data["debug"] = $debug;
|
||||
$data["images"] = $images;
|
||||
$data["captions"] = $captions;
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data);
|
||||
exit();
|
||||
|
||||
// vim: set ts=3 sw=3 et:
|
19
authfunctions.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
//
|
||||
// This function is called at the beginning of any pages where
|
||||
// user login is required. Feel free to change the logic between
|
||||
// the lines indicated below.
|
||||
//
|
||||
function require_login () {
|
||||
if ( !$_SESSION['validated'] ) {
|
||||
// ******** START OF AUTH LOGIC ********
|
||||
$_SESSION['appurl'] = $_SERVER['REQUEST_URI'];
|
||||
header('Location: /jajauth/login.php');
|
||||
exit();
|
||||
// ********* END OF AUTH LOGIC *********
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
3
comics/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Comics "Viewing" Folder
|
||||
|
||||
This is the folder where comics get extracted for viewing in the web browser. The folder must be owned by the user which runs the web server.
|
4
core/jquery-1.7.1.min.js
vendored
Normal file
2
core/jquery-3.6.0.min.js
vendored
Normal file
1
core/simpleLightbox.min.css
vendored
Normal file
1
core/simpleLightbox.min.js
vendored
Normal file
1
core/simpleLightbox.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Project source: https://github.com/dbrekalo/simpleLightbox
|
1
core/toastr.min.css
vendored
Normal file
2
core/toastr.min.js
vendored
Normal file
100
css/comics.css
Normal file
|
@ -0,0 +1,100 @@
|
|||
|
||||
body {
|
||||
background-color: #121211;
|
||||
color: #ddddd1;
|
||||
font-family: 'Comic Sans MS';
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
a, a:link, a:visited, a:active {
|
||||
text-decoration: none;
|
||||
color: #22dd22;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 24pt;
|
||||
font-weight: bold;
|
||||
font-family: 'Comic Sans MS';
|
||||
text-align: center;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
border-bottom: 2px solid #ddddd1;
|
||||
}
|
||||
|
||||
.listcontainer {
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
/*
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
overflow: auto;
|
||||
width: -moz-fit-content;
|
||||
width: -webkit-fit-content;
|
||||
width: fit-content;
|
||||
*/
|
||||
}
|
||||
|
||||
.list {
|
||||
width: 100%;
|
||||
margin: 10px auto auto auto;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
/*
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin: 0 auto 0 auto;
|
||||
width: 1190px;
|
||||
*/
|
||||
}
|
||||
|
||||
.item {
|
||||
cursor: pointer;
|
||||
width: 220px;
|
||||
height: 330px;
|
||||
margin: 5px;
|
||||
border: 2px solid #ddddd1;
|
||||
padding: 2px;
|
||||
display: inline-block;
|
||||
/*
|
||||
float: left;
|
||||
*/
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.readborder {
|
||||
border-color: green !important;
|
||||
}
|
||||
|
||||
.debug {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 42;
|
||||
}
|
||||
|
||||
div.sorter {
|
||||
position: absolute;
|
||||
float: left;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 10;
|
||||
font-size: 24pt;
|
||||
font-weight: bold;
|
||||
font-family: 'Comic Sans MS';
|
||||
}
|
||||
div.name {
|
||||
position: absolute;
|
||||
float: right;
|
||||
top: 0px;
|
||||
right: 5px;
|
||||
z-index: 20;
|
||||
font-size: 24pt;
|
||||
font-weight: bold;
|
||||
font-family: 'Comic Sans MS';
|
||||
}
|
48
css/reset.css
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
23
downloadcomic.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
require 'header.php';
|
||||
|
||||
require_login();
|
||||
|
||||
if ( isset($_REQUEST['comic']) ) {
|
||||
$comic = makePathSafe(base64_decode(urldecode(($_REQUEST['comic']))));
|
||||
$comicfull = COMICSDIR . $comic;
|
||||
} else {
|
||||
exit();
|
||||
}
|
||||
|
||||
header("Pragma: public");
|
||||
header("Content-Type: application/octet-stream");
|
||||
header("Content-Disposition: attachment; filename=\"" . trim(basename($comicfull)) . "\"");
|
||||
header("Content-Description: " . trim(basename($comicfull)));
|
||||
header("Expires: 0");
|
||||
header("Cache-Control: must-revalidate");
|
||||
header("Content-length: " . filesize($comicfull));
|
||||
readfile($comicfull);
|
||||
|
||||
exit();
|
122
functions.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
function microtime_float() {
|
||||
list($usec, $sec) = explode(" ", microtime());
|
||||
return ((float)$usec + (float)$sec);
|
||||
}
|
||||
|
||||
function makePathSafe($path = "") {
|
||||
if ( $path == "" ) return "";
|
||||
// Stick forward slashes on the ends to make matching more consistent
|
||||
$path = "/" . $path . "/";
|
||||
// Remove all instances of dots between forward slashes
|
||||
while ( preg_match("/\/\.{0,}\//", $path) ) {
|
||||
$path = preg_replace("/\/\.{0,}\//", "/", $path);
|
||||
}
|
||||
// Replace all instances of two consecutive forward slashes
|
||||
while ( strpos($path, "//") !== false ) {
|
||||
$path = str_replace("//", "/", $path);
|
||||
}
|
||||
// Remove all leading forward slashes
|
||||
while ( substr($path, 0, 1) == '/' ) {
|
||||
$path = substr($path, 1);
|
||||
}
|
||||
// Remove all trailing forward slashes
|
||||
while ( substr($path, -1) == '/' ) {
|
||||
$path = substr($path, 0, strlen($path)-1);
|
||||
}
|
||||
$path = "/" . $path;
|
||||
return $path;
|
||||
}
|
||||
|
||||
function makeThumb($item = "") {
|
||||
if ( $item == "" ) { return false; }
|
||||
if ( is_dir($item) ) {
|
||||
$isfolder = true;
|
||||
$folder = $item;
|
||||
$files = array();
|
||||
if ( $fh = opendir($folder) ) {
|
||||
while ( false !== ($entry = readdir($fh)) ) {
|
||||
if ( is_file($item . "/" . $entry) ) {
|
||||
$files[] = $entry;
|
||||
}
|
||||
}
|
||||
closedir($fh);
|
||||
natsort($files);
|
||||
}
|
||||
if ( count($files) == 0 ) { return false; }
|
||||
reset($files);
|
||||
$comic = $folder . "/" . current($files);
|
||||
$outfile = THUMBSDIR . substr($folder, strlen(COMICSDIR)) . "_oem";
|
||||
} elseif ( is_file($item) ) {
|
||||
$isfolder = false;
|
||||
$file = $item;
|
||||
$comic = $file;
|
||||
$targetdir = THUMBSDIR . substr(dirname($file), strlen(COMICSDIR)) . "/";
|
||||
if ( !is_dir($targetdir) ) {
|
||||
mkdir($targetdir, 0755, true);
|
||||
}
|
||||
$outfile = $targetdir . substr(basename($file), 0, -4) . "_oem";
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if ( substr($comic, -3) == "cbz" ) {
|
||||
$zip = new ZipArchive();
|
||||
$opened = $zip->open($comic);
|
||||
if ( !$opened ) { return false; }
|
||||
$lowest = "~";
|
||||
$imgdata = null;
|
||||
for ( $i=0; $i<$zip->numFiles; $i++ ) {
|
||||
$imgname = basename($zip->getNameIndex($i));
|
||||
if ( (strcmp($lowest, $imgname) > 0)
|
||||
&& ((strcasecmp(substr($imgname, -3), "jpg") == 0)
|
||||
|| (strcasecmp(substr($imgname, -3), "png") == 0)) ) {
|
||||
$lowest = $imgname;
|
||||
$imgdata = $zip->getFromIndex($i);
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
if ( is_null($imgdata) ) return false;
|
||||
$didwrite = file_put_contents($outfile, $imgdata);
|
||||
if ( !$didwrite ) return false;
|
||||
} elseif ( substr($comic, -3) == "cbr" ) {
|
||||
$rar_file = rar_open($comic);
|
||||
if ( $rar_file === false ) { return false; }
|
||||
$entries = rar_list($rar_file);
|
||||
$lowest = "~";
|
||||
foreach ( $entries as $entry ) {
|
||||
$imgname = $entry->getName();
|
||||
if ( (strcmp($lowest, $imgname) > 0)
|
||||
&& ((strcasecmp(substr($imgname, -3), "jpg") == 0)
|
||||
|| (strcasecmp(substr($imgname, -3), "png") == 0)) ) {
|
||||
$lowest = $imgname;
|
||||
$ext = strtolower(substr($imgname, -3));
|
||||
$didwrite = $entry->extract(false, $outfile);
|
||||
if ( !$didwrite ) { return false; }
|
||||
}
|
||||
}
|
||||
rar_close($rar_file);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$input = new Imagick($outfile);
|
||||
$input->setImageFormat("jpg");
|
||||
$width = $input->getImageWidth();
|
||||
$height = $input->getImageHeight();
|
||||
$scale = 200 / $width;
|
||||
$newx = 200;
|
||||
$newy = intval($height * $scale);
|
||||
if ( $newy > 300 ) {
|
||||
$newy = 300;
|
||||
$scale = $height / 300;
|
||||
$newx = intval($width / $scale);
|
||||
}
|
||||
$thumb = substr($outfile, 0, -4) . ".jpg";
|
||||
$thumb = str_replace("#", "", $thumb);
|
||||
$input->resizeImage($newx, $newy, Imagick::FILTER_SINC, 1);
|
||||
$written = file_put_contents($thumb, $input->getImageBlob());
|
||||
unlink($outfile);
|
||||
return (($written === false) ? false : true);
|
||||
}
|
||||
|
||||
// vim: set ai et ts=3 sw=3:
|
51
header.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
// Script defining constants and variables used in the comics system
|
||||
require 'variables.php';
|
||||
// Script containing global functions used by all scripts
|
||||
require 'functions.php';
|
||||
// Script containing the "require_login() function"
|
||||
// This can be changed to suit local implementation needs but must
|
||||
// be named "require_login() and take no parameters
|
||||
require 'authfunctions.php';
|
||||
|
||||
// Start the session
|
||||
session_name(SESSIONCOMICS);
|
||||
session_start();
|
||||
|
||||
// This session variable is TRUE when successfully logged in
|
||||
// If set to true, and using default authentication, no login will be required
|
||||
if ( !isset($_SESSION['validated']) ) {
|
||||
$_SESSION['validated'] = false;
|
||||
}
|
||||
|
||||
// This session variable is set to the current browsing folder.
|
||||
// It is relative to the COMICSDIR constant defined in variables.php
|
||||
if ( !isset($_SESSION['compath']) ) {
|
||||
$_SESSION['compath'] = '/';
|
||||
}
|
||||
|
||||
// This session variable is set to the current comic in Base64
|
||||
if ( !isset($_SESSION['comfile']) ) {
|
||||
$_SESSION['comfile'] = "";
|
||||
}
|
||||
|
||||
// Initialize the hash session variable used for SSO
|
||||
// Set the hash to the passed in value if it exists
|
||||
if ( !isset($_SESSION['hash']) ) {
|
||||
$_SESSION['hash'] = "";
|
||||
}
|
||||
if ( isset($_REQUEST['hash']) ) {
|
||||
$_SESSION['hash'] = $_REQUEST['hash'];
|
||||
}
|
||||
|
||||
// Sorting for folders.
|
||||
// Valid values (from constants): SORTBYNAME, SORTBYDATE
|
||||
if ( !isset($_SESSION['sortorder']) ) {
|
||||
$_SESSION['sortorder'] = SORTBYDATE;
|
||||
}
|
||||
|
||||
// Make our PDO database connection which will be used in all scripts
|
||||
$globaldbh = new PDO("mysql:host=" . DBHOST . ";dbname=" . DBNAME, DBUSER, DBPASS);
|
||||
|
||||
?>
|
BIN
img/comics.png
Executable file
After Width: | Height: | Size: 52 KiB |
BIN
img/comics_120.png
Executable file
After Width: | Height: | Size: 30 KiB |
BIN
img/comics_128.png
Executable file
After Width: | Height: | Size: 34 KiB |
BIN
img/comics_152.png
Executable file
After Width: | Height: | Size: 44 KiB |
BIN
img/comics_196.png
Executable file
After Width: | Height: | Size: 62 KiB |
BIN
img/comics_76.png
Executable file
After Width: | Height: | Size: 16 KiB |
BIN
img/nothumb.png
Executable file
After Width: | Height: | Size: 14 KiB |
192
index.php
Normal file
|
@ -0,0 +1,192 @@
|
|||
<?php
|
||||
|
||||
require 'header.php';
|
||||
|
||||
require_login();
|
||||
|
||||
if ( isset($_REQUEST['sortorder']) ) {
|
||||
if ( ($_REQUEST['sortorder'] == SORTBYNAME) || ($_REQUEST['sortorder'] == SORTBYDATE) ) {
|
||||
$_SESSION['sortorder'] = $_REQUEST['sortorder'];
|
||||
}
|
||||
}
|
||||
|
||||
$validext = array('cbr', 'cbz');
|
||||
|
||||
if ( isset($_REQUEST['newpath']) ) {
|
||||
$newpath = makepathsafe($_REQUEST['newpath']);
|
||||
if ( is_dir(COMICSDIR . $newpath) ) {
|
||||
$_SESSION['compath'] = $newpath;
|
||||
} else {
|
||||
$_SESSION['compath'] = "/";
|
||||
}
|
||||
}
|
||||
|
||||
$compath = $_SESSION['compath'];
|
||||
|
||||
$fullcompath = COMICSDIR . $compath;
|
||||
$header = basename($compath);
|
||||
if ( $header == "" ) { $header = "Comics"; }
|
||||
|
||||
$fltime = microtime_float();
|
||||
$folders = array();
|
||||
$files = array();
|
||||
if ( $fh = opendir($fullcompath) ) {
|
||||
while ( false !== ($entry = readdir($fh)) ) {
|
||||
$mtime = filemtime($fullcompath . "/" . $entry);
|
||||
if ( ($entry != ".") && ($entry != "..") && is_dir($fullcompath . "/" . $entry) ) {
|
||||
$folders[$mtime] = $entry;
|
||||
}
|
||||
if ( is_file($fullcompath . "/" . $entry)
|
||||
&& in_array(substr($entry, -3), $validext) ) {
|
||||
$files[] = $entry;
|
||||
}
|
||||
}
|
||||
closedir($fh);
|
||||
if ( $_SESSION['sortorder'] == SORTBYNAME ) {
|
||||
natsort($folders);
|
||||
} else {
|
||||
ksort($folders);
|
||||
$folders = array_reverse($folders);
|
||||
}
|
||||
sort($files);
|
||||
}
|
||||
$items = array_merge($folders, $files);
|
||||
$fltime = microtime_float() - $fltime;
|
||||
|
||||
$updir = dirname($compath);
|
||||
$updirlink = urlencode($updir);
|
||||
|
||||
// build up a list of comics and issues which have been
|
||||
$query = "SELECT comic, issue FROM pagetracker WHERE username=:username";
|
||||
$fields = array();
|
||||
$fields[":username"] = $_SESSION['username'];
|
||||
$sth = $globaldbh->prepare($query);
|
||||
$sth->execute($fields);
|
||||
$comics = array();
|
||||
$issues = array();
|
||||
while ( $row = $sth->fetch(PDO::FETCH_ASSOC) ) {
|
||||
if ( !in_array($row['comic'], $comics) ) $comics[] = $row['comic'];
|
||||
if ( !in_array($row['issue'], $issues) ) $issues[] = $row['issue'];
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.5" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<link rel="icon" sizes="128x128" href="img/comics_128.png">
|
||||
<link rel="icon" sizes="196x196" href="img/comics_196.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="img/comics_76.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="img/comics_120.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="img/comics_152.png">
|
||||
<title>Comics Fancy</title>
|
||||
<link rel='stylesheet' type='text/css' href='css/reset.css' media='screen' />
|
||||
<link rel='stylesheet' type='text/css' href='css/comics.css' media='screen' />
|
||||
<link rel="stylesheet" type="text/css" href="core/simpleLightbox.min.css" />
|
||||
<!-- Toastr CSS -->
|
||||
<link rel="stylesheet" type="text/css" href="core/toastr.min.css" />
|
||||
<script type='text/javascript' src='core/jquery-3.6.0.min.js'></script>
|
||||
<script type='text/javascript' src='js/comics.js'></script>
|
||||
<script type='text/javascript' src='core/simpleLightbox.min.js'></script>
|
||||
<script type='text/javascript' src='core/toastr.min.js'></script>
|
||||
<style type='text/css'>
|
||||
.fancybox-outer { background: #323231; }
|
||||
.fancybox-title { font: normal 10px "Comic Sans MS"; }
|
||||
.fancybox-title-over-wrap { color: #bbb; padding: 0px 4px 0px 4px; }
|
||||
.mtest {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
border: 1px solid red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='sorter'>Sort:
|
||||
<?php
|
||||
if ( $_SESSION['sortorder'] == SORTBYNAME ) {
|
||||
echo "<a href='index.php?sortorder=", SORTBYDATE, "'>Name</a>";
|
||||
} else {
|
||||
echo "<a href='index.php?sortorder=", SORTBYNAME, "'>Date</a>";
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class='header' id='header'><?php
|
||||
/*
|
||||
if ( $compath != "/" ) {
|
||||
echo "<a href='index.php?newpath=$updirlink'>$updir";
|
||||
if ( dirname($compath) == "/" ) { echo "Comics"; }
|
||||
echo "</a>/";
|
||||
}
|
||||
echo $header;
|
||||
*/
|
||||
?> </div>
|
||||
<!-- <div class='name'><a href='logout.php'><?php echo htmlspecialchars($_SESSION['name']); ?></a></div> -->
|
||||
<div class='name'><?php
|
||||
if ( $compath != "/" ) {
|
||||
echo "<a href='index.php?newpath=$updirlink'>$updir";
|
||||
if ( dirname($compath) == "/" ) { echo "Comics"; }
|
||||
echo "</a>/";
|
||||
}
|
||||
?></div>
|
||||
<div class='list'>
|
||||
<!-- <div class='listcontainer'> -->
|
||||
<?php
|
||||
|
||||
$htime = microtime_float();
|
||||
$thumbtime = 0;
|
||||
$newthumbs = 0;
|
||||
$thumbfiles = "";
|
||||
$total = count($items);
|
||||
for ( $i=1; $i<=$total; $i++ ) {
|
||||
//for ( $i=6; $i<=6; $i++ ) {
|
||||
if ( $i <= count($folders) ) {
|
||||
$np = urlencode($compath . "/" . $items[$i-1]);
|
||||
$thumbfile = THUMBSDIR . $compath . "/" . $items[$i-1] . ".jpg";
|
||||
} else {
|
||||
$np = urlencode($compath . "/" . substr($items[$i-1], 0, -4) . ".jpg");
|
||||
$thumbfile = THUMBSDIR . $compath . "/" . substr($items[$i-1], 0, -4) . ".jpg";
|
||||
}
|
||||
$thumbfile = str_replace("#", "", $thumbfile);
|
||||
if ( !file_exists($thumbfile) ) {
|
||||
$thumbfiles .= $thumbfile . "<br>";
|
||||
$newthumbs++;
|
||||
$st = microtime_float();
|
||||
$havethumb = makeThumb($fullcompath . "/" . $items[$i-1]);
|
||||
$thumbtime += microtime_float() - $st;
|
||||
if ( !$havethumb ) {
|
||||
$havethumb = true;
|
||||
$thumb = "img/nothumb.png";
|
||||
}
|
||||
}
|
||||
$thumb = "thumbs" . $compath . "/" .basename($thumbfile);
|
||||
$comname = pathinfo($items[$i-1], PATHINFO_FILENAME);
|
||||
if ( strpos($comname, " - ") !== false ) $comname = str_replace(" - ", "<br />", $comname);
|
||||
$classmod = "";
|
||||
if ( $i <= count($folders) ) {
|
||||
if ( in_array($items[$i-1], $comics) ) $classmod=" readborder";
|
||||
echo "<div class='item{$classmod}' ";
|
||||
echo "onClick='document.location=\"index.php?newpath=$np\";'>";
|
||||
$thumburl = htmlentities($thumb, ENT_QUOTES);
|
||||
echo "<img src='$thumburl'><br clear=all />{$comname}</div>\n";
|
||||
} else {
|
||||
if ( in_array($items[$i-1], $issues) ) $classmod=" readborder";
|
||||
$relcomic = trim(base64_encode($compath . "/" . $items[$i-1]), "=");
|
||||
$thumburl = htmlentities($thumb, ENT_QUOTES);
|
||||
echo "<div class='item{$classmod}' id='", $relcomic, "'><a onClick='showComic(\"", $relcomic, "\", \"", htmlspecialchars($comname, ENT_QUOTES), "\");' ";
|
||||
echo "href='javascript:;'><img border=0 src='$thumburl'></a><br clear=all />";
|
||||
echo "<a href='downloadcomic.php?comic={$relcomic}'>{$comname}</a></div>\n";
|
||||
}
|
||||
}
|
||||
$htime = microtime_float() - $htime;
|
||||
?>
|
||||
<!-- </div> -->
|
||||
<div id='debug' class='debug'>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html><?php
|
||||
|
||||
// vim: set ai et ts=3 sw=3:
|
11
install/initial_db_mysql.sql
Normal file
|
@ -0,0 +1,11 @@
|
|||
DROP TABLE IF EXISTS `pagetracker`;
|
||||
CREATE TABLE `pagetracker` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(255) NOT NULL,
|
||||
`comic` varchar(255) NOT NULL,
|
||||
`issue` varchar(255) NOT NULL,
|
||||
`currentpage` int(11) unsigned NOT NULL DEFAULT 0,
|
||||
`lastupdate` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `user_comic` (`username`,`issue`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
44
js/comics.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
// This function is executed after the page load completes on the client
|
||||
$(document).ready(function() {
|
||||
});
|
||||
|
||||
var lightbox = null;
|
||||
|
||||
function updateCurrentPage() {
|
||||
var currentPage = lightbox.currentPosition;
|
||||
$.ajax({
|
||||
url : 'ajax/setpage.php',
|
||||
data : {page: currentPage},
|
||||
dataType : 'json',
|
||||
success : function(data, stat, jqo) {
|
||||
console.log(data.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// This JS function is called when a user clicks on a comic.
|
||||
// "showcomic.php" is called with the comic to view as a parameter.
|
||||
// It returns a JSON object representing the collection of images.
|
||||
// If in debug mode the javascript code is displayed in the browser.
|
||||
// If not in debug mode a lightbox object is created to display the comic.
|
||||
//
|
||||
function showComic(comic, name) {
|
||||
$("#" + comic).addClass("readborder");
|
||||
toastr.success("Extracting and showing the comic \"" + name + "\"...", "Showing Comic");
|
||||
$.ajax({
|
||||
url : 'ajax/showcomic.php',
|
||||
data : {comic: comic},
|
||||
dataType : 'json',
|
||||
success : function(data, stat, jqo) {
|
||||
// Clear out the debug DIV and start the fancybox.
|
||||
$("#debug").html("");
|
||||
lightbox = SimpleLightbox.open({
|
||||
items: data.images,
|
||||
captions: data.captions,
|
||||
startAt: data.startindex,
|
||||
beforeSetContent: updateCurrentPage
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
11
logout.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
require 'header.php';
|
||||
|
||||
require_login();
|
||||
|
||||
session_destroy();
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
|
||||
?>
|
10
sess.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
require 'header.php';
|
||||
require_login();
|
||||
|
||||
$data = array();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($_SESSION);
|
||||
exit();
|
3
thumbs/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Thumbnail Folder
|
||||
|
||||
This is the folder for auto-generated thumbnails. There will be a top level file for each comics folder, and sub-folder named by the comic to hold the thumbnails for each issue. This folder must be owned by the user which runs the web server process.
|
46
variables-dist.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
//
|
||||
// This is the session name. Set it to whatever you want.
|
||||
//
|
||||
define('SESSIONCOMICS', 'JackpotGeneric');
|
||||
|
||||
//
|
||||
// The folder under which your comics are stored (no trailing slash)
|
||||
//
|
||||
define('COMICSDIR', '/storage/Comics');
|
||||
|
||||
//
|
||||
// The folder where the thumbnails for folders and comics get generated.
|
||||
// This folder is expected to be in the same folder as the project.
|
||||
// This folder must be writable by the web server.
|
||||
//
|
||||
define('THUMBSDIR', 'thumbs');
|
||||
|
||||
//
|
||||
// The folder where the comics get extracted for vieweing.
|
||||
// This folder is expected to be in the same folder as the project.
|
||||
// This folder must be writable by the web server.
|
||||
//
|
||||
define('EXTRACTSDIR', 'comics');
|
||||
|
||||
//
|
||||
// Database information for tracking last read page
|
||||
//
|
||||
define('DBHOST', 'localhost');
|
||||
define('DBUSER', 'comics');
|
||||
define('DBPASS', 'comics');
|
||||
define('DBNAME', 'comics');
|
||||
|
||||
//
|
||||
// These are some variables used for development and debugging.
|
||||
// They can be safely ignored.
|
||||
//
|
||||
define('DEBUG_ALL', false);
|
||||
define('DEBUG_SHOWCOMICAJAX', false);
|
||||
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
define('SORTBYNAME', 10000001);
|
||||
define('SORTBYDATE', 10000002);
|