Top ok
This commit is contained in:
parent
21c853397d
commit
559c6f9881
@ -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 && \
|
tar xvzf /tmp/gpoddersync.tar.gz -C apps && \
|
||||||
rm /tmp/gpoddersync.tar.gz && \
|
rm /tmp/gpoddersync.tar.gz && \
|
||||||
cd apps/repod && make build && cd - && \
|
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
|
USER root
|
||||||
|
@ -12,6 +12,7 @@ declare(strict_types=1);
|
|||||||
*/
|
*/
|
||||||
return [
|
return [
|
||||||
'routes' => [
|
'routes' => [
|
||||||
['name' => 'page#index', 'url' => '/', 'verb' => 'GET']
|
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
|
||||||
|
['name' => 'top#index', 'url' => '/top/{limit}', 'verb' => 'GET']
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
66
img/app.svg
66
img/app.svg
@ -1,56 +1,40 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<svg
|
<svg
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
viewBox="0 0 448 512"
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
version="1.1"
|
||||||
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"
|
|
||||||
id="svg4"
|
id="svg4"
|
||||||
sodipodi:docname="app.svg"
|
sodipodi:docname="app.svg"
|
||||||
inkscape:version="0.92.1 r">
|
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||||
<metadata
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
id="metadata10">
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
<rdf:RDF>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<cc:Work
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<defs
|
<defs
|
||||||
id="defs8" />
|
id="defs8" />
|
||||||
<sodipodi:namedview
|
<sodipodi:namedview
|
||||||
|
id="namedview6"
|
||||||
pagecolor="#ffffff"
|
pagecolor="#ffffff"
|
||||||
bordercolor="#666666"
|
bordercolor="#666666"
|
||||||
borderopacity="1"
|
borderopacity="1.0"
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:window-width="789"
|
inkscape:pageopacity="0.0"
|
||||||
inkscape:window-height="480"
|
inkscape:pagecheckerboard="0"
|
||||||
id="namedview6"
|
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
inkscape:zoom="7.375"
|
inkscape:zoom="1.2304688"
|
||||||
inkscape:cx="-8.3389831"
|
inkscape:cx="76.8"
|
||||||
inkscape:cy="16"
|
inkscape:cy="255.59365"
|
||||||
inkscape:window-x="0"
|
inkscape:window-width="2530"
|
||||||
inkscape:window-y="27"
|
inkscape:window-height="1379"
|
||||||
inkscape:window-maximized="0"
|
inkscape:window-x="30"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
inkscape:current-layer="svg4" />
|
inkscape:current-layer="svg4" />
|
||||||
<path
|
<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"
|
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"
|
||||||
display="block"
|
|
||||||
fill="#fff"
|
|
||||||
id="path2"
|
id="path2"
|
||||||
style="fill:#ffffff" />
|
style="fill:#ffffff;fill-opacity:1;opacity:0.6" />
|
||||||
</svg>
|
</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 |
@ -1,2 +0,0 @@
|
|||||||
SPDX-FileCopyrightText: Xéfir Destiny <xefir@crystalyx.net>
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@ -6,6 +6,7 @@ namespace OCA\RePod\Controller;
|
|||||||
|
|
||||||
use OCA\RePod\AppInfo\Application;
|
use OCA\RePod\AppInfo\Application;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||||
use OCP\AppFramework\Http\TemplateResponse;
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
use OCP\Util;
|
use OCP\Util;
|
||||||
@ -23,6 +24,11 @@ class PageController extends Controller
|
|||||||
public function index(): TemplateResponse {
|
public function index(): TemplateResponse {
|
||||||
Util::addScript(Application::APP_ID, 'repod-main');
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
43
lib/Controller/TopController.php
Normal file
43
lib/Controller/TopController.php
Normal 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
9
package-lock.json
generated
@ -15,6 +15,7 @@
|
|||||||
"@nextcloud/router": "^2.1.2",
|
"@nextcloud/router": "^2.1.2",
|
||||||
"@nextcloud/vue": "^7.12.0",
|
"@nextcloud/vue": "^7.12.0",
|
||||||
"vue": "^2",
|
"vue": "^2",
|
||||||
|
"vue-fragment": "^1.6.0",
|
||||||
"vue-material-design-icons": "^5.2.0",
|
"vue-material-design-icons": "^5.2.0",
|
||||||
"vue-router": "^3"
|
"vue-router": "^3"
|
||||||
},
|
},
|
||||||
@ -12954,6 +12955,14 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": 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": {
|
"node_modules/vue-hot-reload-api": {
|
||||||
"version": "2.3.4",
|
"version": "2.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
"@nextcloud/router": "^2.1.2",
|
"@nextcloud/router": "^2.1.2",
|
||||||
"@nextcloud/vue": "^7.12.0",
|
"@nextcloud/vue": "^7.12.0",
|
||||||
"vue": "^2",
|
"vue": "^2",
|
||||||
|
"vue-fragment": "^1.6.0",
|
||||||
"vue-material-design-icons": "^5.2.0",
|
"vue-material-design-icons": "^5.2.0",
|
||||||
"vue-router": "^3"
|
"vue-router": "^3"
|
||||||
},
|
},
|
||||||
|
81
src/components/Top.vue
Normal file
81
src/components/Top.vue
Normal 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>
|
@ -1,5 +1,6 @@
|
|||||||
import { translatePlural as n, translate as t } from '@nextcloud/l10n'
|
import { translatePlural as n, translate as t } from '@nextcloud/l10n'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
import { Plugin } from 'vue-fragment'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { generateFilePath } from '@nextcloud/router'
|
import { generateFilePath } from '@nextcloud/router'
|
||||||
import router from './router.js'
|
import router from './router.js'
|
||||||
@ -8,6 +9,7 @@ import router from './router.js'
|
|||||||
__webpack_public_path__ = generateFilePath(appName, '', 'js/')
|
__webpack_public_path__ = generateFilePath(appName, '', 'js/')
|
||||||
|
|
||||||
Vue.mixin({ methods: { t, n } })
|
Vue.mixin({ methods: { t, n } })
|
||||||
|
Vue.use(Plugin)
|
||||||
|
|
||||||
export default new Vue({
|
export default new Vue({
|
||||||
el: '#content',
|
el: '#content',
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<p>
|
<p>
|
||||||
<NcTextField :label="t('repod', 'Find a podcast')">
|
<NcTextField :label="t('repod', 'Find a podcast')" value="">
|
||||||
<Magnify />
|
<Magnify />
|
||||||
</NcTextField>
|
</NcTextField>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<Top />
|
||||||
<span>{{ t('repod', 'Discover') }}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Magnify from 'vue-material-design-icons/Magnify.vue'
|
import Magnify from 'vue-material-design-icons/Magnify.vue'
|
||||||
import { NcTextField } from '@nextcloud/vue'
|
import { NcTextField } from '@nextcloud/vue'
|
||||||
|
import Top from '../components/Top.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Discover',
|
name: 'Discover',
|
||||||
components: {
|
components: {
|
||||||
Magnify,
|
Magnify,
|
||||||
NcTextField,
|
NcTextField,
|
||||||
|
Top,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -38,5 +37,8 @@ export default {
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.main {
|
.main {
|
||||||
margin: 11px 55px;
|
margin: 11px 55px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user