mirror of
https://github.com/Yetangitu/owncloud-apps.git
synced 2025-10-03 14:59:19 +02:00
- add rudimentary epub parser for metadata extraction
- add cover images - add configurable preview settings (should probably be in core or in a separate app) - add some metadata to feed template (file size, type and filename)
This commit is contained in:
parent
64cfb7925e
commit
007b7c7791
13 changed files with 704 additions and 12 deletions
30
files_opds/admin.php
Normal file
30
files_opds/admin.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - Files_Opds app
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Frank de Lange
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Files_Opds;
|
||||||
|
|
||||||
|
\OCP\Util::addScript('files_opds', 'admin');
|
||||||
|
\OCP\Util::addStyle('files_opds', 'settings');
|
||||||
|
|
||||||
|
$formats = array(
|
||||||
|
["epub" => Config::getPreview('OC\Preview\Epub') ? 1 : 0 ],
|
||||||
|
["pdf" => Config::getPreview('OC\Preview\PDF') ? 1 : 0],
|
||||||
|
["openoffice" => Config::getPreview('OC\Preview\OpenOffice') ? 1 : 0],
|
||||||
|
["msoffice" => Config::getPreview('OC\Preview\MSOfficeDoc') ? 1 : 0]
|
||||||
|
);
|
||||||
|
|
||||||
|
$tmpl = new \OCP\Template('files_opds', 'admin');
|
||||||
|
$tmpl->assign('previewFormats', $formats);
|
||||||
|
$tmpl->assign('cover-x', Config::getApp('cover-x', '200'));
|
||||||
|
$tmpl->assign('cover-y', Config::getApp('cover-y', '200'));
|
||||||
|
$tmpl->assign('thumb-x', Config::getApp('thumb-x', '36'));
|
||||||
|
$tmpl->assign('thumb-y', Config::getApp('thumb-y', '36'));
|
||||||
|
|
||||||
|
return $tmpl->fetchPage();
|
54
files_opds/ajax/admin.php
Normal file
54
files_opds/ajax/admin.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - Files_Opds App
|
||||||
|
*
|
||||||
|
* @author Frank de Lange
|
||||||
|
* @copyright 2014 Frank de Lange
|
||||||
|
*
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Files_Opds;
|
||||||
|
|
||||||
|
\OCP\JSON::callCheck();
|
||||||
|
\OCP\JSON::checkLoggedIn();
|
||||||
|
|
||||||
|
$l = new \OC_L10N('files_opds');
|
||||||
|
|
||||||
|
if (isset($_POST['opdsCoverX'])) {
|
||||||
|
// set dimensions, using sane defaults just in case
|
||||||
|
$opdsCoverX = isset($_POST['opdsCoverX']) ? (int) $_POST['opdsCoverX'] : 200;
|
||||||
|
$opdsCoverY = isset($_POST['opdsCoverY']) ? (int) $_POST['opdsCoverY'] : 200;
|
||||||
|
$opdsThumbX = isset($_POST['opdsThumbX']) ? (int) $_POST['opdsThumbX'] : 36;
|
||||||
|
$opdsThumbY = isset($_POST['opdsThumbY']) ? (int) $_POST['opdsThumbY'] : 36;
|
||||||
|
|
||||||
|
Config::setApp('cover-x', $opdsCoverX);
|
||||||
|
Config::setApp('cover-y', $opdsCoverY);
|
||||||
|
Config::setApp('thumb-x', $opdsThumbX);
|
||||||
|
Config::setApp('thumb-y', $opdsThumbX);
|
||||||
|
} else {
|
||||||
|
// set preview preferences
|
||||||
|
$opdsPreviewEpub = $_POST['opdsPreviewEpub'];
|
||||||
|
$opdsPreviewPdf = $_POST['opdsPreviewPdf'];
|
||||||
|
$opdsPreviewOpenOffice = $_POST['opdsPreviewOpenOffice'];
|
||||||
|
$opdsPreviewMsOffice = $_POST['opdsPreviewMsOffice'];
|
||||||
|
|
||||||
|
Config::setPreview('OC\Preview\Epub',$opdsPreviewEpub);
|
||||||
|
Config::setPreview('OC\Preview\PDF',$opdsPreviewPdf);
|
||||||
|
Config::setPreview('OC\Preview\OpenDocument',$opdsPreviewOpenOffice);
|
||||||
|
Config::setPreview('OC\Preview\StarOffice',$opdsPreviewOpenOffice);
|
||||||
|
Config::setPreview('OC\Preview\MSOfficeDoc',$opdsPreviewMsOffice);
|
||||||
|
Config::setPreview('OC\Preview\MSOffice2003',$opdsPreviewMsOffice);
|
||||||
|
Config::setPreview('OC\Preview\MSOffice2007',$opdsPreviewMsOffice);
|
||||||
|
}
|
||||||
|
|
||||||
|
\OCP\JSON::success(
|
||||||
|
array(
|
||||||
|
'data' => array('message'=> $l->t('Settings updated successfully.'))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
exit();
|
||||||
|
|
|
@ -2,6 +2,14 @@
|
||||||
|
|
||||||
$l = OC_L10N::get('files_opds');
|
$l = OC_L10N::get('files_opds');
|
||||||
|
|
||||||
|
require 'files_opds/lib/epub-preview.php';
|
||||||
|
|
||||||
\OCP\App::registerPersonal('files_opds', 'personal');
|
\OCP\App::registerPersonal('files_opds', 'personal');
|
||||||
|
\OCP\App::registerAdmin('files_opds', 'admin');
|
||||||
|
|
||||||
|
/* enable preview providers... */
|
||||||
|
// \OCA\Files_Opds\Config::setPreview('OC\Preview\Epub',true);
|
||||||
|
|
||||||
|
/* ..and register preview provider */
|
||||||
|
\OC\Preview::registerProvider('OC\Preview\Epub');
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<name>OPDS catalog</name>
|
<name>OPDS catalog</name>
|
||||||
<description>Personal OPDS catalog</description>
|
<description>Personal OPDS catalog</description>
|
||||||
<licence>AGPL</licence>
|
<licence>AGPL</licence>
|
||||||
<version>0.1.2</version>
|
<version>0.2</version>
|
||||||
<author>Frank de Lange</author>
|
<author>Frank de Lange</author>
|
||||||
<requiremin>7.0</requiremin>
|
<requiremin>7.0</requiremin>
|
||||||
<shipped>true</shipped>
|
<shipped>true</shipped>
|
||||||
|
|
7
files_opds/css/settings.css
Normal file
7
files_opds/css/settings.css
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#opds .indent {
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#opds .double-indent {
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
53
files_opds/js/admin.js
Normal file
53
files_opds/js/admin.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
$(document).ready(function(){
|
||||||
|
// save settings
|
||||||
|
var opdsAdminSettings = {
|
||||||
|
save : function() {
|
||||||
|
var epub = document.getElementById('opds-preview-epub').checked ? 'true' : 'false';
|
||||||
|
var pdf = document.getElementById('opds-preview-pdf').checked ? 'true' : 'false';
|
||||||
|
var openoffice = document.getElementById('opds-preview-openoffice').checked ? 'true' : 'false';
|
||||||
|
var msoffice = document.getElementById('opds-preview-msoffice').checked ? 'true' : 'false';
|
||||||
|
var data = {
|
||||||
|
opdsPreviewEpub : epub,
|
||||||
|
opdsPreviewPdf : pdf,
|
||||||
|
opdsPreviewOpenOffice : openoffice,
|
||||||
|
opdsPreviewMsOffice : msoffice
|
||||||
|
};
|
||||||
|
OC.msg.startSaving('#opds-admin .msg');
|
||||||
|
$.post(OC.filePath('files_opds', 'ajax', 'admin.php'), data, opdsAdminSettings.afterSave);
|
||||||
|
},
|
||||||
|
afterSave : function(data){
|
||||||
|
OC.msg.finishedSaving('#opds .msg', data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var opdsAdminCoverSettings = {
|
||||||
|
save : function() {
|
||||||
|
var data = {
|
||||||
|
opdsCoverX : $('#opds-cover-x').val(),
|
||||||
|
opdsCoverY : $('#opds-cover-y').val(),
|
||||||
|
opdsThumbX : $('#opds-thumb-x').val(),
|
||||||
|
opdsThumbY : $('#opds-thumb-y').val()
|
||||||
|
};
|
||||||
|
OC.msg.startSaving('#opds-admin .msg');
|
||||||
|
$.post(OC.filePath('files_opds', 'ajax', 'admin.php'), data, opdsAdminCoverSettings.afterSave);
|
||||||
|
},
|
||||||
|
afterSave : function(data){
|
||||||
|
OC.msg.finishedSaving('#opds .msg', data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$('#opds-preview-epub').on("change", opdsAdminSettings.save);
|
||||||
|
$('#opds-preview-pdf').on("change", opdsAdminSettings.save);
|
||||||
|
$('#opds-preview-openoffice').on("change", opdsAdminSettings.save);
|
||||||
|
$('#opds-preview-msoffice').on("change", opdsAdminSettings.save);
|
||||||
|
|
||||||
|
$('#opds-cover-x,#opds-cover-y,#opds-thumb-x,#opds-thumb-y').blur(opdsAdminCoverSettings.save);
|
||||||
|
$('#opds-cover-x,#opds-cover-y,#opds-thumb-x,#opds-thumb-y').keypress(function( event ) {
|
||||||
|
if (event.which == 13) {
|
||||||
|
event.preventDefault();
|
||||||
|
opdsAdminCoverSettings.save();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
|
@ -38,4 +38,74 @@ class Config
|
||||||
public static function set($key, $value) {
|
public static function set($key, $value) {
|
||||||
return \OCP\Config::setUserValue(\OCP\User::getUser(), 'files_opds', $key, $value);
|
return \OCP\Config::setUserValue(\OCP\User::getUser(), 'files_opds', $key, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get app config value
|
||||||
|
*
|
||||||
|
* @param string $key value to retrieve
|
||||||
|
* @param string $default default value to use
|
||||||
|
* @return string retrieved value or default
|
||||||
|
*/
|
||||||
|
public static function getApp($key, $default) {
|
||||||
|
return \OCP\Config::getAppValue('files_opds', $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set app config value
|
||||||
|
*
|
||||||
|
* @param string $key key for value to change
|
||||||
|
* @param string $value value to use
|
||||||
|
* @return bool success
|
||||||
|
*/
|
||||||
|
public static function setApp($key, $value) {
|
||||||
|
return \OCP\Config::setAppValue('files_opds', $key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get preview status
|
||||||
|
*
|
||||||
|
* @param string format
|
||||||
|
* @return bool (true = enabled, false = disabled)
|
||||||
|
*/
|
||||||
|
public static function getPreview($format) {
|
||||||
|
$enablePreviewProviders = \OCP\Config::getSystemValue('enabledPreviewProviders', null);
|
||||||
|
if (!($enablePreviewProviders === null)) {
|
||||||
|
return in_array($format, $enablePreviewProviders);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief enable/disable preview for selected format
|
||||||
|
*
|
||||||
|
* @param string format
|
||||||
|
* @param bool enable (true = enable, false = disable, default = false)
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function setPreview($format, $enable = 'false') {
|
||||||
|
$enablePreviewProviders = \OCP\Config::getSystemValue('enabledPreviewProviders', null);
|
||||||
|
if ($enable == 'true') {
|
||||||
|
if ($enablePreviewProviders === null) {
|
||||||
|
// set up default providers
|
||||||
|
$enablePreviewProviders = array();
|
||||||
|
array_push($enablePreviewProviders,
|
||||||
|
'OC\Preview\Image',
|
||||||
|
'OC\Preview\MP3',
|
||||||
|
'OC\Preview\TXT',
|
||||||
|
'OC\Preview\MarkDown');
|
||||||
|
}
|
||||||
|
if (!(in_array($format,$enablePreviewProviders))) {
|
||||||
|
array_push($enablePreviewProviders, $format);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!($enablePreviewProviders == null)) {
|
||||||
|
$enablePreviewProviders = array_diff($enablePreviewProviders, array($format));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(\OCP\Config::setSystemValue('enabledPreviewProviders', $enablePreviewProviders))) {
|
||||||
|
logWarn("Failed to enable " . $format . " preview provider (config.php readonly?)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
48
files_opds/lib/epub-preview.php
Normal file
48
files_opds/lib/epub-preview.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - Files_Opds App
|
||||||
|
*
|
||||||
|
* @author Frank de Lange
|
||||||
|
* @copyright 2014 Frank de Lange
|
||||||
|
*
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OC\Preview;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Epub preview - returns cover or null
|
||||||
|
*/
|
||||||
|
class Epub extends Provider {
|
||||||
|
|
||||||
|
public function getMimeType() {
|
||||||
|
return '/application\/epub\+zip/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
|
||||||
|
//get fileinfo
|
||||||
|
$fileInfo = $fileview->getFileInfo($path);
|
||||||
|
if(!$fileInfo) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$absPath = $fileview->toTmpFile($path);
|
||||||
|
|
||||||
|
$epub = new \OCA\Files_Opds\Epub($absPath);
|
||||||
|
|
||||||
|
$cover = $epub->Cover();
|
||||||
|
|
||||||
|
if ($cover) {
|
||||||
|
|
||||||
|
$image = new \OC_Image();
|
||||||
|
|
||||||
|
$image->loadFromData($cover['data']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (($cover !== null) && $image->valid()) ? $image : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
332
files_opds/lib/epub.php
Normal file
332
files_opds/lib/epub.php
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - Files_Opds App
|
||||||
|
*
|
||||||
|
* @author Frank de Lange
|
||||||
|
* @copyright 2014 Frank de Lange
|
||||||
|
*
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Files_Opds;
|
||||||
|
|
||||||
|
use \DOMXpath;
|
||||||
|
use \DOMElement;
|
||||||
|
use \DOMDocument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Epub class, a simpleminded read-only epub parser intended for metadata extraction
|
||||||
|
* based on https://github.com/splitbrain/php-epub-meta
|
||||||
|
*/
|
||||||
|
class Epub {
|
||||||
|
protected $xml;
|
||||||
|
protected $xpath;
|
||||||
|
protected $file;
|
||||||
|
protected $meta;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*
|
||||||
|
* @param string $file path to epub file to work on
|
||||||
|
* @throws Exception if metadata could not be loaded
|
||||||
|
*/
|
||||||
|
public function __construct($file) {
|
||||||
|
// open file
|
||||||
|
$this->file = $file;
|
||||||
|
$zip = new \ZipArchive();
|
||||||
|
if(!($zip->open($this->file))){
|
||||||
|
\OC_Log::write('epub', "Failed to read epub file", \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read container data
|
||||||
|
$data = $zip->getFromName('META-INF/container.xml');
|
||||||
|
if($data == false){
|
||||||
|
\OC_Log::write('epub', "Failed to access epub container data", \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xml = new DOMDocument();
|
||||||
|
$xml->registerNodeClass('DOMElement','\OCA\Files_Opds\EPubDOMElement');
|
||||||
|
$xml->loadXML($data);
|
||||||
|
$xpath = new EPubDOMXPath($xml);
|
||||||
|
$nodes = $xpath->query('//n:rootfiles/n:rootfile[@media-type="application/oebps-package+xml"]');
|
||||||
|
$this->meta = $nodes->item(0)->attr('full-path');
|
||||||
|
|
||||||
|
// load metadata
|
||||||
|
$data = $zip->getFromName($this->meta);
|
||||||
|
if(!$data){
|
||||||
|
\OC_Log::write('epub', 'Failed to access epub metadata', \OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xml = new \DOMDocument();
|
||||||
|
$this->xml->registerNodeClass('DOMElement','\OCA\Files_Opds\EPubDOMElement');
|
||||||
|
$this->xml->loadXML($data);
|
||||||
|
$this->xml->formatOutput = true;
|
||||||
|
$this->xpath = new EPubDOMXPath($this->xml);
|
||||||
|
|
||||||
|
$zip->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief file name getter
|
||||||
|
* @return string filename
|
||||||
|
*/
|
||||||
|
public static function file() {
|
||||||
|
return $this->file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get author(s)
|
||||||
|
*
|
||||||
|
* @return array $authors
|
||||||
|
*/
|
||||||
|
public static function Authors() {
|
||||||
|
// read current data
|
||||||
|
$rolefix = false;
|
||||||
|
$authors = array();
|
||||||
|
$nodes = $this->xpath->query('//opf:metadata/dc:creator[@opf:role="aut"]');
|
||||||
|
if($nodes->length == 0){
|
||||||
|
// no nodes where found, let's try again without role
|
||||||
|
$nodes = $this->xpath->query('//opf:metadata/dc:creator');
|
||||||
|
$rolefix = true;
|
||||||
|
}
|
||||||
|
foreach($nodes as $node){
|
||||||
|
$name = $node->nodeValue;
|
||||||
|
$as = $node->attr('opf:file-as');
|
||||||
|
if(!$as){
|
||||||
|
$as = $name;
|
||||||
|
$node->attr('opf:file-as',$as);
|
||||||
|
}
|
||||||
|
if($rolefix){
|
||||||
|
$node->attr('opf:role','aut');
|
||||||
|
}
|
||||||
|
$authors[$as] = $name;
|
||||||
|
}
|
||||||
|
return $authors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get book title
|
||||||
|
*
|
||||||
|
* @param string $title
|
||||||
|
*/
|
||||||
|
public function Title(){
|
||||||
|
return $this->get('dc:title');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get language
|
||||||
|
*
|
||||||
|
* @param string $lang
|
||||||
|
*/
|
||||||
|
public function Language(){
|
||||||
|
return $this->get('dc:language');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get publisher info
|
||||||
|
*
|
||||||
|
* @return string $publisher
|
||||||
|
*/
|
||||||
|
public function Publisher(){
|
||||||
|
return $this->get('dc:publisher');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get copyright info
|
||||||
|
*
|
||||||
|
* @return string $rights
|
||||||
|
*/
|
||||||
|
public function Copyright(){
|
||||||
|
return $this->get('dc:rights');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get description
|
||||||
|
*
|
||||||
|
* @return string $description
|
||||||
|
*/
|
||||||
|
public function Description(){
|
||||||
|
return $this->get('dc:description');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get ISBN number
|
||||||
|
*
|
||||||
|
* @return string $isbn
|
||||||
|
*/
|
||||||
|
public function ISBN(){
|
||||||
|
return $this->get('dc:identifier','opf:scheme','ISBN');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get Google Books ID
|
||||||
|
*
|
||||||
|
* @return string $google
|
||||||
|
*/
|
||||||
|
public function Google(){
|
||||||
|
return $this->get('dc:identifier','opf:scheme','GOOGLE');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get Amazon ID
|
||||||
|
*
|
||||||
|
* @return string $amazon
|
||||||
|
*/
|
||||||
|
public function Amazon(){
|
||||||
|
return $this->get('dc:identifier','opf:scheme','AMAZON');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get subjects (aka. tags)
|
||||||
|
*
|
||||||
|
* @return array $subjects
|
||||||
|
*/
|
||||||
|
public function Subjects(){
|
||||||
|
$subjects = array();
|
||||||
|
$nodes = $this->xpath->query('//opf:metadata/dc:subject');
|
||||||
|
foreach($nodes as $node){
|
||||||
|
$subjects[] = $node->nodeValue;
|
||||||
|
}
|
||||||
|
return $subjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get cover data
|
||||||
|
*
|
||||||
|
* Returns an associative array with the following keys:
|
||||||
|
*
|
||||||
|
* mime - filetype (usually image/jpeg)
|
||||||
|
* data - binary image data
|
||||||
|
* found - internal path, or false if no image is set in epub
|
||||||
|
*
|
||||||
|
* @return array or null
|
||||||
|
*/
|
||||||
|
public function Cover(){
|
||||||
|
$nodes = $this->xpath->query('//opf:metadata/opf:meta[@name="cover"]');
|
||||||
|
if($nodes->length) {
|
||||||
|
$coverid = (String) $nodes->item(0)->attr('opf:content');
|
||||||
|
if ($coverid) {
|
||||||
|
$nodes = $this->xpath->query('//opf:manifest/opf:item[@id="'.$coverid.'"]');
|
||||||
|
if ($nodes->length) {
|
||||||
|
$mime = $nodes->item(0)->attr('opf:media-type');
|
||||||
|
$path = $nodes->item(0)->attr('opf:href');
|
||||||
|
$path = dirname('/'.$this->meta).'/'.$path; // image path is relative to meta file
|
||||||
|
$path = ltrim($path,'/');
|
||||||
|
$zip = new \ZipArchive();
|
||||||
|
if($zip->open($this->file)){
|
||||||
|
$data = $zip->getFromName($path);
|
||||||
|
return array(
|
||||||
|
'mime' => $mime,
|
||||||
|
'data' => $data,
|
||||||
|
'found' => $path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief simple getter for simple meta attributes
|
||||||
|
*
|
||||||
|
* It should only be used for attributes that are expected to be unique
|
||||||
|
*
|
||||||
|
* @param string $item XML node to get
|
||||||
|
* @param string $att Attribute name
|
||||||
|
* @param string $aval Attribute value
|
||||||
|
* @return string node value
|
||||||
|
*/
|
||||||
|
protected function get($item, $att=false, $aval=false){
|
||||||
|
$xpath = '//opf:metadata/'.$item;
|
||||||
|
if ($att) {
|
||||||
|
$xpath .= "[@$att=\"$aval\"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
$nodes = $this->xpath->query($xpath);
|
||||||
|
if($nodes->length){
|
||||||
|
return $nodes->item(0)->nodeValue;
|
||||||
|
}else{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EPubDOMXPath extends DOMXPath {
|
||||||
|
public function __construct(DOMDocument $doc){
|
||||||
|
parent::__construct($doc);
|
||||||
|
|
||||||
|
if(is_a($doc->documentElement, '\OCA\Files_Opds\EPubDOMElement')){
|
||||||
|
foreach($doc->documentElement->namespaces as $ns => $url){
|
||||||
|
$this->registerNamespace($ns,$url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EPubDOMElement extends DOMElement {
|
||||||
|
public $namespaces = array(
|
||||||
|
'n' => 'urn:oasis:names:tc:opendocument:xmlns:container',
|
||||||
|
'opf' => 'http://www.idpf.org/2007/opf',
|
||||||
|
'dc' => 'http://purl.org/dc/elements/1.1/'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct($name, $value='', $namespaceURI=''){
|
||||||
|
list($ns,$name) = $this->splitns($name);
|
||||||
|
$value = htmlspecialchars($value);
|
||||||
|
if(!$namespaceURI && $ns){
|
||||||
|
$namespaceURI = $this->namespaces[$ns];
|
||||||
|
}
|
||||||
|
parent::__construct($name, $value, $namespaceURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief split given name in namespace prefix and local part
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return array (namespace, name)
|
||||||
|
*/
|
||||||
|
public function splitns($name){
|
||||||
|
$list = explode(':',$name,2);
|
||||||
|
if(count($list) < 2) array_unshift($list,'');
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief simple EPub namespace aware attribute getter
|
||||||
|
*
|
||||||
|
* @param string attribute
|
||||||
|
* @return string attribute value
|
||||||
|
*/
|
||||||
|
public function attr($attr){
|
||||||
|
list($ns,$attr) = $this->splitns($attr);
|
||||||
|
|
||||||
|
$nsuri = '';
|
||||||
|
if($ns){
|
||||||
|
$nsuri = $this->namespaces[$ns];
|
||||||
|
if(!$this->namespaceURI){
|
||||||
|
if($this->isDefaultNamespace($nsuri)){
|
||||||
|
$nsuri = '';
|
||||||
|
}
|
||||||
|
}elseif($this->namespaceURI == $nsuri){
|
||||||
|
$nsuri = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($nsuri){
|
||||||
|
return $this->getAttributeNS($nsuri,$attr);
|
||||||
|
}else{
|
||||||
|
return $this->getAttribute($attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace OCA\Files_Opds;
|
||||||
class Files extends \OCA\Files\Helper
|
class Files extends \OCA\Files\Helper
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Formats the file info to be returned as OPDS to the client.
|
* Formats the file info to be returned as OPDS to the client
|
||||||
*
|
*
|
||||||
* @param \OCP\Files\FileInfo $i
|
* @param \OCP\Files\FileInfo $i
|
||||||
* @return array formatted file info
|
* @return array formatted file info
|
||||||
|
@ -28,11 +28,16 @@ class Files extends \OCA\Files\Helper
|
||||||
|
|
||||||
$entry['id'] = $i['fileid'];
|
$entry['id'] = $i['fileid'];
|
||||||
$entry['mtime'] = $i['mtime'] * 1000;
|
$entry['mtime'] = $i['mtime'] * 1000;
|
||||||
$entry['icon'] = self::determineIcon($i);
|
|
||||||
$entry['name'] = $i->getName();
|
$entry['name'] = $i->getName();
|
||||||
$entry['mimetype'] = $i['mimetype'];
|
|
||||||
$entry['size'] = $i['size'];
|
|
||||||
$entry['type'] = $i['type'];
|
$entry['type'] = $i['type'];
|
||||||
|
if ($i['type'] === 'file') {
|
||||||
|
$entry['mimetype'] = $i['mimetype'];
|
||||||
|
$entry['preview'] = self::getPreview($i);
|
||||||
|
$entry['thumbnail'] = self::getThumbnail($i);
|
||||||
|
$entry['humansize'] = \OC_Helper::humanFileSize($i['size']);
|
||||||
|
} else {
|
||||||
|
$entry['icon'] = self::determineIcon($i);
|
||||||
|
}
|
||||||
return $entry;
|
return $entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +59,33 @@ class Files extends \OCA\Files\Helper
|
||||||
return $files;
|
return $files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get preview for file
|
||||||
|
* @param \OCP\Files\FileInfo $i
|
||||||
|
* @return string preview URL
|
||||||
|
*/
|
||||||
|
public static function getPreview($i) {
|
||||||
|
if (\OC::$server->getPreviewManager()->isMimeSupported($i['mimetype'])) {
|
||||||
|
return \OC_Helper::linkToRoute( 'core_ajax_preview', array('x' => Config::getApp('cover-x', '200'), 'y' => Config::getApp('cover-y', '200'), 'file' => \OC\Files\Filesystem::normalizePath(\OC\Files\Filesystem::getPath($i['fileid']))));
|
||||||
|
} else {
|
||||||
|
return self::determineIcon($i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get thumbnail for file
|
||||||
|
* @param \OCP\Files\FileInfo $i
|
||||||
|
* @return string preview URL
|
||||||
|
*/
|
||||||
|
public static function getThumbnail($i) {
|
||||||
|
if (\OC::$server->getPreviewManager()->isMimeSupported($i['mimetype'])) {
|
||||||
|
return \OC_Helper::linkToRoute( 'core_ajax_preview', array('x' => Config::getApp('thumb-x', '36'), 'y' => Config::getApp('thumb-y', '36'), 'file' => \OC\Files\Filesystem::normalizePath(\OC\Files\Filesystem::getPath($i['fileid']))));
|
||||||
|
} else {
|
||||||
|
return self::determineIcon($i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief check if $child is a subdirectory of $parent
|
* @brief check if $child is a subdirectory of $parent
|
||||||
*
|
*
|
||||||
|
|
48
files_opds/templates/admin.php
Normal file
48
files_opds/templates/admin.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - Files_Opds App
|
||||||
|
*
|
||||||
|
* @author Frank de Lange
|
||||||
|
* @copyright 2014 Frank de Lange
|
||||||
|
*
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function checkBox($format) {
|
||||||
|
foreach($format as $name => $enabled) {
|
||||||
|
echo '<input type="checkbox" id="opds-preview-' . $name . '" name="opds-preview-' . $name . '" ' . ($enabled == 1 ? 'checked >' : '>');
|
||||||
|
echo '<label for="opds-preview-' . $name . '">' . $name . '</label>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="section" id="opds">
|
||||||
|
<h2><?php p($l->t('OPDS')); ?></h2>
|
||||||
|
<h3>Enable preview for:<span class="msg"></span></h3>
|
||||||
|
<div class="indent">
|
||||||
|
<?php foreach ($_['previewFormats'] as $format): ?>
|
||||||
|
<div>
|
||||||
|
<?php checkBox($format); ?>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div>
|
||||||
|
<p>Cover size</p>
|
||||||
|
<label for="opds-cover-x"><?php p($l->t('width')) ?></label>
|
||||||
|
<input type="text" id="opds-cover-x" title="<?php p($l->t("Enter cover image width in pixels")); ?>" value="<?php p($_['cover-x']) ?>" />
|
||||||
|
<label for="opds-cover-y"><?php p($l->t('height')) ?></label>
|
||||||
|
<input type="text" id="opds-cover-y" title="<?php p($l->t("Enter cover image height in pixels")); ?>" value="<?php p($_['cover-y']) ?>" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>Cover thumbnail size</p>
|
||||||
|
<label for="opds-thumb-x"><?php p($l->t('width')) ?></label>
|
||||||
|
<input type="text" id="opds-thumb-x" title="<?php p($l->t("Enter thumbnail width in pixels")); ?>" value="<?php p($_['thumb-x']) ?>" />
|
||||||
|
<label for="opds-thumb-y"><?php p($l->t('height')) ?></label>
|
||||||
|
<input type="text" id="opds-thumb-y" title="<?php p($l->t("Enter thumbnail height in pixels")); ?>" value="<?php p($_['thumb-y']) ?>" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -10,11 +10,19 @@
|
||||||
* later.
|
* later.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
function formatMetadata($humansize,$mimetype,$name) {
|
||||||
|
return "Size: " . $humansize . "\n"
|
||||||
|
. "Type: " . $mimetype . "\n"
|
||||||
|
. "Filename: " . $name;
|
||||||
|
}
|
||||||
|
|
||||||
echo '<?xml version="1.0" encoding="UTF-8"?>';
|
echo '<?xml version="1.0" encoding="UTF-8"?>';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom"
|
<feed xmlns="http://www.w3.org/2005/Atom"
|
||||||
xmlns:dc="http://purl.org/dc/terms/"
|
xmlns:dc="http://purl.org/dc/terms/"
|
||||||
|
xmlns:dcterms="http://purl.org/dc/terms/"
|
||||||
xmlns:opds="http://opds-spec.org/2010/catalog">
|
xmlns:opds="http://opds-spec.org/2010/catalog">
|
||||||
<id>id:<?php p($_['feed_id']); ?></id>
|
<id>id:<?php p($_['feed_id']); ?></id>
|
||||||
<title><?php p($l->t("%s's library", array($_['user']))); ?></title>
|
<title><?php p($l->t("%s's library", array($_['user']))); ?></title>
|
||||||
|
@ -54,19 +62,20 @@ echo '<?xml version="1.0" encoding="UTF-8"?>';
|
||||||
<title><?php p($file['name']); ?></title>
|
<title><?php p($file['name']); ?></title>
|
||||||
<updated><?php p(date("Y-m-d\TH:i:sP", $file['mtime'])); ?></updated>
|
<updated><?php p(date("Y-m-d\TH:i:sP", $file['mtime'])); ?></updated>
|
||||||
<id>id:<?php p($file['id']); ?></id>
|
<id>id:<?php p($file['id']); ?></id>
|
||||||
|
<dcterms:extent><?php p($file['humansize']); ?></dcterms:extent>
|
||||||
<link type="<?php p($file['mimetype']); ?>"
|
<link type="<?php p($file['mimetype']); ?>"
|
||||||
rel="alternate"
|
rel="alternate"
|
||||||
href="?id=<?php p($file['id']); ?>"/>
|
href="?id=<?php p($file['id']); ?>"/>
|
||||||
<link type="<?php p($file['mimetype']); ?>"
|
<link type="<?php p($file['mimetype']); ?>"
|
||||||
rel="http://opds-spec.org/acquisition/open-access"
|
rel="http://opds-spec.org/acquisition/open-access"
|
||||||
href="?id=<?php p($file['id']); ?>"/>
|
href="?id=<?php p($file['id']); ?>"/>
|
||||||
<link href="<?php p($file['icon']); ?>"
|
<link href="<?php p($file['preview']); ?>"
|
||||||
rel="http://opds-spec.org/image"
|
rel="http://opds-spec.org/image"
|
||||||
type="image/jpeg" />
|
type="image/jpeg" />
|
||||||
<link href="<?php p($file['icon']); ?>"
|
<link href="<?php p($file['thumbnail']); ?>"
|
||||||
rel="http://opds-spec.org/image/thumbnail"
|
rel="http://opds-spec.org/image/thumbnail"
|
||||||
type="image/jpeg" />
|
type="image/jpeg" />
|
||||||
<content type="text"></content>
|
<content type="text"><?php p(formatMetadata($file['humansize'],$file['mimetype'],$file['name'])); ?></content>
|
||||||
</entry>
|
</entry>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
@ -89,19 +98,20 @@ echo '<?xml version="1.0" encoding="UTF-8"?>';
|
||||||
<title><?php p($file['name']); ?></title>
|
<title><?php p($file['name']); ?></title>
|
||||||
<updated><?php p(date("Y-m-d\TH:i:sP", $file['mtime'])); ?></updated>
|
<updated><?php p(date("Y-m-d\TH:i:sP", $file['mtime'])); ?></updated>
|
||||||
<id>id:<?php p($file['id']); ?></id>
|
<id>id:<?php p($file['id']); ?></id>
|
||||||
|
<dcterms:extent><?php p($file['humansize']); ?></dcterms:extent>
|
||||||
<link type="<?php p($file['mimetype']); ?>"
|
<link type="<?php p($file['mimetype']); ?>"
|
||||||
rel="alternate"
|
rel="alternate"
|
||||||
href="?id=<?php p($file['id']); ?>"/>
|
href="?id=<?php p($file['id']); ?>"/>
|
||||||
<link type="<?php p($file['mimetype']); ?>"
|
<link type="<?php p($file['mimetype']); ?>"
|
||||||
rel="http://opds-spec.org/acquisition/open-access"
|
rel="http://opds-spec.org/acquisition/open-access"
|
||||||
href="?id=<?php p($file['id']); ?>"/>
|
href="?id=<?php p($file['id']); ?>"/>
|
||||||
<link href="<?php p($file['icon']); ?>"
|
<link href="<?php p($file['preview']); ?>"
|
||||||
rel="http://opds-spec.org/image"
|
rel="http://opds-spec.org/image"
|
||||||
type="image/jpeg" />
|
type="image/jpeg" />
|
||||||
<link href="<?php p($file['icon']); ?>"
|
<link href="<?php p($file['thumbnail']); ?>"
|
||||||
rel="http://opds-spec.org/image/thumbnail"
|
rel="http://opds-spec.org/image/thumbnail"
|
||||||
type="image/jpeg" />
|
type="image/jpeg" />
|
||||||
<content type="text"></content>
|
<content type="text"><?php p(formatMetadata($file['humansize'],$file['mimetype'],$file['name'])); ?></content>
|
||||||
</entry>
|
</entry>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="section" id="opds-personal">
|
<div class="section" id="opds">
|
||||||
<h2><?php p($l->t('OPDS')); ?></h2>
|
<h2><?php p($l->t('OPDS')); ?></h2>
|
||||||
<div>
|
<div>
|
||||||
<input id="opds-enable" name="opds-enable" value="<?php p($_['opdsEnable-value']) ?>" <?php p($_['opdsEnable-checked']) ?> type="checkbox">
|
<input id="opds-enable" name="opds-enable" value="<?php p($_['opdsEnable-value']) ?>" <?php p($_['opdsEnable-checked']) ?> type="checkbox">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue