Compare commits
98 Commits
Author | SHA1 | Date | |
---|---|---|---|
0d017bbc68 | |||
|
3b2981d201 | ||
25949e98c9 | |||
b002e3bab8 | |||
d80044934f | |||
|
4d88f485fb | ||
|
ae66036a82 | ||
674f0193db | |||
ccc903be97 | |||
10c7a1f907 | |||
a6ab9c69d9 | |||
285e9f7dfb | |||
60fc620b79 | |||
5588bb93e3 | |||
b97d4487bb | |||
29c29cdfdd | |||
d7c3b87d8d | |||
9fa48c2da3 | |||
3cea8d3505 | |||
23280d68b9 | |||
1e1bb03c23 | |||
fc86f62d93 | |||
83e3358e9b | |||
38bc986bb3 | |||
eae106e72b | |||
3c358a3c5c | |||
|
79ee855f9b | ||
|
5150cb6501 | ||
1d85811ad3 | |||
872b0ced0a | |||
|
2a280c3493 | ||
|
c9f922b31d | ||
c983ab8d3b | |||
4f0685ccbd | |||
e165a070c8 | |||
|
622f5ec635 | ||
|
7d64e3370c | ||
fcf99e5bbf | |||
924106202a | |||
ce2412fb01 | |||
6c348d5583 | |||
|
7eef3ceaf0 | ||
|
5321c0a3bf | ||
fe40b7c9f7 | |||
|
11a1db72c6 | ||
7f00696140 | |||
|
33dcbe9162 | ||
5c6542e60c | |||
|
ea6704c537 | ||
df4ac80554 | |||
2b2ab2af8f | |||
|
7b00eb22ff | ||
|
ecee6ff2a8 | ||
57a22d9390 | |||
42c35d3856 | |||
4d199bc02b | |||
|
8a89cc06cd | ||
|
03740231c5 | ||
b54ab2be91 | |||
d1658a9408 | |||
1eb8b35501 | |||
fb7780fead | |||
19c56ef31d | |||
2bad1852d7 | |||
0302489924 | |||
81cb6a0191 | |||
094b7812cd | |||
491ad89242 | |||
01e2dabb65 | |||
a86ea6ab3f | |||
7b7ceef503 | |||
437c7868dd | |||
7c151d8f58 | |||
b7025a7aa1 | |||
42035d6e18 | |||
5ed33d1cf6 | |||
4e4730efd5 | |||
9005b519f3 | |||
b0132287f0 | |||
062da25264 | |||
fd0f8f9c7a | |||
|
35610ee8da | ||
60aedf3be5 | |||
4bafb3306b | |||
58af1f6d40 | |||
|
4eb9236ecb | ||
eb1196c841 | |||
dd275a1f03 | |||
f205d3243f | |||
46b30f1ebb | |||
9be107edc9 | |||
4e6eee96bf | |||
ddef81f92f | |||
456592adfc | |||
|
147311013c | ||
|
99dc3582c4 | ||
2824431330 | |||
a30678bfd2 |
@ -1,9 +1,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
extends: [
|
extends: [
|
||||||
'@nextcloud',
|
'@nextcloud',
|
||||||
|
'@vue/eslint-config-typescript/recommended',
|
||||||
'plugin:pinia/recommended',
|
'plugin:pinia/recommended',
|
||||||
'plugin:prettier/recommended',
|
'plugin:prettier/recommended',
|
||||||
],
|
],
|
||||||
|
parser: 'vue-eslint-parser',
|
||||||
rules: {
|
rules: {
|
||||||
'jsdoc/require-jsdoc': 'off',
|
'jsdoc/require-jsdoc': 'off',
|
||||||
'vue/first-attribute-linebreak': 'off',
|
'vue/first-attribute-linebreak': 'off',
|
@ -14,7 +14,7 @@ jobs:
|
|||||||
|
|
||||||
php:
|
php:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: nextcloud:29
|
container: nextcloud:30
|
||||||
steps:
|
steps:
|
||||||
- run: apt-get update
|
- run: apt-get update
|
||||||
- run: apt-get install -y git nodejs
|
- run: apt-get install -y git nodejs
|
||||||
@ -47,7 +47,7 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
if: gitea.ref_type == 'tag'
|
if: gitea.ref_type == 'tag'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: nextcloud:29
|
container: nextcloud:30
|
||||||
steps:
|
steps:
|
||||||
- run: apt-get update
|
- run: apt-get update
|
||||||
- run: apt-get install -y git nodejs
|
- run: apt-get install -y git nodejs
|
||||||
|
64
CHANGELOG.md
@ -1,4 +1,34 @@
|
|||||||
## 3.0.0 - 2024-08-17
|
## 3.2.0 - Typing fast - 2024-09-15
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- 📝 Add Cardo to list of compatible clients
|
||||||
|
[#176](https://github.com/thrillfall/nextcloud-gpodder/pull/176) reported by @n0vella
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- 🧑💻 Switch entiere project to TypeScript
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- 💄 Missing icon on home when aren't any favorites
|
||||||
|
- 💄 Tweaks spacing in several spaces on Home and banners
|
||||||
|
- 💩 Leverage the available space between the episode title and the play button (but hacky way for now)
|
||||||
|
[#59](https://git.crystalyx.net/Xefir/repod/issues/59#issuecomment-6246) reported by @W_LL_M
|
||||||
|
|
||||||
|
## 3.1.0 - Above the stars - 2024-09-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- ⭐ You can now add favorites subscriptions !
|
||||||
|
It will show's up on the homepage instead of the recommendations witch appear only when you add a new subscription.
|
||||||
|
[#59](https://git.crystalyx.net/Xefir/repod/issues/59) suggested by @W_LL_M, @Jaunty and @Satalink
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- 💥 Use html5 routing instead of hashes. All the URLs has changed removing the `#/` part.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- 🐛 Regression on 3.0 that prevent seeking player to episode last listened position
|
||||||
|
[#136](https://git.crystalyx.net/Xefir/repod/issues/136) reported by @randomuser1967
|
||||||
|
- ⚡ Improve the detection off mis-installed or mis-enabled gpodder app
|
||||||
|
|
||||||
|
## 3.0.0 - What a vue - 2024-08-17
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- 🌐 Add german translation
|
- 🌐 Add german translation
|
||||||
@ -16,7 +46,7 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
### Removed
|
### Removed
|
||||||
- 🗑️ Temporary replacing @nextcloud/dialogs to toastyjs
|
- 🗑️ Temporary replacing @nextcloud/dialogs to toastyjs
|
||||||
|
|
||||||
## 2.3.3 - 2024-06-14
|
## 2.3.3 - The Cake is a Lie - 2024-06-14
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- ⬆️ Update @nextcloud/dialogs to 5.3.2
|
- ⬆️ Update @nextcloud/dialogs to 5.3.2
|
||||||
@ -25,18 +55,18 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
- 🐛 App crashed when no cache system available
|
- 🐛 App crashed when no cache system available
|
||||||
[#107](https://git.crystalyx.net/Xefir/repod/issues/107) reported by @skvaller and @PhilTraere
|
[#107](https://git.crystalyx.net/Xefir/repod/issues/107) reported by @skvaller and @PhilTraere
|
||||||
|
|
||||||
## 2.3.2 - 2024-05-31
|
## 2.3.2 - Young Youth - 2024-05-31
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- 🐛 New subscribe button on search not disapearing if subscribed
|
- 🐛 New subscribe button on search not disapearing if subscribed
|
||||||
- ♿ Missing accessibility label on this button as well
|
- ♿ Missing accessibility label on this button as well
|
||||||
|
|
||||||
## 2.3.1 - 2024-05-29
|
## 2.3.1 - Powerwash the Universe - 2024-05-29
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- ⚡ Reduce app size by not shipping sourcemap
|
- ⚡ Reduce app size by not shipping sourcemap
|
||||||
|
|
||||||
## 2.3.0 - 2024-05-29
|
## 2.3.0 - Star Align - 2024-05-29
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- ➕ Ability to subscribe to podcast from search list
|
- ➕ Ability to subscribe to podcast from search list
|
||||||
@ -53,12 +83,12 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
- ⚰️ Drop support for PHP 8.0
|
- ⚰️ Drop support for PHP 8.0
|
||||||
- 🌐 Removed babel
|
- 🌐 Removed babel
|
||||||
|
|
||||||
## 2.2.1 - 2024-05-18
|
## 2.2.1 - Shami was here - 2024-05-18
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- ♻️ Rollback: Hide unreadable episodes because of insecure sources
|
- ♻️ Rollback: Hide unreadable episodes because of insecure sources
|
||||||
|
|
||||||
## 2.2.0 - 2024-05-18
|
## 2.2.0 - Moving in and out - 2024-05-18
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- 🚨 Linting the code with ESLint
|
- 🚨 Linting the code with ESLint
|
||||||
@ -70,7 +100,7 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
### Fixed
|
### Fixed
|
||||||
- 🔓 Hide unreadable episodes because of insecure sources
|
- 🔓 Hide unreadable episodes because of insecure sources
|
||||||
|
|
||||||
## 2.1.0 - 2024-03-16
|
## 2.1.0 - Pocket Gundams - 2024-03-16
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- 🔍 Add CTA for rating the app on the store
|
- 🔍 Add CTA for rating the app on the store
|
||||||
@ -84,7 +114,7 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
- 🔒 App wasn't working for non admin users
|
- 🔒 App wasn't working for non admin users
|
||||||
[#76](https://git.crystalyx.net/Xefir/repod/issues/76) reported by @devasservice
|
[#76](https://git.crystalyx.net/Xefir/repod/issues/76) reported by @devasservice
|
||||||
|
|
||||||
## 2.0.0 - 2024-03-05
|
## 2.0.0 - Taking Actions - 2024-03-05
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- 🍪 Saving filters preference
|
- 🍪 Saving filters preference
|
||||||
@ -101,13 +131,13 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
### Fixed
|
### Fixed
|
||||||
- ❤️🔥 Better handling ended episodes
|
- ❤️🔥 Better handling ended episodes
|
||||||
|
|
||||||
## 1.5.9 - 2024-02-21
|
## 1.5.9 - Just According to Keikaku - 2024-02-21
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- 🧑💻 Change some endpoints to match gPodder.net "specifications"
|
- 🧑💻 Change some endpoints to match gPodder.net "specifications"
|
||||||
- ⬆️ Update @nextcloud/vue to 8.7.0
|
- ⬆️ Update @nextcloud/vue to 8.7.0
|
||||||
|
|
||||||
## 1.5.8 - 2024-02-11
|
## 1.5.8 - Goblet of Eonothem - 2024-02-11
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fyyd API sometime send empty feeds, ignoring them
|
- Fyyd API sometime send empty feeds, ignoring them
|
||||||
@ -125,19 +155,19 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
### Changed
|
### Changed
|
||||||
- Update @nextcloud/vue to v8.6.2
|
- Update @nextcloud/vue to v8.6.2
|
||||||
|
|
||||||
## 1.5.5 - 2024-02-04
|
## 1.5.5 - Hide and seek - 2024-02-04
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Can't open podcast details if cache missing or misconfigured
|
- Can't open podcast details if cache missing or misconfigured
|
||||||
[#58](https://git.crystalyx.net/Xefir/repod/issues/58) reported by @raxventus
|
[#58](https://git.crystalyx.net/Xefir/repod/issues/58) reported by @raxventus
|
||||||
|
|
||||||
## 1.5.4 - 2024-02-03
|
## 1.5.4 - In search of the truth - 2024-02-03
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Nextcloud search engine didn't work on Nextcloud 26 and 27
|
- Nextcloud search engine didn't work on Nextcloud 26 and 27
|
||||||
[#57](https://git.crystalyx.net/Xefir/repod/issues/57) reported by @JonOfUs
|
[#57](https://git.crystalyx.net/Xefir/repod/issues/57) reported by @JonOfUs
|
||||||
|
|
||||||
## 1.5.3 - 2024-02-01
|
## 1.5.3 - The date where it all ends - 2024-02-01
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Update @nextcloud/vue to v8.6.1
|
- Update @nextcloud/vue to v8.6.1
|
||||||
@ -145,7 +175,7 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
### Fixed
|
### Fixed
|
||||||
- Fix episode listing crashing if an invalid publication date is present in the RSS
|
- Fix episode listing crashing if an invalid publication date is present in the RSS
|
||||||
|
|
||||||
## 1.5.2 - 2024-02-01
|
## 1.5.2 - A little to the top - 2024-02-01
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Update @nextcloud/router to v3.0.0
|
- Update @nextcloud/router to v3.0.0
|
||||||
@ -153,7 +183,7 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
### Fixed
|
### Fixed
|
||||||
- Fix player alignment off by a couple of pixels
|
- Fix player alignment off by a couple of pixels
|
||||||
|
|
||||||
## 1.5.1 - 2024-01-30
|
## 1.5.1 - Play on the PlayHead - 2024-01-30
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Update @nextcloud/vue to v8.6.0
|
- Update @nextcloud/vue to v8.6.0
|
||||||
@ -163,7 +193,7 @@ Thanks to @OiledAmoeba [#120](https://git.crystalyx.net/Xefir/repod/issues/120)
|
|||||||
### Fixed
|
### Fixed
|
||||||
- Force the placement of the filter settings to the top
|
- Force the placement of the filter settings to the top
|
||||||
|
|
||||||
## 1.5.0 - 2024-01-30
|
## 1.5.0 - Featuring the filtering - 2024-01-30
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Filtering options for each podcast section
|
- Filtering options for each podcast section
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM nextcloud:29
|
FROM nextcloud:30
|
||||||
|
|
||||||
ENV NEXTCLOUD_UPDATE=1
|
ENV NEXTCLOUD_UPDATE=1
|
||||||
ENV NEXTCLOUD_ADMIN_USER=repod
|
ENV NEXTCLOUD_ADMIN_USER=repod
|
||||||
|
6
Makefile
@ -140,8 +140,8 @@ appstore:
|
|||||||
--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)/tsconfig.json" \
|
||||||
--exclude="$(app_name)/stylelint.config.js" \
|
--exclude="$(app_name)/stylelint.config.cjs" \
|
||||||
--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" \
|
||||||
@ -153,7 +153,7 @@ appstore:
|
|||||||
--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" \
|
||||||
--exclude="$(app_name)/vite.config.mjs" \
|
--exclude="$(app_name)/vite.config.ts" \
|
||||||
$(app_name)
|
$(app_name)
|
||||||
|
|
||||||
# Start a nextcloud server on Docker to kickstart developement
|
# Start a nextcloud server on Docker to kickstart developement
|
||||||
|
@ -39,6 +39,9 @@ You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) inst
|
|||||||
### Homepage
|
### Homepage
|
||||||
![homepage](./screens/index.png)
|
![homepage](./screens/index.png)
|
||||||
|
|
||||||
|
### Discover
|
||||||
|
![homepage](./screens/discover.png)
|
||||||
|
|
||||||
### Search
|
### Search
|
||||||
![search](./screens/search.png)
|
![search](./screens/search.png)
|
||||||
|
|
||||||
@ -55,6 +58,7 @@ You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) inst
|
|||||||
| [AntennaPod](https://antennapod.org) | Initial purpose for this project, as a synchronization endpoint for this client.<br> Support is available [as of version 2.5.1](https://github.com/AntennaPod/AntennaPod/pull/5243/). |
|
| [AntennaPod](https://antennapod.org) | Initial purpose for this project, as a synchronization endpoint for this client.<br> Support is available [as of version 2.5.1](https://github.com/AntennaPod/AntennaPod/pull/5243/). |
|
||||||
| [KDE Kasts](https://apps.kde.org/de/kasts/) | Supported since version 21.12 |
|
| [KDE Kasts](https://apps.kde.org/de/kasts/) | Supported since version 21.12 |
|
||||||
| [Podcast Merlin](https://github.com/yoyoooooooooo/Podcast-Merlin--Nextcloud-Gpodder-Client-For-Windows) | Full sync support podcast client for Windows |
|
| [Podcast Merlin](https://github.com/yoyoooooooooo/Podcast-Merlin--Nextcloud-Gpodder-Client-For-Windows) | Full sync support podcast client for Windows |
|
||||||
|
| [Cardo](https://n0vella.github.io/#/cardo) | Podcast client with sync support, for Windows, Mac and Linux |
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
@ -7,11 +7,14 @@
|
|||||||
<description><![CDATA[## Features
|
<description><![CDATA[## Features
|
||||||
- 🔍 Browse and subscribe huge collection of podcasts
|
- 🔍 Browse and subscribe huge collection of podcasts
|
||||||
- 🔊 Listen to episodes directly in Nextcloud
|
- 🔊 Listen to episodes directly in Nextcloud
|
||||||
- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/)
|
- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/) and [other apps](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-gpoddersync)
|
||||||
|
- 📱 Mobile friendly interface
|
||||||
|
- 📡 Import and export your subscriptions
|
||||||
|
- ➡️ Full features comparison [here](https://git.crystalyx.net/Xefir/repod#comparaison-with-similar-apps-for-nextcloud)
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!]]></description>
|
You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!]]></description>
|
||||||
<version>3.0.0</version>
|
<version>3.2.0</version>
|
||||||
<licence>agpl</licence>
|
<licence>agpl</licence>
|
||||||
<author mail="xefir@crystalyx.net" homepage="https://crystalyx.net">Michel Roux</author>
|
<author mail="xefir@crystalyx.net" homepage="https://crystalyx.net">Michel Roux</author>
|
||||||
<namespace>RePod</namespace>
|
<namespace>RePod</namespace>
|
||||||
@ -20,6 +23,7 @@ You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) inst
|
|||||||
<website>https://git.crystalyx.net/Xefir/repod</website>
|
<website>https://git.crystalyx.net/Xefir/repod</website>
|
||||||
<bugs>https://git.crystalyx.net/Xefir/repod/issues</bugs>
|
<bugs>https://git.crystalyx.net/Xefir/repod/issues</bugs>
|
||||||
<screenshot>https://git.crystalyx.net/Xefir/repod/raw/branch/main/screens/index.png</screenshot>
|
<screenshot>https://git.crystalyx.net/Xefir/repod/raw/branch/main/screens/index.png</screenshot>
|
||||||
|
<screenshot>https://git.crystalyx.net/Xefir/repod/raw/branch/main/screens/discover.png</screenshot>
|
||||||
<screenshot>https://git.crystalyx.net/Xefir/repod/raw/branch/main/screens/search.png</screenshot>
|
<screenshot>https://git.crystalyx.net/Xefir/repod/raw/branch/main/screens/search.png</screenshot>
|
||||||
<screenshot>https://git.crystalyx.net/Xefir/repod/raw/branch/main/screens/episodes.png</screenshot>
|
<screenshot>https://git.crystalyx.net/Xefir/repod/raw/branch/main/screens/episodes.png</screenshot>
|
||||||
<screenshot>https://git.crystalyx.net/Xefir/repod/raw/branch/main/screens/modal.png</screenshot>
|
<screenshot>https://git.crystalyx.net/Xefir/repod/raw/branch/main/screens/modal.png</screenshot>
|
||||||
|
@ -13,6 +13,8 @@ declare(strict_types=1);
|
|||||||
return [
|
return [
|
||||||
'routes' => [
|
'routes' => [
|
||||||
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
|
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
|
||||||
|
['name' => 'page#feed', 'url' => '/feed/{path}', 'verb' => 'GET', 'requirements' => ['path' => '.+']],
|
||||||
|
['name' => 'page#discover', 'url' => '/discover', 'verb' => 'GET'],
|
||||||
['name' => 'episodes#action', 'url' => '/episodes/action', 'verb' => 'GET'],
|
['name' => 'episodes#action', 'url' => '/episodes/action', 'verb' => 'GET'],
|
||||||
['name' => 'episodes#list', 'url' => '/episodes/list', 'verb' => 'GET'],
|
['name' => 'episodes#list', 'url' => '/episodes/list', 'verb' => 'GET'],
|
||||||
['name' => 'opml#export', 'url' => '/opml/export', 'verb' => 'GET'],
|
['name' => 'opml#export', 'url' => '/opml/export', 'verb' => 'GET'],
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
"psalm": "psalm --threads=1 --no-cache --show-info=true"
|
"psalm": "psalm --threads=1 --no-cache --show-info=true"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"nextcloud/ocp": "^29.0.4",
|
"nextcloud/ocp": "^30.0.0",
|
||||||
"roave/security-advisories": "dev-latest",
|
"roave/security-advisories": "dev-latest",
|
||||||
"nextcloud/coding-standard": "^1.2.1",
|
"nextcloud/coding-standard": "^1.3.0",
|
||||||
"vimeo/psalm": "^5.25.0"
|
"vimeo/psalm": "^5.26.1"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"optimize-autoloader": true,
|
"optimize-autoloader": true,
|
||||||
|
363
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "855f98aa313f86222776e061139c42ec",
|
"content-hash": "ca2a3728cd9506c5cdac4ebc3e57acb3",
|
||||||
"packages": [],
|
"packages": [],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
@ -169,26 +169,26 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "composer/pcre",
|
"name": "composer/pcre",
|
||||||
"version": "3.2.0",
|
"version": "3.3.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/composer/pcre.git",
|
"url": "https://github.com/composer/pcre.git",
|
||||||
"reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90"
|
"reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/composer/pcre/zipball/ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
|
"url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4",
|
||||||
"reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
|
"reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.4 || ^8.0"
|
"php": "^7.4 || ^8.0"
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
"phpstan/phpstan": "<1.11.8"
|
"phpstan/phpstan": "<1.11.10"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "^1.11.8",
|
"phpstan/phpstan": "^1.11.10",
|
||||||
"phpstan/phpstan-strict-rules": "^1.1",
|
"phpstan/phpstan-strict-rules": "^1.1",
|
||||||
"phpunit/phpunit": "^8 || ^9"
|
"phpunit/phpunit": "^8 || ^9"
|
||||||
},
|
},
|
||||||
@ -228,7 +228,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/composer/pcre/issues",
|
"issues": "https://github.com/composer/pcre/issues",
|
||||||
"source": "https://github.com/composer/pcre/tree/3.2.0"
|
"source": "https://github.com/composer/pcre/tree/3.3.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -244,7 +244,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-25T09:36:02+00:00"
|
"time": "2024-08-27T18:44:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "composer/semver",
|
"name": "composer/semver",
|
||||||
@ -477,6 +477,73 @@
|
|||||||
},
|
},
|
||||||
"time": "2024-01-30T19:34:25+00:00"
|
"time": "2024-01-30T19:34:25+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "erickskrauch/php-cs-fixer-custom-fixers",
|
||||||
|
"version": "1.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/erickskrauch/php-cs-fixer-custom-fixers.git",
|
||||||
|
"reference": "36fb7f8204c1e17d9b8a24910e2147d0a3973b9c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/erickskrauch/php-cs-fixer-custom-fixers/zipball/36fb7f8204c1e17d9b8a24910e2147d0a3973b9c",
|
||||||
|
"reference": "36fb7f8204c1e17d9b8a24910e2147d0a3973b9c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3",
|
||||||
|
"php": "^7.4 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ely/php-code-style": "^1",
|
||||||
|
"ergebnis/composer-normalize": "^2.28",
|
||||||
|
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2",
|
||||||
|
"phpspec/prophecy": "^1.15",
|
||||||
|
"phpspec/prophecy-phpunit": "^2.0",
|
||||||
|
"phpstan/extension-installer": "^1.3",
|
||||||
|
"phpstan/phpstan": "^1.11.x-dev",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.3",
|
||||||
|
"phpstan/phpstan-strict-rules": "^1.5",
|
||||||
|
"phpunit/phpunit": "^9.5",
|
||||||
|
"phpunitgoodpractices/polyfill": "^1.5",
|
||||||
|
"phpunitgoodpractices/traits": "^1.9.1",
|
||||||
|
"symfony/phpunit-bridge": "^6.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"ErickSkrauch\\PhpCsFixer\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "ErickSkrauch",
|
||||||
|
"email": "erickskrauch@ely.by"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A set of custom fixers for PHP-CS-Fixer",
|
||||||
|
"homepage": "https://github.com/erickskrauch/php-cs-fixer-custom-fixers",
|
||||||
|
"keywords": [
|
||||||
|
"Code style",
|
||||||
|
"dev",
|
||||||
|
"php-cs-fixer"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/erickskrauch/php-cs-fixer-custom-fixers/issues",
|
||||||
|
"source": "https://github.com/erickskrauch/php-cs-fixer-custom-fixers/tree/1.3.0"
|
||||||
|
},
|
||||||
|
"time": "2024-06-21T20:19:52+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "felixfbecker/advanced-json-rpc",
|
"name": "felixfbecker/advanced-json-rpc",
|
||||||
"version": "v3.2.1",
|
"version": "v3.2.1",
|
||||||
@ -580,16 +647,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fidry/cpu-core-counter",
|
"name": "fidry/cpu-core-counter",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/theofidry/cpu-core-counter.git",
|
"url": "https://github.com/theofidry/cpu-core-counter.git",
|
||||||
"reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42"
|
"reference": "8520451a140d3f46ac33042715115e290cf5785f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42",
|
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f",
|
||||||
"reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42",
|
"reference": "8520451a140d3f46ac33042715115e290cf5785f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -629,7 +696,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/theofidry/cpu-core-counter/issues",
|
"issues": "https://github.com/theofidry/cpu-core-counter/issues",
|
||||||
"source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0"
|
"source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -637,20 +704,66 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-02-07T09:43:46+00:00"
|
"time": "2024-08-06T10:04:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "netresearch/jsonmapper",
|
"name": "kubawerlos/php-cs-fixer-custom-fixers",
|
||||||
"version": "v4.4.1",
|
"version": "v3.22.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/cweiske/jsonmapper.git",
|
"url": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers.git",
|
||||||
"reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0"
|
"reference": "8701394f0c7cd450ac4fa577d24589122c1d5d5e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0",
|
"url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/8701394f0c7cd450ac4fa577d24589122c1d5d5e",
|
||||||
"reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0",
|
"reference": "8701394f0c7cd450ac4fa577d24589122c1d5d5e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-filter": "*",
|
||||||
|
"ext-tokenizer": "*",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.61.1",
|
||||||
|
"php": "^7.4 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.6.4 || ^10.5.29"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PhpCsFixerCustomFixers\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Kuba Werłos",
|
||||||
|
"email": "werlos@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A set of custom fixers for PHP CS Fixer",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues",
|
||||||
|
"source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.22.0"
|
||||||
|
},
|
||||||
|
"time": "2024-08-16T20:44:35+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "netresearch/jsonmapper",
|
||||||
|
"version": "v4.5.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/cweiske/jsonmapper.git",
|
||||||
|
"reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8e76efb98ee8b6afc54687045e1b8dba55ac76e5",
|
||||||
|
"reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -686,25 +799,27 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"email": "cweiske@cweiske.de",
|
"email": "cweiske@cweiske.de",
|
||||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1"
|
"source": "https://github.com/cweiske/jsonmapper/tree/v4.5.0"
|
||||||
},
|
},
|
||||||
"time": "2024-01-31T06:18:54+00:00"
|
"time": "2024-09-08T10:13:13+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nextcloud/coding-standard",
|
"name": "nextcloud/coding-standard",
|
||||||
"version": "v1.2.1",
|
"version": "v1.3.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nextcloud/coding-standard.git",
|
"url": "https://github.com/nextcloud/coding-standard.git",
|
||||||
"reference": "cf5f18d989ec62fb4cdc7fc92a36baf34b3d829e"
|
"reference": "e2e6cb1518e3d56ebfb2365bb9fa91ecb50a374c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/cf5f18d989ec62fb4cdc7fc92a36baf34b3d829e",
|
"url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/e2e6cb1518e3d56ebfb2365bb9fa91ecb50a374c",
|
||||||
"reference": "cf5f18d989ec62fb4cdc7fc92a36baf34b3d829e",
|
"reference": "e2e6cb1518e3d56ebfb2365bb9fa91ecb50a374c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"erickskrauch/php-cs-fixer-custom-fixers": "^1.3",
|
||||||
|
"kubawerlos/php-cs-fixer-custom-fixers": "^3.22",
|
||||||
"php": "^7.3|^8.0",
|
"php": "^7.3|^8.0",
|
||||||
"php-cs-fixer/shim": "^3.17"
|
"php-cs-fixer/shim": "^3.17"
|
||||||
},
|
},
|
||||||
@ -727,22 +842,22 @@
|
|||||||
"description": "Nextcloud coding standards for the php cs fixer",
|
"description": "Nextcloud coding standards for the php cs fixer",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nextcloud/coding-standard/issues",
|
"issues": "https://github.com/nextcloud/coding-standard/issues",
|
||||||
"source": "https://github.com/nextcloud/coding-standard/tree/v1.2.1"
|
"source": "https://github.com/nextcloud/coding-standard/tree/v1.3.0"
|
||||||
},
|
},
|
||||||
"time": "2024-02-01T14:54:37+00:00"
|
"time": "2024-09-18T15:52:45+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nextcloud/ocp",
|
"name": "nextcloud/ocp",
|
||||||
"version": "v29.0.4",
|
"version": "v30.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nextcloud-deps/ocp.git",
|
"url": "https://github.com/nextcloud-deps/ocp.git",
|
||||||
"reference": "65b6744fca5d4b3c366754295e5cb0680a580c51"
|
"reference": "a26b4e1f75983f359bd835c2529ce37b5599d58f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/65b6744fca5d4b3c366754295e5cb0680a580c51",
|
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/a26b4e1f75983f359bd835c2529ce37b5599d58f",
|
||||||
"reference": "65b6744fca5d4b3c366754295e5cb0680a580c51",
|
"reference": "a26b4e1f75983f359bd835c2529ce37b5599d58f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -755,7 +870,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-stable29": "29.0.0-dev"
|
"dev-stable30": "30.0.0-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
@ -771,22 +886,22 @@
|
|||||||
"description": "Composer package containing Nextcloud's public API (classes, interfaces)",
|
"description": "Composer package containing Nextcloud's public API (classes, interfaces)",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nextcloud-deps/ocp/issues",
|
"issues": "https://github.com/nextcloud-deps/ocp/issues",
|
||||||
"source": "https://github.com/nextcloud-deps/ocp/tree/v29.0.4"
|
"source": "https://github.com/nextcloud-deps/ocp/tree/v30.0.0"
|
||||||
},
|
},
|
||||||
"time": "2024-07-11T00:37:34+00:00"
|
"time": "2024-09-13T00:40:45+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/php-parser",
|
"name": "nikic/php-parser",
|
||||||
"version": "v4.19.1",
|
"version": "v4.19.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||||
"reference": "4e1b88d21c69391150ace211e9eaf05810858d0b"
|
"reference": "0ed4c8949a32986043e977dbe14776c14d644c45"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b",
|
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ed4c8949a32986043e977dbe14776c14d644c45",
|
||||||
"reference": "4e1b88d21c69391150ace211e9eaf05810858d0b",
|
"reference": "0ed4c8949a32986043e977dbe14776c14d644c45",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -827,22 +942,22 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1"
|
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.2"
|
||||||
},
|
},
|
||||||
"time": "2024-03-17T08:10:35+00:00"
|
"time": "2024-09-17T19:36:00+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "php-cs-fixer/shim",
|
"name": "php-cs-fixer/shim",
|
||||||
"version": "v3.62.0",
|
"version": "v3.64.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/PHP-CS-Fixer/shim.git",
|
"url": "https://github.com/PHP-CS-Fixer/shim.git",
|
||||||
"reference": "7a91d5ce45c486f5b445d95901228507a02f60ae"
|
"reference": "81ccfd24baf3a10810dab1152c403981a790b837"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/7a91d5ce45c486f5b445d95901228507a02f60ae",
|
"url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/81ccfd24baf3a10810dab1152c403981a790b837",
|
||||||
"reference": "7a91d5ce45c486f5b445d95901228507a02f60ae",
|
"reference": "81ccfd24baf3a10810dab1152c403981a790b837",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -879,9 +994,9 @@
|
|||||||
"description": "A tool to automatically fix PHP code style",
|
"description": "A tool to automatically fix PHP code style",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/PHP-CS-Fixer/shim/issues",
|
"issues": "https://github.com/PHP-CS-Fixer/shim/issues",
|
||||||
"source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.62.0"
|
"source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.64.0"
|
||||||
},
|
},
|
||||||
"time": "2024-08-07T17:03:46+00:00"
|
"time": "2024-08-30T23:10:11+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpdocumentor/reflection-common",
|
"name": "phpdocumentor/reflection-common",
|
||||||
@ -1060,16 +1175,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpdoc-parser",
|
"name": "phpstan/phpdoc-parser",
|
||||||
"version": "1.29.1",
|
"version": "1.30.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||||
"reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4"
|
"reference": "51b95ec8670af41009e2b2b56873bad96682413e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4",
|
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/51b95ec8670af41009e2b2b56873bad96682413e",
|
||||||
"reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4",
|
"reference": "51b95ec8670af41009e2b2b56873bad96682413e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1101,9 +1216,9 @@
|
|||||||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1"
|
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.30.1"
|
||||||
},
|
},
|
||||||
"time": "2024-05-31T08:52:43+00:00"
|
"time": "2024-09-07T20:13:05+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/clock",
|
"name": "psr/clock",
|
||||||
@ -1312,12 +1427,12 @@
|
|||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Roave/SecurityAdvisories.git",
|
"url": "https://github.com/Roave/SecurityAdvisories.git",
|
||||||
"reference": "251a4f1fefcc6e6cc90d50514fee6b6e3745cb3e"
|
"reference": "22aca9a3467be44288882a3bcf7f2865abe08ca3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/251a4f1fefcc6e6cc90d50514fee6b6e3745cb3e",
|
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/22aca9a3467be44288882a3bcf7f2865abe08ca3",
|
||||||
"reference": "251a4f1fefcc6e6cc90d50514fee6b6e3745cb3e",
|
"reference": "22aca9a3467be44288882a3bcf7f2865abe08ca3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
@ -1355,7 +1470,7 @@
|
|||||||
"athlon1600/php-proxy-app": "<=3",
|
"athlon1600/php-proxy-app": "<=3",
|
||||||
"austintoddj/canvas": "<=3.4.2",
|
"austintoddj/canvas": "<=3.4.2",
|
||||||
"auth0/wordpress": "<=4.6",
|
"auth0/wordpress": "<=4.6",
|
||||||
"automad/automad": "<=2.0.0.0-alpha5",
|
"automad/automad": "<2.0.0.0-alpha5",
|
||||||
"automattic/jetpack": "<9.8",
|
"automattic/jetpack": "<9.8",
|
||||||
"awesome-support/awesome-support": "<=6.0.7",
|
"awesome-support/awesome-support": "<=6.0.7",
|
||||||
"aws/aws-sdk-php": "<3.288.1",
|
"aws/aws-sdk-php": "<3.288.1",
|
||||||
@ -1414,21 +1529,23 @@
|
|||||||
"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.3",
|
"concrete5/concrete5": "<9.3.4",
|
||||||
"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",
|
||||||
"contao/contao": ">=3,<3.5.37|>=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4",
|
"contao/contao": ">=3,<3.5.37|>=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4",
|
||||||
"contao/core": "<3.5.39",
|
"contao/core": "<3.5.39",
|
||||||
"contao/core-bundle": "<4.13.40|>=5,<5.3.4",
|
"contao/core-bundle": "<4.13.49|>=5,<5.3.15|>=5.4,<5.4.3",
|
||||||
"contao/listing-bundle": ">=3,<=3.5.30|>=4,<4.4.8",
|
"contao/listing-bundle": ">=3,<=3.5.30|>=4,<4.4.8",
|
||||||
"contao/managed-edition": "<=1.5",
|
"contao/managed-edition": "<=1.5",
|
||||||
"corveda/phpsandbox": "<1.3.5",
|
"corveda/phpsandbox": "<1.3.5",
|
||||||
"cosenary/instagram": "<=2.3",
|
"cosenary/instagram": "<=2.3",
|
||||||
"craftcms/cms": "<4.6.2|>=5.0.0.0-beta1,<=5.2.2",
|
"craftcms/cms": "<4.6.2|>=5,<=5.2.2",
|
||||||
"croogo/croogo": "<4",
|
"croogo/croogo": "<4",
|
||||||
"cuyz/valinor": "<0.12",
|
"cuyz/valinor": "<0.12",
|
||||||
|
"czim/file-handling": "<1.5|>=2,<2.3",
|
||||||
"czproject/git-php": "<4.0.3",
|
"czproject/git-php": "<4.0.3",
|
||||||
|
"damienharper/auditor-bundle": "<5.2.6",
|
||||||
"dapphp/securimage": "<3.6.6",
|
"dapphp/securimage": "<3.6.6",
|
||||||
"darylldoyle/safe-svg": "<1.9.10",
|
"darylldoyle/safe-svg": "<1.9.10",
|
||||||
"datadog/dd-trace": ">=0.30,<0.30.2",
|
"datadog/dd-trace": ">=0.30,<0.30.2",
|
||||||
@ -1453,8 +1570,9 @@
|
|||||||
"dolibarr/dolibarr": "<19.0.2",
|
"dolibarr/dolibarr": "<19.0.2",
|
||||||
"dompdf/dompdf": "<2.0.4",
|
"dompdf/dompdf": "<2.0.4",
|
||||||
"doublethreedigital/guest-entries": "<3.1.2",
|
"doublethreedigital/guest-entries": "<3.1.2",
|
||||||
"drupal/core": ">=6,<6.38|>=7,<7.96|>=8,<10.1.8|>=10.2,<10.2.2",
|
"drupal/core": ">=6,<6.38|>=7,<7.96|>=8,<10.1.8|>=10.2,<10.2.2|==11.9999999.9999999.9999999-dev",
|
||||||
"drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4",
|
"drupal/core-recommended": "==11.9999999.9999999.9999999-dev",
|
||||||
|
"drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4|==11.9999999.9999999.9999999-dev",
|
||||||
"duncanmcclean/guest-entries": "<3.1.2",
|
"duncanmcclean/guest-entries": "<3.1.2",
|
||||||
"dweeves/magmi": "<=0.7.24",
|
"dweeves/magmi": "<=0.7.24",
|
||||||
"ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.1.2",
|
"ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.1.2",
|
||||||
@ -1528,7 +1646,7 @@
|
|||||||
"friendsoftypo3/mediace": ">=7.6.2,<7.6.5",
|
"friendsoftypo3/mediace": ">=7.6.2,<7.6.5",
|
||||||
"friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6",
|
"friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6",
|
||||||
"froala/wysiwyg-editor": "<3.2.7|>=4.0.1,<=4.1.3",
|
"froala/wysiwyg-editor": "<3.2.7|>=4.0.1,<=4.1.3",
|
||||||
"froxlor/froxlor": "<2.1.9",
|
"froxlor/froxlor": "<=2.2.0.0-RC3",
|
||||||
"frozennode/administrator": "<=5.0.12",
|
"frozennode/administrator": "<=5.0.12",
|
||||||
"fuel/core": "<1.8.1",
|
"fuel/core": "<1.8.1",
|
||||||
"funadmin/funadmin": "<=3.2|>=3.3.2,<=3.3.3",
|
"funadmin/funadmin": "<=3.2|>=3.3.2,<=3.3.3",
|
||||||
@ -1536,7 +1654,7 @@
|
|||||||
"genix/cms": "<=1.1.11",
|
"genix/cms": "<=1.1.11",
|
||||||
"getformwork/formwork": "<1.13.1|==2.0.0.0-beta1",
|
"getformwork/formwork": "<1.13.1|==2.0.0.0-beta1",
|
||||||
"getgrav/grav": "<1.7.46",
|
"getgrav/grav": "<1.7.46",
|
||||||
"getkirby/cms": "<4.1.1",
|
"getkirby/cms": "<=3.6.6.5|>=3.7,<=3.7.5.4|>=3.8,<=3.8.4.3|>=3.9,<=3.9.8.1|>=3.10,<=3.10.1|>=4,<=4.3",
|
||||||
"getkirby/kirby": "<=2.5.12",
|
"getkirby/kirby": "<=2.5.12",
|
||||||
"getkirby/panel": "<2.5.14",
|
"getkirby/panel": "<2.5.14",
|
||||||
"getkirby/starterkit": "<=3.7.0.2",
|
"getkirby/starterkit": "<=3.7.0.2",
|
||||||
@ -1583,6 +1701,7 @@
|
|||||||
"in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.2.3",
|
"in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.2.3",
|
||||||
"in2code/ipandlanguageredirect": "<5.1.2",
|
"in2code/ipandlanguageredirect": "<5.1.2",
|
||||||
"in2code/lux": "<17.6.1|>=18,<24.0.2",
|
"in2code/lux": "<17.6.1|>=18,<24.0.2",
|
||||||
|
"in2code/powermail": "<7.5.1|>=8,<8.5.1|>=9,<10.9.1|>=11,<12.4.1",
|
||||||
"innologi/typo3-appointments": "<2.0.6",
|
"innologi/typo3-appointments": "<2.0.6",
|
||||||
"intelliants/subrion": "<4.2.2",
|
"intelliants/subrion": "<4.2.2",
|
||||||
"inter-mediator/inter-mediator": "==5.5",
|
"inter-mediator/inter-mediator": "==5.5",
|
||||||
@ -1612,7 +1731,7 @@
|
|||||||
"kelvinmo/simplexrd": "<3.1.1",
|
"kelvinmo/simplexrd": "<3.1.1",
|
||||||
"kevinpapst/kimai2": "<1.16.7",
|
"kevinpapst/kimai2": "<1.16.7",
|
||||||
"khodakhah/nodcms": "<=3",
|
"khodakhah/nodcms": "<=3",
|
||||||
"kimai/kimai": "<2.16",
|
"kimai/kimai": "<=2.20.1",
|
||||||
"kitodo/presentation": "<3.2.3|>=3.3,<3.3.4",
|
"kitodo/presentation": "<3.2.3|>=3.3,<3.3.4",
|
||||||
"klaviyo/magento2-extension": ">=1,<3",
|
"klaviyo/magento2-extension": ">=1,<3",
|
||||||
"knplabs/knp-snappy": "<=1.4.2",
|
"knplabs/knp-snappy": "<=1.4.2",
|
||||||
@ -1645,7 +1764,7 @@
|
|||||||
"lms/routes": "<2.1.1",
|
"lms/routes": "<2.1.1",
|
||||||
"localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2",
|
"localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2",
|
||||||
"luyadev/yii-helpers": "<1.2.1",
|
"luyadev/yii-helpers": "<1.2.1",
|
||||||
"magento/community-edition": "<2.4.5|==2.4.5|>=2.4.5.0-patch1,<2.4.5.0-patch8|==2.4.6|>=2.4.6.0-patch1,<2.4.6.0-patch6|==2.4.7",
|
"magento/community-edition": "<2.4.5|==2.4.5|>=2.4.5.0-patch1,<2.4.5.0-patch9|==2.4.6|>=2.4.6.0-patch1,<2.4.6.0-patch7|==2.4.7|>=2.4.7.0-patch1,<2.4.7.0-patch2",
|
||||||
"magento/core": "<=1.9.4.5",
|
"magento/core": "<=1.9.4.5",
|
||||||
"magento/magento1ce": "<1.9.4.3-dev",
|
"magento/magento1ce": "<1.9.4.3-dev",
|
||||||
"magento/magento1ee": ">=1,<1.14.4.3-dev",
|
"magento/magento1ee": ">=1,<1.14.4.3-dev",
|
||||||
@ -1656,7 +1775,8 @@
|
|||||||
"mantisbt/mantisbt": "<2.26.2",
|
"mantisbt/mantisbt": "<2.26.2",
|
||||||
"marcwillmann/turn": "<0.3.3",
|
"marcwillmann/turn": "<0.3.3",
|
||||||
"matyhtf/framework": "<3.0.6",
|
"matyhtf/framework": "<3.0.6",
|
||||||
"mautic/core": "<4.4.12|>=5.0.0.0-alpha,<5.0.4",
|
"mautic/core": "<4.4.13|>=5.0.0.0-alpha,<5.1.1",
|
||||||
|
"mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1",
|
||||||
"mdanter/ecc": "<2",
|
"mdanter/ecc": "<2",
|
||||||
"mediawiki/core": "<1.36.2",
|
"mediawiki/core": "<1.36.2",
|
||||||
"mediawiki/matomo": "<2.4.3",
|
"mediawiki/matomo": "<2.4.3",
|
||||||
@ -1691,6 +1811,7 @@
|
|||||||
"munkireport/softwareupdate": "<1.6",
|
"munkireport/softwareupdate": "<1.6",
|
||||||
"mustache/mustache": ">=2,<2.14.1",
|
"mustache/mustache": ">=2,<2.14.1",
|
||||||
"namshi/jose": "<2.2",
|
"namshi/jose": "<2.2",
|
||||||
|
"nategood/httpful": "<1",
|
||||||
"neoan3-apps/template": "<1.1.1",
|
"neoan3-apps/template": "<1.1.1",
|
||||||
"neorazorx/facturascripts": "<2022.04",
|
"neorazorx/facturascripts": "<2022.04",
|
||||||
"neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6",
|
"neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6",
|
||||||
@ -1765,7 +1886,7 @@
|
|||||||
"phpmyfaq/phpmyfaq": "<3.2.5|==3.2.5",
|
"phpmyfaq/phpmyfaq": "<3.2.5|==3.2.5",
|
||||||
"phpoffice/common": "<0.2.9",
|
"phpoffice/common": "<0.2.9",
|
||||||
"phpoffice/phpexcel": "<1.8",
|
"phpoffice/phpexcel": "<1.8",
|
||||||
"phpoffice/phpspreadsheet": "<1.16",
|
"phpoffice/phpspreadsheet": "<1.29.1|>=2,<2.1.1|>=2.2,<2.2.1",
|
||||||
"phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36",
|
"phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36",
|
||||||
"phpservermon/phpservermon": "<3.6",
|
"phpservermon/phpservermon": "<3.6",
|
||||||
"phpsysinfo/phpsysinfo": "<3.4.3",
|
"phpsysinfo/phpsysinfo": "<3.4.3",
|
||||||
@ -1774,9 +1895,10 @@
|
|||||||
"phpxmlrpc/extras": "<0.6.1",
|
"phpxmlrpc/extras": "<0.6.1",
|
||||||
"phpxmlrpc/phpxmlrpc": "<4.9.2",
|
"phpxmlrpc/phpxmlrpc": "<4.9.2",
|
||||||
"pi/pi": "<=2.5",
|
"pi/pi": "<=2.5",
|
||||||
"pimcore/admin-ui-classic-bundle": "<=1.5.1",
|
"pimcore/admin-ui-classic-bundle": "<1.5.4",
|
||||||
"pimcore/customer-management-framework-bundle": "<4.0.6",
|
"pimcore/customer-management-framework-bundle": "<4.0.6",
|
||||||
"pimcore/data-hub": "<1.2.4",
|
"pimcore/data-hub": "<1.2.4",
|
||||||
|
"pimcore/data-importer": "<1.8.9|>=1.9,<1.9.3",
|
||||||
"pimcore/demo": "<10.3",
|
"pimcore/demo": "<10.3",
|
||||||
"pimcore/ecommerce-framework-bundle": "<1.0.10",
|
"pimcore/ecommerce-framework-bundle": "<1.0.10",
|
||||||
"pimcore/perspective-editor": "<1.5.1",
|
"pimcore/perspective-editor": "<1.5.1",
|
||||||
@ -1807,7 +1929,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",
|
"pxlrbt/filament-excel": "<1.1.14|>=2.0.0.0-alpha,<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",
|
||||||
@ -1958,7 +2080,7 @@
|
|||||||
"tinymighty/wiki-seo": "<1.2.2",
|
"tinymighty/wiki-seo": "<1.2.2",
|
||||||
"titon/framework": "<9.9.99",
|
"titon/framework": "<9.9.99",
|
||||||
"tobiasbg/tablepress": "<=2.0.0.0-RC1",
|
"tobiasbg/tablepress": "<=2.0.0.0-RC1",
|
||||||
"topthink/framework": "<6.0.17|>=6.1,<6.1.5|>=8,<8.0.4",
|
"topthink/framework": "<6.0.17|>=6.1,<=8.0.4",
|
||||||
"topthink/think": "<=6.1.1",
|
"topthink/think": "<=6.1.1",
|
||||||
"topthink/thinkphp": "<=3.2.3",
|
"topthink/thinkphp": "<=3.2.3",
|
||||||
"torrentpier/torrentpier": "<=2.4.3",
|
"torrentpier/torrentpier": "<=2.4.3",
|
||||||
@ -1967,7 +2089,7 @@
|
|||||||
"truckersmp/phpwhois": "<=4.3.1",
|
"truckersmp/phpwhois": "<=4.3.1",
|
||||||
"ttskch/pagination-service-provider": "<1",
|
"ttskch/pagination-service-provider": "<1",
|
||||||
"twbs/bootstrap": "<=3.4.1|>=4,<=4.6.2",
|
"twbs/bootstrap": "<=3.4.1|>=4,<=4.6.2",
|
||||||
"twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3",
|
"twig/twig": "<1.44.8|>=2,<2.16.1|>=3,<3.11.1|>=3.12,<3.14",
|
||||||
"typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2",
|
"typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2",
|
||||||
"typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1",
|
"typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1",
|
||||||
"typo3/cms-core": "<=8.7.56|>=9,<=9.5.47|>=10,<=10.4.44|>=11,<=11.5.36|>=12,<=12.4.14|>=13,<=13.1",
|
"typo3/cms-core": "<=8.7.56|>=9,<=9.5.47|>=10,<=10.4.44|>=11,<=11.5.36|>=12,<=12.4.14|>=13,<=13.1",
|
||||||
@ -2019,6 +2141,7 @@
|
|||||||
"winter/wn-dusk-plugin": "<2.1",
|
"winter/wn-dusk-plugin": "<2.1",
|
||||||
"winter/wn-system-module": "<1.2.4",
|
"winter/wn-system-module": "<1.2.4",
|
||||||
"wintercms/winter": "<=1.2.3",
|
"wintercms/winter": "<=1.2.3",
|
||||||
|
"wireui/wireui": "<1.19.3|>=2,<2.1.3",
|
||||||
"woocommerce/woocommerce": "<6.6|>=8.8,<8.8.5|>=8.9,<8.9.3",
|
"woocommerce/woocommerce": "<6.6|>=8.8,<8.8.5|>=8.9,<8.9.3",
|
||||||
"wp-cli/wp-cli": ">=0.12,<2.5",
|
"wp-cli/wp-cli": ">=0.12,<2.5",
|
||||||
"wp-graphql/wp-graphql": "<=1.14.5",
|
"wp-graphql/wp-graphql": "<=1.14.5",
|
||||||
@ -2121,7 +2244,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-08-14T19:05:08+00:00"
|
"time": "2024-09-18T23:05:04+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/diff",
|
"name": "sebastian/diff",
|
||||||
@ -2260,16 +2383,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
"version": "v6.4.10",
|
"version": "v6.4.11",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/console.git",
|
"url": "https://github.com/symfony/console.git",
|
||||||
"reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc"
|
"reference": "42686880adaacdad1835ee8fc2a9ec5b7bd63998"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/console/zipball/504974cbe43d05f83b201d6498c206f16fc0cdbc",
|
"url": "https://api.github.com/repos/symfony/console/zipball/42686880adaacdad1835ee8fc2a9ec5b7bd63998",
|
||||||
"reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc",
|
"reference": "42686880adaacdad1835ee8fc2a9ec5b7bd63998",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -2334,7 +2457,7 @@
|
|||||||
"terminal"
|
"terminal"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/console/tree/v6.4.10"
|
"source": "https://github.com/symfony/console/tree/v6.4.11"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -2350,7 +2473,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-26T12:30:32+00:00"
|
"time": "2024-08-15T22:48:29+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/deprecation-contracts",
|
"name": "symfony/deprecation-contracts",
|
||||||
@ -2487,20 +2610,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/polyfill-ctype",
|
||||||
"version": "v1.30.0",
|
"version": "v1.31.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540"
|
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
|
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540",
|
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1"
|
"php": ">=7.2"
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
"ext-ctype": "*"
|
"ext-ctype": "*"
|
||||||
@ -2546,7 +2669,7 @@
|
|||||||
"portable"
|
"portable"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
|
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -2562,24 +2685,24 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-05-31T15:07:36+00:00"
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-intl-grapheme",
|
"name": "symfony/polyfill-intl-grapheme",
|
||||||
"version": "v1.30.0",
|
"version": "v1.31.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||||
"reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a"
|
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a",
|
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
|
||||||
"reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a",
|
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1"
|
"php": ">=7.2"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-intl": "For best performance"
|
"ext-intl": "For best performance"
|
||||||
@ -2624,7 +2747,7 @@
|
|||||||
"shim"
|
"shim"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0"
|
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -2640,24 +2763,24 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-05-31T15:07:36+00:00"
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-intl-normalizer",
|
"name": "symfony/polyfill-intl-normalizer",
|
||||||
"version": "v1.30.0",
|
"version": "v1.31.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||||
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb"
|
"reference": "3833d7255cc303546435cb650316bff708a1c75c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb",
|
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
|
||||||
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb",
|
"reference": "3833d7255cc303546435cb650316bff708a1c75c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1"
|
"php": ">=7.2"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-intl": "For best performance"
|
"ext-intl": "For best performance"
|
||||||
@ -2705,7 +2828,7 @@
|
|||||||
"shim"
|
"shim"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0"
|
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -2721,24 +2844,24 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-05-31T15:07:36+00:00"
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-mbstring",
|
"name": "symfony/polyfill-mbstring",
|
||||||
"version": "v1.30.0",
|
"version": "v1.31.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c"
|
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1"
|
"php": ">=7.2"
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
"ext-mbstring": "*"
|
"ext-mbstring": "*"
|
||||||
@ -2785,7 +2908,7 @@
|
|||||||
"shim"
|
"shim"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0"
|
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -2801,7 +2924,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-06-19T12:30:46+00:00"
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/service-contracts",
|
"name": "symfony/service-contracts",
|
||||||
@ -2888,16 +3011,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/string",
|
"name": "symfony/string",
|
||||||
"version": "v6.4.10",
|
"version": "v6.4.11",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/string.git",
|
"url": "https://github.com/symfony/string.git",
|
||||||
"reference": "ccf9b30251719567bfd46494138327522b9a9446"
|
"reference": "5bc3eb632cf9c8dbfd6529d89be9950d1518883b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/string/zipball/ccf9b30251719567bfd46494138327522b9a9446",
|
"url": "https://api.github.com/repos/symfony/string/zipball/5bc3eb632cf9c8dbfd6529d89be9950d1518883b",
|
||||||
"reference": "ccf9b30251719567bfd46494138327522b9a9446",
|
"reference": "5bc3eb632cf9c8dbfd6529d89be9950d1518883b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -2954,7 +3077,7 @@
|
|||||||
"utf8"
|
"utf8"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/string/tree/v6.4.10"
|
"source": "https://github.com/symfony/string/tree/v6.4.11"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -2970,20 +3093,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-22T10:21:14+00:00"
|
"time": "2024-08-12T09:55:28+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "vimeo/psalm",
|
"name": "vimeo/psalm",
|
||||||
"version": "5.25.0",
|
"version": "5.26.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/vimeo/psalm.git",
|
"url": "https://github.com/vimeo/psalm.git",
|
||||||
"reference": "01a8eb06b9e9cc6cfb6a320bf9fb14331919d505"
|
"reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/vimeo/psalm/zipball/01a8eb06b9e9cc6cfb6a320bf9fb14331919d505",
|
"url": "https://api.github.com/repos/vimeo/psalm/zipball/d747f6500b38ac4f7dfc5edbcae6e4b637d7add0",
|
||||||
"reference": "01a8eb06b9e9cc6cfb6a320bf9fb14331919d505",
|
"reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -3004,7 +3127,7 @@
|
|||||||
"felixfbecker/language-server-protocol": "^1.5.2",
|
"felixfbecker/language-server-protocol": "^1.5.2",
|
||||||
"fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0",
|
"fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0",
|
||||||
"netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
|
"netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
|
||||||
"nikic/php-parser": "^4.16",
|
"nikic/php-parser": "^4.17",
|
||||||
"php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0",
|
"php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0",
|
||||||
"sebastian/diff": "^4.0 || ^5.0 || ^6.0",
|
"sebastian/diff": "^4.0 || ^5.0 || ^6.0",
|
||||||
"spatie/array-to-xml": "^2.17.0 || ^3.0",
|
"spatie/array-to-xml": "^2.17.0 || ^3.0",
|
||||||
@ -3080,7 +3203,7 @@
|
|||||||
"issues": "https://github.com/vimeo/psalm/issues",
|
"issues": "https://github.com/vimeo/psalm/issues",
|
||||||
"source": "https://github.com/vimeo/psalm"
|
"source": "https://github.com/vimeo/psalm"
|
||||||
},
|
},
|
||||||
"time": "2024-06-16T15:08:35+00:00"
|
"time": "2024-09-08T18:53:08+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "webmozart/assert",
|
"name": "webmozart/assert",
|
||||||
|
13
l10n/de.js
@ -5,7 +5,7 @@ OC.L10N.register(
|
|||||||
"Podcast" : "Podcast",
|
"Podcast" : "Podcast",
|
||||||
"RePod" : "RePod",
|
"RePod" : "RePod",
|
||||||
"🔊 Browse, manage and listen to podcasts" : "🔊 Suchen, Verwalten und Anhören von Podcasts",
|
"🔊 Browse, manage and listen to podcasts" : "🔊 Suchen, Verwalten und Anhören von Podcasts",
|
||||||
"## Features\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/)\n\n## Requirements\nYou need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!" : "## Funktionen\n- 🔍 Durchsuchen und abonnieren einer großen Sammlung von Podcasts\n- 🔊 Episoden direkt in Nextcloud anhören\n- 🌐 Synchronisiere deine Aktivität mit [AntennaPod](https://antennapod.org/)\n\n## Voraussetzungen\nDu musst [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installiert haben, um diese App zu benutzen!",
|
"## Features\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/) and [other apps](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-gpoddersync)\n- 📱 Mobile friendly interface\n- 📡 Import and export your subscriptions\n- ➡️ Full features comparison [here](https://git.crystalyx.net/Xefir/repod#comparaison-with-similar-apps-for-nextcloud)\n\n## Requirements\nYou need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!" : "## Funktionen\n- 🔍 Durchsuchen und abonnieren einer großen Sammlung von Podcasts\n- 🔊 Episoden direkt in Nextcloud anhören\n- 🌐 Synchronisiere deine Aktivität mit [AntennaPod](https://antennapod.org/)\n- 📱 Mobile-freundliche Schnittstelle\n- 📡 Importieren und Exportieren Ihrer Abonnements\n\n## Voraussetzungen\nDu musst [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installiert haben, um diese App zu benutzen!",
|
||||||
"Download" : "Herunterladen",
|
"Download" : "Herunterladen",
|
||||||
"Add a RSS link" : "Einen RSS-Link hinzufügen",
|
"Add a RSS link" : "Einen RSS-Link hinzufügen",
|
||||||
"Subscribe" : "Abonnieren",
|
"Subscribe" : "Abonnieren",
|
||||||
@ -18,11 +18,10 @@ OC.L10N.register(
|
|||||||
"Link copied to the clipboard" : "Der Link des Feeds wurde in die Zwischenablage kopiert",
|
"Link copied to the clipboard" : "Der Link des Feeds wurde in die Zwischenablage kopiert",
|
||||||
"Play" : "Abspielen",
|
"Play" : "Abspielen",
|
||||||
"Stop" : "Stopp",
|
"Stop" : "Stopp",
|
||||||
"Mark as read" : "Als gelesen markieren",
|
"Read" : "Gelesen",
|
||||||
"Mark as unread" : "Als ungelesen markieren",
|
|
||||||
"Open website" : "Webseite aufrufen",
|
"Open website" : "Webseite aufrufen",
|
||||||
"Could not fetch episodes" : "Folgen können nicht abgerufen werden",
|
|
||||||
"Could not change the status of the episode" : "Kann den Status der Folge nicht ändern",
|
"Could not change the status of the episode" : "Kann den Status der Folge nicht ändern",
|
||||||
|
"Could not fetch episodes" : "Folgen können nicht abgerufen werden",
|
||||||
"Export subscriptions" : "Abonnements exportieren",
|
"Export subscriptions" : "Abonnements exportieren",
|
||||||
"Filtering episodes" : "Folgen filtern",
|
"Filtering episodes" : "Folgen filtern",
|
||||||
"Show all" : "Zeige alles",
|
"Show all" : "Zeige alles",
|
||||||
@ -33,13 +32,17 @@ OC.L10N.register(
|
|||||||
"Import OPML file" : "Importiere OPML-Datei",
|
"Import OPML file" : "Importiere OPML-Datei",
|
||||||
"Rate RePod ❤️" : "Bewerte RePod ❤️",
|
"Rate RePod ❤️" : "Bewerte RePod ❤️",
|
||||||
"Playback speed" : "Wiedergabegeschwindigkeit",
|
"Playback speed" : "Wiedergabegeschwindigkeit",
|
||||||
|
"Favorite" : "Favorit",
|
||||||
"Are you sure you want to delete this subscription?" : "Bist Du sicher, dass Du das Abonnement löschen möchtest?",
|
"Are you sure you want to delete this subscription?" : "Bist Du sicher, dass Du das Abonnement löschen möchtest?",
|
||||||
"Error while removing the feed" : "Fehler beim Löschen des Feeds",
|
"Error while removing the feed" : "Fehler beim Löschen des Feeds",
|
||||||
|
"You can only have 10 favorites" : "Du kannst nur 10 Favoriten haben",
|
||||||
"Add a podcast" : "Einen Podcast hinzufügen",
|
"Add a podcast" : "Einen Podcast hinzufügen",
|
||||||
"Could not fetch subscriptions" : "Abonnements können nicht abgerufen werden",
|
"Could not fetch subscriptions" : "Abonnements können nicht abgerufen werden",
|
||||||
"Find a podcast" : "Finde einen Podcast",
|
"Find a podcast" : "Finde einen Podcast",
|
||||||
"Error loading feed" : "Fehler beim Laden des Feeds",
|
"Error loading feed" : "Fehler beim Laden des Feeds",
|
||||||
"Missing required app" : "Benötigte App fehlt",
|
"Missing required app" : "Benötigte App fehlt",
|
||||||
"Install GPodder Sync" : "Installiere GPodder Sync"
|
"Install GPodder Sync" : "Installiere GPodder Sync",
|
||||||
|
"Pin some subscriptions to see their latest updates" : "Pinne einige Abonnements, um ihre neuesten Updates zu sehen",
|
||||||
|
"No favorites" : "Keine Favoriten"
|
||||||
},
|
},
|
||||||
"");
|
"");
|
||||||
|
13
l10n/de.json
@ -3,7 +3,7 @@
|
|||||||
"Podcast" : "Podcast",
|
"Podcast" : "Podcast",
|
||||||
"RePod" : "RePod",
|
"RePod" : "RePod",
|
||||||
"🔊 Browse, manage and listen to podcasts" : "🔊 Suchen, Verwalten und Anhören von Podcasts",
|
"🔊 Browse, manage and listen to podcasts" : "🔊 Suchen, Verwalten und Anhören von Podcasts",
|
||||||
"## Features\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/)\n\n## Requirements\nYou need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!" : "## Funktionen\n- 🔍 Durchsuchen und abonnieren einer großen Sammlung von Podcasts\n- 🔊 Episoden direkt in Nextcloud anhören\n- 🌐 Synchronisiere deine Aktivität mit [AntennaPod](https://antennapod.org/)\n\n## Voraussetzungen\nDu musst [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installiert haben, um diese App zu benutzen!",
|
"## Features\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/) and [other apps](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-gpoddersync)\n- 📱 Mobile friendly interface\n- 📡 Import and export your subscriptions\n- ➡️ Full features comparison [here](https://git.crystalyx.net/Xefir/repod#comparaison-with-similar-apps-for-nextcloud)\n\n## Requirements\nYou need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!" : "## Funktionen\n- 🔍 Durchsuchen und abonnieren einer großen Sammlung von Podcasts\n- 🔊 Episoden direkt in Nextcloud anhören\n- 🌐 Synchronisiere deine Aktivität mit [AntennaPod](https://antennapod.org/)\n- 📱 Mobile-freundliche Schnittstelle\n- 📡 Importieren und Exportieren Ihrer Abonnements\n\n## Voraussetzungen\nDu musst [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installiert haben, um diese App zu benutzen!",
|
||||||
"Download" : "Herunterladen",
|
"Download" : "Herunterladen",
|
||||||
"Add a RSS link" : "Einen RSS-Link hinzufügen",
|
"Add a RSS link" : "Einen RSS-Link hinzufügen",
|
||||||
"Subscribe" : "Abonnieren",
|
"Subscribe" : "Abonnieren",
|
||||||
@ -16,11 +16,10 @@
|
|||||||
"Link copied to the clipboard" : "Der Link des Feeds wurde in die Zwischenablage kopiert",
|
"Link copied to the clipboard" : "Der Link des Feeds wurde in die Zwischenablage kopiert",
|
||||||
"Play" : "Abspielen",
|
"Play" : "Abspielen",
|
||||||
"Stop" : "Stopp",
|
"Stop" : "Stopp",
|
||||||
"Mark as read" : "Als gelesen markieren",
|
"Read" : "Gelesen",
|
||||||
"Mark as unread" : "Als ungelesen markieren",
|
|
||||||
"Open website" : "Webseite aufrufen",
|
"Open website" : "Webseite aufrufen",
|
||||||
"Could not fetch episodes" : "Folgen können nicht abgerufen werden",
|
|
||||||
"Could not change the status of the episode" : "Kann den Status der Folge nicht ändern",
|
"Could not change the status of the episode" : "Kann den Status der Folge nicht ändern",
|
||||||
|
"Could not fetch episodes" : "Folgen können nicht abgerufen werden",
|
||||||
"Export subscriptions" : "Abonnements exportieren",
|
"Export subscriptions" : "Abonnements exportieren",
|
||||||
"Filtering episodes" : "Folgen filtern",
|
"Filtering episodes" : "Folgen filtern",
|
||||||
"Show all" : "Zeige alles",
|
"Show all" : "Zeige alles",
|
||||||
@ -31,13 +30,17 @@
|
|||||||
"Import OPML file" : "Importiere OPML-Datei",
|
"Import OPML file" : "Importiere OPML-Datei",
|
||||||
"Rate RePod ❤️" : "Bewerte RePod ❤️",
|
"Rate RePod ❤️" : "Bewerte RePod ❤️",
|
||||||
"Playback speed" : "Wiedergabegeschwindigkeit",
|
"Playback speed" : "Wiedergabegeschwindigkeit",
|
||||||
|
"Favorite" : "Favorit",
|
||||||
"Are you sure you want to delete this subscription?" : "Bist Du sicher, dass Du das Abonnement löschen möchtest?",
|
"Are you sure you want to delete this subscription?" : "Bist Du sicher, dass Du das Abonnement löschen möchtest?",
|
||||||
"Error while removing the feed" : "Fehler beim Löschen des Feeds",
|
"Error while removing the feed" : "Fehler beim Löschen des Feeds",
|
||||||
|
"You can only have 10 favorites" : "Du kannst nur 10 Favoriten haben",
|
||||||
"Add a podcast" : "Einen Podcast hinzufügen",
|
"Add a podcast" : "Einen Podcast hinzufügen",
|
||||||
"Could not fetch subscriptions" : "Abonnements können nicht abgerufen werden",
|
"Could not fetch subscriptions" : "Abonnements können nicht abgerufen werden",
|
||||||
"Find a podcast" : "Finde einen Podcast",
|
"Find a podcast" : "Finde einen Podcast",
|
||||||
"Error loading feed" : "Fehler beim Laden des Feeds",
|
"Error loading feed" : "Fehler beim Laden des Feeds",
|
||||||
"Missing required app" : "Benötigte App fehlt",
|
"Missing required app" : "Benötigte App fehlt",
|
||||||
"Install GPodder Sync" : "Installiere GPodder Sync"
|
"Install GPodder Sync" : "Installiere GPodder Sync",
|
||||||
|
"Pin some subscriptions to see their latest updates" : "Pinne einige Abonnements, um ihre neuesten Updates zu sehen",
|
||||||
|
"No favorites" : "Keine Favoriten"
|
||||||
},"pluralForm" :""
|
},"pluralForm" :""
|
||||||
}
|
}
|
13
l10n/fr.js
@ -5,7 +5,7 @@ OC.L10N.register(
|
|||||||
"Podcast" : "Podcast",
|
"Podcast" : "Podcast",
|
||||||
"RePod" : "RePod",
|
"RePod" : "RePod",
|
||||||
"🔊 Browse, manage and listen to podcasts" : "🔊 Parcourir, gérer et écouter vos podcasts",
|
"🔊 Browse, manage and listen to podcasts" : "🔊 Parcourir, gérer et écouter vos podcasts",
|
||||||
"## Features\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/)\n\n## Requirements\nYou need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!" : "## Fonctionnalités\n- 🔍 Parcourir et s'abonner à une grande collections de podcasts\n- 🔊 Écouter vos épisodes directement sur Nextcloud\n- 🌐 Synchroniser son activité avec [AntennaPod](https://antennapod.org/)\n\n## Pré-requis\nVous devez avoir [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installé pour utiliser cette application !",
|
"## Features\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/) and [other apps](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-gpoddersync)\n- 📱 Mobile friendly interface\n- 📡 Import and export your subscriptions\n- ➡️ Full features comparison [here](https://git.crystalyx.net/Xefir/repod#comparaison-with-similar-apps-for-nextcloud)\n\n## Requirements\nYou need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!" : "## Fonctionnalités\n- 🔍 Parcourir et s'abonner à une grande collections de podcasts\n- 🔊 Écouter vos épisodes directement sur Nextcloud\n- 🌐 Synchroniser son activité avec [AntennaPod](https://antennapod.org/) et d'autres [applications](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-gpoddersync)\n- 📱 Interface optimisée pour mobiles et ordinateurs\n- 📡 Import/export de ses abonnements\n- ➡️ Tableau récapitulatif complet des fonctionnalitées [ici](https://git.crystalyx.net/Xefir/repod#comparaison-with-similar-apps-for-nextcloud)\n\n## Pré-requis\nVous devez avoir [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installé pour utiliser cette application !",
|
||||||
"Download" : "Télécharger",
|
"Download" : "Télécharger",
|
||||||
"Add a RSS link" : "Ajouter un lien RSS",
|
"Add a RSS link" : "Ajouter un lien RSS",
|
||||||
"Subscribe" : "S'abonner",
|
"Subscribe" : "S'abonner",
|
||||||
@ -18,11 +18,10 @@ OC.L10N.register(
|
|||||||
"Link copied to the clipboard" : "Lien vers le flux copié dans le presse-papiers",
|
"Link copied to the clipboard" : "Lien vers le flux copié dans le presse-papiers",
|
||||||
"Play" : "Lecture",
|
"Play" : "Lecture",
|
||||||
"Stop" : "Arrêter",
|
"Stop" : "Arrêter",
|
||||||
"Mark as read" : "Marquer comme lu",
|
"Read" : "Lu",
|
||||||
"Mark as unread" : "Marquer comme non lu",
|
|
||||||
"Open website" : "Ouvrir le site web",
|
"Open website" : "Ouvrir le site web",
|
||||||
"Could not fetch episodes" : "Impossible de récuprer les épisodes",
|
|
||||||
"Could not change the status of the episode" : "Impossible de changer le status de l'épisode",
|
"Could not change the status of the episode" : "Impossible de changer le status de l'épisode",
|
||||||
|
"Could not fetch episodes" : "Impossible de récuprer les épisodes",
|
||||||
"Export subscriptions" : "Exporter les abonnements",
|
"Export subscriptions" : "Exporter les abonnements",
|
||||||
"Filtering episodes" : "Filtrage des épisodes",
|
"Filtering episodes" : "Filtrage des épisodes",
|
||||||
"Show all" : "Montrer tout",
|
"Show all" : "Montrer tout",
|
||||||
@ -33,13 +32,17 @@ OC.L10N.register(
|
|||||||
"Import OPML file" : "Importer un fichier OPML",
|
"Import OPML file" : "Importer un fichier OPML",
|
||||||
"Rate RePod ❤️" : "Donnez votre avis ❤️",
|
"Rate RePod ❤️" : "Donnez votre avis ❤️",
|
||||||
"Playback speed" : "Vitesse de lecture",
|
"Playback speed" : "Vitesse de lecture",
|
||||||
|
"Favorite" : "Favori",
|
||||||
"Are you sure you want to delete this subscription?" : "Êtes-vous sûr de vouloir supprimer ce flux ?",
|
"Are you sure you want to delete this subscription?" : "Êtes-vous sûr de vouloir supprimer ce flux ?",
|
||||||
"Error while removing the feed" : "Erreur lors de la suppression du flux",
|
"Error while removing the feed" : "Erreur lors de la suppression du flux",
|
||||||
|
"You can only have 10 favorites" : "Vous ne pouvez avoir que 10 favoris",
|
||||||
"Add a podcast" : "Ajouter un podcast",
|
"Add a podcast" : "Ajouter un podcast",
|
||||||
"Could not fetch subscriptions" : "Impossible de récupérer les flux",
|
"Could not fetch subscriptions" : "Impossible de récupérer les flux",
|
||||||
"Find a podcast" : "Chercher un podcast",
|
"Find a podcast" : "Chercher un podcast",
|
||||||
"Error loading feed" : "Erreur lors du chargement du flux",
|
"Error loading feed" : "Erreur lors du chargement du flux",
|
||||||
"Missing required app" : "Une application requise est manquante",
|
"Missing required app" : "Une application requise est manquante",
|
||||||
"Install GPodder Sync" : "Installer GPodder Sync"
|
"Install GPodder Sync" : "Installer GPodder Sync",
|
||||||
|
"Pin some subscriptions to see their latest updates" : "Ajoutez des abonnements en favoris pour obtenir les dernières nouvelles ici",
|
||||||
|
"No favorites" : "Aucun favoris"
|
||||||
},
|
},
|
||||||
"");
|
"");
|
||||||
|
13
l10n/fr.json
@ -3,7 +3,7 @@
|
|||||||
"Podcast" : "Podcast",
|
"Podcast" : "Podcast",
|
||||||
"RePod" : "RePod",
|
"RePod" : "RePod",
|
||||||
"🔊 Browse, manage and listen to podcasts" : "🔊 Parcourir, gérer et écouter vos podcasts",
|
"🔊 Browse, manage and listen to podcasts" : "🔊 Parcourir, gérer et écouter vos podcasts",
|
||||||
"## Features\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/)\n\n## Requirements\nYou need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!" : "## Fonctionnalités\n- 🔍 Parcourir et s'abonner à une grande collections de podcasts\n- 🔊 Écouter vos épisodes directement sur Nextcloud\n- 🌐 Synchroniser son activité avec [AntennaPod](https://antennapod.org/)\n\n## Pré-requis\nVous devez avoir [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installé pour utiliser cette application !",
|
"## Features\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/) and [other apps](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-gpoddersync)\n- 📱 Mobile friendly interface\n- 📡 Import and export your subscriptions\n- ➡️ Full features comparison [here](https://git.crystalyx.net/Xefir/repod#comparaison-with-similar-apps-for-nextcloud)\n\n## Requirements\nYou need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!" : "## Fonctionnalités\n- 🔍 Parcourir et s'abonner à une grande collections de podcasts\n- 🔊 Écouter vos épisodes directement sur Nextcloud\n- 🌐 Synchroniser son activité avec [AntennaPod](https://antennapod.org/) et d'autres [applications](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-gpoddersync)\n- 📱 Interface optimisée pour mobiles et ordinateurs\n- 📡 Import/export de ses abonnements\n- ➡️ Tableau récapitulatif complet des fonctionnalitées [ici](https://git.crystalyx.net/Xefir/repod#comparaison-with-similar-apps-for-nextcloud)\n\n## Pré-requis\nVous devez avoir [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installé pour utiliser cette application !",
|
||||||
"Download" : "Télécharger",
|
"Download" : "Télécharger",
|
||||||
"Add a RSS link" : "Ajouter un lien RSS",
|
"Add a RSS link" : "Ajouter un lien RSS",
|
||||||
"Subscribe" : "S'abonner",
|
"Subscribe" : "S'abonner",
|
||||||
@ -16,11 +16,10 @@
|
|||||||
"Link copied to the clipboard" : "Lien vers le flux copié dans le presse-papiers",
|
"Link copied to the clipboard" : "Lien vers le flux copié dans le presse-papiers",
|
||||||
"Play" : "Lecture",
|
"Play" : "Lecture",
|
||||||
"Stop" : "Arrêter",
|
"Stop" : "Arrêter",
|
||||||
"Mark as read" : "Marquer comme lu",
|
"Read" : "Lu",
|
||||||
"Mark as unread" : "Marquer comme non lu",
|
|
||||||
"Open website" : "Ouvrir le site web",
|
"Open website" : "Ouvrir le site web",
|
||||||
"Could not fetch episodes" : "Impossible de récuprer les épisodes",
|
|
||||||
"Could not change the status of the episode" : "Impossible de changer le status de l'épisode",
|
"Could not change the status of the episode" : "Impossible de changer le status de l'épisode",
|
||||||
|
"Could not fetch episodes" : "Impossible de récuprer les épisodes",
|
||||||
"Export subscriptions" : "Exporter les abonnements",
|
"Export subscriptions" : "Exporter les abonnements",
|
||||||
"Filtering episodes" : "Filtrage des épisodes",
|
"Filtering episodes" : "Filtrage des épisodes",
|
||||||
"Show all" : "Montrer tout",
|
"Show all" : "Montrer tout",
|
||||||
@ -31,13 +30,17 @@
|
|||||||
"Import OPML file" : "Importer un fichier OPML",
|
"Import OPML file" : "Importer un fichier OPML",
|
||||||
"Rate RePod ❤️" : "Donnez votre avis ❤️",
|
"Rate RePod ❤️" : "Donnez votre avis ❤️",
|
||||||
"Playback speed" : "Vitesse de lecture",
|
"Playback speed" : "Vitesse de lecture",
|
||||||
|
"Favorite" : "Favori",
|
||||||
"Are you sure you want to delete this subscription?" : "Êtes-vous sûr de vouloir supprimer ce flux ?",
|
"Are you sure you want to delete this subscription?" : "Êtes-vous sûr de vouloir supprimer ce flux ?",
|
||||||
"Error while removing the feed" : "Erreur lors de la suppression du flux",
|
"Error while removing the feed" : "Erreur lors de la suppression du flux",
|
||||||
|
"You can only have 10 favorites" : "Vous ne pouvez avoir que 10 favoris",
|
||||||
"Add a podcast" : "Ajouter un podcast",
|
"Add a podcast" : "Ajouter un podcast",
|
||||||
"Could not fetch subscriptions" : "Impossible de récupérer les flux",
|
"Could not fetch subscriptions" : "Impossible de récupérer les flux",
|
||||||
"Find a podcast" : "Chercher un podcast",
|
"Find a podcast" : "Chercher un podcast",
|
||||||
"Error loading feed" : "Erreur lors du chargement du flux",
|
"Error loading feed" : "Erreur lors du chargement du flux",
|
||||||
"Missing required app" : "Une application requise est manquante",
|
"Missing required app" : "Une application requise est manquante",
|
||||||
"Install GPodder Sync" : "Installer GPodder Sync"
|
"Install GPodder Sync" : "Installer GPodder Sync",
|
||||||
|
"Pin some subscriptions to see their latest updates" : "Ajoutez des abonnements en favoris pour obtenir les dernières nouvelles ici",
|
||||||
|
"No favorites" : "Aucun favoris"
|
||||||
},"pluralForm" :""
|
},"pluralForm" :""
|
||||||
}
|
}
|
@ -32,6 +32,10 @@ class Application extends App implements IBootstrap
|
|||||||
/** @var IInitialState $initialState */
|
/** @var IInitialState $initialState */
|
||||||
$initialState = $appContainer->get(IInitialState::class);
|
$initialState = $appContainer->get(IInitialState::class);
|
||||||
|
|
||||||
|
if (null === $appManager->getAppInfo(self::GPODDERSYNC_ID)) {
|
||||||
|
$appManager->disableApp(self::GPODDERSYNC_ID);
|
||||||
|
}
|
||||||
|
|
||||||
$gpoddersync = $appManager->isEnabledForUser(self::GPODDERSYNC_ID);
|
$gpoddersync = $appManager->isEnabledForUser(self::GPODDERSYNC_ID);
|
||||||
if (!$gpoddersync) {
|
if (!$gpoddersync) {
|
||||||
try {
|
try {
|
||||||
|
@ -8,24 +8,56 @@ use OCA\RePod\AppInfo\Application;
|
|||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||||
use OCP\AppFramework\Http\TemplateResponse;
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\IRequest;
|
||||||
use OCP\Util;
|
use OCP\Util;
|
||||||
|
|
||||||
class PageController extends Controller
|
class PageController extends Controller
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
IRequest $request,
|
||||||
|
private IConfig $config
|
||||||
|
) {
|
||||||
|
parent::__construct(Application::APP_ID, $request);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
*/
|
*/
|
||||||
public function index(): TemplateResponse {
|
public function index(): TemplateResponse {
|
||||||
Util::addScript(Application::APP_ID, 'main');
|
Util::addScript(Application::APP_ID, Application::APP_ID.'-main');
|
||||||
|
|
||||||
$csp = new ContentSecurityPolicy();
|
$csp = new ContentSecurityPolicy();
|
||||||
$csp->addAllowedImageDomain('*');
|
$csp->addAllowedImageDomain('*');
|
||||||
$csp->addAllowedMediaDomain('*');
|
$csp->addAllowedMediaDomain('*');
|
||||||
|
|
||||||
|
if ($this->config->getSystemValueBool('debug', false)) {
|
||||||
|
/** @psalm-suppress DeprecatedMethod */
|
||||||
|
$csp->allowEvalScript();
|
||||||
|
$csp->addAllowedConnectDomain('*');
|
||||||
|
$csp->addAllowedScriptDomain('*');
|
||||||
|
}
|
||||||
|
|
||||||
$response = new TemplateResponse(Application::APP_ID, 'main');
|
$response = new TemplateResponse(Application::APP_ID, 'main');
|
||||||
$response->setContentSecurityPolicy($csp);
|
$response->setContentSecurityPolicy($csp);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @NoAdminRequired
|
||||||
|
* @NoCSRFRequired
|
||||||
|
*/
|
||||||
|
public function discover(): TemplateResponse {
|
||||||
|
return $this->index();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @NoAdminRequired
|
||||||
|
* @NoCSRFRequired
|
||||||
|
*/
|
||||||
|
public function feed(): TemplateResponse {
|
||||||
|
return $this->index();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
3363
package-lock.json
generated
31
package.json
@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "repod",
|
"name": "repod",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build --mode production",
|
"build": "vue-tsc && vite build --mode production",
|
||||||
"dev": "vite build --mode development",
|
"dev": "vite build --mode development",
|
||||||
"dev:watch": "vite build --mode development --watch",
|
"dev:watch": "vite build --mode development --watch",
|
||||||
"watch": "npm run dev:watch",
|
"watch": "npm run dev:watch",
|
||||||
@ -11,12 +12,9 @@
|
|||||||
"stylelint": "stylelint src/**/*.vue src/**/*.scss src/**/*.css",
|
"stylelint": "stylelint src/**/*.vue src/**/*.scss src/**/*.css",
|
||||||
"stylelint:fix": "stylelint src/**/*.vue src/**/*.scss src/**/*.css --fix"
|
"stylelint:fix": "stylelint src/**/*.vue src/**/*.scss src/**/*.css --fix"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
|
||||||
"extends @nextcloud/browserslist-config"
|
|
||||||
],
|
|
||||||
"prettier": "@nextcloud/prettier-config",
|
"prettier": "@nextcloud/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nextcloud/axios": "^2.5.0",
|
"@nextcloud/axios": "^2.5.1",
|
||||||
"@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",
|
||||||
@ -26,18 +24,29 @@
|
|||||||
"linkify-html": "^4.1.3",
|
"linkify-html": "^4.1.3",
|
||||||
"pinia": "^2.2.2",
|
"pinia": "^2.2.2",
|
||||||
"toastify-js": "^1.12.0",
|
"toastify-js": "^1.12.0",
|
||||||
"vite": "^5.4.1",
|
"vite": "^5.4.6",
|
||||||
"vue": "^3.4.38",
|
"vite-plugin-vue-devtools": "^7.4.5",
|
||||||
|
"vue": "^3.5.6",
|
||||||
"vue-material-design-icons": "^5.3.0",
|
"vue-material-design-icons": "^5.3.0",
|
||||||
"vue-router": "^4.4.3"
|
"vue-router": "^4.4.5"
|
||||||
},
|
},
|
||||||
"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",
|
||||||
|
"@types/toastify-js": "^1.12.3",
|
||||||
|
"@vue/eslint-config-typescript": "^13.0.0",
|
||||||
|
"@vue/tsconfig": "^0.5.1",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-pinia": "^0.2.0",
|
"eslint-plugin-pinia": "^0.4.1",
|
||||||
"eslint-plugin-prettier": "^5.2.1"
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
}
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "5.5",
|
||||||
|
"vue-eslint-parser": "^9.4.3",
|
||||||
|
"vue-tsc": "^2.1.6"
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"extends @nextcloud/browserslist-config"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
BIN
screens/discover.png
Normal file
After Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 282 KiB After Width: | Height: | Size: 857 KiB |
Before Width: | Height: | Size: 429 KiB After Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 817 KiB |
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 961 KiB |
@ -7,7 +7,7 @@
|
|||||||
</NcContent>
|
</NcContent>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import 'toastify-js/src/toastify.css'
|
import 'toastify-js/src/toastify.css'
|
||||||
import { mapActions, mapState } from 'pinia'
|
import { mapActions, mapState } from 'pinia'
|
||||||
import Bar from './components/Player/Bar.vue'
|
import Bar from './components/Player/Bar.vue'
|
||||||
@ -15,7 +15,7 @@ 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'
|
import { usePlayer } from './store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<NcAppContent :class="{ padding: episode }">
|
<NcAppContent :class="{ episode }">
|
||||||
<slot />
|
<slot />
|
||||||
</NcAppContent>
|
</NcAppContent>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcAppContent } from '@nextcloud/vue'
|
import { NcAppContent } from '@nextcloud/vue'
|
||||||
import { mapState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
import { usePlayer } from '../../store/player.js'
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppContent',
|
name: 'AppContent',
|
||||||
@ -21,7 +21,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.padding {
|
.episode {
|
||||||
padding-bottom: 6rem;
|
padding-bottom: 6rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<NcAppNavigation :class="{ padding: episode }">
|
<NcAppNavigation :class="{ episode }">
|
||||||
<slot />
|
<slot />
|
||||||
<template #list>
|
<template #list>
|
||||||
<slot name="list" />
|
<slot name="list" />
|
||||||
@ -10,10 +10,10 @@
|
|||||||
</NcAppNavigation>
|
</NcAppNavigation>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcAppNavigation } from '@nextcloud/vue'
|
import { NcAppNavigation } from '@nextcloud/vue'
|
||||||
import { mapState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
import { usePlayer } from '../../store/player.js'
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppNavigation',
|
name: 'AppNavigation',
|
||||||
@ -27,7 +27,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.padding {
|
.episode {
|
||||||
padding-bottom: 6rem;
|
padding-bottom: 6rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
34
src/components/Atoms/EmptyContent.vue
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<NcEmptyContent class="empty">
|
||||||
|
<slot />
|
||||||
|
<template #icon>
|
||||||
|
<slot name="icon" />
|
||||||
|
</template>
|
||||||
|
<template #name>
|
||||||
|
<slot name="name" />
|
||||||
|
</template>
|
||||||
|
<template #description>
|
||||||
|
<slot name="description" />
|
||||||
|
</template>
|
||||||
|
<template #action>
|
||||||
|
<slot name="action" />
|
||||||
|
</template>
|
||||||
|
</NcEmptyContent>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { NcEmptyContent } from '@nextcloud/vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EmptyContent',
|
||||||
|
components: {
|
||||||
|
NcEmptyContent,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.empty {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,7 +2,7 @@
|
|||||||
<NcLoadingIcon class="loading" />
|
<NcLoadingIcon class="loading" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcLoadingIcon } from '@nextcloud/vue'
|
import { NcLoadingIcon } from '@nextcloud/vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -1,37 +1,43 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<NcAvatar :display-name="name" :is-no-user="true" :size="256" :url="image" />
|
<NcAvatar
|
||||||
<h2>{{ name }}</h2>
|
:display-name="episode.name"
|
||||||
<SafeHtml :source="description" />
|
:is-no-user="true"
|
||||||
|
:size="256"
|
||||||
|
:url="episode.image" />
|
||||||
|
<h2>{{ episode.name }}</h2>
|
||||||
|
<SafeHtml :source="episode.description || ''" />
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<NcButton v-if="link" :href="link" target="_blank">
|
<NcButton v-if="episode.link" :href="episode.link" target="_blank">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<OpenInNewIcon :size="20" />
|
<OpenInNewIcon :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ title }}
|
{{ episode.title }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
<NcButton
|
<NcButton
|
||||||
v-if="url"
|
v-if="episode.url"
|
||||||
:download="filenameFromUrl(url)"
|
:download="filenameFromUrl(episode.url)"
|
||||||
:href="url"
|
:href="episode.url"
|
||||||
target="_blank">
|
target="_blank">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<DownloadIcon :size="20" />
|
<DownloadIcon :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ t('repod', 'Download') }}
|
{{ t('repod', 'Download') }}
|
||||||
{{ size ? `(${humanFileSize(size)})` : '' }}
|
{{ episode.size ? `(${humanFileSize(episode.size)})` : '' }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcAvatar, NcButton } from '@nextcloud/vue'
|
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 type { EpisodeInterface } from '../../utils/types.ts'
|
||||||
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 { filenameFromUrl } from '../../utils/url.ts'
|
||||||
import { humanFileSize } from '../../utils/size.js'
|
import { humanFileSize } from '../../utils/size.ts'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Modal',
|
name: 'Modal',
|
||||||
@ -43,38 +49,15 @@ export default {
|
|||||||
SafeHtml,
|
SafeHtml,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
description: {
|
episode: {
|
||||||
type: String,
|
type: Object as () => EpisodeInterface,
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
link: {
|
|
||||||
type: String,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
type: Number,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
filenameFromUrl,
|
filenameFromUrl,
|
||||||
humanFileSize,
|
humanFileSize,
|
||||||
|
t,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div v-sanitize="source" class="html" />
|
<div v-sanitize="source" class="html" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import dompurify from 'dompurify'
|
import dompurify from 'dompurify'
|
||||||
import linkifyHtml from 'linkify-html'
|
import linkifyHtml from 'linkify-html'
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<NcAppNavigationList>
|
<NcAppNavigationList class="list">
|
||||||
<NcAppNavigationNewItem
|
<NcAppNavigationNewItem
|
||||||
:name="t('repod', 'Add a RSS link')"
|
:name="t('repod', 'Add a RSS link')"
|
||||||
@new-item="addSubscription">
|
@new-item="(url) => $router.push(toFeedUrl(url))">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<PlusIcon :size="20" />
|
<PlusIcon :size="20" />
|
||||||
</template>
|
</template>
|
||||||
@ -10,10 +10,11 @@
|
|||||||
</NcAppNavigationList>
|
</NcAppNavigationList>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcAppNavigationList, NcAppNavigationNewItem } from '@nextcloud/vue'
|
import { NcAppNavigationList, NcAppNavigationNewItem } from '@nextcloud/vue'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
import { encodeUrl } from '../../utils/url.js'
|
import { t } from '@nextcloud/l10n'
|
||||||
|
import { toFeedUrl } from '../../utils/url.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AddRss',
|
name: 'AddRss',
|
||||||
@ -23,15 +24,14 @@ export default {
|
|||||||
PlusIcon,
|
PlusIcon,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addSubscription(feedUrl) {
|
t,
|
||||||
this.$router.push(encodeUrl(feedUrl))
|
toFeedUrl,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
ul {
|
.list {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
:key="feed.link"
|
:key="feed.link"
|
||||||
:details="formatLocaleDate(new Date(feed.fetchedAtUnix * 1000))"
|
:details="formatLocaleDate(new Date(feed.fetchedAtUnix * 1000))"
|
||||||
:name="feed.title"
|
:name="feed.title"
|
||||||
:to="toUrl(feed.link)">
|
:to="toFeedUrl(feed.link)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NcAvatar
|
<NcAvatar
|
||||||
:display-name="feed.author"
|
:display-name="feed.author"
|
||||||
@ -19,7 +19,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<NcActionButton
|
<NcActionButton
|
||||||
v-if="!subscriptions.includes(feed.link)"
|
v-if="!getSubByUrl(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')"
|
||||||
@ -34,18 +34,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcActionButton, NcAvatar, NcListItem } from '@nextcloud/vue'
|
import { NcActionButton, NcAvatar, NcListItem } from '@nextcloud/vue'
|
||||||
import { mapActions, mapState } from 'pinia'
|
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 type { PodcastDataInterface } from '../../utils/types.ts'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { debounce } from '../../utils/debounce.js'
|
import { formatLocaleDate } from '../../utils/time.ts'
|
||||||
import { formatLocaleDate } from '../../utils/time.js'
|
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '../../utils/toast.js'
|
import { showError } from '../../utils/toast.ts'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { t } from '@nextcloud/l10n'
|
||||||
import { useSubscriptions } from '../../store/subscriptions.js'
|
import { toFeedUrl } from '../../utils/url.ts'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
@ -62,25 +63,28 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data: () => ({
|
||||||
return {
|
feeds: [] as PodcastDataInterface[],
|
||||||
feeds: [],
|
loading: false,
|
||||||
loading: false,
|
timeout: null as NodeJS.Timeout | null,
|
||||||
}
|
}),
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(useSubscriptions, ['subscriptions']),
|
...mapState(useSubscriptions, ['getSubByUrl']),
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value() {
|
value() {
|
||||||
this.search()
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout)
|
||||||
|
}
|
||||||
|
this.timeout = setTimeout(this.search, 200)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useSubscriptions, ['fetch']),
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
formatLocaleDate,
|
formatLocaleDate,
|
||||||
toUrl,
|
t,
|
||||||
async addSubscription(url) {
|
toFeedUrl,
|
||||||
|
async addSubscription(url: string) {
|
||||||
try {
|
try {
|
||||||
await axios.post(
|
await axios.post(
|
||||||
generateUrl('/apps/gpoddersync/subscription_change/create'),
|
generateUrl('/apps/gpoddersync/subscription_change/create'),
|
||||||
@ -93,14 +97,13 @@ export default {
|
|||||||
console.error(e)
|
console.error(e)
|
||||||
showError(t('repod', 'Error while adding the feed'))
|
showError(t('repod', 'Error while adding the feed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fetch()
|
this.fetch()
|
||||||
},
|
},
|
||||||
search: debounce(async function value() {
|
async search() {
|
||||||
try {
|
try {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
const currentSearch = this.value
|
const currentSearch = this.value
|
||||||
const feeds = await axios.get(
|
const feeds = await axios.get<PodcastDataInterface[]>(
|
||||||
generateUrl('/apps/repod/search?q={value}', {
|
generateUrl('/apps/repod/search?q={value}', {
|
||||||
value: currentSearch,
|
value: currentSearch,
|
||||||
}),
|
}),
|
||||||
@ -118,7 +121,7 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 200),
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<Loading v-if="loading" />
|
<Loading v-if="loading" />
|
||||||
<ul v-if="!loading">
|
<ul v-if="!loading">
|
||||||
<li v-for="top in tops" :key="top.link">
|
<li v-for="top in tops" :key="top.link">
|
||||||
<router-link :to="toUrl(top.link)">
|
<router-link :to="toFeedUrl(top.link)">
|
||||||
<img :src="top.imageUrl" :title="top.author" />
|
<img :src="top.imageUrl" :title="top.author" />
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
@ -12,12 +12,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
|
import type { PodcastDataInterface } from '../../utils/types.ts'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '../../utils/toast.js'
|
import { showError } from '../../utils/toast.ts'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { t } from '@nextcloud/l10n'
|
||||||
|
import { toFeedUrl } from '../../utils/url.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Toplist',
|
name: 'Toplist',
|
||||||
@ -30,12 +32,10 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data: () => ({
|
||||||
return {
|
loading: true,
|
||||||
loading: true,
|
tops: [] as PodcastDataInterface[],
|
||||||
tops: [],
|
}),
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
title() {
|
title() {
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
@ -51,8 +51,8 @@ export default {
|
|||||||
async mounted() {
|
async mounted() {
|
||||||
try {
|
try {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
const tops = await axios.get(
|
const tops = await axios.get<PodcastDataInterface[]>(
|
||||||
generateUrl(`/apps/repod/toplist/${this.type}`),
|
generateUrl('/apps/repod/toplist/{type}', { type: this.type }),
|
||||||
)
|
)
|
||||||
this.tops = tops.data
|
this.tops = tops.data
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -63,7 +63,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toUrl,
|
toFeedUrl,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<img class="background" :src="imageUrl" />
|
<img class="background" :src="feed.imageUrl" />
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div>
|
<div>
|
||||||
<NcAvatar
|
<NcAvatar
|
||||||
:display-name="author || title"
|
:display-name="feed.author || feed.title"
|
||||||
:is-no-user="true"
|
:is-no-user="true"
|
||||||
:size="128"
|
:size="128"
|
||||||
:url="imageUrl" />
|
:url="feed.imageUrl" />
|
||||||
<a class="feed" :href="url" @click.prevent="copyFeed">
|
<a class="feed" :href="url" @click.prevent="copyFeed">
|
||||||
<RssIcon :size="20" />
|
<RssIcon :size="20" />
|
||||||
<i>{{ t('repod', 'Copy feed') }}</i>
|
<i>{{ t('repod', 'Copy feed') }}</i>
|
||||||
@ -15,15 +15,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
<div class="infos">
|
<div class="infos">
|
||||||
<h2>{{ title }}</h2>
|
<h2>{{ feed.title }}</h2>
|
||||||
<a :href="link" target="_blank">
|
<a :href="feed.link" target="_blank">
|
||||||
<i>{{ author }}</i>
|
<i>{{ feed.author }}</i>
|
||||||
</a>
|
</a>
|
||||||
<br /><br />
|
<br /><br />
|
||||||
<SafeHtml :source="description" />
|
<SafeHtml :source="feed.description || ''" />
|
||||||
</div>
|
</div>
|
||||||
<NcAppNavigationNew
|
<NcAppNavigationNew
|
||||||
v-if="!subscriptions.includes(url)"
|
v-if="!getSubByUrl(url)"
|
||||||
:text="t('repod', 'Subscribe')"
|
:text="t('repod', 'Subscribe')"
|
||||||
@click="addSubscription">
|
@click="addSubscription">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@ -35,17 +35,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcAppNavigationNew, NcAvatar } from '@nextcloud/vue'
|
import { NcAppNavigationNew, NcAvatar } from '@nextcloud/vue'
|
||||||
import { mapActions, mapState } from 'pinia'
|
import { mapActions, mapState } from 'pinia'
|
||||||
import { showError, showSuccess } from '../../utils/toast.js'
|
import { showError, showSuccess } from '../../utils/toast.ts'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
|
import type { PodcastDataInterface } from '../../utils/types.ts'
|
||||||
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.ts'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { useSubscriptions } from '../../store/subscriptions.js'
|
import { t } from '@nextcloud/l10n'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Banner',
|
name: 'Banner',
|
||||||
@ -57,35 +59,20 @@ export default {
|
|||||||
SafeHtml,
|
SafeHtml,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
author: {
|
feed: {
|
||||||
type: String,
|
type: Object as () => PodcastDataInterface,
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
imageUrl: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
link: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(useSubscriptions, ['subscriptions']),
|
...mapState(useSubscriptions, ['getSubByUrl']),
|
||||||
url() {
|
url() {
|
||||||
return decodeUrl(this.$route.params.url)
|
return decodeUrl(this.$route.params.url as string)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useSubscriptions, ['fetch']),
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
|
t,
|
||||||
async addSubscription() {
|
async addSubscription() {
|
||||||
try {
|
try {
|
||||||
await axios.post(
|
await axios.post(
|
||||||
@ -99,7 +86,6 @@ export default {
|
|||||||
console.error(e)
|
console.error(e)
|
||||||
showError(t('repod', 'Error while adding the feed'))
|
showError(t('repod', 'Error while adding the feed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fetch()
|
this.fetch()
|
||||||
},
|
},
|
||||||
copyFeed() {
|
copyFeed() {
|
||||||
@ -143,11 +129,13 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.infos {
|
.infos {
|
||||||
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 768px) {
|
@media only screen and (max-width: 768px) {
|
||||||
|
222
src/components/Feed/Episode.vue
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
<template>
|
||||||
|
<NcListItem
|
||||||
|
:active="isCurrentEpisode(episode)"
|
||||||
|
class="episode"
|
||||||
|
:details="
|
||||||
|
!oneLine && episode.pubDate
|
||||||
|
? formatLocaleDate(new Date(episode.pubDate?.date))
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
:force-display-actions="true"
|
||||||
|
:name="episode.name"
|
||||||
|
:one-line="oneLine"
|
||||||
|
:style="{ opacity: hasEnded(episode) ? 0.4 : 1 }"
|
||||||
|
:title="episode.description"
|
||||||
|
@click="modalEpisode = episode">
|
||||||
|
<template #actions>
|
||||||
|
<NcActionButton
|
||||||
|
v-if="!isCurrentEpisode(episode)"
|
||||||
|
:aria-label="t('repod', 'Play')"
|
||||||
|
:title="t('repod', 'Play')"
|
||||||
|
@click="load(episode, url)">
|
||||||
|
<template #icon>
|
||||||
|
<PlayIcon :size="20" />
|
||||||
|
</template>
|
||||||
|
</NcActionButton>
|
||||||
|
<NcActionButton
|
||||||
|
v-if="isCurrentEpisode(episode)"
|
||||||
|
:aria-label="t('repod', 'Stop')"
|
||||||
|
:title="t('repod', 'Stop')"
|
||||||
|
@click="load(null)">
|
||||||
|
<template #icon>
|
||||||
|
<StopIcon :size="20" />
|
||||||
|
</template>
|
||||||
|
</NcActionButton>
|
||||||
|
</template>
|
||||||
|
<template #extra>
|
||||||
|
<NcActions>
|
||||||
|
<NcActionButton
|
||||||
|
v-if="episode.duration"
|
||||||
|
:aria-label="t('repod', 'Read')"
|
||||||
|
:disabled="loading"
|
||||||
|
:model-value="hasEnded(episode)"
|
||||||
|
:name="t('repod', 'Read')"
|
||||||
|
:title="t('repod', 'Read')"
|
||||||
|
@click="markAs(episode, !hasEnded(episode))">
|
||||||
|
<template #icon>
|
||||||
|
<PlaylistPlayIcon v-if="!hasEnded(episode)" :size="20" />
|
||||||
|
<PlaylistRemoveIcon v-if="hasEnded(episode)" :size="20" />
|
||||||
|
</template>
|
||||||
|
</NcActionButton>
|
||||||
|
<NcActionLink
|
||||||
|
v-if="episode.link"
|
||||||
|
:href="episode.link"
|
||||||
|
:name="t('repod', 'Open website')"
|
||||||
|
target="_blank"
|
||||||
|
:title="t('repod', 'Open website')">
|
||||||
|
<template #icon>
|
||||||
|
<OpenInNewIcon :size="20" />
|
||||||
|
</template>
|
||||||
|
</NcActionLink>
|
||||||
|
<NcActionLink
|
||||||
|
v-if="episode.url"
|
||||||
|
:download="filenameFromUrl(episode.url)"
|
||||||
|
:href="episode.url"
|
||||||
|
:name="t('repod', 'Download')"
|
||||||
|
target="_blank"
|
||||||
|
:title="t('repod', 'Download')">
|
||||||
|
<template #icon>
|
||||||
|
<DownloadIcon :size="20" />
|
||||||
|
</template>
|
||||||
|
</NcActionLink>
|
||||||
|
</NcActions>
|
||||||
|
<NcModal v-if="modalEpisode" @close="modalEpisode = null">
|
||||||
|
<Modal :episode="episode" />
|
||||||
|
</NcModal>
|
||||||
|
</template>
|
||||||
|
<template #icon>
|
||||||
|
<NcAvatar
|
||||||
|
:display-name="episode.name"
|
||||||
|
:is-no-user="true"
|
||||||
|
:url="episode.image" />
|
||||||
|
</template>
|
||||||
|
<template #indicator>
|
||||||
|
<NcProgressBar
|
||||||
|
v-if="episode.action && isListening(episode) && !oneLine"
|
||||||
|
class="progress"
|
||||||
|
:value="(episode.action.position * 100) / episode.action.total" />
|
||||||
|
</template>
|
||||||
|
<template #subname>
|
||||||
|
{{ episode.duration }}
|
||||||
|
</template>
|
||||||
|
</NcListItem>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
NcActionButton,
|
||||||
|
NcActionLink,
|
||||||
|
NcActions,
|
||||||
|
NcAvatar,
|
||||||
|
NcListItem,
|
||||||
|
NcModal,
|
||||||
|
NcProgressBar,
|
||||||
|
} from '@nextcloud/vue'
|
||||||
|
import {
|
||||||
|
durationToSeconds,
|
||||||
|
formatEpisodeTimestamp,
|
||||||
|
formatLocaleDate,
|
||||||
|
} from '../../utils/time.ts'
|
||||||
|
import { hasEnded, isListening } from '../../utils/status.ts'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import DownloadIcon from 'vue-material-design-icons/Download.vue'
|
||||||
|
import type { EpisodeInterface } from '../../utils/types.ts'
|
||||||
|
import Modal from '../Atoms/Modal.vue'
|
||||||
|
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
|
||||||
|
import PlayIcon from 'vue-material-design-icons/Play.vue'
|
||||||
|
import PlaylistPlayIcon from 'vue-material-design-icons/PlaylistPlay.vue'
|
||||||
|
import PlaylistRemoveIcon from 'vue-material-design-icons/PlaylistRemove.vue'
|
||||||
|
import StopIcon from 'vue-material-design-icons/Stop.vue'
|
||||||
|
import axios from '@nextcloud/axios'
|
||||||
|
import { filenameFromUrl } from '../../utils/url.ts'
|
||||||
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import { showError } from '../../utils/toast.ts'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Episode',
|
||||||
|
components: {
|
||||||
|
DownloadIcon,
|
||||||
|
Modal,
|
||||||
|
NcActionButton,
|
||||||
|
NcActionLink,
|
||||||
|
NcActions,
|
||||||
|
NcAvatar,
|
||||||
|
NcListItem,
|
||||||
|
NcModal,
|
||||||
|
NcProgressBar,
|
||||||
|
OpenInNewIcon,
|
||||||
|
PlayIcon,
|
||||||
|
PlaylistPlayIcon,
|
||||||
|
PlaylistRemoveIcon,
|
||||||
|
StopIcon,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
episode: {
|
||||||
|
type: Object as () => EpisodeInterface,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
oneLine: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
loading: false,
|
||||||
|
modalEpisode: null as EpisodeInterface | null,
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
...mapState(usePlayer, { playerEpisode: 'episode' }),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['load']),
|
||||||
|
filenameFromUrl,
|
||||||
|
formatLocaleDate,
|
||||||
|
hasEnded,
|
||||||
|
isListening,
|
||||||
|
t,
|
||||||
|
isCurrentEpisode(episode: EpisodeInterface) {
|
||||||
|
return this.playerEpisode?.url === episode.url
|
||||||
|
},
|
||||||
|
async markAs(episode: EpisodeInterface, read: boolean) {
|
||||||
|
try {
|
||||||
|
this.loading = true
|
||||||
|
episode.action = {
|
||||||
|
podcast: this.url,
|
||||||
|
episode: episode.url,
|
||||||
|
guid: episode.guid,
|
||||||
|
action: 'play',
|
||||||
|
timestamp: formatEpisodeTimestamp(new Date()),
|
||||||
|
started: episode.action?.started || 0,
|
||||||
|
position: read ? durationToSeconds(episode.duration || '') : 0,
|
||||||
|
total: durationToSeconds(episode.duration || ''),
|
||||||
|
}
|
||||||
|
await axios.post(
|
||||||
|
generateUrl('/apps/gpoddersync/episode_action/create'),
|
||||||
|
[episode.action],
|
||||||
|
)
|
||||||
|
if (read && this.isCurrentEpisode(episode)) {
|
||||||
|
this.load(null)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
showError(t('repod', 'Could not change the status of the episode'))
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.progress {
|
||||||
|
margin-top: 0.4rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.episode .list-item-content__name {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.episode .list-item-content__subname {
|
||||||
|
flex-basis: auto;
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,175 +2,39 @@
|
|||||||
<div>
|
<div>
|
||||||
<Loading v-if="loading" />
|
<Loading v-if="loading" />
|
||||||
<ul v-if="!loading">
|
<ul v-if="!loading">
|
||||||
<NcListItem
|
<Episode
|
||||||
v-for="episode in filteredEpisodes"
|
v-for="episode in filteredEpisodes"
|
||||||
:key="episode.guid"
|
:key="episode.guid"
|
||||||
:active="isCurrentEpisode(episode)"
|
:episode="episode"
|
||||||
:details="formatLocaleDate(new Date(episode.pubDate?.date))"
|
:url="url" />
|
||||||
:force-display-actions="true"
|
|
||||||
:href="$route.href"
|
|
||||||
:name="episode.name"
|
|
||||||
:style="{ opacity: hasEnded(episode) ? 0.4 : 1 }"
|
|
||||||
target="_self"
|
|
||||||
:title="episode.description"
|
|
||||||
@click="modalEpisode = episode">
|
|
||||||
<template #actions>
|
|
||||||
<NcActionButton
|
|
||||||
v-if="!isCurrentEpisode(episode)"
|
|
||||||
:aria-label="t('repod', 'Play')"
|
|
||||||
:title="t('repod', 'Play')"
|
|
||||||
@click="load(episode, url)">
|
|
||||||
<template #icon>
|
|
||||||
<PlayIcon :size="20" />
|
|
||||||
</template>
|
|
||||||
</NcActionButton>
|
|
||||||
<NcActionButton
|
|
||||||
v-if="isCurrentEpisode(episode)"
|
|
||||||
:aria-label="t('repod', 'Stop')"
|
|
||||||
:title="t('repod', 'Stop')"
|
|
||||||
@click="load(null)">
|
|
||||||
<template #icon>
|
|
||||||
<StopIcon :size="20" />
|
|
||||||
</template>
|
|
||||||
</NcActionButton>
|
|
||||||
</template>
|
|
||||||
<template #extra>
|
|
||||||
<NcActions>
|
|
||||||
<NcActionButton
|
|
||||||
v-if="episode.duration && !hasEnded(episode)"
|
|
||||||
:aria-label="t('repod', 'Mark as read')"
|
|
||||||
:disabled="loadingAction"
|
|
||||||
:name="t('repod', 'Mark as read')"
|
|
||||||
:title="t('repod', 'Mark as read')"
|
|
||||||
@click="markAs(episode, true)">
|
|
||||||
<template #icon>
|
|
||||||
<PlaylistPlayIcon :size="20" />
|
|
||||||
</template>
|
|
||||||
</NcActionButton>
|
|
||||||
<NcActionButton
|
|
||||||
v-if="episode.duration && hasEnded(episode)"
|
|
||||||
:aria-label="t('repod', 'Mark as unread')"
|
|
||||||
:disabled="loadingAction"
|
|
||||||
:name="t('repod', 'Mark as unread')"
|
|
||||||
:title="t('repod', 'Mark as unread')"
|
|
||||||
@click="markAs(episode, false)">
|
|
||||||
<template #icon>
|
|
||||||
<PlaylistRemoveIcon :size="20" />
|
|
||||||
</template>
|
|
||||||
</NcActionButton>
|
|
||||||
<NcActionLink
|
|
||||||
v-if="episode.link"
|
|
||||||
:href="episode.link"
|
|
||||||
:name="t('repod', 'Open website')"
|
|
||||||
target="_blank"
|
|
||||||
:title="t('repod', 'Open website')">
|
|
||||||
<template #icon>
|
|
||||||
<OpenInNewIcon :size="20" />
|
|
||||||
</template>
|
|
||||||
</NcActionLink>
|
|
||||||
<NcActionLink
|
|
||||||
v-if="episode.url"
|
|
||||||
:download="filenameFromUrl(episode.url)"
|
|
||||||
:href="episode.url"
|
|
||||||
:name="t('repod', 'Download')"
|
|
||||||
target="_blank"
|
|
||||||
:title="t('repod', 'Download')">
|
|
||||||
<template #icon>
|
|
||||||
<DownloadIcon :size="20" />
|
|
||||||
</template>
|
|
||||||
</NcActionLink>
|
|
||||||
</NcActions>
|
|
||||||
</template>
|
|
||||||
<template #icon>
|
|
||||||
<NcAvatar
|
|
||||||
:display-name="episode.name"
|
|
||||||
:is-no-user="true"
|
|
||||||
:url="episode.image" />
|
|
||||||
</template>
|
|
||||||
<template #indicator>
|
|
||||||
<NcProgressBar
|
|
||||||
v-if="isListening(episode)"
|
|
||||||
class="progress"
|
|
||||||
:value="
|
|
||||||
(episode.action.position * 100) / episode.action.total
|
|
||||||
" />
|
|
||||||
</template>
|
|
||||||
<template #subname>
|
|
||||||
{{ episode.duration }}
|
|
||||||
</template>
|
|
||||||
</NcListItem>
|
|
||||||
</ul>
|
</ul>
|
||||||
<NcModal v-if="modalEpisode" @close="modalEpisode = null">
|
|
||||||
<Modal
|
|
||||||
:description="modalEpisode.description"
|
|
||||||
:image="modalEpisode.image"
|
|
||||||
:link="modalEpisode.link"
|
|
||||||
:name="modalEpisode.name"
|
|
||||||
:size="modalEpisode.size"
|
|
||||||
:title="modalEpisode.title"
|
|
||||||
:url="modalEpisode.url" />
|
|
||||||
</NcModal>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import {
|
import { hasEnded, isListening } from '../../utils/status.ts'
|
||||||
NcActionButton,
|
import Episode from './Episode.vue'
|
||||||
NcActionLink,
|
import type { EpisodeInterface } from '../../utils/types.ts'
|
||||||
NcActions,
|
|
||||||
NcAvatar,
|
|
||||||
NcListItem,
|
|
||||||
NcModal,
|
|
||||||
NcProgressBar,
|
|
||||||
} from '@nextcloud/vue'
|
|
||||||
import { decodeUrl, filenameFromUrl } from '../../utils/url.js'
|
|
||||||
import {
|
|
||||||
durationToSeconds,
|
|
||||||
formatEpisodeTimestamp,
|
|
||||||
formatLocaleDate,
|
|
||||||
} from '../../utils/time.js'
|
|
||||||
import { mapActions, mapState } from 'pinia'
|
|
||||||
import DownloadIcon from 'vue-material-design-icons/Download.vue'
|
|
||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
import Modal from '../Atoms/Modal.vue'
|
|
||||||
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
|
|
||||||
import PlayIcon from 'vue-material-design-icons/Play.vue'
|
|
||||||
import PlaylistPlayIcon from 'vue-material-design-icons/PlaylistPlay.vue'
|
|
||||||
import PlaylistRemoveIcon from 'vue-material-design-icons/PlaylistRemove.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.ts'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '../../utils/toast.js'
|
import { mapState } from 'pinia'
|
||||||
import { usePlayer } from '../../store/player.js'
|
import { showError } from '../../utils/toast.ts'
|
||||||
import { useSettings } from '../../store/settings.js'
|
import { t } from '@nextcloud/l10n'
|
||||||
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
import { useSettings } from '../../store/settings.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Episodes',
|
name: 'Episodes',
|
||||||
components: {
|
components: {
|
||||||
DownloadIcon,
|
Episode,
|
||||||
Loading,
|
Loading,
|
||||||
Modal,
|
|
||||||
NcActionButton,
|
|
||||||
NcActionLink,
|
|
||||||
NcActions,
|
|
||||||
NcAvatar,
|
|
||||||
NcListItem,
|
|
||||||
NcModal,
|
|
||||||
NcProgressBar,
|
|
||||||
OpenInNewIcon,
|
|
||||||
PlayIcon,
|
|
||||||
PlaylistPlayIcon,
|
|
||||||
PlaylistRemoveIcon,
|
|
||||||
StopIcon,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
episodes: [],
|
|
||||||
loading: true,
|
|
||||||
loadingAction: false,
|
|
||||||
modalEpisode: null,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
data: () => ({
|
||||||
|
episodes: [] as EpisodeInterface[],
|
||||||
|
loading: true,
|
||||||
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(usePlayer, ['episode']),
|
...mapState(usePlayer, ['episode']),
|
||||||
...mapState(useSettings, ['filters']),
|
...mapState(useSettings, ['filters']),
|
||||||
@ -179,27 +43,24 @@ export default {
|
|||||||
if (!this.filters.listened && this.hasEnded(episode)) {
|
if (!this.filters.listened && this.hasEnded(episode)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.filters.listening && this.isListening(episode)) {
|
if (!this.filters.listening && this.isListening(episode)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.filters.unlistened && !this.isListening(episode)) {
|
if (!this.filters.unlistened && !this.isListening(episode)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
url() {
|
url() {
|
||||||
return decodeUrl(this.$route.params.url)
|
return decodeUrl(this.$route.params.url as string)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
episode() {
|
episode() {
|
||||||
if (this.episode) {
|
if (this.episode) {
|
||||||
this.episodes = this.episodes.map((e) =>
|
this.episodes = this.episodes.map((e) =>
|
||||||
e.url === this.episode.url ? this.episode : e,
|
e.url === this.episode?.url ? this.episode : e,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -207,13 +68,15 @@ export default {
|
|||||||
async mounted() {
|
async mounted() {
|
||||||
try {
|
try {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
const episodes = await axios.get(
|
const episodes = await axios.get<EpisodeInterface[]>(
|
||||||
generateUrl('/apps/repod/episodes/list?url={url}', {
|
generateUrl('/apps/repod/episodes/list?url={url}', {
|
||||||
url: this.url,
|
url: this.url,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
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 || '').getTime() -
|
||||||
|
new Date(a.pubDate?.date || '').getTime(),
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
@ -223,63 +86,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(usePlayer, ['load']),
|
hasEnded,
|
||||||
filenameFromUrl,
|
isListening,
|
||||||
formatLocaleDate,
|
|
||||||
hasEnded(episode) {
|
|
||||||
return (
|
|
||||||
episode.action &&
|
|
||||||
(episode.action.action === 'DELETE' ||
|
|
||||||
(episode.action.position > 0 &&
|
|
||||||
episode.action.total > 0 &&
|
|
||||||
episode.action.position >= episode.action.total))
|
|
||||||
)
|
|
||||||
},
|
|
||||||
isCurrentEpisode(episode) {
|
|
||||||
return this.episode && this.episode.url === episode.url
|
|
||||||
},
|
|
||||||
isListening(episode) {
|
|
||||||
return (
|
|
||||||
episode.action &&
|
|
||||||
episode.action.action &&
|
|
||||||
episode.action.action.toLowerCase() === 'play' &&
|
|
||||||
episode.action.position > 0 &&
|
|
||||||
!this.hasEnded(episode)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
async markAs(episode, read) {
|
|
||||||
try {
|
|
||||||
this.loadingAction = true
|
|
||||||
episode.action = {
|
|
||||||
podcast: this.url,
|
|
||||||
episode: episode.url,
|
|
||||||
guid: episode.guid,
|
|
||||||
action: 'play',
|
|
||||||
timestamp: formatEpisodeTimestamp(new Date()),
|
|
||||||
started: episode.action ? episode.action.started : 0,
|
|
||||||
position: read ? durationToSeconds(episode.duration) : 0,
|
|
||||||
total: durationToSeconds(episode.duration),
|
|
||||||
}
|
|
||||||
await axios.post(
|
|
||||||
generateUrl('/apps/gpoddersync/episode_action/create'),
|
|
||||||
[episode.action],
|
|
||||||
)
|
|
||||||
if (read && this.episode && episode.url === this.episode.url) {
|
|
||||||
this.load(null)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
showError(t('repod', 'Could not change the status of the episode'))
|
|
||||||
} finally {
|
|
||||||
this.loadingAction = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.progress {
|
|
||||||
margin-top: 0.4rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
105
src/components/Feed/Favorite.vue
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<template>
|
||||||
|
<NcGuestContent class="guest">
|
||||||
|
<Loading v-if="!feed.data" />
|
||||||
|
<NcAvatar
|
||||||
|
v-if="feed.data"
|
||||||
|
class="avatar"
|
||||||
|
:display-name="feed.data.author || feed.data.title"
|
||||||
|
:is-no-user="true"
|
||||||
|
:size="222"
|
||||||
|
:url="feed.data.imageUrl" />
|
||||||
|
<div v-if="feed.data" class="list">
|
||||||
|
<h2 class="title">{{ feed.data.title }}</h2>
|
||||||
|
<Loading v-if="loading" />
|
||||||
|
<ul v-if="!loading">
|
||||||
|
<Episode
|
||||||
|
v-for="episode in episodes"
|
||||||
|
:key="episode.guid"
|
||||||
|
:episode="episode"
|
||||||
|
:one-line="true"
|
||||||
|
:url="feed.metrics.url" />
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</NcGuestContent>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import type { EpisodeInterface, SubscriptionInterface } from '../../utils/types.ts'
|
||||||
|
import { NcAvatar, NcGuestContent } from '@nextcloud/vue'
|
||||||
|
import Episode from './Episode.vue'
|
||||||
|
import Loading from '../Atoms/Loading.vue'
|
||||||
|
import axios from '@nextcloud/axios'
|
||||||
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import { hasEnded } from '../../utils/status.ts'
|
||||||
|
import { showError } from '../../utils/toast.ts'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Favorite',
|
||||||
|
components: {
|
||||||
|
Episode,
|
||||||
|
Loading,
|
||||||
|
NcAvatar,
|
||||||
|
NcGuestContent,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
feed: {
|
||||||
|
type: Object as () => SubscriptionInterface,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
episodes: [] as EpisodeInterface[],
|
||||||
|
loading: true,
|
||||||
|
}),
|
||||||
|
async mounted() {
|
||||||
|
try {
|
||||||
|
this.loading = true
|
||||||
|
const episodes = await axios.get<EpisodeInterface[]>(
|
||||||
|
generateUrl('/apps/repod/episodes/list?url={url}', {
|
||||||
|
url: this.feed.metrics.url,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
this.episodes = [...episodes.data]
|
||||||
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
new Date(b.pubDate?.date || '').getTime() -
|
||||||
|
new Date(a.pubDate?.date || '').getTime(),
|
||||||
|
)
|
||||||
|
.filter((episode) => !this.hasEnded(episode))
|
||||||
|
.slice(0, 4)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
showError(t('repod', 'Could not fetch episodes'))
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
hasEnded,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.guest {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem;
|
||||||
|
margin: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 768px) {
|
||||||
|
.avatar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import Controls from './Controls.vue'
|
import Controls from './Controls.vue'
|
||||||
import Infos from './Infos.vue'
|
import Infos from './Infos.vue'
|
||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
@ -21,7 +21,7 @@ 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 { mapState } from 'pinia'
|
||||||
import { usePlayer } from '../../store/player.js'
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Bar',
|
name: 'Bar',
|
||||||
@ -78,7 +78,7 @@ export default {
|
|||||||
|
|
||||||
@media only screen and (max-width: 768px) {
|
@media only screen and (max-width: 768px) {
|
||||||
.infos {
|
.infos {
|
||||||
flex: 2;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timer,
|
.timer,
|
||||||
|
@ -5,11 +5,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { mapActions, mapState } from 'pinia'
|
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'
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Controls',
|
name: 'Controls',
|
||||||
|
@ -1,30 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="root">
|
<div v-if="episode && podcastUrl" class="root">
|
||||||
<strong class="pointer" @click="modal = true">
|
<strong class="pointer" @click="modal = true">
|
||||||
{{ episode.name }}
|
{{ episode.name }}
|
||||||
</strong>
|
</strong>
|
||||||
<router-link :to="hash">
|
<router-link :to="toFeedUrl(podcastUrl)">
|
||||||
<i>{{ 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 :episode="episode" />
|
||||||
:description="episode.description"
|
|
||||||
:image="episode.image"
|
|
||||||
:link="episode.link"
|
|
||||||
:name="episode.name"
|
|
||||||
:size="episode.size"
|
|
||||||
:title="episode.title"
|
|
||||||
:url="episode.url" />
|
|
||||||
</NcModal>
|
</NcModal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
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 { mapState } from 'pinia'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { toFeedUrl } from '../../utils/url.ts'
|
||||||
import { usePlayer } from '../../store/player.js'
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Infos',
|
name: 'Infos',
|
||||||
@ -32,16 +25,14 @@ export default {
|
|||||||
Modal,
|
Modal,
|
||||||
NcModal,
|
NcModal,
|
||||||
},
|
},
|
||||||
data() {
|
data: () => ({
|
||||||
return {
|
modal: false,
|
||||||
modal: false,
|
}),
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(usePlayer, ['episode', 'podcastUrl']),
|
...mapState(usePlayer, ['episode', 'podcastUrl']),
|
||||||
hash() {
|
},
|
||||||
return toUrl(this.podcastUrl)
|
methods: {
|
||||||
},
|
toFeedUrl,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<input
|
<input
|
||||||
|
v-if="duration"
|
||||||
class="progress"
|
class="progress"
|
||||||
:max="duration"
|
:max="duration"
|
||||||
min="0"
|
min="0"
|
||||||
type="range"
|
type="range"
|
||||||
:value="currentTime"
|
:value="currentTime"
|
||||||
@change="(event) => seek(event.target.value)" />
|
@change="
|
||||||
|
(event) => seek(parseInt((event.target as HTMLInputElement).value))
|
||||||
|
" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { mapActions, mapState } from 'pinia'
|
import { mapActions, mapState } from 'pinia'
|
||||||
import { usePlayer } from '../../store/player.js'
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProgressBar',
|
name: 'ProgressBar',
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div v-if="currentTime && duration" class="root">
|
||||||
<span>{{ formatTimer(new Date(currentTime * 1000)) }}</span>
|
<span>{{ formatTimer(new Date(currentTime * 1000)) }}</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span>{{ formatTimer(new Date(duration * 1000)) }}</span>
|
<span>{{ formatTimer(new Date(duration * 1000)) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { formatTimer } from '../../utils/time.js'
|
import { formatTimer } from '../../utils/time.ts'
|
||||||
import { mapState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
import { usePlayer } from '../../store/player.js'
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Timer',
|
name: 'Timer',
|
||||||
@ -23,7 +23,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
div {
|
.root {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
@ -26,17 +26,20 @@
|
|||||||
step="0.1"
|
step="0.1"
|
||||||
type="range"
|
type="range"
|
||||||
:value="volume"
|
:value="volume"
|
||||||
@change="(event) => setVolume(event.target.value)" />
|
@change="
|
||||||
|
(event) =>
|
||||||
|
setVolume(parseInt((event.target as HTMLInputElement).value))
|
||||||
|
" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { mapActions, mapState } from 'pinia'
|
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'
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Volume',
|
name: 'Volume',
|
||||||
@ -46,11 +49,9 @@ export default {
|
|||||||
VolumeMediumIcon,
|
VolumeMediumIcon,
|
||||||
VolumeMuteIcon,
|
VolumeMuteIcon,
|
||||||
},
|
},
|
||||||
data() {
|
data: () => ({
|
||||||
return {
|
volumeMuted: 0,
|
||||||
volumeMuted: 0,
|
}),
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(usePlayer, ['volume']),
|
...mapState(usePlayer, ['volume']),
|
||||||
},
|
},
|
||||||
|
@ -8,10 +8,11 @@
|
|||||||
</NcAppNavigationItem>
|
</NcAppNavigationItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import ExportIcon from 'vue-material-design-icons/Export.vue'
|
import ExportIcon from 'vue-material-design-icons/Export.vue'
|
||||||
import { NcAppNavigationItem } from '@nextcloud/vue'
|
import { NcAppNavigationItem } from '@nextcloud/vue'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Export',
|
name: 'Export',
|
||||||
@ -21,6 +22,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
generateUrl,
|
generateUrl,
|
||||||
|
t,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -39,13 +39,13 @@
|
|||||||
</NcAppNavigationItem>
|
</NcAppNavigationItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcActionCheckbox, NcAppNavigationItem } from '@nextcloud/vue'
|
import { NcActionCheckbox, NcAppNavigationItem } from '@nextcloud/vue'
|
||||||
import { mapActions, mapState } from 'pinia'
|
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 { t } from '@nextcloud/l10n'
|
||||||
import { useSettings } from '../../store/settings.js'
|
import { useSettings } from '../../store/settings.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Filters',
|
name: 'Filters',
|
||||||
@ -65,14 +65,9 @@ export default {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
try {
|
|
||||||
const filters = getCookie('repod.filters')
|
|
||||||
this.filters = JSON.parse(filters)
|
|
||||||
} catch {}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useSettings, ['setFilters']),
|
...mapActions(useSettings, ['setFilters']),
|
||||||
|
t,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -29,12 +29,13 @@
|
|||||||
</NcAppNavigationItem>
|
</NcAppNavigationItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcAppNavigationItem, NcModal } from '@nextcloud/vue'
|
import { NcAppNavigationItem, NcModal } from '@nextcloud/vue'
|
||||||
import ImportIcon from 'vue-material-design-icons/Import.vue'
|
import ImportIcon from 'vue-material-design-icons/Import.vue'
|
||||||
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 { t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Import',
|
name: 'Import',
|
||||||
@ -44,19 +45,19 @@ export default {
|
|||||||
NcAppNavigationItem,
|
NcAppNavigationItem,
|
||||||
NcModal,
|
NcModal,
|
||||||
},
|
},
|
||||||
data() {
|
data: () => ({
|
||||||
return {
|
loading: false,
|
||||||
loading: false,
|
modal: false,
|
||||||
modal: false,
|
}),
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
generateUrl,
|
generateUrl,
|
||||||
async importOpml(event) {
|
t,
|
||||||
|
async importOpml(event: Event) {
|
||||||
try {
|
try {
|
||||||
const formData = new FormData(event.target)
|
const target = event.target as HTMLFormElement
|
||||||
this.importLoading = true
|
const formData = new FormData(target)
|
||||||
await axios.post(event.target.action, formData)
|
this.loading = true
|
||||||
|
await axios.post(target.action, formData)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -8,9 +8,10 @@
|
|||||||
</NcAppNavigationItem>
|
</NcAppNavigationItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcAppNavigationItem } from '@nextcloud/vue'
|
import { NcAppNavigationItem } from '@nextcloud/vue'
|
||||||
import StarIcon from 'vue-material-design-icons/Star.vue'
|
import StarIcon from 'vue-material-design-icons/Star.vue'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Rate',
|
name: 'Rate',
|
||||||
@ -18,5 +19,8 @@ export default {
|
|||||||
NcAppNavigationItem,
|
NcAppNavigationItem,
|
||||||
StarIcon,
|
StarIcon,
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
t,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
</NcAppNavigationSettings>
|
</NcAppNavigationSettings>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import Export from './Export.vue'
|
import Export from './Export.vue'
|
||||||
import Filters from './Filters.vue'
|
import Filters from './Filters.vue'
|
||||||
import Import from './Import.vue'
|
import Import from './Import.vue'
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</NcAppNavigationItem>
|
</NcAppNavigationItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcAppNavigationItem, NcCounterBubble } from '@nextcloud/vue'
|
import { NcAppNavigationItem, NcCounterBubble } from '@nextcloud/vue'
|
||||||
import { mapActions, mapState } from 'pinia'
|
import { mapActions, mapState } from 'pinia'
|
||||||
import MinusIcon from 'vue-material-design-icons/Minus.vue'
|
import MinusIcon from 'vue-material-design-icons/Minus.vue'
|
||||||
@ -23,7 +23,8 @@ 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'
|
import { t } from '@nextcloud/l10n'
|
||||||
|
import { usePlayer } from '../../store/player.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Speed',
|
name: 'Speed',
|
||||||
@ -41,8 +42,9 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(usePlayer, ['setRate']),
|
...mapActions(usePlayer, ['setRate']),
|
||||||
changeRate(diff) {
|
t,
|
||||||
const newRate = (this.rate + diff).toPrecision(2)
|
changeRate(diff: number) {
|
||||||
|
const newRate = parseFloat((this.rate + diff).toPrecision(2))
|
||||||
this.setRate(newRate > 0 ? newRate : this.rate)
|
this.setRate(newRate > 0 ? newRate : this.rate)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
<template>
|
|
||||||
<NcAppNavigationItem
|
|
||||||
:loading="loading"
|
|
||||||
:name="feed ? feed.title : url"
|
|
||||||
:to="hash">
|
|
||||||
<template #actions>
|
|
||||||
<NcActionButton
|
|
||||||
:aria-label="t(`core`, 'Delete')"
|
|
||||||
:name="t(`core`, 'Delete')"
|
|
||||||
:title="t(`core`, 'Delete')"
|
|
||||||
@click="deleteSubscription">
|
|
||||||
<template #icon>
|
|
||||||
<DeleteIcon :size="20" />
|
|
||||||
</template>
|
|
||||||
</NcActionButton>
|
|
||||||
</template>
|
|
||||||
<template #icon>
|
|
||||||
<NcAvatar
|
|
||||||
v-if="feed"
|
|
||||||
:display-name="feed.author || feed.title"
|
|
||||||
:is-no-user="true"
|
|
||||||
:url="feed.imageUrl" />
|
|
||||||
<AlertIcon v-if="failed" />
|
|
||||||
</template>
|
|
||||||
</NcAppNavigationItem>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { NcActionButton, NcAppNavigationItem, NcAvatar } from '@nextcloud/vue'
|
|
||||||
import AlertIcon from 'vue-material-design-icons/Alert.vue'
|
|
||||||
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
|
|
||||||
import axios from '@nextcloud/axios'
|
|
||||||
import { generateUrl } from '@nextcloud/router'
|
|
||||||
import { mapActions } from 'pinia'
|
|
||||||
import { showError } from '../../utils/toast.js'
|
|
||||||
import { toUrl } from '../../utils/url.js'
|
|
||||||
import { useSubscriptions } from '../../store/subscriptions.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Item',
|
|
||||||
components: {
|
|
||||||
AlertIcon,
|
|
||||||
DeleteIcon,
|
|
||||||
NcActionButton,
|
|
||||||
NcAppNavigationItem,
|
|
||||||
NcAvatar,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
url: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
failed: false,
|
|
||||||
loading: true,
|
|
||||||
feed: null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
hash() {
|
|
||||||
return toUrl(this.url)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
try {
|
|
||||||
const podcastData = await axios.get(
|
|
||||||
generateUrl(
|
|
||||||
'/apps/gpoddersync/personal_settings/podcast_data?url={url}',
|
|
||||||
{
|
|
||||||
url: this.url,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
this.feed = podcastData.data.data
|
|
||||||
} catch (e) {
|
|
||||||
this.failed = true
|
|
||||||
console.error(e)
|
|
||||||
} finally {
|
|
||||||
this.loading = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions(useSubscriptions, ['fetch']),
|
|
||||||
async deleteSubscription() {
|
|
||||||
if (
|
|
||||||
confirm(
|
|
||||||
t('repod', 'Are you sure you want to delete this subscription?'),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
this.loading = true
|
|
||||||
await axios.post(
|
|
||||||
generateUrl('/apps/gpoddersync/subscription_change/create'),
|
|
||||||
{ add: [], remove: [this.url] },
|
|
||||||
)
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
showError(t('repod', 'Error while removing the feed'))
|
|
||||||
} finally {
|
|
||||||
this.loading = false
|
|
||||||
this.fetch()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
148
src/components/Sidebar/Subscription.vue
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<template>
|
||||||
|
<NcAppNavigationItem
|
||||||
|
:loading="loading"
|
||||||
|
:name="feed?.data?.title || url"
|
||||||
|
:to="toFeedUrl(url)">
|
||||||
|
<template #actions>
|
||||||
|
<NcActionButton
|
||||||
|
:aria-label="t('repod', 'Favorite')"
|
||||||
|
:model-value="feed?.isFavorite"
|
||||||
|
:name="t('repod', 'Favorite')"
|
||||||
|
:title="t('repod', 'Favorite')"
|
||||||
|
@update:modelValue="switchFavorite($event)">
|
||||||
|
<template #icon>
|
||||||
|
<StarPlusIcon v-if="!feed?.isFavorite" :size="20" />
|
||||||
|
<StarRemoveIcon v-if="feed?.isFavorite" :size="20" />
|
||||||
|
</template>
|
||||||
|
</NcActionButton>
|
||||||
|
<NcActionButton
|
||||||
|
:aria-label="t(`core`, 'Delete')"
|
||||||
|
:name="t(`core`, 'Delete')"
|
||||||
|
:title="t(`core`, 'Delete')"
|
||||||
|
@click="deleteSubscription">
|
||||||
|
<template #icon>
|
||||||
|
<DeleteIcon :size="20" />
|
||||||
|
</template>
|
||||||
|
</NcActionButton>
|
||||||
|
</template>
|
||||||
|
<template #icon>
|
||||||
|
<NcAvatar
|
||||||
|
:display-name="feed?.data?.author || feed?.data?.title"
|
||||||
|
:is-no-user="true"
|
||||||
|
:url="feed?.data?.imageUrl" />
|
||||||
|
<StarIcon v-if="feed?.isFavorite" class="star" :size="20" />
|
||||||
|
<AlertIcon v-if="failed" />
|
||||||
|
</template>
|
||||||
|
</NcAppNavigationItem>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { NcActionButton, NcAppNavigationItem, NcAvatar } from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import AlertIcon from 'vue-material-design-icons/Alert.vue'
|
||||||
|
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
|
||||||
|
import type { PersonalSettingsPodcastDataInterface } from '../../utils/types.ts'
|
||||||
|
import StarIcon from 'vue-material-design-icons/Star.vue'
|
||||||
|
import StarPlusIcon from 'vue-material-design-icons/StarPlus.vue'
|
||||||
|
import StarRemoveIcon from 'vue-material-design-icons/StarRemove.vue'
|
||||||
|
import axios from '@nextcloud/axios'
|
||||||
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import { showError } from '../../utils/toast.ts'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
import { toFeedUrl } from '../../utils/url.ts'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.ts'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Subscription',
|
||||||
|
components: {
|
||||||
|
AlertIcon,
|
||||||
|
DeleteIcon,
|
||||||
|
NcActionButton,
|
||||||
|
NcAppNavigationItem,
|
||||||
|
NcAvatar,
|
||||||
|
StarIcon,
|
||||||
|
StarPlusIcon,
|
||||||
|
StarRemoveIcon,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
failed: false,
|
||||||
|
loading: true,
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
...mapState(useSubscriptions, ['subs']),
|
||||||
|
feed() {
|
||||||
|
return this.subs.find((sub) => sub.metrics.url === this.url)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
try {
|
||||||
|
const podcastData =
|
||||||
|
await axios.get<PersonalSettingsPodcastDataInterface>(
|
||||||
|
generateUrl(
|
||||||
|
'/apps/gpoddersync/personal_settings/podcast_data?url={url}',
|
||||||
|
{
|
||||||
|
url: this.url,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
this.addMetadatas(this.url, podcastData.data.data)
|
||||||
|
} catch (e) {
|
||||||
|
this.failed = true
|
||||||
|
console.error(e)
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useSubscriptions, ['fetch', 'addMetadatas', 'setFavorite']),
|
||||||
|
t,
|
||||||
|
toFeedUrl,
|
||||||
|
async deleteSubscription() {
|
||||||
|
if (
|
||||||
|
confirm(
|
||||||
|
t('repod', 'Are you sure you want to delete this subscription?'),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
this.loading = true
|
||||||
|
await axios.post(
|
||||||
|
generateUrl('/apps/gpoddersync/subscription_change/create'),
|
||||||
|
{ add: [], remove: [this.url] },
|
||||||
|
)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
showError(t('repod', 'Error while removing the feed'))
|
||||||
|
} finally {
|
||||||
|
this.setFavorite(this.url, false)
|
||||||
|
this.loading = false
|
||||||
|
this.fetch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
switchFavorite(value: boolean) {
|
||||||
|
if (value) {
|
||||||
|
if (this.subs.filter((sub) => sub.isFavorite).length >= 10) {
|
||||||
|
showError(t('repod', 'You can only have 10 favorites'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setFavorite(this.url, value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.star {
|
||||||
|
bottom: 2px;
|
||||||
|
color: yellow;
|
||||||
|
left: 22px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,7 +2,7 @@
|
|||||||
<AppNavigation>
|
<AppNavigation>
|
||||||
<template #list>
|
<template #list>
|
||||||
<NcAppContentList>
|
<NcAppContentList>
|
||||||
<router-link to="/">
|
<router-link to="/discover">
|
||||||
<NcAppNavigationNew :text="t('repod', 'Add a podcast')">
|
<NcAppNavigationNew :text="t('repod', 'Add a podcast')">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<PlusIcon :size="20" />
|
<PlusIcon :size="20" />
|
||||||
@ -11,10 +11,14 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
<Loading v-if="loading" />
|
<Loading v-if="loading" />
|
||||||
<NcAppNavigationList v-if="!loading">
|
<NcAppNavigationList v-if="!loading">
|
||||||
<Item
|
<Subscription
|
||||||
v-for="subscriptionUrl of subscriptions"
|
v-for="sub of subs.filter((sub) => sub.isFavorite)"
|
||||||
:key="subscriptionUrl"
|
:key="sub.metrics.url"
|
||||||
:url="subscriptionUrl" />
|
:url="sub.metrics.url" />
|
||||||
|
<Subscription
|
||||||
|
v-for="sub of subs.filter((sub) => !sub.isFavorite)"
|
||||||
|
:key="sub.metrics.url"
|
||||||
|
:url="sub.metrics.url" />
|
||||||
</NcAppNavigationList>
|
</NcAppNavigationList>
|
||||||
</NcAppContentList>
|
</NcAppContentList>
|
||||||
</template>
|
</template>
|
||||||
@ -24,7 +28,7 @@
|
|||||||
</AppNavigation>
|
</AppNavigation>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import {
|
import {
|
||||||
NcAppContentList,
|
NcAppContentList,
|
||||||
NcAppNavigationList,
|
NcAppNavigationList,
|
||||||
@ -32,32 +36,31 @@ import {
|
|||||||
} from '@nextcloud/vue'
|
} from '@nextcloud/vue'
|
||||||
import { mapActions, mapState } from 'pinia'
|
import { mapActions, mapState } from 'pinia'
|
||||||
import AppNavigation from '../Atoms/AppNavigation.vue'
|
import AppNavigation from '../Atoms/AppNavigation.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 '../../utils/toast.js'
|
import Subscription from './Subscription.vue'
|
||||||
import { useSubscriptions } from '../../store/subscriptions.js'
|
import { showError } from '../../utils/toast.ts'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.ts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Subscriptions',
|
name: 'Subscriptions',
|
||||||
components: {
|
components: {
|
||||||
AppNavigation,
|
AppNavigation,
|
||||||
Item,
|
|
||||||
Loading,
|
Loading,
|
||||||
NcAppContentList,
|
NcAppContentList,
|
||||||
NcAppNavigationList,
|
NcAppNavigationList,
|
||||||
NcAppNavigationNew,
|
NcAppNavigationNew,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
Settings,
|
Settings,
|
||||||
|
Subscription,
|
||||||
},
|
},
|
||||||
data() {
|
data: () => ({
|
||||||
return {
|
loading: true,
|
||||||
loading: true,
|
}),
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(useSubscriptions, ['subscriptions']),
|
...mapState(useSubscriptions, ['subs']),
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
try {
|
try {
|
||||||
@ -71,6 +74,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useSubscriptions, ['fetch']),
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
|
t,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import { n, t } from '@nextcloud/l10n'
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import router from './router.js'
|
import router from './router.ts'
|
||||||
|
|
||||||
const Vue = createApp(App)
|
const Vue = createApp(App)
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
|
|
||||||
Vue.mixin({ methods: { t, n } })
|
|
||||||
Vue.use(pinia)
|
Vue.use(pinia)
|
||||||
Vue.use(router)
|
Vue.use(router)
|
||||||
Vue.mount('#content')
|
Vue.mount('#content')
|
@ -1,17 +1,22 @@
|
|||||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
import { createRouter, createWebHistory } 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 Home from './views/Home.vue'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(generateUrl('apps/repod')),
|
history: createWebHistory(generateUrl('apps/repod')),
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
|
component: Home,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/discover',
|
||||||
component: Discover,
|
component: Discover,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:url',
|
path: '/feed/:url',
|
||||||
component: Feed,
|
component: Feed,
|
||||||
},
|
},
|
||||||
],
|
],
|
@ -1,18 +1,19 @@
|
|||||||
|
import type { EpisodeActionInterface, EpisodeInterface } from '../utils/types.ts'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { formatEpisodeTimestamp } from '../utils/time.js'
|
import { formatEpisodeTimestamp } from '../utils/time.ts'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
|
||||||
const audio = new Audio()
|
const audio = new Audio()
|
||||||
|
|
||||||
export const usePlayer = defineStore('player', {
|
export const usePlayer = defineStore('player', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
currentTime: null,
|
currentTime: null as number | null,
|
||||||
duration: null,
|
duration: null as number | null,
|
||||||
episode: null,
|
episode: null as EpisodeInterface | null,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
paused: null,
|
paused: true,
|
||||||
podcastUrl: null,
|
podcastUrl: null as string | null,
|
||||||
volume: 1,
|
volume: 1,
|
||||||
rate: 1,
|
rate: 1,
|
||||||
started: 0,
|
started: 0,
|
||||||
@ -29,27 +30,26 @@ export const usePlayer = defineStore('player', {
|
|||||||
audio.ontimeupdate = () => (this.currentTime = audio.currentTime)
|
audio.ontimeupdate = () => (this.currentTime = audio.currentTime)
|
||||||
audio.onvolumechange = () => (this.volume = audio.volume)
|
audio.onvolumechange = () => (this.volume = audio.volume)
|
||||||
},
|
},
|
||||||
async load(episode, podcastUrl) {
|
async load(episode: EpisodeInterface | null, podcastUrl?: string) {
|
||||||
this.episode = episode
|
this.episode = episode
|
||||||
this.podcastUrl = podcastUrl
|
this.podcastUrl = podcastUrl || null
|
||||||
|
|
||||||
if (this.episode) {
|
if (this.episode?.url) {
|
||||||
audio.src = this.episode.url
|
audio.src = this.episode.url
|
||||||
audio.load()
|
audio.load()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const action = await axios.get(
|
const action = await axios.get<EpisodeActionInterface>(
|
||||||
generateUrl('/apps/repod/episodes/action?url={url}', {
|
generateUrl('/apps/repod/episodes/action?url={url}', {
|
||||||
url: this.episode.url,
|
url: this.episode.url,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
this.episode.action = action
|
this.episode.action = action.data
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.episode.action &&
|
this.episode.action &&
|
||||||
this.episode.action.position &&
|
|
||||||
this.episode.action.position < this.episode.action.total
|
this.episode.action.position < this.episode.action.total
|
||||||
) {
|
) {
|
||||||
audio.currentTime = this.episode.action.position
|
audio.currentTime = this.episode.action.position
|
||||||
@ -73,7 +73,7 @@ export const usePlayer = defineStore('player', {
|
|||||||
this.paused = false
|
this.paused = false
|
||||||
this.started = audio.currentTime
|
this.started = audio.currentTime
|
||||||
},
|
},
|
||||||
seek(currentTime) {
|
seek(currentTime: number) {
|
||||||
audio.currentTime = currentTime
|
audio.currentTime = currentTime
|
||||||
this.time()
|
this.time()
|
||||||
},
|
},
|
||||||
@ -82,6 +82,10 @@ export const usePlayer = defineStore('player', {
|
|||||||
this.episode = null
|
this.episode = null
|
||||||
},
|
},
|
||||||
time() {
|
time() {
|
||||||
|
if (!this.podcastUrl || !this.episode?.url) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.episode.action = {
|
this.episode.action = {
|
||||||
podcast: this.podcastUrl,
|
podcast: this.podcastUrl,
|
||||||
episode: this.episode.url,
|
episode: this.episode.url,
|
||||||
@ -92,14 +96,15 @@ export const usePlayer = defineStore('player', {
|
|||||||
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'), [
|
||||||
this.episode.action,
|
this.episode.action,
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
setVolume(volume) {
|
setVolume(volume: number) {
|
||||||
audio.volume = volume
|
audio.volume = volume
|
||||||
},
|
},
|
||||||
setRate(rate) {
|
setRate(rate: number) {
|
||||||
audio.playbackRate = rate
|
audio.playbackRate = rate
|
||||||
},
|
},
|
||||||
},
|
},
|
@ -1,18 +0,0 @@
|
|||||||
import { defineStore } from 'pinia'
|
|
||||||
import { setCookie } from '../utils/cookies.js'
|
|
||||||
|
|
||||||
export const useSettings = defineStore('settings', {
|
|
||||||
state: () => ({
|
|
||||||
filters: {
|
|
||||||
listened: true,
|
|
||||||
listening: true,
|
|
||||||
unlistened: true,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
actions: {
|
|
||||||
setFilters(filters) {
|
|
||||||
this.filters = { ...this.filters, ...filters }
|
|
||||||
setCookie('repod.filters', JSON.stringify(this.filters), 365)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
37
src/store/settings.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { getCookie, setCookie } from '../utils/cookies.ts'
|
||||||
|
import type { FiltersInterface } from '../utils/types.ts'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useSettings = defineStore('settings', {
|
||||||
|
state: () => {
|
||||||
|
try {
|
||||||
|
const filters = JSON.parse(getCookie('repod.filters') || '{}') || {}
|
||||||
|
|
||||||
|
if (!filters.length) {
|
||||||
|
throw new Error('Empty cookie')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
listened: filters.listened,
|
||||||
|
listening: filters.listening,
|
||||||
|
unlistened: filters.unlistened,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
listened: true,
|
||||||
|
listening: true,
|
||||||
|
unlistened: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setFilters(filters: Partial<FiltersInterface>) {
|
||||||
|
this.filters = { ...this.filters, ...filters }
|
||||||
|
setCookie('repod.filters', JSON.stringify(this.filters), 365)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
@ -1,20 +0,0 @@
|
|||||||
import axios from '@nextcloud/axios'
|
|
||||||
import { defineStore } from 'pinia'
|
|
||||||
import { generateUrl } from '@nextcloud/router'
|
|
||||||
|
|
||||||
export const useSubscriptions = defineStore('subscriptions', {
|
|
||||||
state: () => ({
|
|
||||||
subscriptions: [],
|
|
||||||
}),
|
|
||||||
actions: {
|
|
||||||
async fetch() {
|
|
||||||
const metrics = await axios.get(
|
|
||||||
generateUrl('/apps/gpoddersync/personal_settings/metrics'),
|
|
||||||
)
|
|
||||||
const subs = [...metrics.data.subscriptions].sort(
|
|
||||||
(a, b) => b.listenedSeconds - a.listenedSeconds,
|
|
||||||
)
|
|
||||||
this.subscriptions = subs.map((sub) => sub.url)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
59
src/store/subscriptions.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import type {
|
||||||
|
PersonalSettingsMetricsInterface,
|
||||||
|
PodcastDataInterface,
|
||||||
|
SubscriptionInterface,
|
||||||
|
} from '../utils/types.ts'
|
||||||
|
import { getCookie, setCookie } from '../utils/cookies.ts'
|
||||||
|
import axios from '@nextcloud/axios'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
|
||||||
|
export const useSubscriptions = defineStore('subscriptions', {
|
||||||
|
state: () => ({
|
||||||
|
subs: [] as SubscriptionInterface[],
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
getSubByUrl: (state) => (url: string) =>
|
||||||
|
state.subs.find((sub) => sub.metrics.url === url),
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
async fetch() {
|
||||||
|
let favorites: string[] = []
|
||||||
|
try {
|
||||||
|
favorites = JSON.parse(getCookie('repod.favorites') || '[]') || []
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
const metrics = await axios.get<PersonalSettingsMetricsInterface>(
|
||||||
|
generateUrl('/apps/gpoddersync/personal_settings/metrics'),
|
||||||
|
)
|
||||||
|
|
||||||
|
this.subs = [...metrics.data.subscriptions]
|
||||||
|
.sort((a, b) => b.listenedSeconds - a.listenedSeconds)
|
||||||
|
.map((sub) => ({
|
||||||
|
metrics: sub,
|
||||||
|
isFavorite: favorites.includes(sub.url),
|
||||||
|
data: this.subs.find((s) => s.metrics.url === sub.url)?.data,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
addMetadatas(link: string, data: PodcastDataInterface) {
|
||||||
|
this.subs = this.subs.map((sub) =>
|
||||||
|
sub.metrics.url === link ? { ...sub, data } : sub,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
setFavorite(link: string, isFavorite: boolean) {
|
||||||
|
this.subs = this.subs.map((sub) =>
|
||||||
|
sub.metrics.url === link ? { ...sub, isFavorite } : sub,
|
||||||
|
)
|
||||||
|
|
||||||
|
setCookie(
|
||||||
|
'repod.favorites',
|
||||||
|
JSON.stringify(
|
||||||
|
this.subs
|
||||||
|
.filter((sub) => sub.isFavorite)
|
||||||
|
.map((sub) => sub.metrics.url),
|
||||||
|
),
|
||||||
|
365,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
@ -4,7 +4,7 @@
|
|||||||
* @param {string} name Nom du cookie à récupérer
|
* @param {string} name Nom du cookie à récupérer
|
||||||
* @return {string|null}
|
* @return {string|null}
|
||||||
*/
|
*/
|
||||||
export const getCookie = (name) => {
|
export const getCookie = (name: string): string | null => {
|
||||||
const cookies = document.cookie.split('; ')
|
const cookies = document.cookie.split('; ')
|
||||||
const value = cookies.find((c) => c.startsWith(name + '='))?.split('=')[1]
|
const value = cookies.find((c) => c.startsWith(name + '='))?.split('=')[1]
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
@ -19,7 +19,7 @@ export const getCookie = (name) => {
|
|||||||
* @param {string} value Value du cookie
|
* @param {string} value Value du cookie
|
||||||
* @param {number} days Durée de vie du cookie (en jours)
|
* @param {number} days Durée de vie du cookie (en jours)
|
||||||
*/
|
*/
|
||||||
export const setCookie = (name, value, days) => {
|
export const setCookie = (name: string, value: string, days: number) => {
|
||||||
const date = new Date()
|
const date = new Date()
|
||||||
date.setDate(date.getDate() + days)
|
date.setDate(date.getDate() + days)
|
||||||
document.cookie = `${name}=${encodeURIComponent(value)}; expires=${date.toUTCString()}; SameSite=Strict;`
|
document.cookie = `${name}=${encodeURIComponent(value)}; expires=${date.toUTCString()}; SameSite=Strict;`
|
@ -1,12 +0,0 @@
|
|||||||
// https://stackoverflow.com/a/53486112
|
|
||||||
export const debounce = (fn, delay) => {
|
|
||||||
let timeoutID = null
|
|
||||||
return function () {
|
|
||||||
clearTimeout(timeoutID)
|
|
||||||
const args = arguments
|
|
||||||
const that = this
|
|
||||||
timeoutID = setTimeout(function () {
|
|
||||||
fn.apply(that, args)
|
|
||||||
}, delay)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,8 @@
|
|||||||
// https://stackoverflow.com/a/20732091
|
// https://stackoverflow.com/a/20732091
|
||||||
export const humanFileSize = (size) => {
|
export const humanFileSize = (size: number) => {
|
||||||
const i = size === 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024))
|
const i = size === 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024))
|
||||||
return (
|
return (
|
||||||
(size / Math.pow(1024, i)).toFixed(2) * 1 +
|
(size / Math.pow(1024, i)).toFixed(2) +
|
||||||
' ' +
|
' ' +
|
||||||
['B', 'kB', 'MB', 'GB', 'TB'][i]
|
['B', 'kB', 'MB', 'GB', 'TB'][i]
|
||||||
)
|
)
|
16
src/utils/status.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import type { EpisodeInterface } from './types'
|
||||||
|
|
||||||
|
export const hasEnded = (episode: EpisodeInterface) =>
|
||||||
|
episode.action &&
|
||||||
|
episode.action.action &&
|
||||||
|
(episode.action.action.toLowerCase() === 'delete' ||
|
||||||
|
(episode.action.position > 0 &&
|
||||||
|
episode.action.total > 0 &&
|
||||||
|
episode.action.position >= episode.action.total))
|
||||||
|
|
||||||
|
export const isListening = (episode: EpisodeInterface) =>
|
||||||
|
episode.action &&
|
||||||
|
episode.action.action &&
|
||||||
|
episode.action.action.toLowerCase() === 'play' &&
|
||||||
|
episode.action.position > 0 &&
|
||||||
|
!hasEnded(episode)
|
@ -3,9 +3,9 @@
|
|||||||
* @param {Date} date The date
|
* @param {Date} date The date
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
export const formatTimer = (date) => {
|
export const formatTimer = (date: Date): string => {
|
||||||
const minutes = date.getUTCMinutes().toString().padStart(2, 0)
|
const minutes = date.getUTCMinutes().toString().padStart(2, '0')
|
||||||
const seconds = date.getUTCSeconds().toString().padStart(2, 0)
|
const seconds = date.getUTCSeconds().toString().padStart(2, '0')
|
||||||
let timer = `${minutes}:${seconds}`
|
let timer = `${minutes}:${seconds}`
|
||||||
|
|
||||||
if (date.getUTCHours()) {
|
if (date.getUTCHours()) {
|
||||||
@ -20,7 +20,7 @@ export const formatTimer = (date) => {
|
|||||||
* @param {Date} date The date
|
* @param {Date} date The date
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
export const formatEpisodeTimestamp = (date) => {
|
export const formatEpisodeTimestamp = (date: Date): string => {
|
||||||
const year = date.getFullYear()
|
const year = date.getFullYear()
|
||||||
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||||
const day = date.getDate().toString().padStart(2, '0')
|
const day = date.getDate().toString().padStart(2, '0')
|
||||||
@ -36,7 +36,7 @@ export const formatEpisodeTimestamp = (date) => {
|
|||||||
* @param {Date} date The date
|
* @param {Date} date The date
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
export const formatLocaleDate = (date) =>
|
export const formatLocaleDate = (date: Date): string =>
|
||||||
date.toLocaleDateString(undefined, { dateStyle: 'medium' })
|
date.toLocaleDateString(undefined, { dateStyle: 'medium' })
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,7 +44,7 @@ export const formatLocaleDate = (date) =>
|
|||||||
* @param {string} duration The duration feed's entry
|
* @param {string} duration The duration feed's entry
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
export const durationToSeconds = (duration) => {
|
export const durationToSeconds = (duration: string): number => {
|
||||||
const splitDuration = duration.split(':').reverse()
|
const splitDuration = duration.split(':').reverse()
|
||||||
let seconds = parseInt(splitDuration[0])
|
let seconds = parseInt(splitDuration[0])
|
||||||
seconds += splitDuration.length > 1 ? parseInt(splitDuration[1]) * 60 : 0
|
seconds += splitDuration.length > 1 ? parseInt(splitDuration[1]) * 60 : 0
|
@ -1,12 +0,0 @@
|
|||||||
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)')
|
|
14
src/utils/toast.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import toastify from 'toastify-js'
|
||||||
|
|
||||||
|
export const showMessage = (text: string, backgroundColor: string) =>
|
||||||
|
toastify({
|
||||||
|
text,
|
||||||
|
backgroundColor,
|
||||||
|
}).showToast()
|
||||||
|
|
||||||
|
export const showError = (text: string) => showMessage(text, 'var(--color-error)')
|
||||||
|
export const showWarning = (text: string) =>
|
||||||
|
showMessage(text, 'var(--color-warning)')
|
||||||
|
export const showInfo = (text: string) => showMessage(text, 'var(--color-primary)')
|
||||||
|
export const showSuccess = (text: string) =>
|
||||||
|
showMessage(text, 'var(--color-success)')
|
73
src/utils/types.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
export interface EpisodeActionInterface {
|
||||||
|
podcast: string
|
||||||
|
episode: string
|
||||||
|
action: string
|
||||||
|
timestamp: string
|
||||||
|
started: number
|
||||||
|
position: number
|
||||||
|
total: number
|
||||||
|
guid?: string
|
||||||
|
id?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EpisodeInterface {
|
||||||
|
title: string
|
||||||
|
url: string
|
||||||
|
name: string
|
||||||
|
link?: string
|
||||||
|
image?: string
|
||||||
|
description?: string
|
||||||
|
fetchedAtUnix: number
|
||||||
|
guid: string
|
||||||
|
type?: string
|
||||||
|
size?: number
|
||||||
|
pubDate?: {
|
||||||
|
date: string
|
||||||
|
timezone_type: number
|
||||||
|
timezone: string
|
||||||
|
}
|
||||||
|
duration?: string
|
||||||
|
action?: EpisodeActionInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FiltersInterface {
|
||||||
|
listened: boolean
|
||||||
|
listening: boolean
|
||||||
|
unlistened: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PodcastDataInterface {
|
||||||
|
title: string
|
||||||
|
author?: string
|
||||||
|
link: string
|
||||||
|
description?: string
|
||||||
|
imageUrl?: string
|
||||||
|
fetchedAtUnix: number
|
||||||
|
imageBlob?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PodcastMetricsInterface {
|
||||||
|
url: string
|
||||||
|
listenedSeconds: number
|
||||||
|
actionCounts: {
|
||||||
|
delete: number
|
||||||
|
download: number
|
||||||
|
flattr: number
|
||||||
|
new: number
|
||||||
|
play: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SubscriptionInterface {
|
||||||
|
data?: PodcastDataInterface
|
||||||
|
isFavorite: boolean
|
||||||
|
metrics: PodcastMetricsInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PersonalSettingsMetricsInterface {
|
||||||
|
subscriptions: PodcastMetricsInterface[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PersonalSettingsPodcastDataInterface {
|
||||||
|
data: PodcastDataInterface
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
export const encodeUrl = (url) => encodeURIComponent(btoa(url))
|
|
||||||
export const decodeUrl = (url) => atob(decodeURIComponent(url))
|
|
||||||
export const toUrl = (url) => `/${encodeUrl(url)}`
|
|
||||||
export const filenameFromUrl = (str) => {
|
|
||||||
const url = new URL(str)
|
|
||||||
return url.pathname.split('/').pop()
|
|
||||||
}
|
|
5
src/utils/url.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const encodeUrl = (url: string) => encodeURIComponent(btoa(url))
|
||||||
|
export const decodeUrl = (url: string) => atob(decodeURIComponent(url))
|
||||||
|
export const toFeedUrl = (url: string) => `/feed/${encodeUrl(url)}`
|
||||||
|
export const filenameFromUrl = (url: string) =>
|
||||||
|
new URL(url).pathname.split('/').pop()
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppContent class="main">
|
<AppContent class="padding">
|
||||||
<NcTextField v-model="search" :label="t('repod', 'Find a podcast')">
|
<NcTextField v-model="search" :label="t('repod', 'Find a podcast')">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Magnify :size="20" />
|
<Magnify :size="20" />
|
||||||
@ -12,13 +12,14 @@
|
|||||||
</AppContent>
|
</AppContent>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import AddRss from '../components/Discover/AddRss.vue'
|
import AddRss from '../components/Discover/AddRss.vue'
|
||||||
import AppContent from '../components/Atoms/AppContent.vue'
|
import AppContent from '../components/Atoms/AppContent.vue'
|
||||||
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 Search from '../components/Discover/Search.vue'
|
import Search from '../components/Discover/Search.vue'
|
||||||
import Toplist from '../components/Discover/Toplist.vue'
|
import Toplist from '../components/Discover/Toplist.vue'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Discover',
|
name: 'Discover',
|
||||||
@ -30,16 +31,17 @@ export default {
|
|||||||
Search,
|
Search,
|
||||||
Toplist,
|
Toplist,
|
||||||
},
|
},
|
||||||
data() {
|
data: () => ({
|
||||||
return {
|
search: '',
|
||||||
search: '',
|
}),
|
||||||
}
|
methods: {
|
||||||
|
t,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.main {
|
.padding {
|
||||||
padding: 15px 51px;
|
padding: 15px 51px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,35 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppContent>
|
<AppContent>
|
||||||
<Loading v-if="loading" />
|
<Loading v-if="loading" />
|
||||||
<NcEmptyContent
|
<EmptyContent v-if="failed" :name="t('repod', 'Error loading feed')">
|
||||||
v-if="failed"
|
|
||||||
class="error"
|
|
||||||
:name="t('repod', 'Error loading feed')">
|
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Alert />
|
<Alert />
|
||||||
</template>
|
</template>
|
||||||
</NcEmptyContent>
|
</EmptyContent>
|
||||||
<Banner
|
<Banner v-if="feed" :feed="feed" />
|
||||||
v-if="feed"
|
|
||||||
:author="feed.author"
|
|
||||||
:description="feed.description"
|
|
||||||
:image-url="feed.imageUrl"
|
|
||||||
:link="feed.link"
|
|
||||||
:title="feed.title" />
|
|
||||||
<Episodes v-if="feed" />
|
<Episodes v-if="feed" />
|
||||||
</AppContent>
|
</AppContent>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import Alert from 'vue-material-design-icons/Alert.vue'
|
import Alert from 'vue-material-design-icons/Alert.vue'
|
||||||
import AppContent from '../components/Atoms/AppContent.vue'
|
import AppContent from '../components/Atoms/AppContent.vue'
|
||||||
import Banner from '../components/Feed/Banner.vue'
|
import Banner from '../components/Feed/Banner.vue'
|
||||||
|
import EmptyContent from '../components/Atoms/EmptyContent.vue'
|
||||||
import Episodes from '../components/Feed/Episodes.vue'
|
import Episodes from '../components/Feed/Episodes.vue'
|
||||||
import Loading from '../components/Atoms/Loading.vue'
|
import Loading from '../components/Atoms/Loading.vue'
|
||||||
import { NcEmptyContent } from '@nextcloud/vue'
|
import type { PodcastDataInterface } from '../utils/types.ts'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { decodeUrl } from '../utils/url.js'
|
import { decodeUrl } from '../utils/url.ts'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Feed',
|
name: 'Feed',
|
||||||
@ -37,25 +30,24 @@ export default {
|
|||||||
Alert,
|
Alert,
|
||||||
AppContent,
|
AppContent,
|
||||||
Banner,
|
Banner,
|
||||||
|
EmptyContent,
|
||||||
Episodes,
|
Episodes,
|
||||||
Loading,
|
Loading,
|
||||||
NcEmptyContent,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
failed: false,
|
|
||||||
loading: true,
|
|
||||||
feed: null,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
data: () => ({
|
||||||
|
failed: false,
|
||||||
|
loading: true,
|
||||||
|
feed: null as PodcastDataInterface | null,
|
||||||
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
url() {
|
url() {
|
||||||
return decodeUrl(this.$route.params.url)
|
return decodeUrl(this.$route.params.url as string)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
try {
|
try {
|
||||||
const podcastData = await axios.get(
|
this.loading = true
|
||||||
|
const podcastData = await axios.get<PodcastDataInterface>(
|
||||||
generateUrl('/apps/repod/podcast?url={url}', { url: this.url }),
|
generateUrl('/apps/repod/podcast?url={url}', { url: this.url }),
|
||||||
)
|
)
|
||||||
this.feed = podcastData.data
|
this.feed = podcastData.data
|
||||||
@ -66,11 +58,8 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
t,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.error {
|
|
||||||
margin: 2rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<NcAppContent class="content">
|
<AppContent>
|
||||||
<NcEmptyContent :name="t('repod', 'Missing required app')">
|
<EmptyContent :name="t('repod', 'Missing required app')">
|
||||||
<template #action>
|
<template #action>
|
||||||
<NcButton :href="gPodderSyncUrl">
|
<NcButton :href="gPodderSyncUrl">
|
||||||
{{ t('repod', 'Install GPodder Sync') }}
|
{{ t('repod', 'Install GPodder Sync') }}
|
||||||
@ -9,27 +9,33 @@
|
|||||||
<template #icon>
|
<template #icon>
|
||||||
<Alert />
|
<Alert />
|
||||||
</template>
|
</template>
|
||||||
</NcEmptyContent>
|
</EmptyContent>
|
||||||
</NcAppContent>
|
</AppContent>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { NcAppContent, NcButton, NcEmptyContent } from '@nextcloud/vue'
|
|
||||||
import Alert from 'vue-material-design-icons/Alert.vue'
|
import Alert from 'vue-material-design-icons/Alert.vue'
|
||||||
|
import AppContent from '../components/Atoms/AppContent.vue'
|
||||||
|
import EmptyContent from '../components/Atoms/EmptyContent.vue'
|
||||||
|
import { NcButton } from '@nextcloud/vue'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'GPodder',
|
name: 'GPodder',
|
||||||
components: {
|
components: {
|
||||||
Alert,
|
Alert,
|
||||||
NcAppContent,
|
AppContent,
|
||||||
|
EmptyContent,
|
||||||
NcButton,
|
NcButton,
|
||||||
NcEmptyContent,
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
gPodderSyncUrl() {
|
gPodderSyncUrl() {
|
||||||
return generateUrl('/settings/apps/installed/gpoddersync')
|
return generateUrl('/settings/apps/installed/gpoddersync')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
t,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
48
src/views/Home.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<AppContent>
|
||||||
|
<EmptyContent
|
||||||
|
v-if="!favorites.length"
|
||||||
|
:description="
|
||||||
|
t('repod', 'Pin some subscriptions to see their latest updates')
|
||||||
|
"
|
||||||
|
:name="t('repod', 'No favorites')">
|
||||||
|
<template #icon>
|
||||||
|
<StarOffIcon />
|
||||||
|
</template>
|
||||||
|
</EmptyContent>
|
||||||
|
<ul v-if="favorites.length">
|
||||||
|
<li v-for="favorite in favorites" :key="favorite.metrics.url">
|
||||||
|
<Favorite :feed="favorite" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</AppContent>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import AppContent from '../components/Atoms/AppContent.vue'
|
||||||
|
import EmptyContent from '../components/Atoms/EmptyContent.vue'
|
||||||
|
import Favorite from '../components/Feed/Favorite.vue'
|
||||||
|
import StarOffIcon from 'vue-material-design-icons/StarOff.vue'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
|
import { useSubscriptions } from '../store/subscriptions.ts'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Home',
|
||||||
|
components: {
|
||||||
|
AppContent,
|
||||||
|
EmptyContent,
|
||||||
|
Favorite,
|
||||||
|
StarOffIcon,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useSubscriptions, ['subs']),
|
||||||
|
favorites() {
|
||||||
|
return this.subs.filter((sub) => sub.isFavorite)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
t,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
@ -6,7 +6,9 @@ namespace OCA\GPodderSync\Core\SubscriptionChange;
|
|||||||
|
|
||||||
class SubscriptionChangeRequestParser
|
class SubscriptionChangeRequestParser
|
||||||
{
|
{
|
||||||
public function __construct(private SubscriptionChangesReader $subscriptionChangeReader) {}
|
public function __construct(
|
||||||
|
private SubscriptionChangesReader $subscriptionChangeReader
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return SubscriptionChange[]
|
* @return SubscriptionChange[]
|
||||||
|
@ -8,7 +8,9 @@ use OCA\GPodderSync\Core\EpisodeAction\EpisodeAction;
|
|||||||
|
|
||||||
class EpisodeActionRepository
|
class EpisodeActionRepository
|
||||||
{
|
{
|
||||||
public function __construct(private EpisodeActionMapper $episodeActionMapper) {}
|
public function __construct(
|
||||||
|
private EpisodeActionMapper $episodeActionMapper
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return EpisodeAction[]
|
* @return EpisodeAction[]
|
||||||
|
@ -8,7 +8,9 @@ use OCP\DB\Exception;
|
|||||||
|
|
||||||
class EpisodeActionWriter
|
class EpisodeActionWriter
|
||||||
{
|
{
|
||||||
public function __construct(private EpisodeActionMapper $episodeActionMapper) {}
|
public function __construct(
|
||||||
|
private EpisodeActionMapper $episodeActionMapper
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return EpisodeActionEntity
|
* @return EpisodeActionEntity
|
||||||
|
@ -6,7 +6,9 @@ namespace OCA\GPodderSync\Db\SubscriptionChange;
|
|||||||
|
|
||||||
class SubscriptionChangeRepository
|
class SubscriptionChangeRepository
|
||||||
{
|
{
|
||||||
public function __construct(private SubscriptionChangeMapper $subscriptionChangeMapper) {}
|
public function __construct(
|
||||||
|
private SubscriptionChangeMapper $subscriptionChangeMapper
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return SubscriptionChangeEntity[]
|
* @return SubscriptionChangeEntity[]
|
||||||
|
@ -6,7 +6,9 @@ namespace OCA\GPodderSync\Db\SubscriptionChange;
|
|||||||
|
|
||||||
class SubscriptionChangeWriter
|
class SubscriptionChangeWriter
|
||||||
{
|
{
|
||||||
public function __construct(private SubscriptionChangeMapper $subscriptionChangeMapper) {}
|
public function __construct(
|
||||||
|
private SubscriptionChangeMapper $subscriptionChangeMapper
|
||||||
|
) {}
|
||||||
|
|
||||||
public function purge(): void {}
|
public function purge(): void {}
|
||||||
|
|
||||||
|
@ -32,7 +32,13 @@ msgid ""
|
|||||||
"## Features\n"
|
"## Features\n"
|
||||||
"- 🔍 Browse and subscribe huge collection of podcasts\n"
|
"- 🔍 Browse and subscribe huge collection of podcasts\n"
|
||||||
"- 🔊 Listen to episodes directly in Nextcloud\n"
|
"- 🔊 Listen to episodes directly in Nextcloud\n"
|
||||||
"- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/)\n"
|
"- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/) and [other "
|
||||||
|
"apps](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-"
|
||||||
|
"gpoddersync)\n"
|
||||||
|
"- 📱 Mobile friendly interface\n"
|
||||||
|
"- 📡 Import and export your subscriptions\n"
|
||||||
|
"- ➡️ Full features comparison [here](https://git.crystalyx.net/Xefir/"
|
||||||
|
"repod#comparaison-with-similar-apps-for-nextcloud)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"## Requirements\n"
|
"## Requirements\n"
|
||||||
"You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
"You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
||||||
@ -42,6 +48,8 @@ msgstr ""
|
|||||||
"- 🔍 Durchsuchen und abonnieren einer großen Sammlung von Podcasts\n"
|
"- 🔍 Durchsuchen und abonnieren einer großen Sammlung von Podcasts\n"
|
||||||
"- 🔊 Episoden direkt in Nextcloud anhören\n"
|
"- 🔊 Episoden direkt in Nextcloud anhören\n"
|
||||||
"- 🌐 Synchronisiere deine Aktivität mit [AntennaPod](https://antennapod.org/)\n"
|
"- 🌐 Synchronisiere deine Aktivität mit [AntennaPod](https://antennapod.org/)\n"
|
||||||
|
"- 📱 Mobile-freundliche Schnittstelle\n"
|
||||||
|
"- 📡 Importieren und Exportieren Ihrer Abonnements\n"
|
||||||
"\n"
|
"\n"
|
||||||
"## Voraussetzungen\n"
|
"## Voraussetzungen\n"
|
||||||
"Du musst [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
"Du musst [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
||||||
@ -83,21 +91,18 @@ msgstr "Abspielen"
|
|||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "Stopp"
|
msgstr "Stopp"
|
||||||
|
|
||||||
msgid "Mark as read"
|
msgid "Read"
|
||||||
msgstr "Als gelesen markieren"
|
msgstr "Gelesen"
|
||||||
|
|
||||||
msgid "Mark as unread"
|
|
||||||
msgstr "Als ungelesen markieren"
|
|
||||||
|
|
||||||
msgid "Open website"
|
msgid "Open website"
|
||||||
msgstr "Webseite aufrufen"
|
msgstr "Webseite aufrufen"
|
||||||
|
|
||||||
msgid "Could not fetch episodes"
|
|
||||||
msgstr "Folgen können nicht abgerufen werden"
|
|
||||||
|
|
||||||
msgid "Could not change the status of the episode"
|
msgid "Could not change the status of the episode"
|
||||||
msgstr "Kann den Status der Folge nicht ändern"
|
msgstr "Kann den Status der Folge nicht ändern"
|
||||||
|
|
||||||
|
msgid "Could not fetch episodes"
|
||||||
|
msgstr "Folgen können nicht abgerufen werden"
|
||||||
|
|
||||||
msgid "Export subscriptions"
|
msgid "Export subscriptions"
|
||||||
msgstr "Abonnements exportieren"
|
msgstr "Abonnements exportieren"
|
||||||
|
|
||||||
@ -128,12 +133,18 @@ msgstr "Bewerte RePod ❤️"
|
|||||||
msgid "Playback speed"
|
msgid "Playback speed"
|
||||||
msgstr "Wiedergabegeschwindigkeit"
|
msgstr "Wiedergabegeschwindigkeit"
|
||||||
|
|
||||||
|
msgid "Favorite"
|
||||||
|
msgstr "Favorit"
|
||||||
|
|
||||||
msgid "Are you sure you want to delete this subscription?"
|
msgid "Are you sure you want to delete this subscription?"
|
||||||
msgstr "Bist Du sicher, dass Du das Abonnement löschen möchtest?"
|
msgstr "Bist Du sicher, dass Du das Abonnement löschen möchtest?"
|
||||||
|
|
||||||
msgid "Error while removing the feed"
|
msgid "Error while removing the feed"
|
||||||
msgstr "Fehler beim Löschen des Feeds"
|
msgstr "Fehler beim Löschen des Feeds"
|
||||||
|
|
||||||
|
msgid "You can only have 10 favorites"
|
||||||
|
msgstr "Du kannst nur 10 Favoriten haben"
|
||||||
|
|
||||||
msgid "Add a podcast"
|
msgid "Add a podcast"
|
||||||
msgstr "Einen Podcast hinzufügen"
|
msgstr "Einen Podcast hinzufügen"
|
||||||
|
|
||||||
@ -151,3 +162,9 @@ msgstr "Benötigte App fehlt"
|
|||||||
|
|
||||||
msgid "Install GPodder Sync"
|
msgid "Install GPodder Sync"
|
||||||
msgstr "Installiere GPodder Sync"
|
msgstr "Installiere GPodder Sync"
|
||||||
|
|
||||||
|
msgid "Pin some subscriptions to see their latest updates"
|
||||||
|
msgstr "Pinne einige Abonnements, um ihre neuesten Updates zu sehen"
|
||||||
|
|
||||||
|
msgid "No favorites"
|
||||||
|
msgstr "Keine Favoriten"
|
||||||
|
@ -32,7 +32,13 @@ msgid ""
|
|||||||
"## Features\n"
|
"## Features\n"
|
||||||
"- 🔍 Browse and subscribe huge collection of podcasts\n"
|
"- 🔍 Browse and subscribe huge collection of podcasts\n"
|
||||||
"- 🔊 Listen to episodes directly in Nextcloud\n"
|
"- 🔊 Listen to episodes directly in Nextcloud\n"
|
||||||
"- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/)\n"
|
"- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/) and [other "
|
||||||
|
"apps](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-"
|
||||||
|
"gpoddersync)\n"
|
||||||
|
"- 📱 Mobile friendly interface\n"
|
||||||
|
"- 📡 Import and export your subscriptions\n"
|
||||||
|
"- ➡️ Full features comparison [here](https://git.crystalyx.net/Xefir/"
|
||||||
|
"repod#comparaison-with-similar-apps-for-nextcloud)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"## Requirements\n"
|
"## Requirements\n"
|
||||||
"You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
"You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
||||||
@ -41,7 +47,13 @@ msgstr ""
|
|||||||
"## Fonctionnalités\n"
|
"## Fonctionnalités\n"
|
||||||
"- 🔍 Parcourir et s'abonner à une grande collections de podcasts\n"
|
"- 🔍 Parcourir et s'abonner à une grande collections de podcasts\n"
|
||||||
"- 🔊 Écouter vos épisodes directement sur Nextcloud\n"
|
"- 🔊 Écouter vos épisodes directement sur Nextcloud\n"
|
||||||
"- 🌐 Synchroniser son activité avec [AntennaPod](https://antennapod.org/)\n"
|
"- 🌐 Synchroniser son activité avec [AntennaPod](https://antennapod.org/) et d'autres "
|
||||||
|
"[applications](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-"
|
||||||
|
"gpoddersync)\n"
|
||||||
|
"- 📱 Interface optimisée pour mobiles et ordinateurs\n"
|
||||||
|
"- 📡 Import/export de ses abonnements\n"
|
||||||
|
"- ➡️ Tableau récapitulatif complet des fonctionnalitées [ici](https://git.crystalyx."
|
||||||
|
"net/Xefir/repod#comparaison-with-similar-apps-for-nextcloud)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"## Pré-requis\n"
|
"## Pré-requis\n"
|
||||||
"Vous devez avoir [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
"Vous devez avoir [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
||||||
@ -83,21 +95,18 @@ msgstr "Lecture"
|
|||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "Arrêter"
|
msgstr "Arrêter"
|
||||||
|
|
||||||
msgid "Mark as read"
|
msgid "Read"
|
||||||
msgstr "Marquer comme lu"
|
msgstr "Lu"
|
||||||
|
|
||||||
msgid "Mark as unread"
|
|
||||||
msgstr "Marquer comme non lu"
|
|
||||||
|
|
||||||
msgid "Open website"
|
msgid "Open website"
|
||||||
msgstr "Ouvrir le site web"
|
msgstr "Ouvrir le site web"
|
||||||
|
|
||||||
msgid "Could not fetch episodes"
|
|
||||||
msgstr "Impossible de récuprer les épisodes"
|
|
||||||
|
|
||||||
msgid "Could not change the status of the episode"
|
msgid "Could not change the status of the episode"
|
||||||
msgstr "Impossible de changer le status de l'épisode"
|
msgstr "Impossible de changer le status de l'épisode"
|
||||||
|
|
||||||
|
msgid "Could not fetch episodes"
|
||||||
|
msgstr "Impossible de récuprer les épisodes"
|
||||||
|
|
||||||
msgid "Export subscriptions"
|
msgid "Export subscriptions"
|
||||||
msgstr "Exporter les abonnements"
|
msgstr "Exporter les abonnements"
|
||||||
|
|
||||||
@ -128,12 +137,18 @@ msgstr "Donnez votre avis ❤️"
|
|||||||
msgid "Playback speed"
|
msgid "Playback speed"
|
||||||
msgstr "Vitesse de lecture"
|
msgstr "Vitesse de lecture"
|
||||||
|
|
||||||
|
msgid "Favorite"
|
||||||
|
msgstr "Favori"
|
||||||
|
|
||||||
msgid "Are you sure you want to delete this subscription?"
|
msgid "Are you sure you want to delete this subscription?"
|
||||||
msgstr "Êtes-vous sûr de vouloir supprimer ce flux ?"
|
msgstr "Êtes-vous sûr de vouloir supprimer ce flux ?"
|
||||||
|
|
||||||
msgid "Error while removing the feed"
|
msgid "Error while removing the feed"
|
||||||
msgstr "Erreur lors de la suppression du flux"
|
msgstr "Erreur lors de la suppression du flux"
|
||||||
|
|
||||||
|
msgid "You can only have 10 favorites"
|
||||||
|
msgstr "Vous ne pouvez avoir que 10 favoris"
|
||||||
|
|
||||||
msgid "Add a podcast"
|
msgid "Add a podcast"
|
||||||
msgstr "Ajouter un podcast"
|
msgstr "Ajouter un podcast"
|
||||||
|
|
||||||
@ -151,3 +166,9 @@ msgstr "Une application requise est manquante"
|
|||||||
|
|
||||||
msgid "Install GPodder Sync"
|
msgid "Install GPodder Sync"
|
||||||
msgstr "Installer GPodder Sync"
|
msgstr "Installer GPodder Sync"
|
||||||
|
|
||||||
|
msgid "Pin some subscriptions to see their latest updates"
|
||||||
|
msgstr "Ajoutez des abonnements en favoris pour obtenir les dernières nouvelles ici"
|
||||||
|
|
||||||
|
msgid "No favorites"
|
||||||
|
msgstr "Aucun favoris"
|
||||||
|
@ -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-08-09 10:10+0000\n"
|
"POT-Creation-Date: 2024-09-15 13:40+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"
|
||||||
@ -40,7 +40,13 @@ msgid ""
|
|||||||
"## Features\n"
|
"## Features\n"
|
||||||
"- 🔍 Browse and subscribe huge collection of podcasts\n"
|
"- 🔍 Browse and subscribe huge collection of podcasts\n"
|
||||||
"- 🔊 Listen to episodes directly in Nextcloud\n"
|
"- 🔊 Listen to episodes directly in Nextcloud\n"
|
||||||
"- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/)\n"
|
"- 🌐 Sync your activity with [AntennaPod](https://antennapod.org/) and [other "
|
||||||
|
"apps](https://git.crystalyx.net/Xefir/repod#clients-supporting-sync-of-"
|
||||||
|
"gpoddersync)\n"
|
||||||
|
"- 📱 Mobile friendly interface\n"
|
||||||
|
"- 📡 Import and export your subscriptions\n"
|
||||||
|
"- ➡️ Full features comparison [here](https://git.crystalyx.net/Xefir/"
|
||||||
|
"repod#comparaison-with-similar-apps-for-nextcloud)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"## Requirements\n"
|
"## Requirements\n"
|
||||||
"You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
"You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) "
|
||||||
@ -48,8 +54,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:1
|
#: /app/specialVueFakeDummyForL10nScript.js:1
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:27
|
#: /app/specialVueFakeDummyForL10nScript.js:24
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:28
|
#: /app/specialVueFakeDummyForL10nScript.js:25
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -106,96 +112,109 @@ msgstr ""
|
|||||||
#: /app/specialVueFakeDummyForL10nScript.js:19
|
#: /app/specialVueFakeDummyForL10nScript.js:19
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:20
|
#: /app/specialVueFakeDummyForL10nScript.js:20
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:21
|
#: /app/specialVueFakeDummyForL10nScript.js:21
|
||||||
msgid "Mark as read"
|
msgid "Read"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:22
|
#: /app/specialVueFakeDummyForL10nScript.js:22
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:23
|
#: /app/specialVueFakeDummyForL10nScript.js:23
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:24
|
|
||||||
msgid "Mark as unread"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:25
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:26
|
|
||||||
msgid "Open website"
|
msgid "Open website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:29
|
#: /app/specialVueFakeDummyForL10nScript.js:26
|
||||||
msgid "Could not fetch episodes"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: /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:31
|
#: /app/specialVueFakeDummyForL10nScript.js:27
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:28
|
||||||
|
msgid "Could not fetch episodes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:29
|
||||||
msgid "Export subscriptions"
|
msgid "Export subscriptions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:32
|
#: /app/specialVueFakeDummyForL10nScript.js:30
|
||||||
msgid "Filtering episodes"
|
msgid "Filtering episodes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:33
|
#: /app/specialVueFakeDummyForL10nScript.js:31
|
||||||
msgid "Show all"
|
msgid "Show all"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:34
|
#: /app/specialVueFakeDummyForL10nScript.js:32
|
||||||
msgid "Listened"
|
msgid "Listened"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:35
|
#: /app/specialVueFakeDummyForL10nScript.js:33
|
||||||
msgid "Listening"
|
msgid "Listening"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:36
|
#: /app/specialVueFakeDummyForL10nScript.js:34
|
||||||
msgid "Unlistened"
|
msgid "Unlistened"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:37
|
#: /app/specialVueFakeDummyForL10nScript.js:35
|
||||||
msgid "Import subscriptions"
|
msgid "Import subscriptions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:38
|
#: /app/specialVueFakeDummyForL10nScript.js:36
|
||||||
msgid "Import OPML file"
|
msgid "Import OPML file"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:39
|
#: /app/specialVueFakeDummyForL10nScript.js:37
|
||||||
msgid "Rate RePod ❤️"
|
msgid "Rate RePod ❤️"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:40
|
#: /app/specialVueFakeDummyForL10nScript.js:38
|
||||||
msgid "Playback speed"
|
msgid "Playback speed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:39
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:40
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:41
|
#: /app/specialVueFakeDummyForL10nScript.js:41
|
||||||
msgid "Are you sure you want to delete this subscription?"
|
msgid "Favorite"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:42
|
#: /app/specialVueFakeDummyForL10nScript.js:42
|
||||||
msgid "Error while removing the feed"
|
msgid "Are you sure you want to delete this subscription?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:43
|
#: /app/specialVueFakeDummyForL10nScript.js:43
|
||||||
msgid "Add a podcast"
|
msgid "Error while removing the feed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:44
|
#: /app/specialVueFakeDummyForL10nScript.js:44
|
||||||
msgid "Could not fetch subscriptions"
|
msgid "You can only have 10 favorites"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:45
|
#: /app/specialVueFakeDummyForL10nScript.js:45
|
||||||
msgid "Find a podcast"
|
msgid "Add a podcast"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:46
|
#: /app/specialVueFakeDummyForL10nScript.js:46
|
||||||
msgid "Error loading feed"
|
msgid "Could not fetch subscriptions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:47
|
#: /app/specialVueFakeDummyForL10nScript.js:47
|
||||||
msgid "Missing required app"
|
msgid "Find a podcast"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /app/specialVueFakeDummyForL10nScript.js:48
|
#: /app/specialVueFakeDummyForL10nScript.js:48
|
||||||
|
msgid "Error loading feed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:49
|
||||||
|
msgid "Missing required app"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:50
|
||||||
msgid "Install GPodder Sync"
|
msgid "Install GPodder Sync"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:51
|
||||||
|
msgid "Pin some subscriptions to see their latest updates"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /app/specialVueFakeDummyForL10nScript.js:52
|
||||||
|
msgid "No favorites"
|
||||||
|
msgstr ""
|
||||||
|
19
tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.json",
|
||||||
|
"include": ["./src/**/*.ts", "./src/**/*.vue", "**/*.ts"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"rootDir": ".",
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
},
|
||||||
|
"vueCompilerOptions": {
|
||||||
|
"target": 3.3,
|
||||||
|
},
|
||||||
|
}
|
@ -1,22 +0,0 @@
|
|||||||
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 },
|
|
||||||
)
|
|
20
vite.config.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { createAppConfig } from '@nextcloud/vite-config'
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||||
|
|
||||||
|
const config = defineConfig(({ mode }) => ({
|
||||||
|
build: {
|
||||||
|
sourcemap: false,
|
||||||
|
},
|
||||||
|
define: {
|
||||||
|
__VUE_PROD_DEVTOOLS__: mode !== 'production',
|
||||||
|
},
|
||||||
|
plugins: [vueDevTools()],
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default createAppConfig(
|
||||||
|
{
|
||||||
|
main: 'src/main.ts',
|
||||||
|
},
|
||||||
|
{ config, inlineCSS: true },
|
||||||
|
)
|