Top ok
Some checks failed
repod / nextcloud-25 (push) Failing after 55s
repod / nextcloud-27 (push) Failing after 41s
repod / nodejs (push) Successful in 1m40s

This commit is contained in:
Michel Roux 2023-07-03 00:12:40 +02:00
parent 21c853397d
commit 559c6f9881
11 changed files with 183 additions and 54 deletions

View File

@ -18,6 +18,8 @@ RUN curl -sSLo /tmp/gpoddersync.tar.gz https://github.com/thrillfall/nextcloud-g
tar xvzf /tmp/gpoddersync.tar.gz -C apps && \
rm /tmp/gpoddersync.tar.gz && \
cd apps/repod && make build && cd - && \
php occ app:enable gpoddersync repod
php occ app:enable gpoddersync repod && \
php occ config:system:set debug --value=true && \
php occ config:system:set memcache.local --value=none
USER root

View File

@ -12,6 +12,7 @@ declare(strict_types=1);
*/
return [
'routes' => [
['name' => 'page#index', 'url' => '/', 'verb' => 'GET']
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'top#index', 'url' => '/top/{limit}', 'verb' => 'GET']
]
];

View File

@ -1,56 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="32"
width="32"
version="1"
viewBox="0 0 32 32"
viewBox="0 0 448 512"
version="1.1"
id="svg4"
sodipodi:docname="app.svg"
inkscape:version="0.92.1 r">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:window-width="789"
inkscape:window-height="480"
id="namedview6"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="7.375"
inkscape:cx="-8.3389831"
inkscape:cy="16"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="0"
inkscape:zoom="1.2304688"
inkscape:cx="76.8"
inkscape:cy="255.59365"
inkscape:window-width="2530"
inkscape:window-height="1379"
inkscape:window-x="30"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<path
d="M13.733 0a.915.915 0 0 0-.933.934V3.6c-1.182.304-2.243.794-3.267 1.4L7.6 3.068a.93.93 0 0 0-1.334 0l-3.2 3.2a.93.93 0 0 0 0 1.334L5 9.535c-.607 1.024-1.097 2.085-1.4 3.267H.933a.915.915 0 0 0-.933.934v4.533c0 .53.403.934.933.934H3.6c.303 1.182.793 2.243 1.4 3.267l-1.934 1.935a.93.93 0 0 0 0 1.333l3.2 3.2a.93.93 0 0 0 1.333 0L9.532 27c1.024.61 2.085 1.097 3.266 1.4v2.667c0 .53.402.933.932.933h4.534c.53 0 .933-.403.933-.935V28.4c1.18-.305 2.24-.795 3.265-1.4L24.4 28.93a.93.93 0 0 0 1.332 0l3.2-3.2a.93.93 0 0 0 0-1.333L27 22.465c.607-1.024 1.096-2.085 1.4-3.266h2.665a.915.915 0 0 0 .935-.933v-4.534a.915.915 0 0 0-.934-.933H28.4c-.304-1.182-.792-2.243-1.4-3.267L28.932 7.6a.93.93 0 0 0 0-1.334l-3.2-3.2a.93.93 0 0 0-1.333 0L22.465 5c-1.024-.607-2.084-1.097-3.266-1.4V.933A.915.915 0 0 0 18.267 0zM16 8.87A7.134 7.134 0 0 1 23.13 16 7.134 7.134 0 0 1 16 23.133c-3.936 0-7.13-3.196-7.13-7.132S12.063 8.87 16 8.87z"
display="block"
fill="#fff"
d="M267.429 488.563C262.286 507.573 242.858 512 224 512c-18.857 0-38.286-4.427-43.428-23.437C172.927 460.134 160 388.898 160 355.75c0-35.156 31.142-43.75 64-43.75s64 8.594 64 43.75c0 32.949-12.871 104.179-20.571 132.813zM156.867 288.554c-18.693-18.308-29.958-44.173-28.784-72.599 2.054-49.724 42.395-89.956 92.124-91.881C274.862 121.958 320 165.807 320 220c0 26.827-11.064 51.116-28.866 68.552-2.675 2.62-2.401 6.986.628 9.187 9.312 6.765 16.46 15.343 21.234 25.363 1.741 3.654 6.497 4.66 9.449 1.891 28.826-27.043 46.553-65.783 45.511-108.565-1.855-76.206-63.595-138.208-139.793-140.369C146.869 73.753 80 139.215 80 220c0 41.361 17.532 78.7 45.55 104.989 2.953 2.771 7.711 1.77 9.453-1.887 4.774-10.021 11.923-18.598 21.235-25.363 3.029-2.2 3.304-6.566.629-9.185zM224 0C100.204 0 0 100.185 0 224c0 89.992 52.602 165.647 125.739 201.408 4.333 2.118 9.267-1.544 8.535-6.31-2.382-15.512-4.342-30.946-5.406-44.339-.146-1.836-1.149-3.486-2.678-4.512-47.4-31.806-78.564-86.016-78.187-147.347.592-96.237 79.29-174.648 175.529-174.899C320.793 47.747 400 126.797 400 224c0 61.932-32.158 116.49-80.65 147.867-.999 14.037-3.069 30.588-5.624 47.23-.732 4.767 4.203 8.429 8.535 6.31C395.227 389.727 448 314.187 448 224 448 100.205 347.815 0 224 0zm0 160c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64z"
id="path2"
style="fill:#ffffff" />
style="fill:#ffffff;fill-opacity:1;opacity:0.6" />
</svg>
<!--
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,2 +0,0 @@
SPDX-FileCopyrightText: Xéfir Destiny <xefir@crystalyx.net>
SPDX-License-Identifier: AGPL-3.0-or-later

View File

