refacto: simplify EpisodeActionExtraData API
This commit is contained in:
parent
f266186656
commit
785414f33f
@ -30,7 +30,7 @@ class EpisodesController extends Controller
|
|||||||
$episodes = $this->episodeActionReader->parseRssXml((string) $feed->getBody());
|
$episodes = $this->episodeActionReader->parseRssXml((string) $feed->getBody());
|
||||||
|
|
||||||
usort($episodes, fn (EpisodeActionExtraData $a, EpisodeActionExtraData $b) => $b->getFetchedAtUnix() <=> $a->getFetchedAtUnix());
|
usort($episodes, fn (EpisodeActionExtraData $a, EpisodeActionExtraData $b) => $b->getFetchedAtUnix() <=> $a->getFetchedAtUnix());
|
||||||
$episodes = array_intersect_key($episodes, array_unique(array_map(fn (EpisodeActionExtraData $episode) => $episode->getEpisodeGuid(), $episodes)));
|
$episodes = array_intersect_key($episodes, array_unique(array_map(fn (EpisodeActionExtraData $episode) => $episode->getGuid(), $episodes)));
|
||||||
|
|
||||||
return new JSONResponse($episodes, $feed->getStatusCode());
|
return new JSONResponse($episodes, $feed->getStatusCode());
|
||||||
}
|
}
|
||||||
|
@ -7,81 +7,99 @@ namespace OCA\RePod\Core\EpisodeAction;
|
|||||||
use OCA\GPodderSync\Core\EpisodeAction\EpisodeAction;
|
use OCA\GPodderSync\Core\EpisodeAction\EpisodeAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://github.com/pbek/nextcloud-nextpod/blob/main/lib/Core/EpisodeAction/EpisodeActionExtraData.php.
|
* Base: https://github.com/pbek/nextcloud-nextpod/blob/main/lib/Core/EpisodeAction/EpisodeActionExtraData.php.
|
||||||
|
* Specs: https://github.com/Podcast-Standards-Project/PSP-1-Podcast-RSS-Specification/blob/main/README.md#required-item-elements.
|
||||||
*
|
*
|
||||||
* @psalm-import-type EpisodeActionType from EpisodeAction
|
* @psalm-import-type EpisodeActionType from EpisodeAction
|
||||||
*
|
*
|
||||||
* @psalm-type EpisodeActionExtraDataType = array{
|
* @psalm-type EpisodeActionExtraDataType = array{
|
||||||
* episodeUrl: ?string,
|
* podcast: string,
|
||||||
* podcastName: ?string,
|
* url: ?string,
|
||||||
* episodeName: ?string,
|
* name: string,
|
||||||
* episodeLink: ?string,
|
* link: ?string,
|
||||||
* episodeImage: ?string,
|
* image: ?string,
|
||||||
* episodeDescription: ?string,
|
* description: ?string,
|
||||||
* fetchedAtUnix: int,
|
* fetchedAtUnix: int,
|
||||||
* episodeGuid: string,
|
* guid: string,
|
||||||
* episodePubDate: ?\DateTime,
|
* type: ?string,
|
||||||
* episodeFilesize: ?int,
|
* size: ?int,
|
||||||
* episodeDuration: ?int,
|
* pubDate: ?\DateTime,
|
||||||
* episodeAction: ?EpisodeActionType
|
* duration: ?int,
|
||||||
|
* action: ?EpisodeActionType
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
class EpisodeActionExtraData implements \JsonSerializable
|
class EpisodeActionExtraData implements \JsonSerializable
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private ?string $episodeUrl,
|
private string $podcast,
|
||||||
private ?string $podcastName,
|
private ?string $url,
|
||||||
private ?string $episodeName,
|
private string $name,
|
||||||
private ?string $episodeLink,
|
private ?string $link,
|
||||||
private ?string $episodeImage,
|
private ?string $image,
|
||||||
private ?string $episodeDescription,
|
private ?string $description,
|
||||||
private int $fetchedAtUnix,
|
private int $fetchedAtUnix,
|
||||||
private string $episodeGuid,
|
private string $guid,
|
||||||
private ?\DateTime $episodePubDate,
|
private ?string $type,
|
||||||
private ?int $episodeFilesize,
|
private ?int $size,
|
||||||
private ?int $episodeDuration,
|
private ?\DateTime $pubDate,
|
||||||
private ?EpisodeAction $episodeAction
|
private ?int $duration,
|
||||||
) {
|
private ?EpisodeAction $action
|
||||||
$this->episodeUrl = $episodeUrl;
|
) {}
|
||||||
$this->podcastName = $podcastName;
|
|
||||||
$this->episodeName = $episodeName;
|
|
||||||
$this->episodeLink = $episodeLink;
|
|
||||||
$this->episodeImage = $episodeImage;
|
|
||||||
$this->episodeDescription = $episodeDescription;
|
|
||||||
$this->fetchedAtUnix = $fetchedAtUnix;
|
|
||||||
$this->episodeGuid = $episodeGuid;
|
|
||||||
$this->episodePubDate = $episodePubDate;
|
|
||||||
$this->episodeFilesize = $episodeFilesize;
|
|
||||||
$this->episodeDuration = $episodeDuration;
|
|
||||||
$this->episodeAction = $episodeAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __toString(): string {
|
public function __toString(): string {
|
||||||
return $this->episodeUrl ?? '/no episodeUrl/';
|
return $this->url ?? '/no episodeUrl/';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEpisodeGuid(): string {
|
public function getPodcast(): string {
|
||||||
return $this->episodeGuid;
|
return $this->podcast;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEpisodePubDate(): ?\DateTime {
|
public function getUrl(): ?string {
|
||||||
return $this->episodePubDate;
|
return $this->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEpisodeFilesize(): ?int {
|
public function getName(): string {
|
||||||
return $this->episodeFilesize;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEpisodeDuration(): ?int {
|
public function getLink(): ?string {
|
||||||
return $this->episodeDuration;
|
return $this->link;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEpisodeAction(): ?EpisodeAction {
|
public function getImage(): ?string {
|
||||||
return $this->episodeAction;
|
return $this->image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEpisodeUrl(): ?string {
|
public function getDescription(): ?string {
|
||||||
return $this->episodeUrl;
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFetchedAtUnix(): int {
|
||||||
|
return $this->fetchedAtUnix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGuid(): string {
|
||||||
|
return $this->guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): ?string {
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSize(): ?int {
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPubDate(): ?\DateTime {
|
||||||
|
return $this->pubDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDuration(): ?int {
|
||||||
|
return $this->duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAction(): ?EpisodeAction {
|
||||||
|
return $this->action;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,18 +108,19 @@ class EpisodeActionExtraData implements \JsonSerializable
|
|||||||
public function toArray(): array {
|
public function toArray(): array {
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'podcastName' => $this->podcastName,
|
'podcast' => $this->podcast,
|
||||||
'episodeUrl' => $this->episodeUrl,
|
'url' => $this->url,
|
||||||
'episodeName' => $this->episodeName,
|
'name' => $this->name,
|
||||||
'episodeLink' => $this->episodeLink,
|
'link' => $this->link,
|
||||||
'episodeImage' => $this->episodeImage,
|
'image' => $this->image,
|
||||||
'episodeDescription' => $this->episodeDescription,
|
'description' => $this->description,
|
||||||
'fetchedAtUnix' => $this->fetchedAtUnix,
|
'fetchedAtUnix' => $this->fetchedAtUnix,
|
||||||
'episodeGuid' => $this->episodeGuid,
|
'guid' => $this->guid,
|
||||||
'episodePubDate' => $this->episodePubDate,
|
'type' => $this->type,
|
||||||
'episodeFilesize' => $this->episodeFilesize,
|
'size' => $this->size,
|
||||||
'episodeDuration' => $this->episodeDuration,
|
'pubDate' => $this->pubDate,
|
||||||
'episodeAction' => $this->episodeAction ? $this->episodeAction->toArray() : null,
|
'duration' => $this->duration,
|
||||||
|
'action' => $this->action ? $this->action->toArray() : null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,24 +130,4 @@ class EpisodeActionExtraData implements \JsonSerializable
|
|||||||
public function jsonSerialize(): mixed {
|
public function jsonSerialize(): mixed {
|
||||||
return $this->toArray();
|
return $this->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPodcastName(): ?string {
|
|
||||||
return $this->podcastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEpisodeName(): ?string {
|
|
||||||
return $this->episodeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEpisodeLink(): ?string {
|
|
||||||
return $this->episodeLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFetchedAtUnix(): int {
|
|
||||||
return $this->fetchedAtUnix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEpisodeImage(): ?string {
|
|
||||||
return $this->episodeImage;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,8 @@ class EpisodeActionReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://github.com/pbek/nextcloud-nextpod/blob/main/lib/Core/EpisodeAction/EpisodeActionExtraData.php#L119.
|
* Base: https://github.com/pbek/nextcloud-nextpod/blob/main/lib/Core/EpisodeAction/EpisodeActionExtraData.php#L119.
|
||||||
|
* Specs : https://github.com/Podcast-Standards-Project/PSP-1-Podcast-RSS-Specification/blob/main/README.md.
|
||||||
*
|
*
|
||||||
* @return EpisodeActionExtraData[]
|
* @return EpisodeActionExtraData[]
|
||||||
* @throws \Exception if the XML data could not be parsed
|
* @throws \Exception if the XML data could not be parsed
|
||||||
@ -29,101 +30,104 @@ class EpisodeActionReader
|
|||||||
$episodes = [];
|
$episodes = [];
|
||||||
$xml = new \SimpleXMLElement($xmlString);
|
$xml = new \SimpleXMLElement($xmlString);
|
||||||
$channel = $xml->channel;
|
$channel = $xml->channel;
|
||||||
|
$podcast = (string) $channel->title;
|
||||||
|
|
||||||
// Find episode by url and add data for it
|
// Find episode by url and add data for it
|
||||||
/** @var \SimpleXMLElement $item */
|
/** @var \SimpleXMLElement $item */
|
||||||
foreach ($channel->item as $item) {
|
foreach ($channel->item as $item) {
|
||||||
$episodeUrl = (string) $item->enclosure['url'];
|
$url = (string) $item->enclosure['url'];
|
||||||
|
$type = (string) $item->enclosure['type'];
|
||||||
// Get episode guid
|
$size = (int) $item->enclosure['length'];
|
||||||
$episodeGuid = (string) $item->guid;
|
$guid = (string) $item->guid;
|
||||||
|
$rawDuration = $this->stringOrNull($item->duration);
|
||||||
// Get episode filesize
|
|
||||||
$episodeFilesize = (int) $item->enclosure['length'];
|
|
||||||
|
|
||||||
// Get episode action
|
// Get episode action
|
||||||
$episodeAction = $this->episodeActionRepository->findByGuid($episodeGuid, $this->userService->getUserUID());
|
$action = $this->episodeActionRepository->findByGuid($guid, $this->userService->getUserUID());
|
||||||
|
|
||||||
if ($episodeAction) {
|
if ($action) {
|
||||||
$episodeUrl = $episodeAction->getEpisode();
|
$url = $action->getEpisode();
|
||||||
} else {
|
} else {
|
||||||
$episodeAction = $this->episodeActionRepository->findByEpisodeUrl($episodeUrl, $this->userService->getUserUID());
|
$action = $this->episodeActionRepository->findByEpisodeUrl($url, $this->userService->getUserUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get episode name
|
// Get episode name
|
||||||
$episodeName = $this->stringOrNull($item->title);
|
$name = (string) $item->title;
|
||||||
|
|
||||||
// Get episode link
|
// Get episode link
|
||||||
$episodeLink = $this->stringOrNull($item->link);
|
$link = $this->stringOrNull($item->link);
|
||||||
|
|
||||||
// Get episode image
|
// Get episode image
|
||||||
$episodeImage = $this->stringOrNull($channel->image->url);
|
$image = $this->stringOrNull($channel->image->url);
|
||||||
|
|
||||||
$episodeChildren = $item->children('http://www.itunes.com/dtds/podcast-1.0.dtd');
|
$itemChildren = $item->children('http://www.itunes.com/dtds/podcast-1.0.dtd');
|
||||||
if ($episodeChildren) {
|
if ($itemChildren) {
|
||||||
$episodeImageAttributes = (array) $episodeChildren->image->attributes();
|
$imageAttributes = (array) $itemChildren->image->attributes();
|
||||||
$episodeImage = $this->stringOrNull(array_key_exists('href', $episodeImageAttributes) ? (string) $episodeImageAttributes['href'] : '');
|
$image = $this->stringOrNull(array_key_exists('href', $imageAttributes) ? (string) $imageAttributes['href'] : '');
|
||||||
$iTunesChildren = $item->children('itunes', true);
|
$iTunesItemChildren = $item->children('itunes', true);
|
||||||
|
$iTunesChannelChildren = $channel->children('itunes', true);
|
||||||
|
|
||||||
// Get episode duration
|
// Get episode duration
|
||||||
if ($iTunesChildren) {
|
if ($iTunesItemChildren) {
|
||||||
$rawDuration = $this->stringOrNull((string) $iTunesChildren->duration);
|
$rawDuration = $this->stringOrNull($rawDuration ?? $iTunesItemChildren->duration);
|
||||||
$splitDuration = array_reverse(explode(':', $rawDuration ?? ''));
|
|
||||||
$episodeDuration = (int) $splitDuration[0];
|
|
||||||
$episodeDuration += !empty($splitDuration[1]) ? (int) $splitDuration[1] * 60 : 0;
|
|
||||||
$episodeDuration += !empty($splitDuration[2]) ? (int) $splitDuration[2] * 60 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($iTunesChildren && !$episodeImage) {
|
if ($iTunesItemChildren && !$image) {
|
||||||
$episodeImage = $this->stringOrNull((string) $iTunesChildren->image['href']);
|
$image = $this->stringOrNull($iTunesItemChildren->image['href']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($iTunesChildren && !$episodeImage) {
|
if ($iTunesChannelChildren && !$image) {
|
||||||
$episodeImage = $this->stringOrNull((string) $iTunesChildren->image['href']);
|
$image = $this->stringOrNull($iTunesChannelChildren->image['href']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$episodeImage) {
|
if (!$image) {
|
||||||
$channelChildren = $channel->children('http://www.itunes.com/dtds/podcast-1.0.dtd');
|
$channelChildren = $channel->children('http://www.itunes.com/dtds/podcast-1.0.dtd');
|
||||||
if ($channelChildren) {
|
if ($channelChildren) {
|
||||||
$episodeImageAttributes = (array) $channelChildren->image->attributes();
|
$imageAttributes = (array) $channelChildren->image->attributes();
|
||||||
$episodeImage = $this->stringOrNull(array_key_exists('href', $episodeImageAttributes) ? (string) $episodeImageAttributes['href'] : '');
|
$image = $this->stringOrNull(array_key_exists('href', $imageAttributes) ? (string) $imageAttributes['href'] : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$episodeImage) {
|
if (!$image) {
|
||||||
preg_match('/<itunes:image\s+href="([^"]+)"/', $xmlString, $matches);
|
preg_match('/<itunes:image\s+href="([^"]+)"/', $xmlString, $matches);
|
||||||
$episodeImage = $this->stringOrNull($matches[1]);
|
$image = $this->stringOrNull($matches[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get episode description
|
// Get episode description
|
||||||
$episodeDescription = $this->stringOrNull($item->description);
|
$itemContent = $item->children('content', true);
|
||||||
|
if ($itemContent) {
|
||||||
$episodeContentChildren = $item->children('content', true);
|
$description = $this->stringOrNull($itemContent->encoded);
|
||||||
if ($episodeContentChildren) {
|
} else {
|
||||||
$episodeDescription = $this->stringOrNull($episodeContentChildren->encoded);
|
$description = $this->stringOrNull($item->description);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove tags
|
// Remove tags
|
||||||
$episodeDescription = strip_tags($episodeDescription ?? '');
|
$description = strip_tags($description ?? '');
|
||||||
|
|
||||||
// Get episode pubDate
|
// Get episode pubDate
|
||||||
$rawPubDate = $this->stringOrNull($item->pubDate);
|
$rawPubDate = $this->stringOrNull($item->pubDate);
|
||||||
$episodePubDate = $rawPubDate ? new \DateTime($rawPubDate) : null;
|
$pubDate = $rawPubDate ? new \DateTime($rawPubDate) : null;
|
||||||
|
|
||||||
|
// Get episode duration
|
||||||
|
$splitDuration = array_reverse(explode(':', $rawDuration ?? ''));
|
||||||
|
$duration = (int) $splitDuration[0];
|
||||||
|
$duration += !empty($splitDuration[1]) ? (int) $splitDuration[1] * 60 : 0;
|
||||||
|
$duration += !empty($splitDuration[2]) ? (int) $splitDuration[2] * 60 : 0;
|
||||||
|
|
||||||
$episodes[] = new EpisodeActionExtraData(
|
$episodes[] = new EpisodeActionExtraData(
|
||||||
$episodeUrl,
|
$podcast,
|
||||||
$this->stringOrNull($channel->title),
|
$url,
|
||||||
$episodeName,
|
$name,
|
||||||
$episodeLink,
|
$link,
|
||||||
$episodeImage,
|
$image,
|
||||||
$episodeDescription,
|
$description,
|
||||||
$fetchedAtUnix ?? (new \DateTime())->getTimestamp(),
|
$fetchedAtUnix ?? (new \DateTime())->getTimestamp(),
|
||||||
$episodeGuid,
|
$guid,
|
||||||
$episodePubDate,
|
$type,
|
||||||
$episodeFilesize,
|
$size,
|
||||||
$episodeDuration ?? null,
|
$pubDate,
|
||||||
$episodeAction
|
$duration,
|
||||||
|
$action
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,21 +3,21 @@
|
|||||||
<Loading v-if="loading" />
|
<Loading v-if="loading" />
|
||||||
<AdaptativeList v-if="!loading">
|
<AdaptativeList v-if="!loading">
|
||||||
<NcListItem v-for="episode in episodes"
|
<NcListItem v-for="episode in episodes"
|
||||||
:key="episode.episodeGuid"
|
:key="episode.guid"
|
||||||
:active="isCurrentEpisode(episode)"
|
:active="isCurrentEpisode(episode)"
|
||||||
:class="episode.episodeAction && episode.episodeAction.position >= episode.episodeAction.total ? 'ended': ''"
|
:class="episode.action && episode.action.position >= episode.action.total ? 'ended': ''"
|
||||||
:details="formatDistanceToNow(new Date(episode.episodePubDate.date))"
|
:details="formatDistanceToNow(new Date(episode.pubDate.date))"
|
||||||
:force-display-actions="true"
|
:force-display-actions="true"
|
||||||
:name="episode.episodeName"
|
:name="episode.name"
|
||||||
:title="episode.episodeDescription"
|
:title="episode.description"
|
||||||
@click="modalEpisode = episode">
|
@click="modalEpisode = episode">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NcAvatar :display-name="episode.episodeName"
|
<NcAvatar :display-name="episode.name"
|
||||||
:is-no-user="true"
|
:is-no-user="true"
|
||||||
:url="episode.episodeImage" />
|
:url="episode.image" />
|
||||||
</template>
|
</template>
|
||||||
<template #subname>
|
<template #subname>
|
||||||
{{ formatTimer(new Date(episode.episodeDuration*1000)) }}
|
{{ formatTimer(new Date(episode.duration*1000)) }}
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<NcActionButton v-if="!isCurrentEpisode(episode)" @click="load(episode)">
|
<NcActionButton v-if="!isCurrentEpisode(episode)" @click="load(episode)">
|
||||||
@ -37,12 +37,12 @@
|
|||||||
</AdaptativeList>
|
</AdaptativeList>
|
||||||
<NcModal v-if="modalEpisode"
|
<NcModal v-if="modalEpisode"
|
||||||
@close="modalEpisode = null">
|
@close="modalEpisode = null">
|
||||||
<Modal :episode-description="modalEpisode.episodeDescription"
|
<Modal :description="modalEpisode.description"
|
||||||
:episode-image="modalEpisode.episodeImage"
|
:image="modalEpisode.image"
|
||||||
:episode-link="modalEpisode.episodeLink"
|
:link="modalEpisode.link"
|
||||||
:episode-name="modalEpisode.episodeName"
|
:name="modalEpisode.name"
|
||||||
:episode-url="modalEpisode.episodeUrl"
|
:podcast="modalEpisode.podcast"
|
||||||
:podcast-name="modalEpisode.podcastName" />
|
:url="modalEpisode.url" />
|
||||||
</NcModal>
|
</NcModal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -92,7 +92,7 @@ export default {
|
|||||||
try {
|
try {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
const episodes = await axios.get(generateUrl('/apps/repod/episodes/list?url={url}', { url: this.url }))
|
const episodes = await axios.get(generateUrl('/apps/repod/episodes/list?url={url}', { url: this.url }))
|
||||||
this.episodes = [...episodes.data].sort((a, b) => a.episodePubDate.date < b.episodePubDate.date)
|
this.episodes = episodes.data
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
showError(t('repod', 'Could not fetch episodes'))
|
showError(t('repod', 'Could not fetch episodes'))
|
||||||
@ -104,7 +104,7 @@ export default {
|
|||||||
formatTimer,
|
formatTimer,
|
||||||
formatDistanceToNow,
|
formatDistanceToNow,
|
||||||
isCurrentEpisode(episode) {
|
isCurrentEpisode(episode) {
|
||||||
return this.currentEpisode && this.currentEpisode.episodeUrl === episode.episodeUrl
|
return this.currentEpisode && this.currentEpisode.url === episode.url
|
||||||
},
|
},
|
||||||
load(episode) {
|
load(episode) {
|
||||||
this.$store.dispatch('player/load', episode)
|
this.$store.dispatch('player/load', episode)
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<template>
|
<template>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<NcAvatar :display-name="episodeName"
|
<NcAvatar :display-name="name"
|
||||||
:is-no-user="true"
|
:is-no-user="true"
|
||||||
size="256"
|
size="256"
|
||||||
:url="episodeImage" />
|
:url="image" />
|
||||||
<h2>{{ episodeName }}</h2>
|
<h2>{{ name }}</h2>
|
||||||
<div v-html="description" />
|
<p v-html="strippedDescription" />
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<NcButton v-if="episodeLink" :href="episodeLink" target="_blank">
|
<NcButton v-if="link" :href="link" target="_blank">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<OpenInNew :size="20" />
|
<OpenInNew :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ podcastName }}
|
{{ podcastName }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
<NcButton v-if="episodeUrl" :href="episodeUrl" target="_blank">
|
<NcButton v-if="url" :href="url" target="_blank">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Download :size="20" />
|
<Download :size="20" />
|
||||||
</template>
|
</template>
|
||||||
@ -38,35 +38,35 @@ export default {
|
|||||||
OpenInNew,
|
OpenInNew,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
episodeName: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
episodeImage: {
|
image: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
episodeDescription: {
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
url: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
episodeUrl: {
|
link: {
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
episodeLink: {
|
|
||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
podcastName: {
|
podcast: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
description() {
|
strippedDescription() {
|
||||||
const pre = document.createElement('pre')
|
const pre = document.createElement('pre')
|
||||||
pre.innerHTML = this.episodeDescription
|
pre.innerHTML = this.description
|
||||||
const strippedDescription = pre.textContent || pre.innerText || ''
|
const strippedDescription = pre.textContent || pre.innerText || ''
|
||||||
return strippedDescription.replace(/\n/g, '<br>')
|
return strippedDescription.replace(/\n/g, '<br>')
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<Loading v-if="!player.loaded" />
|
<Loading v-if="!player.loaded" />
|
||||||
<ProgressBar v-if="player.loaded" />
|
<ProgressBar v-if="player.loaded" />
|
||||||
<div v-if="player.loaded" class="player">
|
<div v-if="player.loaded" class="player">
|
||||||
<img :src="player.episode.episodeImage">
|
<img :src="player.episode.image">
|
||||||
<Infos class="infos" />
|
<Infos class="infos" />
|
||||||
<Controls class="controls" />
|
<Controls class="controls" />
|
||||||
<Timer class="timer" />
|
<Timer class="timer" />
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<a :href="player.episode.episodeLink" target="_blank">
|
<a :href="player.episode.link" target="_blank">
|
||||||
<strong>{{ player.episode.episodeName }}</strong>
|
<strong>{{ player.episode.name }}</strong>
|
||||||
</a>
|
</a>
|
||||||
<router-link :to="toUrl(player.podcastUrl)">
|
<router-link :to="toUrl(player.podcastUrl)">
|
||||||
<i>{{ player.episode.podcastName }}</i>
|
<i>{{ player.episode.podcast }}</i>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -44,7 +44,7 @@ export const player = {
|
|||||||
|
|
||||||
if (episode) {
|
if (episode) {
|
||||||
state.podcastUrl = atob(router.currentRoute.params.url)
|
state.podcastUrl = atob(router.currentRoute.params.url)
|
||||||
audio.src = episode.episodeUrl
|
audio.src = episode.url
|
||||||
audio.load()
|
audio.load()
|
||||||
audio.play()
|
audio.play()
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ export const player = {
|
|||||||
load: async (context, episode) => {
|
load: async (context, episode) => {
|
||||||
context.commit('episode', episode)
|
context.commit('episode', episode)
|
||||||
try {
|
try {
|
||||||
const action = await axios.get(generateUrl('/apps/repod/episodes/action?url={url}', { url: episode.episodeUrl }))
|
const action = await axios.get(generateUrl('/apps/repod/episodes/action?url={url}', { url: episode.url }))
|
||||||
context.commit('action', action.data)
|
context.commit('action', action.data)
|
||||||
} catch {}
|
} catch {}
|
||||||
},
|
},
|
||||||
@ -87,19 +87,18 @@ export const player = {
|
|||||||
stop: (context) => {
|
stop: (context) => {
|
||||||
context.dispatch('pause')
|
context.dispatch('pause')
|
||||||
context.commit('episode', null)
|
context.commit('episode', null)
|
||||||
context.commit('action', null)
|
|
||||||
},
|
},
|
||||||
time: async (context) => axios.post(generateUrl('/apps/gpoddersync/episode_action/create'), [{
|
time: async (context) => axios.post(generateUrl('/apps/gpoddersync/episode_action/create'), [{
|
||||||
podcast: context.state.podcastUrl,
|
podcast: context.state.podcastUrl,
|
||||||
episode: context.state.episode.episodeUrl,
|
episode: context.state.episode.url,
|
||||||
guid: context.state.episode.episodeGuid,
|
guid: context.state.episode.guid,
|
||||||
action: 'play',
|
action: 'play',
|
||||||
timestamp: format(new Date(), 'yyyy-MM-dd\'T\'HH:mm:ss'),
|
timestamp: format(new Date(), 'yyyy-MM-dd\'T\'HH:mm:ss'),
|
||||||
started: Math.round(context.state.action ? context.state.action.started : 0),
|
started: Math.round(context.state.action ? context.state.action.started : 0),
|
||||||
position: Math.round(audio.currentTime),
|
position: Math.round(audio.currentTime),
|
||||||
total: Math.round(audio.duration),
|
total: Math.round(audio.duration),
|
||||||
}]),
|
}]),
|
||||||
volume: (context, volume) => {
|
volume: (_, volume) => {
|
||||||
audio.volume = volume
|
audio.volume = volume
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user