From 2a3d30f0184042bcb9efcb1761cf6a60eff175a0 Mon Sep 17 00:00:00 2001 From: Michel Roux Date: Fri, 3 Jan 2025 16:17:12 +0100 Subject: [PATCH] feat: :sparkles: add notifications and author --- CHANGELOG.md | 6 ++++ appinfo/info.xml | 2 +- .../EpisodeAction/EpisodeActionExtraData.php | 7 +++++ .../EpisodeAction/EpisodeActionReader.php | 8 +++++ src/components/Atoms/Modal.vue | 2 ++ src/components/Feed/Episode.vue | 12 +++++++- src/store/player.ts | 29 +++++++++++++++++++ src/utils/types.ts | 1 + 8 files changed, 65 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c99cd20..f1b44ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 3.5.4 - Under the spotlight - 2025-01-03 + +### Added +- 🧑‍🎤 Added the episode author on the list and modal +- ✨ Added cover image and episode infos on desktop and mobile notifications + ## 3.5.3 - Hangover - 2025-01-03 ### Fixed diff --git a/appinfo/info.xml b/appinfo/info.xml index 4e80990..07195fa 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -14,7 +14,7 @@ ## Requirements You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!]]> - 3.5.3 + 3.5.4 agpl Michel Roux RePod diff --git a/lib/Core/EpisodeAction/EpisodeActionExtraData.php b/lib/Core/EpisodeAction/EpisodeActionExtraData.php index 1422176..860c4e9 100644 --- a/lib/Core/EpisodeAction/EpisodeActionExtraData.php +++ b/lib/Core/EpisodeAction/EpisodeActionExtraData.php @@ -18,6 +18,7 @@ use OCA\GPodderSync\Core\EpisodeAction\EpisodeAction; * name: string, * link: ?string, * image: ?string, + * author: ?string, * description: ?string, * fetchedAtUnix: int, * guid: string, @@ -36,6 +37,7 @@ class EpisodeActionExtraData implements \JsonSerializable, \Stringable private readonly string $name, private readonly ?string $link, private readonly ?string $image, + private readonly ?string $author, private readonly ?string $description, private readonly int $fetchedAtUnix, private readonly string $guid, @@ -70,6 +72,10 @@ class EpisodeActionExtraData implements \JsonSerializable, \Stringable return $this->image; } + public function getAuthor(): ?string { + return $this->author; + } + public function getDescription(): ?string { return $this->description; } @@ -113,6 +119,7 @@ class EpisodeActionExtraData implements \JsonSerializable, \Stringable 'name' => $this->name, 'link' => $this->link, 'image' => $this->image, + 'author' => $this->author, 'description' => $this->description, 'fetchedAtUnix' => $this->fetchedAtUnix, 'guid' => $this->guid, diff --git a/lib/Core/EpisodeAction/EpisodeActionReader.php b/lib/Core/EpisodeAction/EpisodeActionReader.php index c21f256..6a13682 100644 --- a/lib/Core/EpisodeAction/EpisodeActionReader.php +++ b/lib/Core/EpisodeAction/EpisodeActionReader.php @@ -81,6 +81,13 @@ class EpisodeActionReader extends CoreEpisodeActionReader } } + // Get episode author + if (isset($iTunesItemChildren)) { + $author = $this->stringOrNull($iTunesItemChildren->author); + } else { + $author = $this->stringOrNull($item->author); + } + // Get episode description $itemContent = $item->children('content', true); if (isset($itemContent)) { @@ -116,6 +123,7 @@ class EpisodeActionReader extends CoreEpisodeActionReader $name, $link, $image, + $author, $description, $fetchedAtUnix ?? (new \DateTime())->getTimestamp(), $guid, diff --git a/src/components/Atoms/Modal.vue b/src/components/Atoms/Modal.vue index 500c844..b4945e1 100644 --- a/src/components/Atoms/Modal.vue +++ b/src/components/Atoms/Modal.vue @@ -6,6 +6,8 @@ :size="256" :url="episode.image" />

{{ episode.name }}

+ {{ episode.author }} +
diff --git a/src/components/Feed/Episode.vue b/src/components/Feed/Episode.vue index b0c9f3a..3dbe6c4 100644 --- a/src/components/Feed/Episode.vue +++ b/src/components/Feed/Episode.vue @@ -2,6 +2,7 @@ @@ -218,4 +219,13 @@ export default { flex-basis: auto; flex-grow: 0; } + +.episode .list-item-details__extra { + flex-direction: row-reverse; + gap: 1rem; +} + +.episode .list-item-details__counter { + max-width: fit-content; +} diff --git a/src/store/player.ts b/src/store/player.ts index f4872c6..17b51df 100644 --- a/src/store/player.ts +++ b/src/store/player.ts @@ -48,6 +48,34 @@ export const usePlayer = defineStore('player', { conflict() { this.playCount = 0 }, + metadatas(episode: EpisodeInterface) { + // https://developer.mozilla.org/en-US/docs/Web/API/Media_Session_API + navigator.mediaSession.metadata = new MediaMetadata({ + title: episode.name, + artist: episode.author, + album: episode.title, + artwork: episode.image ? [{ src: episode.image }] : [], + }) + + navigator.mediaSession.setActionHandler('play', this.play) + navigator.mediaSession.setActionHandler('pause', this.pause) + navigator.mediaSession.setActionHandler('stop', this.stop) + navigator.mediaSession.setActionHandler( + 'seekbackward', + (details: MediaSessionActionDetails) => + this.seek(audio.currentTime - (details.seekOffset || 10)), + ) + navigator.mediaSession.setActionHandler( + 'seekforward', + (details: MediaSessionActionDetails) => + this.seek(audio.currentTime + (details.seekOffset || 30)), + ) + navigator.mediaSession.setActionHandler( + 'seekto', + (details: MediaSessionActionDetails) => + !details.fastSeek && this.seek(details.seekTime || 0), + ) + }, async load(episode: EpisodeInterface | null, podcastUrl?: string) { this.episode = episode this.podcastUrl = podcastUrl || null @@ -75,6 +103,7 @@ export const usePlayer = defineStore('player', { } audio.play() + this.metadatas(this.episode) } else { this.loaded = false this.podcastUrl = null diff --git a/src/utils/types.ts b/src/utils/types.ts index b16dd49..851dd34 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -16,6 +16,7 @@ export interface EpisodeInterface { name: string link?: string image?: string + author?: string description?: string fetchedAtUnix: number guid: string