Compare commits
No commits in common. "f246d2c1b5bd330cddd4040245af049d10855224" and "ce1dc19ff9d8e33fb6c4285152e2b9fa14223704" have entirely different histories.
f246d2c1b5
...
ce1dc19ff9
.eslintrc.cjspackage.json
.gitea/workflows
.l10nignore.nvmrcCHANGELOG.mdDockerfileMakefileappinfo
composer.jsoncomposer.locklib
AppInfo
Controller
Provider
src
stubs
stylelint.config.cjstemplates
tsconfig.jsonvite.config.ts
9
.eslintrc.cjs
Normal file
9
.eslintrc.cjs
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
extends: ['@nextcloud/eslint-config/vue3', 'plugin:prettier/recommended'],
|
||||
rules: {
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
'vue/first-attribute-linebreak': 'off',
|
||||
'sort-imports': 'error',
|
||||
'vue/attributes-order': ['error', { alphabetical: true }],
|
||||
},
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
name: opds_catalog
|
||||
name: app_template
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
@ -26,6 +26,24 @@ jobs:
|
||||
- run: composer run cs:check
|
||||
- run: composer run phpstan
|
||||
|
||||
nodejs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: skjnldsv/read-package-engines-version-actions@v3
|
||||
id: versions
|
||||
with:
|
||||
fallbackNode: '^20'
|
||||
fallbackNpm: '^10'
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ steps.versions.outputs.nodeVersion }}
|
||||
- run: npm i -g 'npm@${{ steps.versions.outputs.npmVersion }}'
|
||||
- run: npm ci
|
||||
- run: npm run lint
|
||||
- run: npm run stylelint
|
||||
- run: npm run build
|
||||
|
||||
release:
|
||||
if: gitea.ref_type == 'tag'
|
||||
runs-on: ubuntu-latest
|
||||
@ -36,6 +54,15 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- run: curl -sSLo /usr/local/bin/composer https://getcomposer.org/download/latest-stable/composer.phar
|
||||
- run: chmod +x /usr/local/bin/composer
|
||||
- uses: skjnldsv/read-package-engines-version-actions@v3
|
||||
id: versions
|
||||
with:
|
||||
fallbackNode: '^20'
|
||||
fallbackNpm: '^10'
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ steps.versions.outputs.nodeVersion }}
|
||||
- run: npm i -g 'npm@${{ steps.versions.outputs.npmVersion }}'
|
||||
- run: make dist
|
||||
- uses: akkuman/gitea-release-action@v1
|
||||
with:
|
||||
|
14
.l10nignore
Normal file
14
.l10nignore
Normal file
@ -0,0 +1,14 @@
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
vendor/
|
||||
vendor-bin/*/vendor/
|
||||
|
||||
.php-cs-fixer.cache
|
||||
tests/.phpunit.cache
|
||||
|
||||
node_modules/
|
||||
js/
|
||||
css/
|
||||
|
||||
build/
|
1
.nvmrc
Normal file
1
.nvmrc
Normal file
@ -0,0 +1 @@
|
||||
20
|
46
CHANGELOG.md
46
CHANGELOG.md
@ -1,46 +1,12 @@
|
||||
## 0.8.8 - 2018-01-31
|
||||
### Changed
|
||||
- some minor changes to the preference sections
|
||||
# Changelog
|
||||
|
||||
## 0.8.5 - 0.8.7
|
||||
### Changed
|
||||
- debugging NC and OC package signing collision
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 0.8.4 - 2018-01-19
|
||||
### Changed
|
||||
- signed package for publication in Owncloud marketplace
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.8.3 - 2018-01-18
|
||||
### Changed
|
||||
- increased maximum version for OC and NC
|
||||
## [Unreleased]
|
||||
|
||||
## 0.8.2 - 2017-01-19
|
||||
### Fixed
|
||||
- Support login tokens ('app passwords', NC/OC) and 2FA (NC)
|
||||
|
||||
## 0.8.1 - 2017-01-14
|
||||
### Changed
|
||||
- more robust preview generator, fallback to mimetype icon when showPreview throws exception
|
||||
|
||||
## 0.8.0 - 2017-01-14
|
||||
### New
|
||||
- FictionBook 2 (.fb2) metadata parser
|
||||
- FB2 preview provider
|
||||
|
||||
## 0.7.3 - 2017-01-09
|
||||
### Fixed
|
||||
- XML error after deleting an epub file from Library
|
||||
- [#23](https://github.com/Yetangitu/owncloud-apps/issues/23)
|
||||
|
||||
## 0.7.2 - 2017-01-09
|
||||
### Changed
|
||||
- Modified info.xml, now with working screenshot url...
|
||||
|
||||
## 0.7.1 - 2017-01-09
|
||||
### Added
|
||||
- Modified info.xml, added screenshot
|
||||
|
||||
## 0.7.0 - 2017-01-09
|
||||
### Changed
|
||||
- New logo
|
||||
- First release to be compatible with Nextcloud
|
||||
- First release
|
||||
|
@ -1,6 +1,6 @@
|
||||
FROM nextcloud:30
|
||||
|
||||
ARG APP_NAME=opds_catalog
|
||||
ARG APP_NAME=app_template
|
||||
ENV NEXTCLOUD_UPDATE=1
|
||||
ENV NEXTCLOUD_ADMIN_USER=$APP_NAME
|
||||
ENV NEXTCLOUD_ADMIN_PASSWORD=$APP_NAME
|
||||
@ -8,7 +8,7 @@ ENV NEXTCLOUD_INIT_HTACCESS=1
|
||||
ENV SQLITE_DATABASE=$APP_NAME
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y sqlite3 && \
|
||||
apt-get install -y nodejs npm sqlite3 && \
|
||||
rm -f /usr/local/etc/php/conf.d/opcache-recommended.ini && \
|
||||
/entrypoint.sh true
|
||||
|
||||
|
36
Makefile
36
Makefile
@ -19,6 +19,9 @@ build:
|
||||
ifneq (,$(wildcard $(CURDIR)/composer.json))
|
||||
make composer
|
||||
endif
|
||||
ifneq (,$(wildcard $(CURDIR)/package.json))
|
||||
make npm
|
||||
endif
|
||||
|
||||
# Installs and updates the composer dependencies. If composer is not installed
|
||||
# a copy is fetched from the web
|
||||
@ -34,6 +37,12 @@ else
|
||||
composer install --prefer-dist
|
||||
endif
|
||||
|
||||
# Installs npm dependencies
|
||||
.PHONY: npm
|
||||
npm:
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
# Removes the appstore build
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@ -44,6 +53,9 @@ clean:
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
rm -rf vendor
|
||||
rm -rf node_modules
|
||||
rm -rf js/vendor
|
||||
rm -rf js/node_modules
|
||||
|
||||
# Builds the source and appstore package
|
||||
.PHONY: dist
|
||||
@ -59,7 +71,10 @@ source:
|
||||
tar -C .. -cvzf $(source_package_name).tar.gz \
|
||||
--exclude-vcs \
|
||||
--exclude="$(app_name)/build" \
|
||||
--exclude="$(app_name)/js/node_modules" \
|
||||
--exclude="$(app_name)/node_modules" \
|
||||
--exclude="$(app_name)/*.log" \
|
||||
--exclude="$(app_name)/js/*.log" \
|
||||
$(app_name)
|
||||
|
||||
# Builds the source package for the app store, ignores php tests, js tests
|
||||
@ -68,12 +83,14 @@ source:
|
||||
appstore:
|
||||
rm -rf $(appstore_build_directory)
|
||||
mkdir -p $(appstore_build_directory)
|
||||
composer install --prefer-dist --no-dev
|
||||
tar -C .. -cvzf $(appstore_package_name).tar.gz \
|
||||
$(app_name)/appinfo \
|
||||
$(app_name)/css \
|
||||
$(app_name)/img \
|
||||
$(app_name)/js \
|
||||
$(app_name)/l10n \
|
||||
$(app_name)/lib \
|
||||
$(app_name)/vendor \
|
||||
$(app_name)/templates \
|
||||
$(app_name)/CHANGELOG.md
|
||||
|
||||
# Start a nextcloud server on Docker to kickstart developement
|
||||
@ -83,3 +100,18 @@ dev: build
|
||||
docker rm $(app_name) || true
|
||||
docker build -t $(app_name) .
|
||||
docker run -itd --rm --name $(app_name) -v $(CURDIR):/var/www/html/apps/$(app_name) -p 80:80 $(app_name)
|
||||
npm run watch || docker stop $(app_name)
|
||||
|
||||
# Generate translations
|
||||
.PHONY: l10n
|
||||
l10n:
|
||||
docker run --rm \
|
||||
-v $(CURDIR):/app \
|
||||
--entrypoint php \
|
||||
nextcloudci/translations \
|
||||
/translationtool.phar create-pot-files
|
||||
docker run --rm \
|
||||
-v $(CURDIR):/app \
|
||||
--entrypoint php \
|
||||
nextcloudci/translations \
|
||||
/translationtool.phar convert-po-files
|
||||
|
@ -1,18 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
|
||||
<id>opds_catalog</id>
|
||||
<id>app_template</id>
|
||||
<name>App Template</name>
|
||||
<summary>An example summary</summary>
|
||||
<description>An example description</description>
|
||||
<version>1.0.0</version>
|
||||
<licence>agpl</licence>
|
||||
<author mail="example@example.com" homepage="https://example.com">Example</author>
|
||||
<namespace>OpdsCatalog</namespace>
|
||||
<namespace>AppTemplate</namespace>
|
||||
<category>customization</category>
|
||||
<bugs>https://example.com/bugs</bugs>
|
||||
<dependencies>
|
||||
<php min-version="8.1"/>
|
||||
<nextcloud min-version="29" max-version="31"/>
|
||||
</dependencies>
|
||||
<navigations>
|
||||
<navigation>
|
||||
<id>app_template</id>
|
||||
<name>App Template</name>
|
||||
<route>app_template.page.index</route>
|
||||
<icon>app.svg</icon>
|
||||
<type>link</type>
|
||||
</navigation>
|
||||
</navigations>
|
||||
</info>
|
||||
|
@ -1,19 +1,19 @@
|
||||
{
|
||||
"name": "nextcloud/opds_catalog",
|
||||
"name": "nextcloud/app_template",
|
||||
"description": "An example description",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"authors": [
|
||||
{
|
||||
"name": "example",
|
||||
"email": "example@example.com",
|
||||
"homepage": "https://example.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"OCA\\OpdsCatalog\\": "lib/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"OCA\\AppTemplate\\": "lib/",
|
||||
"OCP\\": "vendor/nextcloud/ocp/OCP/"
|
||||
},
|
||||
"files": [
|
||||
"stubs/OC_Image.php"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './vendor-bin/*' -not -path './build/*' -print0 | xargs -0 -n1 php -l",
|
||||
@ -23,16 +23,14 @@
|
||||
"rector": "rector && composer cs:fix"
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"kiwilan/php-ebook": "^3.0.04",
|
||||
"kiwilan/php-opds": "^2.1.0"
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"nextcloud/ocp": "^30.0.6",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"nextcloud/coding-standard": "^1.3.2",
|
||||
"nextcloud/rector": "^0.3.1",
|
||||
"phpstan/phpstan": "~1.12.19",
|
||||
"phpstan/phpstan": "~1.12.18",
|
||||
"rector/rector": "~1.2.10"
|
||||
},
|
||||
"config": {
|
||||
|
2010
composer.lock
generated
2010
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -2,12 +2,8 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\OpdsCatalog\AppInfo;
|
||||
namespace OCA\AppTemplate\AppInfo;
|
||||
|
||||
use OCA\OpdsCatalog\Provider\AmazonPreviewProvider;
|
||||
use OCA\OpdsCatalog\Provider\ComicBookPreviewProvider;
|
||||
use OCA\OpdsCatalog\Provider\EpubPreviewProvider;
|
||||
use OCA\OpdsCatalog\Provider\FictionBookPreviewProvider;
|
||||
use OCP\AppFramework\App;
|
||||
use OCP\AppFramework\Bootstrap\IBootContext;
|
||||
use OCP\AppFramework\Bootstrap\IBootstrap;
|
||||
@ -15,18 +11,13 @@ use OCP\AppFramework\Bootstrap\IRegistrationContext;
|
||||
|
||||
class Application extends App implements IBootstrap
|
||||
{
|
||||
public const APP_ID = 'opds_catalog';
|
||||
public const APP_ID = 'app_template';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(self::APP_ID);
|
||||
}
|
||||
|
||||
public function register(IRegistrationContext $context): void {
|
||||
$context->registerPreviewProvider(AmazonPreviewProvider::class, '/application\/(vnd.amazon.(ebook|mobi8-ebook)|x-(mobi8|mobipocket)-ebook)/');
|
||||
$context->registerPreviewProvider(ComicBookPreviewProvider::class, '/application\/(vnd.comicbook[+-](rar|zip)|x-cb[7rtz])/');
|
||||
$context->registerPreviewProvider(EpubPreviewProvider::class, '/application\/epub\+zip/');
|
||||
$context->registerPreviewProvider(FictionBookPreviewProvider::class, '/application\/x-fictionbook.*/');
|
||||
}
|
||||
public function register(IRegistrationContext $context): void {}
|
||||
|
||||
public function boot(IBootContext $context): void {}
|
||||
}
|
||||
|
@ -2,120 +2,26 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\OpdsCatalog\Controller;
|
||||
namespace OCA\AppTemplate\Controller;
|
||||
|
||||
use Kiwilan\Ebook\Ebook;
|
||||
use Kiwilan\Opds\Entries\OpdsEntryBook;
|
||||
use Kiwilan\Opds\Entries\OpdsEntryBookAuthor;
|
||||
use Kiwilan\Opds\Entries\OpdsEntryNavigation;
|
||||
use Kiwilan\Opds\Enums\OpdsVersionEnum;
|
||||
use Kiwilan\Opds\Opds;
|
||||
use Kiwilan\Opds\OpdsConfig;
|
||||
use Kiwilan\Opds\OpdsResponse;
|
||||
use OCA\OpdsCatalog\AppInfo\Application;
|
||||
use OCA\AppTemplate\AppInfo\Application;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\AppFramework\Http\NotFoundResponse;
|
||||
use OCP\AppFramework\Http\Response;
|
||||
use OCP\Files\File;
|
||||
use OCP\Files\Folder;
|
||||
use OCP\Files\IRootFolder;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
use OCP\AppFramework\Http\Attribute\OpenAPI;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
|
||||
class PageController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
private readonly IRootFolder $rootFolder,
|
||||
private readonly IUser $user,
|
||||
private readonly IURLGenerator $urlGenerator
|
||||
) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
}
|
||||
|
||||
#[NoCSRFRequired]
|
||||
#[NoAdminRequired]
|
||||
#[FrontpageRoute(verb: 'GET', url: '/index/{path}', requirements: ['path' => '.*'])]
|
||||
public function index(string $path): Response {
|
||||
$userFolder = $this->rootFolder->getUserFolder($this->user->getUID());
|
||||
$root = $userFolder->get($path);
|
||||
$feeds = [];
|
||||
|
||||
if ($root instanceof Folder) {
|
||||
foreach ($root->getDirectoryListing() as $node) {
|
||||
if ($node instanceof Folder) {
|
||||
$feeds[] = new OpdsEntryNavigation(
|
||||
(string) $node->getId(),
|
||||
$node->getName(),
|
||||
$this->urlGenerator->linkToRouteAbsolute(
|
||||
'opds_catalog.page.index',
|
||||
['path' => $userFolder->getRelativePath($node->getPath()) ?? $path.'/'.$node->getName()]
|
||||
),
|
||||
properties: [
|
||||
'numberOfItems' => count($node->getDirectoryListing()),
|
||||
],
|
||||
updated: new \DateTime('@'.$node->getMTime())
|
||||
);
|
||||
} elseif ($node instanceof File) {
|
||||
$ebook = Ebook::read($node->getPath());
|
||||
if ($ebook instanceof Ebook) {
|
||||
$authors = [];
|
||||
foreach ($ebook->getAuthors() as $author) {
|
||||
if (null !== $author->getName()) {
|
||||
$authors[] = new OpdsEntryBookAuthor($author->getName());
|
||||
}
|
||||
}
|
||||
|
||||
$feeds[] = new OpdsEntryBook(
|
||||
(string) $node->getId(),
|
||||
$ebook->getTitle() ?? $ebook->getFilename(),
|
||||
$this->urlGenerator->linkToRoute('opds_catalog.page.books', ['path' => $path.'/'.$node->getName()]),
|
||||
summary: $ebook->getDescription(),
|
||||
media: $this->urlGenerator->linkTo('', 'core/preview', ['fileId' => $node->getId(), 'x' => 1024, 'y' => 1024]),
|
||||
updated: new \DateTime('@'.$node->getMTime()),
|
||||
download: $this->urlGenerator->linkTo('', 'remote.php/dav/files/'.$this->user->getUID().'/'.$userFolder->getRelativePath($node->getPath())),
|
||||
mediaThumbnail: $this->urlGenerator->linkTo('', 'core/preview', ['fileId' => $node->getId()]),
|
||||
categories: $ebook->getTags(),
|
||||
authors: $authors,
|
||||
published: $ebook->getPublishDate(),
|
||||
volume: $ebook->getVolume(),
|
||||
serie: $ebook->getSeries(),
|
||||
language: $ebook->getLanguage(),
|
||||
identifier: $ebook->getIdentifiers()[0]->getValue(),
|
||||
publisher: $ebook->getPublisher()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$config = new OpdsConfig(
|
||||
name: $this->user->getDisplayName()."'s Library",
|
||||
author: $this->user->getDisplayName(),
|
||||
iconUrl: $this->urlGenerator->getAbsoluteURL('/avatar/'.$this->user->getUID().'/512'),
|
||||
startUrl: $this->urlGenerator->linkToRouteAbsolute('opds_catalog.page.index')
|
||||
#[OpenAPI(OpenAPI::SCOPE_IGNORE)]
|
||||
#[FrontpageRoute(verb: 'GET', url: '/')]
|
||||
public function index(): TemplateResponse {
|
||||
return new TemplateResponse(
|
||||
Application::APP_ID,
|
||||
'index',
|
||||
);
|
||||
|
||||
$opds = Opds::make($config)->feeds($feeds)->get();
|
||||
$response = $opds->getResponse();
|
||||
if ($response instanceof OpdsResponse) {
|
||||
if (OpdsVersionEnum::v1Dot2 === $opds->getVersion()) {
|
||||
// @phpstan-ignore-next-line
|
||||
return new DataResponse(data: $response->getContents(), headers: $response->getHeaders());
|
||||
}
|
||||
|
||||
if (OpdsVersionEnum::v2Dot0 === $opds->getVersion()) {
|
||||
// @phpstan-ignore-next-line
|
||||
return new JSONResponse(data: $response->getJson(), headers: $response->getHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
return new NotFoundResponse();
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\OpdsCatalog\Provider;
|
||||
|
||||
class AmazonPreviewProvider extends EbookPreviewProvider
|
||||
{
|
||||
public function getMimeType(): string {
|
||||
return '/application\/(vnd.amazon.(ebook|mobi8-ebook)|x-(mobi8|mobipocket)-ebook)/';
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\OpdsCatalog\Provider;
|
||||
|
||||
class ComicBookPreviewProvider extends EbookPreviewProvider
|
||||
{
|
||||
public function getMimeType(): string {
|
||||
return '/application\/(vnd.comicbook[+-](rar|zip)|x-cb[7rtz])/';
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\OpdsCatalog\Provider;
|
||||
|
||||
use Kiwilan\Ebook\Ebook;
|
||||
use Kiwilan\Ebook\EbookCover;
|
||||
use OCP\Files\File;
|
||||
use OCP\Files\FileInfo;
|
||||
use OCP\IImage;
|
||||
use OCP\Image;
|
||||
use OCP\Preview\IProviderV2;
|
||||
|
||||
abstract class EbookPreviewProvider implements IProviderV2
|
||||
{
|
||||
public function isAvailable(FileInfo $file): bool {
|
||||
return Ebook::isValid($file->getPath());
|
||||
}
|
||||
|
||||
public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
|
||||
$ebook = Ebook::read($file->getPath());
|
||||
|
||||
if ($ebook instanceof Ebook) {
|
||||
$cover = $ebook->getCover();
|
||||
|
||||
if ($cover instanceof EbookCover) {
|
||||
$path = $cover->getPath();
|
||||
|
||||
if (null !== $path) {
|
||||
$image = new Image();
|
||||
$image->loadFromFile($path);
|
||||
$image->scaleDownToFit($maxX, $maxY);
|
||||
|
||||
return $image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\OpdsCatalog\Provider;
|
||||
|
||||
class EpubPreviewProvider extends EbookPreviewProvider
|
||||
{
|
||||
public function getMimeType(): string {
|
||||
return '/application\/epub\+zip/';
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\OpdsCatalog\Provider;
|
||||
|
||||
class FictionBookPreviewProvider extends EbookPreviewProvider
|
||||
{
|
||||
public function getMimeType(): string {
|
||||
return '/application\/x-fictionbook.*/';
|
||||
}
|
||||
}
|
40
package.json
Normal file
40
package.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "app_template",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"engines": {
|
||||
"node": "^20.0.0",
|
||||
"npm": "^10.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"dev": "vite --mode development build",
|
||||
"watch": "vite --mode development build --watch",
|
||||
"lint": "vue-tsc && eslint src",
|
||||
"lint:fix": "vue-tsc && eslint src --fix",
|
||||
"stylelint": "stylelint src/**/*.vue src/**/*.scss src/**/*.css",
|
||||
"stylelint:fix": "stylelint src/**/*.vue src/**/*.scss src/**/*.css --fix"
|
||||
},
|
||||
"type": "module",
|
||||
"browserslist": [
|
||||
"extends @nextcloud/browserslist-config"
|
||||
],
|
||||
"dependencies": {
|
||||
"@formatjs/intl-segmenter": "^11.7.9",
|
||||
"@nextcloud/vite-config": "^2.3.1",
|
||||
"@nextcloud/vue": "9.0.0-alpha.6",
|
||||
"vite": "^6.1.0",
|
||||
"vue": "^3.5.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextcloud/browserslist-config": "^3.0.1",
|
||||
"@nextcloud/eslint-config": "^8.4.2",
|
||||
"@nextcloud/prettier-config": "^1.1.0",
|
||||
"@nextcloud/stylelint-config": "^3.0.1",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"typescript": "~5.5.4",
|
||||
"vue-tsc": "^2.2.2"
|
||||
},
|
||||
"prettier": "@nextcloud/prettier-config"
|
||||
}
|
26
src/App.vue
Normal file
26
src/App.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<NcAppContent>
|
||||
<div id="app_template">
|
||||
<h1>Hello world!</h1>
|
||||
</div>
|
||||
</NcAppContent>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { NcAppContent } from '@nextcloud/vue'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
NcAppContent,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
#app_template {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 16px;
|
||||
}
|
||||
</style>
|
6
src/main.ts
Normal file
6
src/main.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import '@formatjs/intl-segmenter/polyfill'
|
||||
import App from './App.vue'
|
||||
import { createApp } from 'vue'
|
||||
|
||||
const View = createApp(App)
|
||||
View.mount('#app_template')
|
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
use OCP\IImage;
|
||||
|
||||
interface OC_Image extends IImage
|
||||
{
|
||||
/**
|
||||
* Loads an image from a local file.
|
||||
*
|
||||
* @param bool|string $imagePath the path to a local file
|
||||
*
|
||||
* @return bool|GdImage An image resource or false on error
|
||||
*/
|
||||
public function loadFromFile($imagePath = false);
|
||||
|
||||
/**
|
||||
* Shrinks larger images to fit within specified boundaries while preserving ratio.
|
||||
*/
|
||||
public function scaleDownToFit(int $maxWidth, int $maxHeight): bool;
|
||||
}
|
3
stylelint.config.cjs
Normal file
3
stylelint.config.cjs
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: 'stylelint-config-recommended-vue',
|
||||
}
|
13
templates/index.php
Normal file
13
templates/index.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use OCA\AppTemplate\AppInfo\Application;
|
||||
use OCP\Util;
|
||||
|
||||
Util::addScript(Application::APP_ID, Application::APP_ID.'-main');
|
||||
Util::addStyle(Application::APP_ID, Application::APP_ID.'-main');
|
||||
|
||||
?>
|
||||
|
||||
<div id="app_template"></div>
|
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig",
|
||||
"include": ["./src/**/*.ts", "./src/**/*.vue", "**/*.ts"],
|
||||
"compilerOptions": {
|
||||
"allowImportingTsExtensions": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"noImplicitAny": false,
|
||||
"rootDir": ".",
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
}
|
||||
}
|
20
vite.config.ts
Normal file
20
vite.config.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { join, resolve } from 'path'
|
||||
import { createAppConfig } from '@nextcloud/vite-config'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
const config = defineConfig({
|
||||
build: {
|
||||
sourcemap: false,
|
||||
},
|
||||
})
|
||||
|
||||
export default createAppConfig(
|
||||
{
|
||||
main: resolve(join('src', 'main.ts')),
|
||||
},
|
||||
{
|
||||
config,
|
||||
createEmptyCSSEntryPoints: true,
|
||||
thirdPartyLicense: false,
|
||||
},
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user