@ -6,6 +6,7 @@ namespace OCA\RePod\Controller;
use OCA\RePod\AppInfo\Application;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IRequest;
use OCP\Util;
@ -23,6 +24,11 @@ class PageController extends Controller
public function index(): TemplateResponse {
Util::addScript(Application::APP_ID, 'repod-main');
return new TemplateResponse(Application::APP_ID, 'main');
$csp = new ContentSecurityPolicy();
$csp->addAllowedImageDomain('*');
$response = new TemplateResponse(Application::APP_ID, 'main');
$response->setContentSecurityPolicy($csp);
return $response;
}
}

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace OCA\RePod\Controller;
use Exception;
use OCA\RePod\AppInfo\Application;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Http\Client\IClientService;
use OCP\IRequest;
class TopController extends Controller
{
private IClientService $clientService;
public function __construct(IRequest $request, IClientService $clientService) {
parent::__construct(Application::APP_ID, $request);
$this->clientService = $clientService;
}
/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function index(int $limit = 10): JSONResponse {
if (!in_array($limit, [10, 25, 50])) {
return new JSONResponse('Invalid limit, can be 10, 25 or 50.', Http::STATUS_BAD_REQUEST);
}
try {
$client = $this->clientService->newClient();
$response = $client->get("https://rss.applemarketingtools.com/api/v2/fr/podcasts/top/{$limit}/podcasts.json");
$json = json_decode($response->getBody(), flags: JSON_THROW_ON_ERROR);
return new JSONResponse($json, $response->getStatusCode());
} catch (Exception $e) {
return new JSONResponse($e->getMessage(), Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
}

9
package-lock.json generated
View File

@ -15,6 +15,7 @@
"@nextcloud/router": "^2.1.2",
"@nextcloud/vue": "^7.12.0",
"vue": "^2",
"vue-fragment": "^1.6.0",
"vue-material-design-icons": "^5.2.0",
"vue-router": "^3"
},
@ -12954,6 +12955,14 @@
"dev": true,
"peer": true
},
"node_modules/vue-fragment": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/vue-fragment/-/vue-fragment-1.6.0.tgz",
"integrity": "sha512-a5T8ZZZK/EQzgVShEl374HbobUJ0a7v12BzOzS6Z/wd/5EE/5SffcyHC+7bf9hP3L7Yc0hhY/GhMdwFQ25O/8A==",
"peerDependencies": {
"vue": "^2.5.16"
}
},
"node_modules/vue-hot-reload-api": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",

View File

@ -24,6 +24,7 @@
"@nextcloud/router": "^2.1.2",
"@nextcloud/vue": "^7.12.0",
"vue": "^2",
"vue-fragment": "^1.6.0",
"vue-material-design-icons": "^5.2.0",
"vue-router": "^3"
},

81
src/components/Top.vue Normal file
View File

@ -0,0 +1,81 @@
<template>
<fragment>
<p>
<NcLoadingIcon v-if="loading" />
<ul v-if="!loading" class="tops">
<li v-for="top in tops.feed.results" :key="top.id">
<img :src="top.artworkUrl100" :alt="top.artistName" :title="top.artistName">
</li>
</ul>
</p>
<p>
<NcButton v-if="showMore" @click="more">
{{ t('repod', 'More') }}
</NcButton>
</p>
</fragment>
</template>
<script>
import { NcButton, NcLoadingIcon } from '@nextcloud/vue'
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import { showError } from '@nextcloud/dialogs'
export default {
name: 'Top',
components: {
NcButton,
NcLoadingIcon,
},
data() {
return {
tops: [],
loading: true,
showMore: true,
}
},
computed: {
},
async mounted() {
await this.fetch(10)
},
methods: {
async more() {
this.showMore = false
await this.fetch(50)
},
async fetch(limit) {
this.loading = true
try {
const top = await axios.get(generateUrl('/apps/repod/top/{limit}', { limit }))
this.tops = top.data
} catch (e) {
console.error(e)
showError(t('repod', 'Could not fetch subscriptions'))
}
this.loading = false
},
},
}
</script>
<style scoped>
.tops {
display: flex;
flex-wrap: wrap;
gap: 2rem 5%;
justify-content: center;
}
.tops li {
flex-basis: 15%;
}
.tops li img {
height: 100%;
width: 100%;
}
</style>

View File

@ -1,5 +1,6 @@
import { translatePlural as n, translate as t } from '@nextcloud/l10n'
import App from './App.vue'
import { Plugin } from 'vue-fragment'
import Vue from 'vue'
import { generateFilePath } from '@nextcloud/router'
import router from './router.js'
@ -8,6 +9,7 @@ import router from './router.js'
__webpack_public_path__ = generateFilePath(appName, '', 'js/')
Vue.mixin({ methods: { t, n } })
Vue.use(Plugin)
export default new Vue({
el: '#content',

View File

@ -1,29 +1,28 @@
<template>
<div class="main">
<p>
<NcTextField :label="t('repod', 'Find a podcast')">
<NcTextField :label="t('repod', 'Find a podcast')" value="">
<Magnify />
</NcTextField>
</p>
<p>
<span>{{ t('repod', 'Discover') }}</span>
</p>
<Top />
</div>
</template>
<script>
import Magnify from 'vue-material-design-icons/Magnify.vue'
import { NcTextField } from '@nextcloud/vue'
import Top from '../components/Top.vue'
export default {
name: 'Discover',
components: {
Magnify,
NcTextField,
Top,
},
data() {
return {
}
},
computed: {
@ -36,7 +35,10 @@ export default {
</script>
<style scoped>
.main {
margin: 11px 55px;
}
.main {
margin: 11px 55px;
display: flex;
flex-direction: column;
gap: 2rem;
}
</style>