feat: add notifications and author
All checks were successful
repod / xml (push) Successful in 12s
repod / php (push) Successful in 1m0s
repod / nodejs (push) Successful in 1m38s
repod / release (push) Successful in 1m16s

This commit is contained in:
Michel Roux 2025-01-03 16:17:12 +01:00
parent 514a12d756
commit 2a3d30f018
8 changed files with 65 additions and 2 deletions

View File

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

View File

@ -14,7 +14,7 @@
## Requirements
You need to have [GPodderSync](https://apps.nextcloud.com/apps/gpoddersync) installed to use this app!]]></description>
<version>3.5.3</version>
<version>3.5.4</version>
<licence>agpl</licence>
<author mail="xefir@crystalyx.net" homepage="https://crystalyx.net">Michel Roux</author>
<namespace>RePod</namespace>

View File

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

View File

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

View File

@ -6,6 +6,8 @@
:size="256"
:url="episode.image" />
<h2>{{ episode.name }}</h2>
<i v-if="episode.author">{{ episode.author }}</i>
<br />
<SafeHtml :source="episode.description || ''" />
<div class="flex">
<NcButton v-if="episode.link" :href="episode.link" target="_blank">

View File

@ -2,6 +2,7 @@
<NcListItem
:active="isCurrentEpisode(episode)"
class="episode"
:counter-number="episode.duration"
:details="
!oneLine && episode.pubDate
? formatLocaleDate(new Date(episode.pubDate?.date))
@ -92,7 +93,7 @@
:value="(episode.action.position * 100) / episode.action.total" />
</template>
<template #subname>
{{ episode.duration }}
{{ !oneLine ? episode.author : '' }}
</template>
</NcListItem>
</template>
@ -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;
}
</style>

View File

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

View File

@ -16,6 +16,7 @@ export interface EpisodeInterface {
name: string
link?: string
image?: string
author?: string
description?: string
fetchedAtUnix: number
guid: string