Compare commits
33 Commits
5917c59610
...
5b08cf970e
Author | SHA1 | Date | |
---|---|---|---|
5b08cf970e | |||
cf6dd25378 | |||
a2c3b389ba | |||
66b59c52fa | |||
36c3bd875b | |||
5742d1a762 | |||
bd9e3691b9 | |||
19427809ca | |||
544c91edee | |||
cf6bd440bf | |||
891d4762d0 | |||
a2b63241cc | |||
5db93914d2 | |||
68ada2b0e0 | |||
c91c17ae66 | |||
b4160d23d2 | |||
caf0bb7ec0 | |||
5f528e6b9b | |||
196bc23b1a | |||
e78e3b2565 | |||
b67123b578 | |||
53543a259f | |||
7efb0327d4 | |||
81af0c219f | |||
1feb0291bb | |||
989d5d38e1 | |||
b4ccd98f77 | |||
75da02e05b | |||
1530e8b294 | |||
7e359bdf29 | |||
082161e177 | |||
04ed6b101a | |||
6456ccc3d0 |
@ -1,5 +1,9 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ['@nextcloud', 'plugin:prettier/recommended'],
|
extends: [
|
||||||
|
'@nextcloud',
|
||||||
|
'plugin:pinia/recommended',
|
||||||
|
'plugin:prettier/recommended',
|
||||||
|
],
|
||||||
rules: {
|
rules: {
|
||||||
'jsdoc/require-jsdoc': 'off',
|
'jsdoc/require-jsdoc': 'off',
|
||||||
'vue/first-attribute-linebreak': 'off',
|
'vue/first-attribute-linebreak': 'off',
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
In the Nextcloud community, participants from all over the world come together to create Free Software for a free internet. This is made possible by the support, hard work and enthusiasm of thousands of people, including those who create and use Nextcloud software.
|
|
||||||
|
|
||||||
Our code of conduct offers some guidance to ensure Nextcloud participants can cooperate effectively in a positive and inspiring atmosphere, and to explain how together we can strengthen and support each other.
|
|
||||||
|
|
||||||
The Code of Conduct is shared by all contributors and users who engage with the Nextcloud team and its community services. It presents a summary of the shared values and “common sense” thinking in our community.
|
|
||||||
|
|
||||||
You can find our full code of conduct on our website: https://nextcloud.com/code-of-conduct/
|
|
||||||
|
|
||||||
Please, keep our CoC in mind when you contribute! That way, everyone can be a part of our community in a productive, positive, creative and fun way.
|
|
87
Makefile
87
Makefile
@ -103,14 +103,14 @@ dist: build
|
|||||||
source:
|
source:
|
||||||
rm -rf $(source_build_directory)
|
rm -rf $(source_build_directory)
|
||||||
mkdir -p $(source_build_directory)
|
mkdir -p $(source_build_directory)
|
||||||
tar cvzf $(source_package_name).tar.gz \
|
tar -C .. -cvzf $(source_package_name).tar.gz \
|
||||||
--exclude-vcs \
|
--exclude-vcs \
|
||||||
--exclude="../$(app_name)/build" \
|
--exclude="$(app_name)/build" \
|
||||||
--exclude="../$(app_name)/js/node_modules" \
|
--exclude="$(app_name)/js/node_modules" \
|
||||||
--exclude="../$(app_name)/node_modules" \
|
--exclude="$(app_name)/node_modules" \
|
||||||
--exclude="../$(app_name)/*.log" \
|
--exclude="$(app_name)/*.log" \
|
||||||
--exclude="../$(app_name)/js/*.log" \
|
--exclude="$(app_name)/js/*.log" \
|
||||||
../$(app_name)
|
$(app_name)
|
||||||
|
|
||||||
# Builds the source package for the app store, ignores php tests, js tests
|
# Builds the source package for the app store, ignores php tests, js tests
|
||||||
# and build related folders that are unnecessary for an appstore release
|
# and build related folders that are unnecessary for an appstore release
|
||||||
@ -118,42 +118,43 @@ source:
|
|||||||
appstore:
|
appstore:
|
||||||
rm -rf $(appstore_build_directory)
|
rm -rf $(appstore_build_directory)
|
||||||
mkdir -p $(appstore_build_directory)
|
mkdir -p $(appstore_build_directory)
|
||||||
tar cvzf $(appstore_package_name).tar.gz \
|
tar -C .. -cvzf $(appstore_package_name).tar.gz \
|
||||||
--exclude="../$(app_name)/build" \
|
--exclude="$(app_name)/build" \
|
||||||
--exclude="../$(app_name)/tests" \
|
--exclude="$(app_name)/tests" \
|
||||||
--exclude="../$(app_name)/Makefile" \
|
--exclude="$(app_name)/Makefile" \
|
||||||
--exclude="../$(app_name)/*.log" \
|
--exclude="$(app_name)/*.log" \
|
||||||
--exclude="../$(app_name)/phpunit*xml" \
|
--exclude="$(app_name)/phpunit*xml" \
|
||||||
--exclude="../$(app_name)/composer.*" \
|
--exclude="$(app_name)/composer.*" \
|
||||||
--exclude="../$(app_name)/node_modules" \
|
--exclude="$(app_name)/node_modules" \
|
||||||
--exclude="../$(app_name)/js/node_modules" \
|
--exclude="$(app_name)/js/node_modules" \
|
||||||
--exclude="../$(app_name)/js/tests" \
|
--exclude="$(app_name)/js/tests" \
|
||||||
--exclude="../$(app_name)/js/test" \
|
--exclude="$(app_name)/js/test" \
|
||||||
--exclude="../$(app_name)/js/*.log" \
|
--exclude="$(app_name)/js/*.log" \
|
||||||
--exclude="../$(app_name)/js/package.json" \
|
--exclude="$(app_name)/js/package.json" \
|
||||||
--exclude="../$(app_name)/js/bower.json" \
|
--exclude="$(app_name)/js/bower.json" \
|
||||||
--exclude="../$(app_name)/js/karma.*" \
|
--exclude="$(app_name)/js/karma.*" \
|
||||||
--exclude="../$(app_name)/js/protractor.*" \
|
--exclude="$(app_name)/js/protractor.*" \
|
||||||
--exclude="../$(app_name)/package.json" \
|
--exclude="$(app_name)/package.json" \
|
||||||
--exclude="../$(app_name)/bower.json" \
|
--exclude="$(app_name)/bower.json" \
|
||||||
--exclude="../$(app_name)/karma.*" \
|
--exclude="$(app_name)/karma.*" \
|
||||||
--exclude="../$(app_name)/protractor\.*" \
|
--exclude="$(app_name)/protractor\.*" \
|
||||||
--exclude="../$(app_name)/.*" \
|
--exclude="$(app_name)/.*" \
|
||||||
--exclude="../$(app_name)/js/.*" \
|
--exclude="$(app_name)/js/.*" \
|
||||||
--exclude="../$(app_name)/webpack.js" \
|
--exclude="$(app_name)/webpack.js" \
|
||||||
--exclude="../$(app_name)/stylelint.config.js" \
|
--exclude="$(app_name)/stylelint.config.js" \
|
||||||
--exclude="../$(app_name)/README.md" \
|
--exclude="$(app_name)/README.md" \
|
||||||
--exclude="../$(app_name)/package-lock.json" \
|
--exclude="$(app_name)/package-lock.json" \
|
||||||
--exclude="../$(app_name)/LICENSE" \
|
--exclude="$(app_name)/LICENSE" \
|
||||||
--exclude="../$(app_name)/src" \
|
--exclude="$(app_name)/src" \
|
||||||
--exclude="../$(app_name)/stubs" \
|
--exclude="$(app_name)/stubs" \
|
||||||
--exclude="../$(app_name)/screens" \
|
--exclude="$(app_name)/screens" \
|
||||||
--exclude="../$(app_name)/vendor" \
|
--exclude="$(app_name)/vendor" \
|
||||||
--exclude="../$(app_name)/translationfiles" \
|
--exclude="$(app_name)/translationfiles" \
|
||||||
--exclude="../$(app_name)/Dockerfile" \
|
--exclude="$(app_name)/Dockerfile" \
|
||||||
--exclude="../$(app_name)/psalm.xml" \
|
--exclude="$(app_name)/psalm.xml" \
|
||||||
--exclude="../$(app_name)/renovate.json" \
|
--exclude="$(app_name)/renovate.json" \
|
||||||
../$(app_name)
|
--exclude="$(app_name)/vite.config.mjs" \
|
||||||
|
$(app_name)
|
||||||
|
|
||||||
# Start a nextcloud server on Docker to kickstart developement
|
# Start a nextcloud server on Docker to kickstart developement
|
||||||
.PHONY: dev
|
.PHONY: dev
|
||||||
|
18
composer.lock
generated
18
composer.lock
generated
@ -1312,12 +1312,12 @@
|
|||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Roave/SecurityAdvisories.git",
|
"url": "https://github.com/Roave/SecurityAdvisories.git",
|
||||||
"reference": "176422aa2c339a0f4e56b92862c67a94e2b584fb"
|
"reference": "251a4f1fefcc6e6cc90d50514fee6b6e3745cb3e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/176422aa2c339a0f4e56b92862c67a94e2b584fb",
|
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/251a4f1fefcc6e6cc90d50514fee6b6e3745cb3e",
|
||||||
"reference": "176422aa2c339a0f4e56b92862c67a94e2b584fb",
|
"reference": "251a4f1fefcc6e6cc90d50514fee6b6e3745cb3e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
@ -1414,7 +1414,7 @@
|
|||||||
"codeigniter4/shield": "<1.0.0.0-beta8",
|
"codeigniter4/shield": "<1.0.0.0-beta8",
|
||||||
"codiad/codiad": "<=2.8.4",
|
"codiad/codiad": "<=2.8.4",
|
||||||
"composer/composer": "<1.10.27|>=2,<2.2.24|>=2.3,<2.7.7",
|
"composer/composer": "<1.10.27|>=2,<2.2.24|>=2.3,<2.7.7",
|
||||||
"concrete5/concrete5": "<=9.3.2",
|
"concrete5/concrete5": "<9.3.3",
|
||||||
"concrete5/core": "<8.5.8|>=9,<9.1",
|
"concrete5/core": "<8.5.8|>=9,<9.1",
|
||||||
"contao-components/mediaelement": ">=2.14.2,<2.21.1",
|
"contao-components/mediaelement": ">=2.14.2,<2.21.1",
|
||||||
"contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4",
|
"contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4",
|
||||||
@ -1483,7 +1483,7 @@
|
|||||||
"ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12",
|
"ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12",
|
||||||
"ezsystems/ezplatform-kernel": "<1.2.5.1-dev|>=1.3,<1.3.35",
|
"ezsystems/ezplatform-kernel": "<1.2.5.1-dev|>=1.3,<1.3.35",
|
||||||
"ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8",
|
"ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8",
|
||||||
"ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1-dev",
|
"ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1-dev|>=3.3,<3.3.40",
|
||||||
"ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15",
|
"ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15",
|
||||||
"ezsystems/ezplatform-user": ">=1,<1.0.1",
|
"ezsystems/ezplatform-user": ">=1,<1.0.1",
|
||||||
"ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.31",
|
"ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.31",
|
||||||
@ -1564,6 +1564,7 @@
|
|||||||
"hyn/multi-tenant": ">=5.6,<5.7.2",
|
"hyn/multi-tenant": ">=5.6,<5.7.2",
|
||||||
"ibexa/admin-ui": ">=4.2,<4.2.3|>=4.6.0.0-beta1,<4.6.9",
|
"ibexa/admin-ui": ">=4.2,<4.2.3|>=4.6.0.0-beta1,<4.6.9",
|
||||||
"ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3|>=4.5,<4.5.6|>=4.6,<4.6.2",
|
"ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3|>=4.5,<4.5.6|>=4.6,<4.6.2",
|
||||||
|
"ibexa/fieldtype-richtext": ">=4.6,<4.6.10",
|
||||||
"ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3",
|
"ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3",
|
||||||
"ibexa/post-install": "<=1.0.4",
|
"ibexa/post-install": "<=1.0.4",
|
||||||
"ibexa/solr": ">=4.5,<4.5.4",
|
"ibexa/solr": ">=4.5,<4.5.4",
|
||||||
@ -1806,6 +1807,7 @@
|
|||||||
"pubnub/pubnub": "<6.1",
|
"pubnub/pubnub": "<6.1",
|
||||||
"pusher/pusher-php-server": "<2.2.1",
|
"pusher/pusher-php-server": "<2.2.1",
|
||||||
"pwweb/laravel-core": "<=0.3.6.0-beta",
|
"pwweb/laravel-core": "<=0.3.6.0-beta",
|
||||||
|
"pxlrbt/filament-excel": "<2.3.3",
|
||||||
"pyrocms/pyrocms": "<=3.9.1",
|
"pyrocms/pyrocms": "<=3.9.1",
|
||||||
"qcubed/qcubed": "<=3.1.1",
|
"qcubed/qcubed": "<=3.1.1",
|
||||||
"quickapps/cms": "<=2.0.0.0-beta2",
|
"quickapps/cms": "<=2.0.0.0-beta2",
|
||||||
@ -1833,8 +1835,8 @@
|
|||||||
"serluck/phpwhois": "<=4.2.6",
|
"serluck/phpwhois": "<=4.2.6",
|
||||||
"sfroemken/url_redirect": "<=1.2.1",
|
"sfroemken/url_redirect": "<=1.2.1",
|
||||||
"sheng/yiicms": "<=1.2",
|
"sheng/yiicms": "<=1.2",
|
||||||
"shopware/core": "<6.5.8.8-dev|>=6.6.0.0-RC1-dev,<6.6.1",
|
"shopware/core": "<=6.5.8.12|>=6.6,<=6.6.5",
|
||||||
"shopware/platform": "<6.5.8.8-dev|>=6.6.0.0-RC1-dev,<6.6.1",
|
"shopware/platform": "<=6.5.8.12|>=6.6,<=6.6.5",
|
||||||
"shopware/production": "<=6.3.5.2",
|
"shopware/production": "<=6.3.5.2",
|
||||||
"shopware/shopware": "<=5.7.17",
|
"shopware/shopware": "<=5.7.17",
|
||||||
"shopware/storefront": "<=6.4.8.1|>=6.5.8,<6.5.8.7-dev",
|
"shopware/storefront": "<=6.4.8.1|>=6.5.8,<6.5.8.7-dev",
|
||||||
@ -2119,7 +2121,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-08-05T22:04:39+00:00"
|
"time": "2024-08-14T19:05:08+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/diff",
|
"name": "sebastian/diff",
|
||||||
|
8526
package-lock.json
generated
8526
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
29
package.json
29
package.json
@ -2,11 +2,14 @@
|
|||||||
"name": "repod",
|
"name": "repod",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "NODE_ENV=production webpack --config webpack.js --progress",
|
"build": "vite build --mode production",
|
||||||
"dev": "NODE_ENV=development webpack --config webpack.js --progress",
|
"dev": "vite build --mode development",
|
||||||
"watch": "NODE_ENV=development webpack --config webpack.js --progress --watch",
|
"dev:watch": "vite build --mode development --watch",
|
||||||
|
"watch": "npm run dev:watch",
|
||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
"stylelint": "stylelint src/**/*.vue src/**/*.scss src/**/*.css"
|
"lint:fix": "eslint src --fix",
|
||||||
|
"stylelint": "stylelint src/**/*.vue src/**/*.scss src/**/*.css",
|
||||||
|
"stylelint:fix": "stylelint src/**/*.vue src/**/*.scss src/**/*.css --fix"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"extends @nextcloud/browserslist-config"
|
"extends @nextcloud/browserslist-config"
|
||||||
@ -14,27 +17,27 @@
|
|||||||
"prettier": "@nextcloud/prettier-config",
|
"prettier": "@nextcloud/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nextcloud/axios": "^2.5.0",
|
"@nextcloud/axios": "^2.5.0",
|
||||||
"@nextcloud/dialogs": "^6.0.0",
|
|
||||||
"@nextcloud/initial-state": "^2.2.0",
|
"@nextcloud/initial-state": "^2.2.0",
|
||||||
"@nextcloud/l10n": "^3.1.0",
|
"@nextcloud/l10n": "^3.1.0",
|
||||||
"@nextcloud/router": "^3.0.1",
|
"@nextcloud/router": "^3.0.1",
|
||||||
"@nextcloud/vue": "^8.16.0",
|
"@nextcloud/vite-config": "^2.2.2",
|
||||||
|
"@nextcloud/vue": "9.0.0-alpha.5",
|
||||||
"dompurify": "^3.1.6",
|
"dompurify": "^3.1.6",
|
||||||
"linkify-html": "^4.1.3",
|
"linkify-html": "^4.1.3",
|
||||||
"vue": "^2",
|
"pinia": "^2.2.2",
|
||||||
|
"toastify-js": "^1.12.0",
|
||||||
|
"vite": "^5.4.1",
|
||||||
|
"vue": "^3.4.38",
|
||||||
"vue-material-design-icons": "^5.3.0",
|
"vue-material-design-icons": "^5.3.0",
|
||||||
"vue-router": "^3",
|
"vue-router": "^4.4.3"
|
||||||
"vuex": "^3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nextcloud/browserslist-config": "^3.0.1",
|
"@nextcloud/browserslist-config": "^3.0.1",
|
||||||
"@nextcloud/eslint-config": "^8.4.1",
|
"@nextcloud/eslint-config": "^8.4.1",
|
||||||
"@nextcloud/prettier-config": "^1.1.0",
|
"@nextcloud/prettier-config": "^1.1.0",
|
||||||
"@nextcloud/stylelint-config": "^3.0.1",
|
"@nextcloud/stylelint-config": "^3.0.1",
|
||||||
"@nextcloud/webpack-vue-config": "^6.0.1",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.2.1",
|
"eslint-plugin-pinia": "^0.2.0",
|
||||||
"eslint-webpack-plugin": "^4.2.0",
|
"eslint-plugin-prettier": "^5.2.1"
|
||||||
"stylelint-webpack-plugin": "^5.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
src/App.vue
17
src/App.vue
@ -8,12 +8,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import '@nextcloud/dialogs/style.css'
|
import 'toastify-js/src/toastify.css'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import Bar from './components/Player/Bar.vue'
|
import Bar from './components/Player/Bar.vue'
|
||||||
import GPodder from './views/GPodder.vue'
|
import GPodder from './views/GPodder.vue'
|
||||||
import { NcContent } from '@nextcloud/vue'
|
import { NcContent } from '@nextcloud/vue'
|
||||||
import Subscriptions from './components/Sidebar/Subscriptions.vue'
|
import Subscriptions from './components/Sidebar/Subscriptions.vue'
|
||||||
import { loadState } from '@nextcloud/initial-state'
|
import { loadState } from '@nextcloud/initial-state'
|
||||||
|
import { usePlayer } from './store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
@ -24,9 +26,22 @@ export default {
|
|||||||
Subscriptions,
|
Subscriptions,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState(usePlayer, ['paused']),
|
||||||
gpodder() {
|
gpodder() {
|
||||||
return loadState('repod', 'gpodder', false)
|
return loadState('repod', 'gpodder', false)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
setInterval(this.loop, 40000)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['init', 'time']),
|
||||||
|
loop() {
|
||||||
|
if (this.paused === false) {
|
||||||
|
this.time()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<NcAppContent :class="episode ? 'padding' : ''">
|
<NcAppContent :class="{ padding: episode }">
|
||||||
<slot />
|
<slot />
|
||||||
</NcAppContent>
|
</NcAppContent>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcAppContent } from '@nextcloud/vue'
|
import { NcAppContent } from '@nextcloud/vue'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppContent',
|
name: 'AppContent',
|
||||||
@ -13,9 +15,7 @@ export default {
|
|||||||
NcAppContent,
|
NcAppContent,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
episode() {
|
...mapState(usePlayer, ['episode']),
|
||||||
return this.$store.state.player.episode
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<NcAppNavigation :class="episode ? 'padding' : ''">
|
<NcAppNavigation :class="{ padding: episode }">
|
||||||
<slot />
|
<slot />
|
||||||
<template #list>
|
<template #list>
|
||||||
<slot name="list" />
|
<slot name="list" />
|
||||||
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcAppNavigation } from '@nextcloud/vue'
|
import { NcAppNavigation } from '@nextcloud/vue'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppNavigation',
|
name: 'AppNavigation',
|
||||||
@ -19,9 +21,7 @@ export default {
|
|||||||
NcAppNavigation,
|
NcAppNavigation,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
episode() {
|
...mapState(usePlayer, ['episode']),
|
||||||
return this.$store.state.player.episode
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="flex">
|
||||||
<NcAvatar :display-name="name" :is-no-user="true" :size="256" :url="image" />
|
<NcAvatar :display-name="name" :is-no-user="true" :size="256" :url="image" />
|
||||||
<h2>{{ name }}</h2>
|
<h2>{{ name }}</h2>
|
||||||
<SafeHtml :source="description" />
|
<SafeHtml :source="description" />
|
||||||
<div>
|
<div class="flex">
|
||||||
<NcButton v-if="link" :href="link" target="_blank">
|
<NcButton v-if="link" :href="link" target="_blank">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<OpenInNewIcon :size="20" />
|
<OpenInNewIcon :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
<NcButton v-if="url" :href="url" target="_blank">
|
<NcButton
|
||||||
|
v-if="url"
|
||||||
|
:download="filenameFromUrl(url)"
|
||||||
|
:href="url"
|
||||||
|
target="_blank">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<DownloadIcon :size="20" />
|
<DownloadIcon :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ t('repod', 'Download') }} {{ size ? `(${episodeFileSize})` : '' }}
|
{{ t('repod', 'Download') }}
|
||||||
|
{{ size ? `(${humanFileSize(size)})` : '' }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -25,6 +30,7 @@ import { NcAvatar, NcButton } from '@nextcloud/vue'
|
|||||||
import DownloadIcon from 'vue-material-design-icons/Download.vue'
|
import DownloadIcon from 'vue-material-design-icons/Download.vue'
|
||||||
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
|
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
|
||||||
import SafeHtml from './SafeHtml.vue'
|
import SafeHtml from './SafeHtml.vue'
|
||||||
|
import { filenameFromUrl } from '../../utils/url.js'
|
||||||
import { humanFileSize } from '../../utils/size.js'
|
import { humanFileSize } from '../../utils/size.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -66,16 +72,15 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
methods: {
|
||||||
episodeFileSize() {
|
filenameFromUrl,
|
||||||
return humanFileSize(this.size)
|
humanFileSize,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
div {
|
.flex {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -3,15 +3,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import dompurify from 'dompurify'
|
||||||
import linkifyHtml from 'linkify-html'
|
import linkifyHtml from 'linkify-html'
|
||||||
import { sanitize } from 'dompurify'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SafeHtml',
|
name: 'SafeHtml',
|
||||||
directives: {
|
directives: {
|
||||||
sanitize: {
|
sanitize: {
|
||||||
inserted(el, binding) {
|
mounted(el, binding) {
|
||||||
el.innerHTML = sanitize(
|
el.innerHTML = dompurify.sanitize(
|
||||||
linkifyHtml(binding.value, {
|
linkifyHtml(binding.value, {
|
||||||
nl2br: true,
|
nl2br: true,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<NcActionButton
|
<NcActionButton
|
||||||
v-if="!isSubscribed(feed.link)"
|
v-if="!subscriptions.includes(feed.link)"
|
||||||
:aria-label="t('repod', 'Subscribe')"
|
:aria-label="t('repod', 'Subscribe')"
|
||||||
:name="t('repod', 'Subscribe')"
|
:name="t('repod', 'Subscribe')"
|
||||||
:title="t('repod', 'Subscribe')"
|
:title="t('repod', 'Subscribe')"
|
||||||
@ -36,14 +36,16 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcActionButton, NcAvatar, NcListItem } from '@nextcloud/vue'
|
import { NcActionButton, NcAvatar, NcListItem } from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { debounce } from '../../utils/debounce.js'
|
import { debounce } from '../../utils/debounce.js'
|
||||||
import { formatLocaleDate } from '../../utils/time.js'
|
import { formatLocaleDate } from '../../utils/time.js'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '@nextcloud/dialogs'
|
import { showError } from '../../utils/toast.js'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { toUrl } from '../../utils/url.js'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
@ -66,12 +68,16 @@ export default {
|
|||||||
loading: false,
|
loading: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useSubscriptions, ['subscriptions']),
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value() {
|
value() {
|
||||||
this.search()
|
this.search()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
formatLocaleDate,
|
formatLocaleDate,
|
||||||
toUrl,
|
toUrl,
|
||||||
async addSubscription(url) {
|
async addSubscription(url) {
|
||||||
@ -88,10 +94,7 @@ export default {
|
|||||||
showError(t('repod', 'Error while adding the feed'))
|
showError(t('repod', 'Error while adding the feed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.dispatch('subscriptions/fetch')
|
this.fetch()
|
||||||
},
|
|
||||||
isSubscribed(url) {
|
|
||||||
return this.$store.state.subscriptions.subscriptions.includes(url)
|
|
||||||
},
|
},
|
||||||
search: debounce(async function value() {
|
search: debounce(async function value() {
|
||||||
try {
|
try {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '@nextcloud/dialogs'
|
import { showError } from '../../utils/toast.js'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { toUrl } from '../../utils/url.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<SafeHtml :source="description" />
|
<SafeHtml :source="description" />
|
||||||
</div>
|
</div>
|
||||||
<NcAppNavigationNew
|
<NcAppNavigationNew
|
||||||
v-if="!isSubscribed"
|
v-if="!subscriptions.includes(url)"
|
||||||
:text="t('repod', 'Subscribe')"
|
:text="t('repod', 'Subscribe')"
|
||||||
@click="addSubscription">
|
@click="addSubscription">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@ -37,13 +37,15 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcAppNavigationNew, NcAvatar } from '@nextcloud/vue'
|
import { NcAppNavigationNew, NcAvatar } from '@nextcloud/vue'
|
||||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { showError, showSuccess } from '../../utils/toast.js'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
import RssIcon from 'vue-material-design-icons/Rss.vue'
|
import RssIcon from 'vue-material-design-icons/Rss.vue'
|
||||||
import SafeHtml from '../Atoms/SafeHtml.vue'
|
import SafeHtml from '../Atoms/SafeHtml.vue'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { decodeUrl } from '../../utils/url.js'
|
import { decodeUrl } from '../../utils/url.js'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Banner',
|
name: 'Banner',
|
||||||
@ -77,14 +79,13 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState(useSubscriptions, ['subscriptions']),
|
||||||
url() {
|
url() {
|
||||||
return decodeUrl(this.$route.params.url)
|
return decodeUrl(this.$route.params.url)
|
||||||
},
|
},
|
||||||
isSubscribed() {
|
|
||||||
return this.$store.state.subscriptions.subscriptions.includes(this.url)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
async addSubscription() {
|
async addSubscription() {
|
||||||
try {
|
try {
|
||||||
await axios.post(
|
await axios.post(
|
||||||
@ -99,7 +100,7 @@ export default {
|
|||||||
showError(t('repod', 'Error while adding the feed'))
|
showError(t('repod', 'Error while adding the feed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.dispatch('subscriptions/fetch')
|
this.fetch()
|
||||||
},
|
},
|
||||||
copyFeed() {
|
copyFeed() {
|
||||||
window.navigator.clipboard.writeText(this.url)
|
window.navigator.clipboard.writeText(this.url)
|
||||||
|
@ -6,18 +6,20 @@
|
|||||||
v-for="episode in filteredEpisodes"
|
v-for="episode in filteredEpisodes"
|
||||||
:key="episode.guid"
|
:key="episode.guid"
|
||||||
:active="isCurrentEpisode(episode)"
|
:active="isCurrentEpisode(episode)"
|
||||||
:class="hasEnded(episode) ? 'ended' : ''"
|
|
||||||
:details="formatLocaleDate(new Date(episode.pubDate?.date))"
|
:details="formatLocaleDate(new Date(episode.pubDate?.date))"
|
||||||
:force-display-actions="true"
|
:force-display-actions="true"
|
||||||
|
:href="$route.href"
|
||||||
:name="episode.name"
|
:name="episode.name"
|
||||||
|
:style="{ opacity: hasEnded(episode) ? 0.4 : 1 }"
|
||||||
|
target="_self"
|
||||||
:title="episode.description"
|
:title="episode.description"
|
||||||
@click="modalEpisode = episode">
|
@click="modalEpisode = episode">
|
||||||
<template #extra-actions>
|
<template #actions>
|
||||||
<NcActionButton
|
<NcActionButton
|
||||||
v-if="!isCurrentEpisode(episode)"
|
v-if="!isCurrentEpisode(episode)"
|
||||||
:aria-label="t('repod', 'Play')"
|
:aria-label="t('repod', 'Play')"
|
||||||
:title="t('repod', 'Play')"
|
:title="t('repod', 'Play')"
|
||||||
@click="load(episode)">
|
@click="load(episode, url)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<PlayIcon :size="20" />
|
<PlayIcon :size="20" />
|
||||||
</template>
|
</template>
|
||||||
@ -32,7 +34,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</NcActionButton>
|
</NcActionButton>
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #extra>
|
||||||
|
<NcActions>
|
||||||
<NcActionButton
|
<NcActionButton
|
||||||
v-if="episode.duration && !hasEnded(episode)"
|
v-if="episode.duration && !hasEnded(episode)"
|
||||||
:aria-label="t('repod', 'Mark as read')"
|
:aria-label="t('repod', 'Mark as read')"
|
||||||
@ -67,6 +70,7 @@
|
|||||||
</NcActionLink>
|
</NcActionLink>
|
||||||
<NcActionLink
|
<NcActionLink
|
||||||
v-if="episode.url"
|
v-if="episode.url"
|
||||||
|
:download="filenameFromUrl(episode.url)"
|
||||||
:href="episode.url"
|
:href="episode.url"
|
||||||
:name="t('repod', 'Download')"
|
:name="t('repod', 'Download')"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@ -75,6 +79,7 @@
|
|||||||
<DownloadIcon :size="20" />
|
<DownloadIcon :size="20" />
|
||||||
</template>
|
</template>
|
||||||
</NcActionLink>
|
</NcActionLink>
|
||||||
|
</NcActions>
|
||||||
</template>
|
</template>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NcAvatar
|
<NcAvatar
|
||||||
@ -112,18 +117,20 @@
|
|||||||
import {
|
import {
|
||||||
NcActionButton,
|
NcActionButton,
|
||||||
NcActionLink,
|
NcActionLink,
|
||||||
|
NcActions,
|
||||||
NcAvatar,
|
NcAvatar,
|
||||||
NcListItem,
|
NcListItem,
|
||||||
NcModal,
|
NcModal,
|
||||||
NcProgressBar,
|
NcProgressBar,
|
||||||
} from '@nextcloud/vue'
|
} from '@nextcloud/vue'
|
||||||
|
import { decodeUrl, filenameFromUrl } from '../../utils/url.js'
|
||||||
import {
|
import {
|
||||||
durationToSeconds,
|
durationToSeconds,
|
||||||
formatEpisodeTimestamp,
|
formatEpisodeTimestamp,
|
||||||
formatLocaleDate,
|
formatLocaleDate,
|
||||||
} from '../../utils/time.js'
|
} from '../../utils/time.js'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import DownloadIcon from 'vue-material-design-icons/Download.vue'
|
import DownloadIcon from 'vue-material-design-icons/Download.vue'
|
||||||
import { EventBus } from '../../store/bus.js'
|
|
||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
import Modal from '../Atoms/Modal.vue'
|
import Modal from '../Atoms/Modal.vue'
|
||||||
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
|
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
|
||||||
@ -132,9 +139,10 @@ import PlaylistPlayIcon from 'vue-material-design-icons/PlaylistPlay.vue'
|
|||||||
import PlaylistRemoveIcon from 'vue-material-design-icons/PlaylistRemove.vue'
|
import PlaylistRemoveIcon from 'vue-material-design-icons/PlaylistRemove.vue'
|
||||||
import StopIcon from 'vue-material-design-icons/Stop.vue'
|
import StopIcon from 'vue-material-design-icons/Stop.vue'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { decodeUrl } from '../../utils/url.js'
|
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '@nextcloud/dialogs'
|
import { showError } from '../../utils/toast.js'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
import { useSettings } from '../../store/settings.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Episodes',
|
name: 'Episodes',
|
||||||
@ -144,6 +152,7 @@ export default {
|
|||||||
Modal,
|
Modal,
|
||||||
NcActionButton,
|
NcActionButton,
|
||||||
NcActionLink,
|
NcActionLink,
|
||||||
|
NcActions,
|
||||||
NcAvatar,
|
NcAvatar,
|
||||||
NcListItem,
|
NcListItem,
|
||||||
NcModal,
|
NcModal,
|
||||||
@ -163,12 +172,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
currentEpisode() {
|
...mapState(usePlayer, ['episode']),
|
||||||
return this.$store.state.player.episode
|
...mapState(useSettings, ['filters']),
|
||||||
},
|
|
||||||
filters() {
|
|
||||||
return this.$store.state.settings.filters
|
|
||||||
},
|
|
||||||
filteredEpisodes() {
|
filteredEpisodes() {
|
||||||
return this.episodes.filter((episode) => {
|
return this.episodes.filter((episode) => {
|
||||||
if (!this.filters.listened && this.hasEnded(episode)) {
|
if (!this.filters.listened && this.hasEnded(episode)) {
|
||||||
@ -190,6 +195,15 @@ export default {
|
|||||||
return decodeUrl(this.$route.params.url)
|
return decodeUrl(this.$route.params.url)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
episode() {
|
||||||
|
if (this.episode) {
|
||||||
|
this.episodes = this.episodes.map((e) =>
|
||||||
|
e.url === this.episode.url ? this.episode : e,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
try {
|
try {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
@ -201,7 +215,6 @@ export default {
|
|||||||
this.episodes = [...episodes.data].sort(
|
this.episodes = [...episodes.data].sort(
|
||||||
(a, b) => new Date(b.pubDate?.date) - new Date(a.pubDate?.date),
|
(a, b) => new Date(b.pubDate?.date) - new Date(a.pubDate?.date),
|
||||||
)
|
)
|
||||||
EventBus.$on('updateEpisodesList', this.updateList)
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
showError(t('repod', 'Could not fetch episodes'))
|
showError(t('repod', 'Could not fetch episodes'))
|
||||||
@ -209,10 +222,9 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destroyed() {
|
|
||||||
EventBus.$off('updateEpisodesList')
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['load']),
|
||||||
|
filenameFromUrl,
|
||||||
formatLocaleDate,
|
formatLocaleDate,
|
||||||
hasEnded(episode) {
|
hasEnded(episode) {
|
||||||
return (
|
return (
|
||||||
@ -224,18 +236,17 @@ export default {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
isCurrentEpisode(episode) {
|
isCurrentEpisode(episode) {
|
||||||
return this.currentEpisode && this.currentEpisode.url === episode.url
|
return this.episode && this.episode.url === episode.url
|
||||||
},
|
},
|
||||||
isListening(episode) {
|
isListening(episode) {
|
||||||
return (
|
return (
|
||||||
episode.action &&
|
episode.action &&
|
||||||
|
episode.action.action &&
|
||||||
episode.action.action.toLowerCase() === 'play' &&
|
episode.action.action.toLowerCase() === 'play' &&
|
||||||
|
episode.action.position > 0 &&
|
||||||
!this.hasEnded(episode)
|
!this.hasEnded(episode)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
load(episode) {
|
|
||||||
this.$store.dispatch('player/load', episode)
|
|
||||||
},
|
|
||||||
async markAs(episode, read) {
|
async markAs(episode, read) {
|
||||||
try {
|
try {
|
||||||
this.loadingAction = true
|
this.loadingAction = true
|
||||||
@ -253,7 +264,9 @@ export default {
|
|||||||
generateUrl('/apps/gpoddersync/episode_action/create'),
|
generateUrl('/apps/gpoddersync/episode_action/create'),
|
||||||
[episode.action],
|
[episode.action],
|
||||||
)
|
)
|
||||||
this.updateList(episode)
|
if (read && this.episode && episode.url === this.episode.url) {
|
||||||
|
this.load(null)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
showError(t('repod', 'Could not change the status of the episode'))
|
showError(t('repod', 'Could not change the status of the episode'))
|
||||||
@ -261,20 +274,11 @@ export default {
|
|||||||
this.loadingAction = false
|
this.loadingAction = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateList(episode) {
|
|
||||||
this.episodes = this.episodes.map((e) =>
|
|
||||||
e.url === episode.url ? episode : e,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.ended {
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress {
|
.progress {
|
||||||
margin-top: 0.4rem;
|
margin-top: 0.4rem;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="player.episode" class="footer">
|
<div v-if="episode" class="footer">
|
||||||
<img class="background" :src="player.episode.image" />
|
<img class="background" :src="episode.image" />
|
||||||
<Loading v-if="!player.loaded" />
|
<Loading v-if="!loaded" />
|
||||||
<ProgressBar v-if="player.loaded" />
|
<ProgressBar v-if="loaded" />
|
||||||
<div v-if="player.loaded" class="player">
|
<div v-if="loaded" class="player">
|
||||||
<img :src="player.episode.image" />
|
<img :src="episode.image" />
|
||||||
<Infos class="infos" />
|
<Infos class="infos" />
|
||||||
<Controls class="controls" />
|
<Controls class="controls" />
|
||||||
<Timer class="timer" />
|
<Timer class="timer" />
|
||||||
@ -20,6 +20,8 @@ import Loading from '../Atoms/Loading.vue'
|
|||||||
import ProgressBar from './ProgressBar.vue'
|
import ProgressBar from './ProgressBar.vue'
|
||||||
import Timer from './Timer.vue'
|
import Timer from './Timer.vue'
|
||||||
import Volume from './Volume.vue'
|
import Volume from './Volume.vue'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Bar',
|
name: 'Bar',
|
||||||
@ -32,9 +34,7 @@ export default {
|
|||||||
Volume,
|
Volume,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['episode', 'loaded']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<PauseIcon
|
<PauseIcon v-if="!paused" class="pointer" :size="50" @click="pause" />
|
||||||
v-if="!player.paused"
|
<PlayIcon v-if="paused" class="pointer" :size="50" @click="play" />
|
||||||
class="pointer"
|
|
||||||
:size="50"
|
|
||||||
@click="$store.dispatch('player/pause')" />
|
|
||||||
<PlayIcon
|
|
||||||
v-if="player.paused"
|
|
||||||
class="pointer"
|
|
||||||
:size="50"
|
|
||||||
@click="$store.dispatch('player/play')" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import PauseIcon from 'vue-material-design-icons/Pause.vue'
|
import PauseIcon from 'vue-material-design-icons/Pause.vue'
|
||||||
import PlayIcon from 'vue-material-design-icons/Play.vue'
|
import PlayIcon from 'vue-material-design-icons/Play.vue'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Controls',
|
name: 'Controls',
|
||||||
@ -24,9 +18,10 @@ export default {
|
|||||||
PlayIcon,
|
PlayIcon,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['paused']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['play', 'pause']),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<strong class="pointer" @click="modal = true">
|
<strong class="pointer" @click="modal = true">
|
||||||
{{ player.episode.name }}
|
{{ episode.name }}
|
||||||
</strong>
|
</strong>
|
||||||
<router-link :to="hash">
|
<router-link :to="hash">
|
||||||
<i>{{ player.episode.title }}</i>
|
<i>{{ episode.title }}</i>
|
||||||
</router-link>
|
</router-link>
|
||||||
<NcModal v-if="modal" @close="modal = false">
|
<NcModal v-if="modal" @close="modal = false">
|
||||||
<Modal
|
<Modal
|
||||||
:description="player.episode.description"
|
:description="episode.description"
|
||||||
:image="player.episode.image"
|
:image="episode.image"
|
||||||
:link="player.episode.link"
|
:link="episode.link"
|
||||||
:name="player.episode.name"
|
:name="episode.name"
|
||||||
:size="player.episode.size"
|
:size="episode.size"
|
||||||
:title="player.episode.title"
|
:title="episode.title"
|
||||||
:url="player.episode.url" />
|
:url="episode.url" />
|
||||||
</NcModal>
|
</NcModal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -22,7 +22,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import Modal from '../Atoms/Modal.vue'
|
import Modal from '../Atoms/Modal.vue'
|
||||||
import { NcModal } from '@nextcloud/vue'
|
import { NcModal } from '@nextcloud/vue'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { toUrl } from '../../utils/url.js'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Infos',
|
name: 'Infos',
|
||||||
@ -36,11 +38,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['episode', 'podcastUrl']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
hash() {
|
hash() {
|
||||||
return toUrl(this.player.podcastUrl)
|
return toUrl(this.podcastUrl)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<input
|
<input
|
||||||
class="progress"
|
class="progress"
|
||||||
:max="player.duration"
|
:max="duration"
|
||||||
min="0"
|
min="0"
|
||||||
type="range"
|
type="range"
|
||||||
:value="player.currentTime"
|
:value="currentTime"
|
||||||
@change="(event) => $store.dispatch('player/seek', event.target.value)" />
|
@change="(event) => seek(event.target.value)" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProgressBar',
|
name: 'ProgressBar',
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['duration', 'currentTime']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['seek']),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<span>{{ formatTimer(new Date(player.currentTime * 1000)) }}</span>
|
<span>{{ formatTimer(new Date(currentTime * 1000)) }}</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span>{{ formatTimer(new Date(player.duration * 1000)) }}</span>
|
<span>{{ formatTimer(new Date(duration * 1000)) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { formatTimer } from '../../utils/time.js'
|
import { formatTimer } from '../../utils/time.js'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Timer',
|
name: 'Timer',
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['duration', 'currentTime']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatTimer,
|
formatTimer,
|
||||||
|
@ -1,42 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VolumeHighIcon
|
<VolumeHighIcon
|
||||||
v-if="player.volume > 0.7"
|
v-if="volume > 0.7"
|
||||||
class="pointer"
|
class="pointer"
|
||||||
:size="30"
|
:size="30"
|
||||||
@click="mute" />
|
@click="mute" />
|
||||||
<VolumeLowIcon
|
<VolumeLowIcon
|
||||||
v-if="player.volume > 0 && player.volume <= 0.3"
|
v-if="volume > 0 && volume <= 0.3"
|
||||||
class="pointer"
|
class="pointer"
|
||||||
:size="30"
|
:size="30"
|
||||||
@click="mute" />
|
@click="mute" />
|
||||||
<VolumeMediumIcon
|
<VolumeMediumIcon
|
||||||
v-if="player.volume > 0.3 && player.volume <= 0.7"
|
v-if="volume > 0.3 && volume <= 0.7"
|
||||||
class="pointer"
|
class="pointer"
|
||||||
:size="30"
|
:size="30"
|
||||||
@click="mute" />
|
@click="mute" />
|
||||||
<VolumeMuteIcon
|
<VolumeMuteIcon
|
||||||
v-if="player.volume === 0"
|
v-if="volume === 0"
|
||||||
class="pointer"
|
class="pointer"
|
||||||
:size="30"
|
:size="30"
|
||||||
@click="$store.dispatch('player/volume', volumeMuted)" />
|
@click="setVolume(volumeMuted)" />
|
||||||
<input
|
<input
|
||||||
max="1"
|
max="1"
|
||||||
min="0"
|
min="0"
|
||||||
step="0.1"
|
step="0.1"
|
||||||
type="range"
|
type="range"
|
||||||
:value="player.volume"
|
:value="volume"
|
||||||
@change="
|
@change="(event) => setVolume(event.target.value)" />
|
||||||
(event) => $store.dispatch('player/volume', event.target.value)
|
|
||||||
" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import VolumeHighIcon from 'vue-material-design-icons/VolumeHigh.vue'
|
import VolumeHighIcon from 'vue-material-design-icons/VolumeHigh.vue'
|
||||||
import VolumeLowIcon from 'vue-material-design-icons/VolumeLow.vue'
|
import VolumeLowIcon from 'vue-material-design-icons/VolumeLow.vue'
|
||||||
import VolumeMediumIcon from 'vue-material-design-icons/VolumeMedium.vue'
|
import VolumeMediumIcon from 'vue-material-design-icons/VolumeMedium.vue'
|
||||||
import VolumeMuteIcon from 'vue-material-design-icons/VolumeMute.vue'
|
import VolumeMuteIcon from 'vue-material-design-icons/VolumeMute.vue'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Volume',
|
name: 'Volume',
|
||||||
@ -52,14 +52,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['volume']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['setVolume']),
|
||||||
mute() {
|
mute() {
|
||||||
this.volumeMuted = this.player.volume
|
this.volumeMuted = this.volume
|
||||||
this.$store.dispatch('player/volume', 0)
|
this.setVolume(0)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -5,40 +5,30 @@
|
|||||||
:name="t('repod', 'Filtering episodes')">
|
:name="t('repod', 'Filtering episodes')">
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<NcActionCheckbox
|
<NcActionCheckbox
|
||||||
:checked="all"
|
|
||||||
:disabled="all"
|
:disabled="all"
|
||||||
@update:checked="
|
:model-value="all"
|
||||||
(checked) =>
|
@change="
|
||||||
$store.commit('settings/filters', {
|
setFilters({
|
||||||
listened: checked,
|
listened: true,
|
||||||
listening: checked,
|
listening: true,
|
||||||
unlistened: checked,
|
unlistened: true,
|
||||||
})
|
})
|
||||||
">
|
">
|
||||||
{{ t('repod', 'Show all') }}
|
{{ t('repod', 'Show all') }}
|
||||||
</NcActionCheckbox>
|
</NcActionCheckbox>
|
||||||
<NcActionCheckbox
|
<NcActionCheckbox
|
||||||
:checked="filters.listened"
|
:model-value="filters.listened"
|
||||||
@update:checked="
|
@change="setFilters({ listened: !filters.listened })">
|
||||||
(checked) =>
|
|
||||||
$store.commit('settings/filters', { listened: checked })
|
|
||||||
">
|
|
||||||
{{ t('repod', 'Listened') }}
|
{{ t('repod', 'Listened') }}
|
||||||
</NcActionCheckbox>
|
</NcActionCheckbox>
|
||||||
<NcActionCheckbox
|
<NcActionCheckbox
|
||||||
:checked="filters.listening"
|
:model-value="filters.listening"
|
||||||
@update:checked="
|
@change="setFilters({ listening: !filters.listening })">
|
||||||
(checked) =>
|
|
||||||
$store.commit('settings/filters', { listening: checked })
|
|
||||||
">
|
|
||||||
{{ t('repod', 'Listening') }}
|
{{ t('repod', 'Listening') }}
|
||||||
</NcActionCheckbox>
|
</NcActionCheckbox>
|
||||||
<NcActionCheckbox
|
<NcActionCheckbox
|
||||||
:checked="filters.unlistened"
|
:model-value="filters.unlistened"
|
||||||
@update:checked="
|
@change="setFilters({ unlistened: !filters.unlistened })">
|
||||||
(checked) =>
|
|
||||||
$store.commit('settings/filters', { unlistened: checked })
|
|
||||||
">
|
|
||||||
{{ t('repod', 'Unlistened') }}
|
{{ t('repod', 'Unlistened') }}
|
||||||
</NcActionCheckbox>
|
</NcActionCheckbox>
|
||||||
</template>
|
</template>
|
||||||
@ -51,8 +41,11 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcActionCheckbox, NcAppNavigationItem } from '@nextcloud/vue'
|
import { NcActionCheckbox, NcAppNavigationItem } from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import FilterIcon from 'vue-material-design-icons/Filter.vue'
|
import FilterIcon from 'vue-material-design-icons/Filter.vue'
|
||||||
import FilterSettingsIcon from 'vue-material-design-icons/FilterSettings.vue'
|
import FilterSettingsIcon from 'vue-material-design-icons/FilterSettings.vue'
|
||||||
|
import { getCookie } from '../../utils/cookies.js'
|
||||||
|
import { useSettings } from '../../store/settings.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Filters',
|
name: 'Filters',
|
||||||
@ -63,6 +56,7 @@ export default {
|
|||||||
NcActionCheckbox,
|
NcActionCheckbox,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState(useSettings, ['filters']),
|
||||||
all() {
|
all() {
|
||||||
return (
|
return (
|
||||||
this.filters.listened &&
|
this.filters.listened &&
|
||||||
@ -70,12 +64,15 @@ export default {
|
|||||||
this.filters.unlistened
|
this.filters.unlistened
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
filters() {
|
|
||||||
return this.$store.state.settings.filters
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$store.dispatch('settings/fetch')
|
try {
|
||||||
|
const filters = getCookie('repod.filters')
|
||||||
|
this.filters = JSON.parse(filters)
|
||||||
|
} catch {}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useSettings, ['setFilters']),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,27 +3,27 @@
|
|||||||
<template #extra>
|
<template #extra>
|
||||||
<div class="extra">
|
<div class="extra">
|
||||||
<MinusIcon class="pointer" :size="20" @click="changeRate(-0.1)" />
|
<MinusIcon class="pointer" :size="20" @click="changeRate(-0.1)" />
|
||||||
<NcCounterBubble class="counter">
|
<NcCounterBubble class="counter">x{{ rate }}</NcCounterBubble>
|
||||||
x{{ player.rate }}
|
|
||||||
</NcCounterBubble>
|
|
||||||
<PlusIcon class="pointer" :size="20" @click="changeRate(0.1)" />
|
<PlusIcon class="pointer" :size="20" @click="changeRate(0.1)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<SpeedometerSlowIcon v-if="player.rate < 1" :size="20" />
|
<SpeedometerSlowIcon v-if="rate < 1" :size="20" />
|
||||||
<SpeedometerMediumIcon v-if="player.rate === 1" :size="20" />
|
<SpeedometerMediumIcon v-if="rate === 1" :size="20" />
|
||||||
<SpeedometerIcon v-if="player.rate > 1" :size="20" />
|
<SpeedometerIcon v-if="rate > 1" :size="20" />
|
||||||
</template>
|
</template>
|
||||||
</NcAppNavigationItem>
|
</NcAppNavigationItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcAppNavigationItem, NcCounterBubble } from '@nextcloud/vue'
|
import { NcAppNavigationItem, NcCounterBubble } from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import MinusIcon from 'vue-material-design-icons/Minus.vue'
|
import MinusIcon from 'vue-material-design-icons/Minus.vue'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
import SpeedometerIcon from 'vue-material-design-icons/Speedometer.vue'
|
import SpeedometerIcon from 'vue-material-design-icons/Speedometer.vue'
|
||||||
import SpeedometerMediumIcon from 'vue-material-design-icons/SpeedometerMedium.vue'
|
import SpeedometerMediumIcon from 'vue-material-design-icons/SpeedometerMedium.vue'
|
||||||
import SpeedometerSlowIcon from 'vue-material-design-icons/SpeedometerSlow.vue'
|
import SpeedometerSlowIcon from 'vue-material-design-icons/SpeedometerSlow.vue'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Speed',
|
name: 'Speed',
|
||||||
@ -37,17 +37,13 @@ export default {
|
|||||||
SpeedometerSlowIcon,
|
SpeedometerSlowIcon,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['rate']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['setRate']),
|
||||||
changeRate(diff) {
|
changeRate(diff) {
|
||||||
const newRate = (this.player.rate + diff).toPrecision(2)
|
const newRate = (this.rate + diff).toPrecision(2)
|
||||||
this.$store.dispatch(
|
this.setRate(newRate > 0 ? newRate : this.rate)
|
||||||
'player/rate',
|
|
||||||
newRate > 0 ? newRate : this.player.rate,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,10 @@ import AlertIcon from 'vue-material-design-icons/Alert.vue'
|
|||||||
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
|
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '@nextcloud/dialogs'
|
import { mapActions } from 'pinia'
|
||||||
|
import { showError } from '../../utils/toast.js'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { toUrl } from '../../utils/url.js'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Item',
|
name: 'Item',
|
||||||
@ -80,6 +82,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
async deleteSubscription() {
|
async deleteSubscription() {
|
||||||
if (
|
if (
|
||||||
confirm(
|
confirm(
|
||||||
@ -97,7 +100,7 @@ export default {
|
|||||||
showError(t('repod', 'Error while removing the feed'))
|
showError(t('repod', 'Error while removing the feed'))
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.$store.dispatch('subscriptions/fetch')
|
this.fetch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -30,12 +30,14 @@ import {
|
|||||||
NcAppNavigationList,
|
NcAppNavigationList,
|
||||||
NcAppNavigationNew,
|
NcAppNavigationNew,
|
||||||
} from '@nextcloud/vue'
|
} from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import AppNavigation from '../Atoms/AppNavigation.vue'
|
import AppNavigation from '../Atoms/AppNavigation.vue'
|
||||||
import Item from './Item.vue'
|
import Item from './Item.vue'
|
||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
import Settings from '../Settings/Settings.vue'
|
import Settings from '../Settings/Settings.vue'
|
||||||
import { showError } from '@nextcloud/dialogs'
|
import { showError } from '../../utils/toast.js'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Subscriptions',
|
name: 'Subscriptions',
|
||||||
@ -55,13 +57,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
subscriptions() {
|
...mapState(useSubscriptions, ['subscriptions']),
|
||||||
return this.$store.state.subscriptions.subscriptions
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
try {
|
try {
|
||||||
await this.$store.dispatch('subscriptions/fetch')
|
await this.fetch()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
showError(t('repod', 'Could not fetch subscriptions'))
|
showError(t('repod', 'Could not fetch subscriptions'))
|
||||||
@ -69,5 +69,8 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
16
src/main.js
16
src/main.js
@ -1,13 +1,13 @@
|
|||||||
import { n, t } from '@nextcloud/l10n'
|
import { n, t } from '@nextcloud/l10n'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import Vue from 'vue'
|
import { createApp } from 'vue'
|
||||||
|
import { createPinia } from 'pinia'
|
||||||
import router from './router.js'
|
import router from './router.js'
|
||||||
import store from './store/main.js'
|
|
||||||
|
const Vue = createApp(App)
|
||||||
|
const pinia = createPinia()
|
||||||
|
|
||||||
Vue.mixin({ methods: { t, n } })
|
Vue.mixin({ methods: { t, n } })
|
||||||
|
Vue.use(pinia)
|
||||||
const View = Vue.extend(App)
|
Vue.use(router)
|
||||||
new View({
|
Vue.mount('#content')
|
||||||
router,
|
|
||||||
store,
|
|
||||||
}).$mount('#content')
|
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
import Discover from './views/Discover.vue'
|
import Discover from './views/Discover.vue'
|
||||||
import Feed from './views/Feed.vue'
|
import Feed from './views/Feed.vue'
|
||||||
import Router from 'vue-router'
|
|
||||||
import Vue from 'vue'
|
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
|
||||||
Vue.use(Router)
|
const router = createRouter({
|
||||||
|
history: createWebHashHistory(generateUrl('apps/repod')),
|
||||||
const router = new Router({
|
|
||||||
base: generateUrl('apps/repod'),
|
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
|
|
||||||
export const EventBus = new Vue()
|
|
@ -1,17 +0,0 @@
|
|||||||
import Vuex, { Store } from 'vuex'
|
|
||||||
import Vue from 'vue'
|
|
||||||
import { player } from './player.js'
|
|
||||||
import { settings } from './settings.js'
|
|
||||||
import { subscriptions } from './subscriptions.js'
|
|
||||||
|
|
||||||
Vue.use(Vuex)
|
|
||||||
|
|
||||||
const store = new Store({
|
|
||||||
modules: {
|
|
||||||
player,
|
|
||||||
settings,
|
|
||||||
subscriptions,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export default store
|
|
@ -1,25 +1,12 @@
|
|||||||
import { EventBus } from './bus.js'
|
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { decodeUrl } from '../utils/url.js'
|
import { defineStore } from 'pinia'
|
||||||
import { formatEpisodeTimestamp } from '../utils/time.js'
|
import { formatEpisodeTimestamp } from '../utils/time.js'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import router from '../router.js'
|
|
||||||
import store from './main.js'
|
|
||||||
|
|
||||||
const audio = new Audio()
|
const audio = new Audio()
|
||||||
audio.ondurationchange = () => store.commit('player/duration', audio.duration)
|
|
||||||
audio.onended = () => store.dispatch('player/stop')
|
|
||||||
audio.onloadeddata = () => store.commit('player/loaded', true)
|
|
||||||
audio.onplay = () => store.dispatch('player/play')
|
|
||||||
audio.onpause = () => store.dispatch('player/pause')
|
|
||||||
audio.onratechange = () => store.commit('player/rate', audio.playbackRate)
|
|
||||||
audio.onseeked = () => store.commit('player/currentTime', audio.currentTime)
|
|
||||||
audio.ontimeupdate = () => store.commit('player/currentTime', audio.currentTime)
|
|
||||||
audio.onvolumechange = () => store.commit('player/volume', audio.volume)
|
|
||||||
|
|
||||||
export const player = {
|
export const usePlayer = defineStore('player', {
|
||||||
namespaced: true,
|
state: () => ({
|
||||||
state: {
|
|
||||||
currentTime: null,
|
currentTime: null,
|
||||||
duration: null,
|
duration: null,
|
||||||
episode: null,
|
episode: null,
|
||||||
@ -29,119 +16,91 @@ export const player = {
|
|||||||
volume: 1,
|
volume: 1,
|
||||||
rate: 1,
|
rate: 1,
|
||||||
started: 0,
|
started: 0,
|
||||||
},
|
}),
|
||||||
mutations: {
|
|
||||||
action: (state, action) => {
|
|
||||||
state.episode.action = action
|
|
||||||
|
|
||||||
if (action && action.position && action.position < action.total) {
|
|
||||||
audio.currentTime = action.position
|
|
||||||
state.started = audio.currentTime
|
|
||||||
}
|
|
||||||
},
|
|
||||||
currentTime: (state, currentTime) => {
|
|
||||||
state.currentTime = currentTime
|
|
||||||
},
|
|
||||||
duration: (state, duration) => {
|
|
||||||
state.duration = duration
|
|
||||||
},
|
|
||||||
episode: (state, episode) => {
|
|
||||||
state.episode = episode
|
|
||||||
|
|
||||||
if (episode) {
|
|
||||||
state.podcastUrl = decodeUrl(router.currentRoute.params.url)
|
|
||||||
audio.src = episode.url
|
|
||||||
audio.load()
|
|
||||||
audio.play()
|
|
||||||
|
|
||||||
if (
|
|
||||||
episode.action &&
|
|
||||||
episode.action.position &&
|
|
||||||
episode.action.position < episode.action.total
|
|
||||||
) {
|
|
||||||
audio.currentTime = episode.action.position
|
|
||||||
state.started = audio.currentTime
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state.loaded = false
|
|
||||||
state.podcastUrl = null
|
|
||||||
audio.src = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
loaded: (state, loaded) => {
|
|
||||||
state.loaded = loaded
|
|
||||||
},
|
|
||||||
paused: (state, paused) => {
|
|
||||||
state.paused = paused
|
|
||||||
},
|
|
||||||
volume: (state, volume) => {
|
|
||||||
state.volume = volume
|
|
||||||
},
|
|
||||||
rate: (state, rate) => {
|
|
||||||
state.rate = rate
|
|
||||||
},
|
|
||||||
started: (state, started) => {
|
|
||||||
state.started = started
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
actions: {
|
||||||
load: async (context, episode) => {
|
init() {
|
||||||
context.commit('episode', episode)
|
audio.ondurationchange = () => (this.duration = audio.duration)
|
||||||
|
audio.onended = () => this.stop()
|
||||||
|
audio.onloadeddata = () => (this.loaded = true)
|
||||||
|
audio.onpause = () => this.pause()
|
||||||
|
audio.onplay = () => this.play()
|
||||||
|
audio.onratechange = () => (this.rate = audio.playbackRate)
|
||||||
|
audio.onseeked = () => (this.currentTime = audio.currentTime)
|
||||||
|
audio.ontimeupdate = () => (this.currentTime = audio.currentTime)
|
||||||
|
audio.onvolumechange = () => (this.volume = audio.volume)
|
||||||
|
},
|
||||||
|
async load(episode, podcastUrl) {
|
||||||
|
this.episode = episode
|
||||||
|
this.podcastUrl = podcastUrl
|
||||||
|
|
||||||
|
if (this.episode) {
|
||||||
|
audio.src = this.episode.url
|
||||||
|
audio.load()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const action = await axios.get(
|
const action = await axios.get(
|
||||||
generateUrl('/apps/repod/episodes/action?url={url}', {
|
generateUrl('/apps/repod/episodes/action?url={url}', {
|
||||||
url: episode.url,
|
url: this.episode.url,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
context.commit('action', action.data)
|
|
||||||
|
this.episode.action = action
|
||||||
} catch {}
|
} catch {}
|
||||||
},
|
|
||||||
pause: (context) => {
|
if (
|
||||||
audio.pause()
|
this.episode.action &&
|
||||||
context.commit('paused', true)
|
this.episode.action.position &&
|
||||||
context.dispatch('time')
|
this.episode.action.position < this.episode.action.total
|
||||||
},
|
) {
|
||||||
play: (context) => {
|
audio.currentTime = this.episode.action.position
|
||||||
|
this.started = audio.currentTime
|
||||||
|
}
|
||||||
|
|
||||||
audio.play()
|
audio.play()
|
||||||
context.commit('paused', false)
|
} else {
|
||||||
context.commit('started', audio.currentTime)
|
this.loaded = false
|
||||||
|
this.podcastUrl = null
|
||||||
|
audio.src = ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
seek: (context, currentTime) => {
|
pause() {
|
||||||
|
audio.pause()
|
||||||
|
this.paused = true
|
||||||
|
this.time()
|
||||||
|
},
|
||||||
|
play() {
|
||||||
|
audio.play()
|
||||||
|
this.paused = false
|
||||||
|
this.started = audio.currentTime
|
||||||
|
},
|
||||||
|
seek(currentTime) {
|
||||||
audio.currentTime = currentTime
|
audio.currentTime = currentTime
|
||||||
context.dispatch('time')
|
this.time()
|
||||||
},
|
},
|
||||||
stop: (context) => {
|
stop() {
|
||||||
context.dispatch('pause')
|
this.pause()
|
||||||
context.commit('episode', null)
|
this.episode = null
|
||||||
},
|
},
|
||||||
time: async (context) => {
|
time() {
|
||||||
const episode = context.state.episode
|
this.episode.action = {
|
||||||
episode.action = {
|
podcast: this.podcastUrl,
|
||||||
podcast: context.state.podcastUrl,
|
episode: this.episode.url,
|
||||||
episode: context.state.episode.url,
|
guid: this.episode.guid,
|
||||||
guid: context.state.episode.guid,
|
|
||||||
action: 'play',
|
action: 'play',
|
||||||
timestamp: formatEpisodeTimestamp(new Date()),
|
timestamp: formatEpisodeTimestamp(new Date()),
|
||||||
started: Math.round(context.state.started),
|
started: Math.round(this.started),
|
||||||
position: Math.round(audio.currentTime),
|
position: Math.round(audio.currentTime),
|
||||||
total: Math.round(audio.duration),
|
total: Math.round(audio.duration),
|
||||||
}
|
}
|
||||||
axios.post(generateUrl('/apps/gpoddersync/episode_action/create'), [
|
axios.post(generateUrl('/apps/gpoddersync/episode_action/create'), [
|
||||||
episode.action,
|
this.episode.action,
|
||||||
])
|
])
|
||||||
EventBus.$emit('updateEpisodesList', episode)
|
|
||||||
},
|
},
|
||||||
volume: (_, volume) => {
|
setVolume(volume) {
|
||||||
audio.volume = volume
|
audio.volume = volume
|
||||||
},
|
},
|
||||||
rate: (_, rate) => {
|
setRate(rate) {
|
||||||
audio.playbackRate = rate
|
audio.playbackRate = rate
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
|
|
||||||
setInterval(() => {
|
|
||||||
if (player.state.paused === false) {
|
|
||||||
store.dispatch('player/time')
|
|
||||||
}
|
|
||||||
}, 40000)
|
|
||||||
|
@ -1,28 +1,18 @@
|
|||||||
import { getCookie, setCookie } from '../utils/cookies.js'
|
import { defineStore } from 'pinia'
|
||||||
|
import { setCookie } from '../utils/cookies.js'
|
||||||
|
|
||||||
export const settings = {
|
export const useSettings = defineStore('settings', {
|
||||||
namespaced: true,
|
state: () => ({
|
||||||
state: {
|
|
||||||
filters: {
|
filters: {
|
||||||
listened: true,
|
listened: true,
|
||||||
listening: true,
|
listening: true,
|
||||||
unlistened: true,
|
unlistened: true,
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
mutations: {
|
|
||||||
filters: (state, filters) => {
|
|
||||||
state.filters = { ...state.filters, ...filters }
|
|
||||||
setCookie('repod.filters', JSON.stringify(state.filters), 365)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
actions: {
|
||||||
fetch: (context) => {
|
setFilters(filters) {
|
||||||
try {
|
this.filters = { ...this.filters, ...filters }
|
||||||
const filters = getCookie('repod.filters')
|
setCookie('repod.filters', JSON.stringify(this.filters), 365)
|
||||||
context.commit('filters', JSON.parse(filters))
|
|
||||||
} catch (e) {
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
|
@ -1,28 +1,20 @@
|
|||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
|
||||||
export const subscriptions = {
|
export const useSubscriptions = defineStore('subscriptions', {
|
||||||
namespaced: true,
|
state: () => ({
|
||||||
state: {
|
|
||||||
subscriptions: [],
|
subscriptions: [],
|
||||||
},
|
}),
|
||||||
mutations: {
|
|
||||||
set: (state, subscriptions) => {
|
|
||||||
state.subscriptions = subscriptions
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
actions: {
|
||||||
fetch: async (context) => {
|
async fetch() {
|
||||||
const metrics = await axios.get(
|
const metrics = await axios.get(
|
||||||
generateUrl('/apps/gpoddersync/personal_settings/metrics'),
|
generateUrl('/apps/gpoddersync/personal_settings/metrics'),
|
||||||
)
|
)
|
||||||
const subs = [...metrics.data.subscriptions].sort(
|
const subs = [...metrics.data.subscriptions].sort(
|
||||||
(a, b) => b.listenedSeconds - a.listenedSeconds,
|
(a, b) => b.listenedSeconds - a.listenedSeconds,
|
||||||
)
|
)
|
||||||
context.commit(
|
this.subscriptions = subs.map((sub) => sub.url)
|
||||||
'set',
|
|
||||||
subs.map((sub) => sub.url),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
|
12
src/utils/toast.js
Normal file
12
src/utils/toast.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import toastify from 'toastify-js'
|
||||||
|
|
||||||
|
export const showMessage = (text, backgroundColor) =>
|
||||||
|
toastify({
|
||||||
|
text,
|
||||||
|
backgroundColor,
|
||||||
|
}).showToast()
|
||||||
|
|
||||||
|
export const showError = (text) => showMessage(text, 'var(--color-error)')
|
||||||
|
export const showWarning = (text) => showMessage(text, 'var(--color-warning)')
|
||||||
|
export const showInfo = (text) => showMessage(text, 'var(--color-primary)')
|
||||||
|
export const showSuccess = (text) => showMessage(text, 'var(--color-success)')
|
@ -1,3 +1,7 @@
|
|||||||
export const encodeUrl = (url) => encodeURIComponent(btoa(url))
|
export const encodeUrl = (url) => encodeURIComponent(btoa(url))
|
||||||
export const decodeUrl = (url) => atob(decodeURIComponent(url))
|
export const decodeUrl = (url) => atob(decodeURIComponent(url))
|
||||||
export const toUrl = (url) => `/${encodeUrl(url)}`
|
export const toUrl = (url) => `/${encodeUrl(url)}`
|
||||||
|
export const filenameFromUrl = (str) => {
|
||||||
|
const url = new URL(str)
|
||||||
|
return url.pathname.split('/').pop()
|
||||||
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppContent class="main">
|
<AppContent class="main">
|
||||||
<NcTextField :label="t('repod', 'Find a podcast')" :value.sync="search">
|
<NcTextField v-model="search" :label="t('repod', 'Find a podcast')">
|
||||||
|
<template #icon>
|
||||||
<Magnify :size="20" />
|
<Magnify :size="20" />
|
||||||
|
</template>
|
||||||
</NcTextField>
|
</NcTextField>
|
||||||
<Search v-if="search" :value="search" />
|
<Search v-if="search" :value="search" />
|
||||||
<Toplist v-if="!search" type="hot" />
|
<Toplist v-if="!search" type="hot" />
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Nextcloud 3.14159\n"
|
"Project-Id-Version: Nextcloud 3.14159\n"
|
||||||
"Report-Msgid-Bugs-To: translations\\@example.com\n"
|
"Report-Msgid-Bugs-To: translations\\@example.com\n"
|
||||||
"POT-Creation-Date: 2024-07-15 14:40+0000\n"
|
"POT-Creation-Date: 2024-08-09 10:10+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -48,8 +48,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:1
|
#: /app/specialVueFakeDummyForL10nScript.js:1
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:29
|
#: /app/specialVueFakeDummyForL10nScript.js:27
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:30
|
#: /app/specialVueFakeDummyForL10nScript.js:28
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -95,109 +95,107 @@ msgstr ""
|
|||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:15
|
#: /app/specialVueFakeDummyForL10nScript.js:15
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:16
|
#: /app/specialVueFakeDummyForL10nScript.js:16
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:17
|
|
||||||
msgid "Play"
|
msgid "Play"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:17
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:18
|
#: /app/specialVueFakeDummyForL10nScript.js:18
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:19
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:20
|
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:19
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:20
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:21
|
#: /app/specialVueFakeDummyForL10nScript.js:21
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:22
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:23
|
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:22
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:23
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:24
|
#: /app/specialVueFakeDummyForL10nScript.js:24
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:25
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:26
|
|
||||||
msgid "Mark as unread"
|
msgid "Mark as unread"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:27
|
#: /app/specialVueFakeDummyForL10nScript.js:25
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:28
|
#: /app/specialVueFakeDummyForL10nScript.js:26
|
||||||
msgid "Open website"
|
msgid "Open website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:31
|
#: /app/specialVueFakeDummyForL10nScript.js:29
|
||||||
msgid "Could not fetch episodes"
|
msgid "Could not fetch episodes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:32
|
#: /app/specialVueFakeDummyForL10nScript.js:30
|
||||||
msgid "Could not change the status of the episode"
|
msgid "Could not change the status of the episode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:33
|
#: /app/specialVueFakeDummyForL10nScript.js:31
|
||||||
msgid "Export subscriptions"
|
msgid "Export subscriptions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:34
|
#: /app/specialVueFakeDummyForL10nScript.js:32
|
||||||
msgid "Filtering episodes"
|
msgid "Filtering episodes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:35
|
#: /app/specialVueFakeDummyForL10nScript.js:33
|
||||||
msgid "Show all"
|
msgid "Show all"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:36
|
#: /app/specialVueFakeDummyForL10nScript.js:34
|
||||||
msgid "Listened"
|
msgid "Listened"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:37
|
#: /app/specialVueFakeDummyForL10nScript.js:35
|
||||||
msgid "Listening"
|
msgid "Listening"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:38
|
#: /app/specialVueFakeDummyForL10nScript.js:36
|
||||||
msgid "Unlistened"
|
msgid "Unlistened"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:39
|
#: /app/specialVueFakeDummyForL10nScript.js:37
|
||||||
msgid "Import subscriptions"
|
msgid "Import subscriptions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:40
|
#: /app/specialVueFakeDummyForL10nScript.js:38
|
||||||
msgid "Import OPML file"
|
msgid "Import OPML file"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:41
|
#: /app/specialVueFakeDummyForL10nScript.js:39
|
||||||
msgid "Rate RePod ❤️"
|
msgid "Rate RePod ❤️"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:42
|
#: /app/specialVueFakeDummyForL10nScript.js:40
|
||||||
msgid "Playback speed"
|
msgid "Playback speed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:43
|
#: /app/specialVueFakeDummyForL10nScript.js:41
|
||||||
msgid "Are you sure you want to delete this subscription?"
|
msgid "Are you sure you want to delete this subscription?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:44
|
#: /app/specialVueFakeDummyForL10nScript.js:42
|
||||||
msgid "Error while removing the feed"
|
msgid "Error while removing the feed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:45
|
#: /app/specialVueFakeDummyForL10nScript.js:43
|
||||||
msgid "Add a podcast"
|
msgid "Add a podcast"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:46
|
#: /app/specialVueFakeDummyForL10nScript.js:44
|
||||||
msgid "Could not fetch subscriptions"
|
msgid "Could not fetch subscriptions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:47
|
#: /app/specialVueFakeDummyForL10nScript.js:45
|
||||||
msgid "Find a podcast"
|
msgid "Find a podcast"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:48
|
#: /app/specialVueFakeDummyForL10nScript.js:46
|
||||||
msgid "Error loading feed"
|
msgid "Error loading feed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:49
|
#: /app/specialVueFakeDummyForL10nScript.js:47
|
||||||
msgid "Missing required app"
|
msgid "Missing required app"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:50
|
#: /app/specialVueFakeDummyForL10nScript.js:48
|
||||||
msgid "Install GPodder Sync"
|
msgid "Install GPodder Sync"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
22
vite.config.mjs
Normal file
22
vite.config.mjs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { createAppConfig } from '@nextcloud/vite-config'
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
|
||||||
|
const config = defineConfig(({ mode }) => ({
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
entryFileNames: 'js/[name].js',
|
||||||
|
format: 'iife',
|
||||||
|
manualChunks: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sourcemap: mode === 'development',
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default createAppConfig(
|
||||||
|
{
|
||||||
|
main: 'src/main.js',
|
||||||
|
},
|
||||||
|
{ config },
|
||||||
|
)
|
31
webpack.js
31
webpack.js
@ -1,31 +0,0 @@
|
|||||||
const webpackConfig = require('@nextcloud/webpack-vue-config')
|
|
||||||
const ESLintPlugin = require('eslint-webpack-plugin')
|
|
||||||
const StyleLintPlugin = require('stylelint-webpack-plugin')
|
|
||||||
const path = require('path')
|
|
||||||
|
|
||||||
webpackConfig.entry = {
|
|
||||||
main: { import: path.join(__dirname, 'src', 'main.js'), filename: 'main.js' },
|
|
||||||
}
|
|
||||||
|
|
||||||
webpackConfig.plugins.push(
|
|
||||||
new ESLintPlugin({
|
|
||||||
extensions: ['js', 'vue'],
|
|
||||||
files: 'src',
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
webpackConfig.plugins.push(
|
|
||||||
new StyleLintPlugin({
|
|
||||||
files: 'src/**/*.{css,scss,vue}',
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
webpackConfig.module.rules.push({
|
|
||||||
test: /\.svg$/i,
|
|
||||||
type: 'asset/source',
|
|
||||||
})
|
|
||||||
|
|
||||||
webpackConfig.devtool =
|
|
||||||
webpackConfig.mode !== 'production' ? webpackConfig.devtool : false
|
|
||||||
|
|
||||||
module.exports = webpackConfig
|
|
Loading…
Reference in New Issue
Block a user