Compare commits

..

66 Commits
3.1.0 ... main

Author SHA1 Message Date
0d017bbc68 Merge pull request 'chore(deps): update nextcloud docker tag to v30' (#160) from renovate/nextcloud-30.x into main
All checks were successful
repod / xml (push) Successful in 9s
repod / php (push) Successful in 42s
repod / nodejs (push) Successful in 59s
repod / release (push) Has been skipped
Reviewed-on: #160
2024-09-19 06:36:04 +00:00
Renovate Bot
3b2981d201 chore(deps): update nextcloud docker tag to v30
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 1m19s
repod / nodejs (push) Successful in 1m2s
repod / release (push) Has been skipped
2024-09-19 06:34:06 +00:00
25949e98c9 chore: ⬆️ update locks
All checks were successful
repod / xml (push) Successful in 26s
repod / php (push) Successful in 45s
repod / nodejs (push) Successful in 1m8s
repod / release (push) Has been skipped
2024-09-19 08:27:04 +02:00
b002e3bab8 Merge pull request 'chore(deps): update dependency vue to v3.5.6' (#157) from renovate/vue-3.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 8s
repod / php (push) Successful in 41s
repod / nodejs (push) Successful in 1m3s
repod / release (push) Has been skipped
Reviewed-on: #157
2024-09-17 07:15:01 +00:00
d80044934f Merge pull request 'chore(deps): update dependency vite to v5.4.6' (#156) from renovate/vite-5.x-lockfile into main
Some checks failed
repod / nodejs (push) Waiting to run
repod / release (push) Waiting to run
repod / xml (push) Successful in 11s
repod / php (push) Has been cancelled
Reviewed-on: #156
2024-09-17 07:14:28 +00:00
Renovate Bot
4d88f485fb chore(deps): update dependency vue to v3.5.6
All checks were successful
repod / xml (push) Successful in 10s
repod / php (push) Successful in 40s
repod / nodejs (push) Successful in 1m7s
repod / release (push) Has been skipped
2024-09-17 06:34:47 +00:00
Renovate Bot
ae66036a82 chore(deps): update dependency vite to v5.4.6
All checks were successful
repod / xml (push) Successful in 24s
repod / php (push) Successful in 45s
repod / nodejs (push) Successful in 1m9s
repod / release (push) Has been skipped
2024-09-17 06:34:35 +00:00
674f0193db fix: 👷 update makefile to ignore new ts files
All checks were successful
repod / xml (push) Successful in 9s
repod / php (push) Successful in 41s
repod / nodejs (push) Successful in 1m2s
repod / release (push) Successful in 1m15s
2024-09-15 15:47:18 +02:00
ccc903be97 docs: 📝 better wording (#137)
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 40s
repod / nodejs (push) Successful in 1m3s
repod / release (push) Has been skipped
2024-09-15 15:41:30 +02:00
10c7a1f907 docs: 📝 add other app listing (#137)
All checks were successful
repod / xml (push) Successful in 13s
repod / php (push) Successful in 46s
repod / nodejs (push) Successful in 1m15s
repod / release (push) Has been skipped
2024-09-15 15:36:25 +02:00
a6ab9c69d9 chore: 📝 update changelog
All checks were successful
repod / xml (push) Successful in 15s
repod / php (push) Successful in 46s
repod / nodejs (push) Successful in 1m10s
repod / release (push) Has been skipped
2024-09-15 15:28:52 +02:00
285e9f7dfb chore: 🔖 update version
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 41s
repod / nodejs (push) Successful in 1m6s
repod / release (push) Has been skipped
2024-09-15 15:07:47 +02:00
60fc620b79 fix: 📝 update first impressions (fix #137)
Some checks failed
repod / release (push) Waiting to run
repod / xml (push) Successful in 20s
repod / php (push) Successful in 44s
repod / nodejs (push) Has been cancelled
2024-09-15 15:06:00 +02:00
5588bb93e3 fix: 💄 add margin to make favorites more spaced
All checks were successful
repod / xml (push) Successful in 1m45s
repod / php (push) Successful in 52s
repod / nodejs (push) Successful in 1m43s
repod / release (push) Has been skipped
2024-09-15 14:34:13 +02:00
b97d4487bb fix: 🧑‍💻 fix sourcemap crashing on watch by disabling sourcemap entierly 2024-09-15 14:33:37 +02:00
29c29cdfdd Merge pull request 'typescript #149' (#152) from typescript into main
All checks were successful
repod / xml (push) Successful in 12s
repod / php (push) Successful in 38s
repod / nodejs (push) Successful in 1m0s
repod / release (push) Has been skipped
Reviewed-on: #152
2024-09-14 15:26:16 +00:00
d7c3b87d8d chore: ⬆️ update locks
All checks were successful
repod / xml (push) Successful in 10s
repod / php (push) Successful in 35s
repod / nodejs (push) Successful in 57s
repod / release (push) Has been skipped
2024-09-14 17:14:49 +02:00
9fa48c2da3 fix: 📱 fix subscribe button to the right
Some checks failed
repod / xml (push) Successful in 7s
repod / php (push) Failing after 19s
repod / nodejs (push) Successful in 50s
repod / release (push) Has been skipped
2024-09-14 17:11:11 +02:00
3cea8d3505 fix: 🎨 improve small tips 2024-09-14 17:11:11 +02:00
23280d68b9 fix: 🐛 fix all small bugs 2024-09-14 17:11:11 +02:00
1e1bb03c23 chore: ⬆️ update locks 2024-09-14 17:11:11 +02:00
fc86f62d93 refactor: ♻️ typescript ok, need tests 2024-09-14 17:10:56 +02:00
83e3358e9b refactor: 🚧 still working on typescript conversion 2024-09-14 17:10:56 +02:00
38bc986bb3 refactor: 🚧 introducing typescript (not working now) 2024-09-14 17:10:46 +02:00
eae106e72b Merge pull request 'chore(deps): update dependency vue to v3.5.5' (#154) from renovate/vue-3.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 9s
repod / php (push) Successful in 39s
repod / nodejs (push) Successful in 54s
repod / release (push) Has been skipped
Reviewed-on: #154
2024-09-14 09:12:54 +00:00
3c358a3c5c Merge pull request 'chore(deps): update dependency vite to v5.4.5' (#153) from renovate/vite-5.x-lockfile into main
Some checks are pending
repod / xml (push) Waiting to run
repod / php (push) Waiting to run
repod / nodejs (push) Waiting to run
repod / release (push) Waiting to run
Reviewed-on: #153
2024-09-14 09:12:48 +00:00
Renovate Bot
79ee855f9b chore(deps): update dependency vue to v3.5.5
All checks were successful
repod / xml (push) Successful in 7s
repod / php (push) Successful in 37s
repod / nodejs (push) Successful in 43s
repod / release (push) Has been skipped
2024-09-14 06:57:27 +00:00
Renovate Bot
5150cb6501 chore(deps): update dependency vite to v5.4.5
All checks were successful
repod / xml (push) Successful in 1m4s
repod / php (push) Successful in 42s
repod / nodejs (push) Successful in 53s
repod / release (push) Has been skipped
2024-09-14 06:57:16 +00:00
1d85811ad3 Merge pull request 'chore(deps): update dependency nextcloud/ocp to v29.0.7' (#150) from renovate/nextcloud-ocp-29.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 8s
repod / php (push) Successful in 49s
repod / nodejs (push) Successful in 55s
repod / release (push) Has been skipped
Reviewed-on: #150
2024-09-13 07:32:52 +00:00
872b0ced0a Merge pull request 'chore(deps): update dependency vue-router to v4.4.5' (#151) from renovate/vue-router-4.x-lockfile into main
Some checks failed
repod / nodejs (push) Waiting to run
repod / release (push) Waiting to run
repod / xml (push) Successful in 15s
repod / php (push) Has been cancelled
Reviewed-on: #151
2024-09-13 07:32:30 +00:00
Renovate Bot
2a280c3493 chore(deps): update dependency vue-router to v4.4.5
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 46s
repod / nodejs (push) Successful in 51s
repod / release (push) Has been skipped
2024-09-13 06:56:37 +00:00
Renovate Bot
c9f922b31d chore(deps): update dependency nextcloud/ocp to v29.0.7
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 51s
repod / nodejs (push) Successful in 57s
repod / release (push) Has been skipped
2024-09-13 06:56:20 +00:00
c983ab8d3b fix: disable iife and build with inlineCSS enable
All checks were successful
repod / xml (push) Successful in 27s
repod / php (push) Successful in 55s
repod / nodejs (push) Successful in 1m2s
repod / release (push) Has been skipped
2024-09-12 22:10:10 +02:00
4f0685ccbd Merge pull request 'chore(deps): update dependency vite to v5.4.4' (#147) from renovate/vite-5.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 1m29s
repod / php (push) Successful in 57s
repod / nodejs (push) Successful in 1m13s
repod / release (push) Has been skipped
Reviewed-on: #147
2024-09-12 13:40:56 +00:00
e165a070c8 Merge pull request 'chore(deps): update dependency vite-plugin-vue-devtools to v7.4.5' (#148) from renovate/vite-plugin-vue-devtools-7.x-lockfile into main
Some checks failed
repod / php (push) Waiting to run
repod / nodejs (push) Waiting to run
repod / release (push) Waiting to run
repod / xml (push) Has been cancelled
Reviewed-on: #148
2024-09-12 13:40:48 +00:00
Renovate Bot
622f5ec635 chore(deps): update dependency vite-plugin-vue-devtools to v7.4.5
All checks were successful
repod / xml (push) Successful in 12s
repod / php (push) Successful in 47s
repod / nodejs (push) Successful in 54s
repod / release (push) Has been skipped
2024-09-12 06:51:56 +00:00
Renovate Bot
7d64e3370c chore(deps): update dependency vite to v5.4.4
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 57s
repod / nodejs (push) Successful in 1m8s
repod / release (push) Has been skipped
2024-09-12 06:51:39 +00:00
fcf99e5bbf chore: ⬆️ update locks
All checks were successful
repod / xml (push) Successful in 10s
repod / php (push) Successful in 52s
repod / nodejs (push) Successful in 1m4s
repod / release (push) Has been skipped
2024-09-11 09:12:59 +02:00
924106202a docs: 📝 Add Cardo to list of compatible clients 2024-09-11 09:09:07 +02:00
ce2412fb01 Merge pull request 'chore(deps): update dependency vue-router to v4.4.4' (#146) from renovate/vue-router-4.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 9s
repod / php (push) Successful in 55s
repod / nodejs (push) Successful in 1m0s
repod / release (push) Has been skipped
Reviewed-on: #146
2024-09-11 07:06:40 +00:00
6c348d5583 Merge pull request 'chore(deps): update dependency vue to v3.5.4' (#145) from renovate/vue-3.x-lockfile into main
Some checks failed
repod / php (push) Waiting to run
repod / nodejs (push) Waiting to run
repod / release (push) Waiting to run
repod / xml (push) Has been cancelled
Reviewed-on: #145
2024-09-11 07:06:25 +00:00
Renovate Bot
7eef3ceaf0 chore(deps): update dependency vue-router to v4.4.4
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 53s
repod / nodejs (push) Successful in 56s
repod / release (push) Has been skipped
2024-09-11 06:36:34 +00:00
Renovate Bot
5321c0a3bf chore(deps): update dependency vue to v3.5.4
All checks were successful
repod / xml (push) Successful in 1m32s
repod / php (push) Successful in 58s
repod / nodejs (push) Successful in 1m42s
repod / release (push) Has been skipped
2024-09-11 06:36:19 +00:00
fe40b7c9f7 Merge pull request 'chore(deps): update dependency vimeo/psalm to v5.26.1' (#144) from renovate/vimeo-psalm-5.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 13s
repod / php (push) Successful in 56s
repod / nodejs (push) Successful in 1m3s
repod / release (push) Has been skipped
Reviewed-on: #144
2024-09-10 07:14:57 +00:00
Renovate Bot
11a1db72c6 chore(deps): update dependency vimeo/psalm to v5.26.1
All checks were successful
repod / xml (push) Successful in 16s
repod / php (push) Successful in 1m3s
repod / nodejs (push) Successful in 1m15s
repod / release (push) Has been skipped
2024-09-10 06:43:50 +00:00
7f00696140 Merge pull request 'chore(deps): update dependency vimeo/psalm to v5.26.0' (#143) from renovate/vimeo-psalm-5.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 24s
repod / php (push) Successful in 58s
repod / nodejs (push) Successful in 1m15s
repod / release (push) Has been skipped
Reviewed-on: #143
2024-09-09 08:52:40 +00:00
Renovate Bot
33dcbe9162 chore(deps): update dependency vimeo/psalm to v5.26.0
All checks were successful
repod / xml (push) Successful in 1m46s
repod / php (push) Successful in 1m2s
repod / nodejs (push) Successful in 1m45s
repod / release (push) Has been skipped
2024-09-09 06:49:32 +00:00
5c6542e60c Merge pull request 'chore(deps): update dependency vue to v3.5.3' (#142) from renovate/vue-3.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 55s
repod / nodejs (push) Successful in 1m10s
repod / release (push) Has been skipped
Reviewed-on: #142
2024-09-06 07:13:09 +00:00
Renovate Bot
ea6704c537 chore(deps): update dependency vue to v3.5.3
All checks were successful
repod / xml (push) Successful in 1m30s
repod / php (push) Successful in 59s
repod / nodejs (push) Successful in 1m35s
repod / release (push) Has been skipped
2024-09-06 06:49:43 +00:00
df4ac80554 Merge pull request 'chore(deps): update dependency vite-plugin-vue-devtools to v7.4.4' (#140) from renovate/vite-plugin-vue-devtools-7.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 10s
repod / php (push) Successful in 57s
repod / nodejs (push) Successful in 1m10s
repod / release (push) Has been skipped
Reviewed-on: #140
2024-09-05 07:08:30 +00:00
2b2ab2af8f Merge pull request 'chore(deps): update dependency vue to v3.5.1' (#141) from renovate/vue-3.x-lockfile into main
Some checks failed
repod / php (push) Waiting to run
repod / nodejs (push) Waiting to run
repod / release (push) Waiting to run
repod / xml (push) Has been cancelled
Reviewed-on: #141
2024-09-05 07:08:19 +00:00
Renovate Bot
7b00eb22ff chore(deps): update dependency vue to v3.5.1
All checks were successful
repod / xml (push) Successful in 12s
repod / php (push) Successful in 53s
repod / nodejs (push) Successful in 1m0s
repod / release (push) Has been skipped
2024-09-05 06:31:41 +00:00
Renovate Bot
ecee6ff2a8 chore(deps): update dependency vite-plugin-vue-devtools to v7.4.4
All checks were successful
repod / xml (push) Successful in 26s
repod / php (push) Successful in 55s
repod / nodejs (push) Successful in 1m8s
repod / release (push) Has been skipped
2024-09-05 06:31:31 +00:00
57a22d9390 chore: ⬆️ update lock
All checks were successful
repod / xml (push) Successful in 12s
repod / php (push) Successful in 58s
repod / nodejs (push) Successful in 1m2s
repod / release (push) Has been skipped
2024-09-04 10:48:22 +02:00
42c35d3856 Merge pull request 'chore(deps): update dependency vite to v5.4.3' (#139) from renovate/vite-5.x-lockfile into main
All checks were successful
repod / xml (push) Successful in 1m54s
repod / php (push) Successful in 1m38s
repod / nodejs (push) Successful in 1m50s
repod / release (push) Has been skipped
Reviewed-on: #139
2024-09-04 08:41:03 +00:00
4d199bc02b Merge pull request 'chore(deps): update dependency nextcloud/ocp to v29.0.6' (#138) from renovate/nextcloud-ocp-29.x-lockfile into main
Some checks failed
repod / php (push) Waiting to run
repod / nodejs (push) Waiting to run
repod / release (push) Waiting to run
repod / xml (push) Has been cancelled
Reviewed-on: #138
2024-09-04 08:40:23 +00:00
Renovate Bot
8a89cc06cd chore(deps): update dependency vite to v5.4.3
All checks were successful
repod / xml (push) Successful in 12s
repod / php (push) Successful in 56s
repod / nodejs (push) Successful in 53s
repod / release (push) Has been skipped
2024-09-04 06:59:04 +00:00
Renovate Bot
03740231c5 chore(deps): update dependency nextcloud/ocp to v29.0.6
All checks were successful
repod / xml (push) Successful in 36s
repod / php (push) Successful in 58s
repod / nodejs (push) Successful in 1m1s
repod / release (push) Has been skipped
2024-09-04 06:58:41 +00:00
b54ab2be91 style: 💩 leverage the available space between the episode title and the play button (but hacky way) fix #59
All checks were successful
repod / xml (push) Successful in 26s
repod / php (push) Successful in 59s
repod / nodejs (push) Successful in 1m4s
repod / release (push) Has been skipped
2024-09-03 16:12:11 +02:00
d1658a9408 chore: ⬆️ update locks
All checks were successful
repod / xml (push) Successful in 30s
repod / php (push) Successful in 59s
repod / nodejs (push) Successful in 1m6s
repod / release (push) Has been skipped
2024-09-03 14:44:19 +02:00
1eb8b35501 refactor: 🎨 cleanup some old css class
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 55s
repod / nodejs (push) Successful in 59s
repod / release (push) Has been skipped
2024-09-02 15:54:21 +02:00
fb7780fead fix: 🐛 the #list slot breaks navigation on AppContent
All checks were successful
repod / xml (push) Successful in 22s
repod / php (push) Successful in 54s
repod / nodejs (push) Successful in 1m2s
repod / release (push) Has been skipped
2024-09-02 15:35:10 +02:00
19c56ef31d fix: 🔨 move vite dev to main
All checks were successful
repod / xml (push) Successful in 19s
repod / php (push) Successful in 51s
repod / nodejs (push) Successful in 1m4s
repod / release (push) Has been skipped
2024-09-02 14:43:39 +02:00
2bad1852d7 refactor: 🩹 use same condition system on all App atoms
All checks were successful
repod / xml (push) Successful in 11s
repod / php (push) Successful in 50s
repod / nodejs (push) Successful in 59s
repod / release (push) Has been skipped
2024-09-02 14:13:57 +02:00
0302489924 fix: 🏗️ add missing slots on atoms
All checks were successful
repod / xml (push) Successful in 21s
repod / php (push) Successful in 53s
repod / nodejs (push) Successful in 1m1s
repod / release (push) Has been skipped
2024-09-02 14:06:43 +02:00
81cb6a0191 fix: 💄 fix missing icon on empty contents
All checks were successful
repod / xml (push) Successful in 21s
repod / php (push) Successful in 53s
repod / nodejs (push) Successful in 1m10s
repod / release (push) Has been skipped
2024-09-02 12:37:55 +02:00
80 changed files with 1729 additions and 2236 deletions

View File

@ -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',

View File

@ -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

View File

@ -1,4 +1,19 @@
## 3.1.0 - 2024-09-02 ## 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 ### Added
- ⭐ You can now add favorites subscriptions ! - ⭐ You can now add favorites subscriptions !
@ -13,7 +28,7 @@ It will show's up on the homepage instead of the recommendations witch appear on
[#136](https://git.crystalyx.net/Xefir/repod/issues/136) reported by @randomuser1967 [#136](https://git.crystalyx.net/Xefir/repod/issues/136) reported by @randomuser1967
- ⚡ Improve the detection off mis-installed or mis-enabled gpodder app - ⚡ Improve the detection off mis-installed or mis-enabled gpodder app
## 3.0.0 - 2024-08-17 ## 3.0.0 - What a vue - 2024-08-17
### Added ### Added
- 🌐 Add german translation - 🌐 Add german translation
@ -31,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
@ -40,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
@ -68,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
@ -85,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
@ -99,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
@ -116,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
@ -140,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
@ -160,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
@ -168,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
@ -178,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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.1.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>

View File

@ -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.5", "nextcloud/ocp": "^30.0.0",
"roave/security-advisories": "dev-latest", "roave/security-advisories": "dev-latest",
"nextcloud/coding-standard": "^1.2.3", "nextcloud/coding-standard": "^1.3.0",
"vimeo/psalm": "^5.25.0" "vimeo/psalm": "^5.26.1"
}, },
"config": { "config": {
"optimize-autoloader": true, "optimize-autoloader": true,

355
composer.lock generated
View File

@ -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": "a59841dc91b50fc36ec116bab55543b0", "content-hash": "ca2a3728cd9506c5cdac4ebc3e57acb3",
"packages": [], "packages": [],
"packages-dev": [ "packages-dev": [
{ {
@ -169,16 +169,16 @@
}, },
{ {
"name": "composer/pcre", "name": "composer/pcre",
"version": "3.3.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": "1637e067347a0c40bbb1e3cd786b20dcab556a81" "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/1637e067347a0c40bbb1e3cd786b20dcab556a81", "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4",
"reference": "1637e067347a0c40bbb1e3cd786b20dcab556a81", "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -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.3.0" "source": "https://github.com/composer/pcre/tree/3.3.1"
}, },
"funding": [ "funding": [
{ {
@ -244,7 +244,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-08-19T19:43:53+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.3", "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": "bc9c53a5306114b60c4363057aff9c2ed10a54da" "reference": "e2e6cb1518e3d56ebfb2365bb9fa91ecb50a374c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/bc9c53a5306114b60c4363057aff9c2ed10a54da", "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/e2e6cb1518e3d56ebfb2365bb9fa91ecb50a374c",
"reference": "bc9c53a5306114b60c4363057aff9c2ed10a54da", "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.3" "source": "https://github.com/nextcloud/coding-standard/tree/v1.3.0"
}, },
"time": "2024-08-23T14:32:32+00:00" "time": "2024-09-18T15:52:45+00:00"
}, },
{ {
"name": "nextcloud/ocp", "name": "nextcloud/ocp",
"version": "v29.0.5", "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": "53059f1bbcdd624fa1783591da5575faa4284d15" "reference": "a26b4e1f75983f359bd835c2529ce37b5599d58f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/53059f1bbcdd624fa1783591da5575faa4284d15", "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/a26b4e1f75983f359bd835c2529ce37b5599d58f",
"reference": "53059f1bbcdd624fa1783591da5575faa4284d15", "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.5" "source": "https://github.com/nextcloud-deps/ocp/tree/v30.0.0"
}, },
"time": "2024-08-09T00:38:21+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": "f8de2a81061775002d96aea80b12f2ab3c5eeb8d" "reference": "22aca9a3467be44288882a3bcf7f2865abe08ca3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/f8de2a81061775002d96aea80b12f2ab3c5eeb8d", "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/22aca9a3467be44288882a3bcf7f2865abe08ca3",
"reference": "f8de2a81061775002d96aea80b12f2ab3c5eeb8d", "reference": "22aca9a3467be44288882a3bcf7f2865abe08ca3",
"shasum": "" "shasum": ""
}, },
"conflict": { "conflict": {
@ -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",
@ -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-23T19:04:38+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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -26,7 +26,7 @@ class PageController extends Controller
* @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('*');

2538
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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,19 +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.2", "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.4.1", "eslint-plugin-pinia": "^0.4.1",
"eslint-plugin-prettier": "^5.2.1", "eslint-plugin-prettier": "^5.2.1",
"vite-plugin-vue-devtools": "^7.3.9" "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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

After

Width:  |  Height:  |  Size: 857 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 KiB

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 817 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

After

Width:  |  Height:  |  Size: 961 KiB

View File

@ -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',

View File

@ -4,10 +4,10 @@
</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',

View File

@ -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>

View File

@ -1,10 +1,22 @@
<template> <template>
<NcEmptyContent class="empty"> <NcEmptyContent class="empty">
<slot /> <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> </NcEmptyContent>
</template> </template>
<script> <script lang="ts">
import { NcEmptyContent } from '@nextcloud/vue' import { NcEmptyContent } from '@nextcloud/vue'
export default { export default {

View File

@ -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 {

View File

@ -6,7 +6,7 @@
:size="256" :size="256"
:url="episode.image" /> :url="episode.image" />
<h2>{{ episode.name }}</h2> <h2>{{ episode.name }}</h2>
<SafeHtml :source="episode.description" /> <SafeHtml :source="episode.description || ''" />
<div class="flex"> <div class="flex">
<NcButton v-if="episode.link" :href="episode.link" target="_blank"> <NcButton v-if="episode.link" :href="episode.link" target="_blank">
<template #icon> <template #icon>
@ -29,13 +29,15 @@
</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',
@ -48,13 +50,14 @@ export default {
}, },
props: { props: {
episode: { episode: {
type: Object, type: Object as () => EpisodeInterface,
required: true, required: true,
}, },
}, },
methods: { methods: {
filenameFromUrl, filenameFromUrl,
humanFileSize, humanFileSize,
t,
}, },
} }
</script> </script>

View File

@ -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'

View File

@ -1,5 +1,5 @@
<template> <template>
<NcAppNavigationList> <NcAppNavigationList class="list">
<NcAppNavigationNewItem <NcAppNavigationNewItem
:name="t('repod', 'Add a RSS link')" :name="t('repod', 'Add a RSS link')"
@new-item="(url) => $router.push(toFeedUrl(url))"> @new-item="(url) => $router.push(toFeedUrl(url))">
@ -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 { toFeedUrl } from '../../utils/url.js' import { t } from '@nextcloud/l10n'
import { toFeedUrl } from '../../utils/url.ts'
export default { export default {
name: 'AddRss', name: 'AddRss',
@ -23,13 +24,14 @@ export default {
PlusIcon, PlusIcon,
}, },
methods: { methods: {
t,
toFeedUrl, toFeedUrl,
}, },
} }
</script> </script>
<style scoped> <style scoped>
ul { .list {
margin-top: 2rem; margin-top: 2rem;
} }
</style> </style>

View File

@ -19,7 +19,7 @@
</template> </template>
<template #actions> <template #actions>
<NcActionButton <NcActionButton
v-if="!getSubscriptions.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 { toFeedUrl } 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',
@ -63,22 +64,27 @@ export default {
}, },
}, },
data: () => ({ data: () => ({
feeds: [], feeds: [] as PodcastDataInterface[],
loading: false, loading: false,
timeout: null as NodeJS.Timeout | null,
}), }),
computed: { computed: {
...mapState(useSubscriptions, ['getSubscriptions']), ...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,
t,
toFeedUrl, toFeedUrl,
async addSubscription(url) { async addSubscription(url: string) {
try { try {
await axios.post( await axios.post(
generateUrl('/apps/gpoddersync/subscription_change/create'), generateUrl('/apps/gpoddersync/subscription_change/create'),
@ -91,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,
}), }),
@ -116,7 +121,7 @@ export default {
this.loading = false this.loading = false
} }
} }
}, 200), },
}, },
} }
</script> </script>

View File

@ -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 { toFeedUrl } from '../../utils/url.js' import { t } from '@nextcloud/l10n'
import { toFeedUrl } from '../../utils/url.ts'
export default { export default {
name: 'Toplist', name: 'Toplist',
@ -32,7 +34,7 @@ export default {
}, },
data: () => ({ data: () => ({
loading: true, loading: true,
tops: [], tops: [] as PodcastDataInterface[],
}), }),
computed: { computed: {
title() { title() {
@ -49,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) {

View File

@ -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="!getSubscriptions.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, ['getSubscriptions']), ...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) {

View File

@ -1,7 +1,12 @@
<template> <template>
<NcListItem <NcListItem
:active="isCurrentEpisode(episode)" :active="isCurrentEpisode(episode)"
:details="!oneLine ? formatLocaleDate(new Date(episode.pubDate?.date)) : ''" class="episode"
:details="
!oneLine && episode.pubDate
? formatLocaleDate(new Date(episode.pubDate?.date))
: ''
"
:force-display-actions="true" :force-display-actions="true"
:name="episode.name" :name="episode.name"
:one-line="oneLine" :one-line="oneLine"
@ -77,17 +82,17 @@
</template> </template>
<template #indicator> <template #indicator>
<NcProgressBar <NcProgressBar
v-if="isListening(episode) && !oneLine" v-if="episode.action && isListening(episode) && !oneLine"
class="progress" class="progress"
:value="(episode.action.position * 100) / episode.action.total" /> :value="(episode.action.position * 100) / episode.action.total" />
</template> </template>
<template v-if="!oneLine" #subname> <template #subname>
{{ episode.duration }} {{ episode.duration }}
</template> </template>
</NcListItem> </NcListItem>
</template> </template>
<script> <script lang="ts">
import { import {
NcActionButton, NcActionButton,
NcActionLink, NcActionLink,
@ -101,10 +106,11 @@ import {
durationToSeconds, durationToSeconds,
formatEpisodeTimestamp, formatEpisodeTimestamp,
formatLocaleDate, formatLocaleDate,
} from '../../utils/time.js' } from '../../utils/time.ts'
import { hasEnded, isListening } from '../../utils/status.js' import { hasEnded, isListening } from '../../utils/status.ts'
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
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 Modal from '../Atoms/Modal.vue' import Modal from '../Atoms/Modal.vue'
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue' import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
import PlayIcon from 'vue-material-design-icons/Play.vue' import PlayIcon from 'vue-material-design-icons/Play.vue'
@ -112,10 +118,11 @@ import PlaylistPlayIcon from 'vue-material-design-icons/PlaylistPlay.vue'
import PlaylistRemoveIcon from 'vue-material-design-icons/PlaylistRemove.vue' import PlaylistRemoveIcon from 'vue-material-design-icons/PlaylistRemove.vue'
import StopIcon from 'vue-material-design-icons/Stop.vue' import StopIcon from 'vue-material-design-icons/Stop.vue'
import axios from '@nextcloud/axios' import axios from '@nextcloud/axios'
import { filenameFromUrl } from '../../utils/url.js' import { filenameFromUrl } from '../../utils/url.ts'
import { generateUrl } from '@nextcloud/router' import { generateUrl } from '@nextcloud/router'
import { showError } from '../../utils/toast.js' import { showError } from '../../utils/toast.ts'
import { usePlayer } from '../../store/player.js' import { t } from '@nextcloud/l10n'
import { usePlayer } from '../../store/player.ts'
export default { export default {
name: 'Episode', name: 'Episode',
@ -137,7 +144,7 @@ export default {
}, },
props: { props: {
episode: { episode: {
type: Object, type: Object as () => EpisodeInterface,
required: true, required: true,
}, },
oneLine: { oneLine: {
@ -151,21 +158,22 @@ export default {
}, },
data: () => ({ data: () => ({
loading: false, loading: false,
modalEpisode: null, modalEpisode: null as EpisodeInterface | null,
}), }),
computed: { computed: {
...mapState(usePlayer, { playerEpisode: 'episode' }), ...mapState(usePlayer, { playerEpisode: 'episode' }),
}, },
methods: { methods: {
...mapActions(usePlayer, ['load']), ...mapActions(usePlayer, ['load']),
filenameFromUrl,
formatLocaleDate, formatLocaleDate,
hasEnded, hasEnded,
isListening, isListening,
filenameFromUrl, t,
isCurrentEpisode(episode) { isCurrentEpisode(episode: EpisodeInterface) {
return this.playerEpisode?.url === episode.url return this.playerEpisode?.url === episode.url
}, },
async markAs(episode, read) { async markAs(episode: EpisodeInterface, read: boolean) {
try { try {
this.loading = true this.loading = true
episode.action = { episode.action = {
@ -175,8 +183,8 @@ export default {
action: 'play', action: 'play',
timestamp: formatEpisodeTimestamp(new Date()), timestamp: formatEpisodeTimestamp(new Date()),
started: episode.action?.started || 0, started: episode.action?.started || 0,
position: read ? durationToSeconds(episode.duration) : 0, position: read ? durationToSeconds(episode.duration || '') : 0,
total: durationToSeconds(episode.duration), total: durationToSeconds(episode.duration || ''),
} }
await axios.post( await axios.post(
generateUrl('/apps/gpoddersync/episode_action/create'), generateUrl('/apps/gpoddersync/episode_action/create'),
@ -201,3 +209,14 @@ export default {
margin-top: 0.4rem; margin-top: 0.4rem;
} }
</style> </style>
<style>
.episode .list-item-content__name {
max-width: 100%;
}
.episode .list-item-content__subname {
flex-basis: auto;
flex-grow: 0;
}
</style>

View File

@ -11,17 +11,19 @@
</div> </div>
</template> </template>
<script> <script lang="ts">
import { hasEnded, isListening } from '../../utils/status.js' import { hasEnded, isListening } from '../../utils/status.ts'
import Episode from './Episode.vue' import Episode from './Episode.vue'
import type { EpisodeInterface } from '../../utils/types.ts'
import Loading from '../Atoms/Loading.vue' import Loading from '../Atoms/Loading.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 { mapState } from 'pinia' import { mapState } from 'pinia'
import { showError } from '../../utils/toast.js' import { showError } from '../../utils/toast.ts'
import { usePlayer } from '../../store/player.js' import { t } from '@nextcloud/l10n'
import { useSettings } from '../../store/settings.js' import { usePlayer } from '../../store/player.ts'
import { useSettings } from '../../store/settings.ts'
export default { export default {
name: 'Episodes', name: 'Episodes',
@ -30,7 +32,7 @@ export default {
Loading, Loading,
}, },
data: () => ({ data: () => ({
episodes: [], episodes: [] as EpisodeInterface[],
loading: true, loading: true,
}), }),
computed: { computed: {
@ -41,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,
) )
} }
}, },
@ -69,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)

View File

@ -1,15 +1,15 @@
<template> <template>
<NcGuestContent class="guest"> <NcGuestContent class="guest">
<Loading v-if="!currentFavoriteData" /> <Loading v-if="!feed.data" />
<NcAvatar <NcAvatar
v-if="currentFavoriteData" v-if="feed.data"
class="avatar" class="avatar"
:display-name="currentFavoriteData.author || currentFavoriteData.title" :display-name="feed.data.author || feed.data.title"
:is-no-user="true" :is-no-user="true"
:size="222" :size="222"
:url="currentFavoriteData.imageUrl" /> :url="feed.data.imageUrl" />
<div class="list"> <div v-if="feed.data" class="list">
<h2 class="title">{{ currentFavoriteData.title }}</h2> <h2 class="title">{{ feed.data.title }}</h2>
<Loading v-if="loading" /> <Loading v-if="loading" />
<ul v-if="!loading"> <ul v-if="!loading">
<Episode <Episode
@ -17,25 +17,25 @@
:key="episode.guid" :key="episode.guid"
:episode="episode" :episode="episode"
:one-line="true" :one-line="true"
:url="url" /> :url="feed.metrics.url" />
</ul> </ul>
</div> </div>
</NcGuestContent> </NcGuestContent>
</template> </template>
<script> <script lang="ts">
import type { EpisodeInterface, SubscriptionInterface } from '../../utils/types.ts'
import { NcAvatar, NcGuestContent } from '@nextcloud/vue' import { NcAvatar, NcGuestContent } from '@nextcloud/vue'
import Episode from './Episode.vue' import Episode from './Episode.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 { hasEnded } from '../../utils/status.js' import { hasEnded } from '../../utils/status.ts'
import { mapState } from 'pinia' import { showError } from '../../utils/toast.ts'
import { showError } from '../../utils/toast.js' import { t } from '@nextcloud/l10n'
import { useSubscriptions } from '../../store/subscriptions.js'
export default { export default {
name: 'Favorites', name: 'Favorite',
components: { components: {
Episode, Episode,
Loading, Loading,
@ -43,32 +43,28 @@ export default {
NcGuestContent, NcGuestContent,
}, },
props: { props: {
url: { feed: {
type: String, type: Object as () => SubscriptionInterface,
required: true, required: true,
}, },
}, },
data: () => ({ data: () => ({
episodes: [], episodes: [] as EpisodeInterface[],
loading: true, loading: true,
}), }),
computed: {
...mapState(useSubscriptions, ['getFavorites']),
currentFavoriteData() {
return this.getFavorites.find((fav) => fav.url === this.url)
},
},
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.feed.metrics.url,
}), }),
) )
this.episodes = [...episodes.data] this.episodes = [...episodes.data]
.sort( .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(),
) )
.filter((episode) => !this.hasEnded(episode)) .filter((episode) => !this.hasEnded(episode))
.slice(0, 4) .slice(0, 4)
@ -90,6 +86,7 @@ export default {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 1rem; gap: 1rem;
margin: 20px !important;
} }
.list { .list {

View File

@ -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',

View File

@ -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',

View File

@ -1,5 +1,5 @@
<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>
@ -12,12 +12,12 @@
</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 { toFeedUrl } 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',

View File

@ -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',

View File

@ -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;

View File

@ -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',

View File

@ -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>

View File

@ -39,12 +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 { useSettings } from '../../store/settings.js' import { t } from '@nextcloud/l10n'
import { useSettings } from '../../store/settings.ts'
export default { export default {
name: 'Filters', name: 'Filters',
@ -66,6 +67,7 @@ export default {
}, },
methods: { methods: {
...mapActions(useSettings, ['setFilters']), ...mapActions(useSettings, ['setFilters']),
t,
}, },
} }
</script> </script>

View File

@ -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',
@ -50,11 +51,13 @@ export default {
}), }),
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 {

View File

@ -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>

View File

@ -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'

View File

@ -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)
}, },
}, },

View File

@ -1,18 +1,18 @@
<template> <template>
<NcAppNavigationItem <NcAppNavigationItem
:loading="loading" :loading="loading"
:name="feed ? feed.title : url" :name="feed?.data?.title || url"
:to="toFeedUrl(url)"> :to="toFeedUrl(url)">
<template #actions> <template #actions>
<NcActionButton <NcActionButton
:aria-label="t('repod', 'Favorite')" :aria-label="t('repod', 'Favorite')"
:model-value="isFavorite" :model-value="feed?.isFavorite"
:name="t('repod', 'Favorite')" :name="t('repod', 'Favorite')"
:title="t('repod', 'Favorite')" :title="t('repod', 'Favorite')"
@update:modelValue="switchFavorite($event)"> @update:modelValue="switchFavorite($event)">
<template #icon> <template #icon>
<StarPlusIcon v-if="!isFavorite" :size="20" /> <StarPlusIcon v-if="!feed?.isFavorite" :size="20" />
<StarRemoveIcon v-if="isFavorite" :size="20" /> <StarRemoveIcon v-if="feed?.isFavorite" :size="20" />
</template> </template>
</NcActionButton> </NcActionButton>
<NcActionButton <NcActionButton
@ -27,29 +27,30 @@
</template> </template>
<template #icon> <template #icon>
<NcAvatar <NcAvatar
v-if="feed" :display-name="feed?.data?.author || feed?.data?.title"
:display-name="feed.author || feed.title"
:is-no-user="true" :is-no-user="true"
:url="feed.imageUrl" /> :url="feed?.data?.imageUrl" />
<StarIcon v-if="feed && isFavorite" class="star" :size="20" /> <StarIcon v-if="feed?.isFavorite" class="star" :size="20" />
<AlertIcon v-if="failed" /> <AlertIcon v-if="failed" />
</template> </template>
</NcAppNavigationItem> </NcAppNavigationItem>
</template> </template>
<script> <script lang="ts">
import { NcActionButton, NcAppNavigationItem, NcAvatar } from '@nextcloud/vue' import { NcActionButton, NcAppNavigationItem, NcAvatar } from '@nextcloud/vue'
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import AlertIcon from 'vue-material-design-icons/Alert.vue' import AlertIcon from 'vue-material-design-icons/Alert.vue'
import DeleteIcon from 'vue-material-design-icons/Delete.vue' import DeleteIcon from 'vue-material-design-icons/Delete.vue'
import type { PersonalSettingsPodcastDataInterface } from '../../utils/types.ts'
import StarIcon from 'vue-material-design-icons/Star.vue' import StarIcon from 'vue-material-design-icons/Star.vue'
import StarPlusIcon from 'vue-material-design-icons/StarPlus.vue' import StarPlusIcon from 'vue-material-design-icons/StarPlus.vue'
import StarRemoveIcon from 'vue-material-design-icons/StarRemove.vue' import StarRemoveIcon from 'vue-material-design-icons/StarRemove.vue'
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 { toFeedUrl } 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: 'Subscription', name: 'Subscription',
@ -72,26 +73,25 @@ export default {
data: () => ({ data: () => ({
failed: false, failed: false,
loading: true, loading: true,
feed: null,
}), }),
computed: { computed: {
...mapState(useSubscriptions, ['getFavorites']), ...mapState(useSubscriptions, ['subs']),
isFavorite() { feed() {
return this.getFavorites.map((fav) => fav.url).includes(this.url) return this.subs.find((sub) => sub.metrics.url === this.url)
}, },
}, },
async mounted() { async mounted() {
try { try {
const podcastData = await axios.get( const podcastData =
generateUrl( await axios.get<PersonalSettingsPodcastDataInterface>(
'/apps/gpoddersync/personal_settings/podcast_data?url={url}', generateUrl(
{ '/apps/gpoddersync/personal_settings/podcast_data?url={url}',
url: this.url, {
}, url: this.url,
), },
) ),
this.feed = podcastData.data.data )
this.editFavoriteData(this.url, podcastData.data.data) this.addMetadatas(this.url, podcastData.data.data)
} catch (e) { } catch (e) {
this.failed = true this.failed = true
console.error(e) console.error(e)
@ -100,12 +100,8 @@ export default {
} }
}, },
methods: { methods: {
...mapActions(useSubscriptions, [ ...mapActions(useSubscriptions, ['fetch', 'addMetadatas', 'setFavorite']),
'fetch', t,
'addFavorite',
'editFavoriteData',
'removeFavorite',
]),
toFeedUrl, toFeedUrl,
async deleteSubscription() { async deleteSubscription() {
if ( if (
@ -123,23 +119,20 @@ export default {
console.error(e) console.error(e)
showError(t('repod', 'Error while removing the feed')) showError(t('repod', 'Error while removing the feed'))
} finally { } finally {
this.removeFavorite(this.url) this.setFavorite(this.url, false)
this.loading = false this.loading = false
this.fetch() this.fetch()
} }
} }
}, },
switchFavorite(value) { switchFavorite(value: boolean) {
if (value) { if (value) {
if (this.getFavorites.length >= 10) { if (this.subs.filter((sub) => sub.isFavorite).length >= 10) {
showError(t('repod', 'You can only have 10 favorites')) showError(t('repod', 'You can only have 10 favorites'))
return return
} }
this.addFavorite(this.url)
} else {
this.removeFavorite(this.url)
} }
this.setFavorite(this.url, value)
}, },
}, },
} }

View File

@ -12,16 +12,13 @@
<Loading v-if="loading" /> <Loading v-if="loading" />
<NcAppNavigationList v-if="!loading"> <NcAppNavigationList v-if="!loading">
<Subscription <Subscription
v-for="url of getFavorites.map((fav) => fav.url)" v-for="sub of subs.filter((sub) => sub.isFavorite)"
:key="url" :key="sub.metrics.url"
:url="url" /> :url="sub.metrics.url" />
<Subscription <Subscription
v-for="url of getSubscriptions.filter( v-for="sub of subs.filter((sub) => !sub.isFavorite)"
(sub) => :key="sub.metrics.url"
!getFavorites.map((fav) => fav.url).includes(sub), :url="sub.metrics.url" />
)"
:key="url"
:url="url" />
</NcAppNavigationList> </NcAppNavigationList>
</NcAppContentList> </NcAppContentList>
</template> </template>
@ -31,7 +28,7 @@
</AppNavigation> </AppNavigation>
</template> </template>
<script> <script lang="ts">
import { import {
NcAppContentList, NcAppContentList,
NcAppNavigationList, NcAppNavigationList,
@ -43,8 +40,9 @@ 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 Subscription from './Subscription.vue' import Subscription from './Subscription.vue'
import { showError } from '../../utils/toast.js' import { showError } from '../../utils/toast.ts'
import { useSubscriptions } from '../../store/subscriptions.js' import { t } from '@nextcloud/l10n'
import { useSubscriptions } from '../../store/subscriptions.ts'
export default { export default {
name: 'Subscriptions', name: 'Subscriptions',
@ -62,7 +60,7 @@ export default {
loading: true, loading: true,
}), }),
computed: { computed: {
...mapState(useSubscriptions, ['getSubscriptions', 'getFavorites']), ...mapState(useSubscriptions, ['subs']),
}, },
async mounted() { async mounted() {
try { try {
@ -76,6 +74,7 @@ export default {
}, },
methods: { methods: {
...mapActions(useSubscriptions, ['fetch']), ...mapActions(useSubscriptions, ['fetch']),
t,
}, },
} }
</script> </script>

View File

@ -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')

View File

@ -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,16 +30,16 @@ 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,
}), }),
@ -72,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()
}, },
@ -81,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,
@ -91,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
}, },
}, },

View File

@ -1,10 +1,16 @@
import { getCookie, setCookie } from '../utils/cookies.js' import { getCookie, setCookie } from '../utils/cookies.ts'
import type { FiltersInterface } from '../utils/types.ts'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export const useSettings = defineStore('settings', { export const useSettings = defineStore('settings', {
state: () => { state: () => {
try { try {
const filters = JSON.parse(getCookie('repod.filters')) const filters = JSON.parse(getCookie('repod.filters') || '{}') || {}
if (!filters.length) {
throw new Error('Empty cookie')
}
return { return {
filters: { filters: {
listened: filters.listened, listened: filters.listened,
@ -23,7 +29,7 @@ export const useSettings = defineStore('settings', {
} }
}, },
actions: { actions: {
setFilters(filters) { setFilters(filters: Partial<FiltersInterface>) {
this.filters = { ...this.filters, ...filters } this.filters = { ...this.filters, ...filters }
setCookie('repod.filters', JSON.stringify(this.filters), 365) setCookie('repod.filters', JSON.stringify(this.filters), 365)
}, },

View File

@ -1,58 +0,0 @@
import { getCookie, setCookie } from '../utils/cookies.js'
import axios from '@nextcloud/axios'
import { defineStore } from 'pinia'
import { generateUrl } from '@nextcloud/router'
export const useSubscriptions = defineStore('subscriptions', {
state: () => ({
subs: [],
favs: [],
}),
getters: {
getSubscriptions: (state) => {
return state.subs
},
getFavorites: (state) => {
return state.favs
.filter((fav) => state.subs.includes(fav.url))
.sort((fav) => fav.lastPub)
},
},
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.subs = subs.map((sub) => sub.url)
try {
const favs = JSON.parse(getCookie('repod.favorites')) || []
this.favs = favs.map((url) => ({ url }))
} catch {}
},
addFavorite(url) {
this.favs.push({ url })
setCookie(
'repod.favorites',
JSON.stringify(this.favs.map((fav) => fav.url)),
365,
)
},
editFavoriteData(url, data) {
this.favs = this.favs.map((fav) =>
fav.url === url ? { ...fav, ...data } : fav,
)
},
removeFavorite(url) {
this.favs = this.favs.filter((fav) => fav.url !== url)
setCookie(
'repod.favorites',
JSON.stringify(this.favs.map((fav) => fav.url)),
365,
)
},
},
})

View 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,
)
},
},
})

View File

@ -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;`

View File

@ -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)
}
}

View File

@ -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]
) )

View File

@ -1,4 +1,6 @@
export const hasEnded = (episode) => import type { EpisodeInterface } from './types'
export const hasEnded = (episode: EpisodeInterface) =>
episode.action && episode.action &&
episode.action.action && episode.action.action &&
(episode.action.action.toLowerCase() === 'delete' || (episode.action.action.toLowerCase() === 'delete' ||
@ -6,7 +8,7 @@ export const hasEnded = (episode) =>
episode.action.total > 0 && episode.action.total > 0 &&
episode.action.position >= episode.action.total)) episode.action.position >= episode.action.total))
export const isListening = (episode) => export const isListening = (episode: EpisodeInterface) =>
episode.action && episode.action &&
episode.action.action && episode.action.action &&
episode.action.action.toLowerCase() === 'play' && episode.action.action.toLowerCase() === 'play' &&

View File

@ -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

View File

@ -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
View 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
View 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
}

View File

@ -1,7 +0,0 @@
export const encodeUrl = (url) => encodeURIComponent(btoa(url))
export const decodeUrl = (url) => atob(decodeURIComponent(url))
export const toFeedUrl = (url) => `/feed/${encodeUrl(url)}`
export const filenameFromUrl = (str) => {
const url = new URL(str)
return url.pathname.split('/').pop()
}

5
src/utils/url.ts Normal file
View 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()

View File

@ -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',
@ -33,6 +34,9 @@ export default {
data: () => ({ data: () => ({
search: '', search: '',
}), }),
methods: {
t,
},
} }
</script> </script>

View File

@ -1,35 +1,28 @@
<template> <template>
<AppContent> <AppContent>
<Loading v-if="loading" /> <Loading v-if="loading" />
<EmptyContent <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>
</EmptyContent> </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 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 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',
@ -44,16 +37,17 @@ export default {
data: () => ({ data: () => ({
failed: false, failed: false,
loading: true, loading: true,
feed: null, 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
@ -64,11 +58,8 @@ export default {
this.loading = false this.loading = false
} }
}, },
methods: {
t,
},
} }
</script> </script>
<style scoped>
.error {
margin: 2rem;
}
</style>

View File

@ -1,6 +1,6 @@
<template> <template>
<AppContent> <AppContent>
<EmptyContent class="empty" :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') }}
@ -13,12 +13,13 @@
</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 EmptyContent from '../components/Atoms/EmptyContent.vue' import EmptyContent from '../components/Atoms/EmptyContent.vue'
import { NcButton } from '@nextcloud/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',
@ -33,5 +34,8 @@ export default {
return generateUrl('/settings/apps/installed/gpoddersync') return generateUrl('/settings/apps/installed/gpoddersync')
}, },
}, },
methods: {
t,
},
} }
</script> </script>

View File

@ -1,42 +1,48 @@
<template> <template>
<AppContent> <AppContent>
<EmptyContent <EmptyContent
v-if="!getFavorites.length" v-if="!favorites.length"
class="empty"
:description=" :description="
t('repod', 'Pin some subscriptions to see their latest updates') t('repod', 'Pin some subscriptions to see their latest updates')
" "
:name="t('repod', 'No favorites')"> :name="t('repod', 'No favorites')">
<template #icon> <template #icon>
<StarOffIcon :size="20" /> <StarOffIcon />
</template> </template>
</EmptyContent> </EmptyContent>
<ul v-if="getFavorites.length"> <ul v-if="favorites.length">
<li v-for="url in getFavorites.map((fav) => fav.url)" :key="url"> <li v-for="favorite in favorites" :key="favorite.metrics.url">
<Favorites :url="url" /> <Favorite :feed="favorite" />
</li> </li>
</ul> </ul>
</AppContent> </AppContent>
</template> </template>
<script> <script lang="ts">
import AppContent from '../components/Atoms/AppContent.vue' import AppContent from '../components/Atoms/AppContent.vue'
import EmptyContent from '../components/Atoms/EmptyContent.vue' import EmptyContent from '../components/Atoms/EmptyContent.vue'
import Favorites from '../components/Feed/Favorites.vue' import Favorite from '../components/Feed/Favorite.vue'
import StarOffIcon from 'vue-material-design-icons/StarOff.vue' import StarOffIcon from 'vue-material-design-icons/StarOff.vue'
import { mapState } from 'pinia' import { mapState } from 'pinia'
import { useSubscriptions } from '../store/subscriptions.js' import { t } from '@nextcloud/l10n'
import { useSubscriptions } from '../store/subscriptions.ts'
export default { export default {
name: 'Home', name: 'Home',
components: { components: {
AppContent, AppContent,
EmptyContent, EmptyContent,
Favorites, Favorite,
StarOffIcon, StarOffIcon,
}, },
computed: { computed: {
...mapState(useSubscriptions, ['getFavorites']), ...mapState(useSubscriptions, ['subs']),
favorites() {
return this.subs.filter((sub) => sub.isFavorite)
},
},
methods: {
t,
}, },
} }
</script> </script>

View File

@ -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[]

View File

@ -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[]

View File

@ -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

View File

@ -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[]

View File

@ -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 {}

View File

@ -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) "

View File

@ -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) "

View File

@ -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-09-02 09:08+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) "

19
tsconfig.json Normal file
View 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,
},
}

View File

@ -4,24 +4,17 @@ import vueDevTools from 'vite-plugin-vue-devtools'
const config = defineConfig(({ mode }) => ({ const config = defineConfig(({ mode }) => ({
build: { build: {
rollupOptions: { sourcemap: false,
output: {
entryFileNames: 'js/[name].js',
format: 'iife',
manualChunks: false,
},
},
sourcemap: mode !== 'production',
}, },
define: { define: {
__VUE_PROD_DEVTOOLS__: mode !== 'production' __VUE_PROD_DEVTOOLS__: mode !== 'production',
}, },
plugins: [vueDevTools()], plugins: [vueDevTools()],
})) }))
export default createAppConfig( export default createAppConfig(
{ {
main: 'src/main.js', main: 'src/main.ts',
}, },
{ config }, { config, inlineCSS: true },
) )