Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • onny/nextcloud-app-podcast
  • petre/nextcloud-app-podcast
2 results
Show changes
Showing
with 1141 additions and 94 deletions
{ "translations": { { "translations": {
"Radio stations" : "Radio Stationen", "Podcast episodes" : "Podcast Episoden",
"Radio" : "Radio", "Podcast" : "Podcast",
"Radio listening app" : "Online Radiosender hören", "🔊 Browse, manage and listen to podcasts" : "🔊 Browse, manage and listen to podcasts",
"Listening to your favorite radio stations in Nextcloud" : "Höre deine Lieblings-Radiosender direkt in Nextcloud", "**🔊 Browse, listen and subscribe to podcasts**\n\nFull featured podcatcher which uses the community index fyyd.de as a source.\n\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- ⭐ Support episode chapters\n- 👂 Smoth audio playback and transitions" : "**🔊 Browse, listen and subscribe to podcasts**\n\nFull featured podcatcher which uses the community index fyyd.de as a source.\n\n- 🔍 Browse and subscribe huge collection of podcasts\n- 🔊 Listen to episodes directly in Nextcloud\n- ⭐ Support episode chapters\n- 👂 Smoth audio playback and transitions",
"Error fetching favorite stations" : "Favorisierte Stationen konnten nicht geladen werden", "Hide" : "Verstecken",
"No favorites added yet!" : "Noch keine favorisierte Stationen vorhanden", "Show" : "Anzeigen",
"Failed to fetch favorite radio stations" : "Favorisierte Stationen konnten nicht geladen werden", "episodes" : "Episoden",
"No favorites yet" : "Noch keine Favoriten", "Error fetching favorite episodes" : "Fehler beim Laden der favorisierten Episoden",
"No recent stations yet" : "Noch keine zuletzt gespielten Stationen", "No episodes added yet!" : "Keine Episoden bis jetzt hinzugefügt!",
"No search results" : "Keine Suchergebnisse", "Failed to fetch favorite podcast episodes" : "Fehler beim Laden der Podcast Episoden",
"Stations you mark as favorite will show up here" : "Radio Stationen die favorisiert wurden werden hier angezeigt", "Show all" : "Zeige alle",
"Stations you recently played will show up here" : "Radio Stationen die vor kurzem gespielt wurden, werden hier angezeigt", "by" : "von",
"No stations were found matching your search term" : "Keine Stationen unter diesen Suchbegriff gefunden", "Show more" : "Zeige mehr",
"No stations here" : "Keine Stationen verfügbar", "Show less" : "Zeige weniger",
"Could not remove station from favorites" : "Radio station konnte nicht von den Favoriten entfernt werden", "Unsubscribe" : "Abbestellen",
"Could not favor station" : "Station konnte nicht favorisiert werden", "Subscribe" : "Abonnieren",
"Lost connection to radio station, retrying ..." : "Verbindung zur Radio Station unterbrochen, versuche wiederzuverbinden ...", "Listening" : "Aktuell höhrend",
"Unable to count play on remote API" : "Wiedergabe konnte nicht gezählt werden von der entfernten API", "Library" : "Bibliothek",
"Could not add station to recent list" : "Radio Station konnte nicht in die zuletzt gespielt Liste aufgenommen werden", "Browse" : "Durchsuchen",
"Countries" : "Länder", "Search" : "Suchen",
"States" : "Staaten",
"Languages" : "Sprachen",
"Tags" : "Stichwörter",
"Could not fetch stations from remote API" : "Radio Stationen konnten nicht von der API geladen werden",
"Unable to load favorites" : "Favoriten konnten nicht geladen werden",
"Top" : "Beliebteste",
"Recent" : "Zuletzt gehört",
"New" : "Neu",
"Favorites" : "Favoriten",
"Categories" : "Kategorien",
"Search" : "Suche",
"Stream URL" : "Stream URL",
"Copy link to clipboard" : "Adresse in die Zwischenablage kopieren",
"Homepage" : "Webseite",
"Country & Language" : "Land und Sprache",
"Codec & Bitrate" : "Codec & Bitrate",
"Link copied to clipboard" : "Adresse in die Zwischenablage kopiert",
"Error while copying link to clipboard" : "Fehler beim Speichern in die Zwischenablage",
"Name" : "Name", "Name" : "Name",
"Add to favorites" : "Zu den Favoriten hinzufügen", "Duration" : "Länge",
"Remove from favorites" : "Von den Favoriten entfernen", "Date" : "Datum",
"Details" : "Weitere Informationen" "Go to episode" : "Gehe zu Episode",
"Go to show" : "Gehe zu Sendung",
"Download" : "Herunterladen",
"Share" : "Teilen",
"Remove from queue" : "Von Wiedergabeliste entfernen",
"Resume" : "Fortsetzen",
"Pause" : "Pausieren",
"Play" : "Abspielen",
"Hot podcasts" : "Zurzeit beliebte Podcasts",
"New podcasts" : "Neue Podcasts",
"Podcasts in" : "Podcasts in",
"Publication date" : "Veröffentlicht",
"Episode chapters" : "Kapitel",
"Pause episode" : "Episode pausieren",
"Resume episode" : "Episode fortsetzen",
"Play episode" : "Episode abspielen",
"Currently listening" : "Zuletzt gehört"
},"pluralForm" :"nplurals=2; plural=(n != 1);" },"pluralForm" :"nplurals=2; plural=(n != 1);"
} }
\ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Podcast App * Podcast App
* *
* @author Jonas Heinrich * @author Jonas Heinrich
* @copyright 2020 Jonas Heinrich <onny@project-insanity.org> * @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
...@@ -67,8 +67,6 @@ class Application extends App implements IBootstrap { ...@@ -67,8 +67,6 @@ class Application extends App implements IBootstrap {
public function registerCsp() { public function registerCsp() {
$manager = $this->getContainer()->getServer()->getContentSecurityPolicyManager(); $manager = $this->getContainer()->getServer()->getContentSecurityPolicyManager();
$policy = new ContentSecurityPolicy(); $policy = new ContentSecurityPolicy();
$policy->addAllowedConnectDomain('https://de1.api.radio-browser.info');
$policy->addAllowedConnectDomain('https://api.fyyd.de');
$policy->addAllowedImageDomain('*'); $policy->addAllowedImageDomain('*');
$policy->addAllowedMediaDomain('*'); $policy->addAllowedMediaDomain('*');
$manager->addDefaultPolicy($policy); $manager->addDefaultPolicy($policy);
......
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Podcast\Controller;
use OCA\Podcast\AppInfo\Application;
use OCA\Podcast\Service\EpisodeService;
use OCA\Podcast\Service\FyydApiService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;
use OCP\ILogger;
use OCP\Http\Client\IClientService;
class EpisodeController extends Controller {
/** @var ILogger */
private $logger;
/** @var EpisodesService */
private $service;
/** @var FyydApiService */
private $fyydapi;
/** @var string */
private $userId;
use Errors;
public function __construct(IRequest $request,
EpisodeService $service,
FyydApiService $fyydapi,
ILogger $logger,
$userId) {
parent::__construct(Application::APP_ID, $request);
$this->service = $service;
$this->fyydapi = $fyydapi;
$this->logger = $logger;
$this->userId = $userId;
}
/**
* @NoAdminRequired
*/
public function index(int $episode_id = null, int $podcast_id = null,
int $count = 20, int $page = 0, string $sortBy = null): DataResponse {
$data = $this->service->findAll($this->userId, $sortBy);
if ($episode_id) {
$list = $this->fyydapi->queryEpisode($episode_id);
foreach($data as $localEpisode) {
if ($localEpisode->getId() === $list['data']['id']) {
$list['data']['lastplayed'] = $localEpisode->getLastplayed();
$list['data']['playtime'] = $localEpisode->getPlaytime();
}
}
return new DataResponse($list);
} else if ($podcast_id) {
$list = $this->fyydapi->queryEpisodes($podcast_id, $count, $page);
foreach($list['data']['episodes'] as $key=>$fyydEpisode) {
foreach($data as $localEpisode) {
if ($localEpisode->getId() === $fyydEpisode['id']) {
$list['data']['episodes'][$key]['lastplayed'] = $localEpisode->getLastplayed();
$list['data']['episodes'][$key]['playtime'] = $localEpisode->getPlaytime();
}
}
}
return new DataResponse($list);
}
$data = array_slice($data, $page * $count, $count);
if (count($data) === $count) {
$nextPage = $page + 1;
} else {
$nextPage = null;
};
$response = [
"meta" => [
"paging" => [
"next_page" => $nextPage,
],
],
"data" => [
"episodes" => $data,
],
];
return new DataResponse($response);
}
/**
* @NoAdminRequired
*/
public function show(int $id): DataResponse {
return $this->handleNotFound(function () use ($id) {
return $this->service->find($id, $this->userId);
});
}
/**
* @NoAdminRequired
*/
public function create(int $id, string $imgURL, string $title,
string $pubdate, int $duration, int $playtime, int $lastplayed,
string $enclosure, string $description, int $podcast_id
): DataResponse {
return new DataResponse($this->service->create($id, $imgURL, $title,
$pubdate, $duration, $playtime, $lastplayed, $enclosure, $description,
$podcast_id, $this->userId));
}
/**
* @NoAdminRequired
*/
public function update(int $id, string $imgURL, string $title,
string $pubdate, int $duration, int $playtime, int $lastplayed,
string $enclosure, string $description, int $podcast_id
): DataResponse {
return $this->handleNotFound(function () use ($id, $imgURL, $title,
$pubdate, $duration, $playtime, $lastplayed, $enclosure, $description,
$podcast_id) {
return $this->service->update($id, $imgURL, $title, $pubdate, $duration,
$playtime, $lastplayed, $enclosure, $description, $podcast_id,
$this->userId);
});
}
/**
* @NoAdminRequired
*/
public function destroy(int $id): DataResponse {
return $this->handleNotFound(function () use ($id) {
return $this->service->delete($id, $this->userId);
});
}
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Podcast App * Podcast App
* *
* @author Jonas Heinrich * @author Jonas Heinrich
* @copyright 2020 Jonas Heinrich <onny@project-insanity.org> * @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
......
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Podcast\Controller;
use OC;
use OCA\Podcast\ExportResponse;
use OCA\Podcast\AppInfo\Application;
use OCA\Podcast\Service\ShowService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;
use SimpleXMLElement;
use DOMDocument;
class ExportController extends Controller {
/** @var ShowService */
private $service;
/** @var string */
private $userId;
use Errors;
public function __construct(IRequest $request,
ShowService $service,
$userId) {
parent::__construct(Application::APP_ID, $request);
$this->service = $service;
$this->userId = $userId;
}
/**
* @NoAdminRequired
*/
public function index() {
$xml = new SimpleXMLElement('<?xml version="1.0"?><opml version="1.0"></opml>');
$trackList = $xml->addChild('body');
foreach($this->service->findAll($this->userId) as $show) {
$track = $trackList->addChild('outline');
$track->addAttribute('type', 'rss');
$track->addAttribute('text', $show->getTitle());
$track->addAttribute('title', $show->getTitle());
$track->addAttribute('xmlUrl', $show->getFeedurl());
$track->addAttribute('htmlUrl', $show->getHomepage());
}
$dom = new DOMDocument("1.0");
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
return new ExportResponse($dom->saveXML());
}
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Podcast App * Podcast App
* *
* @author Jonas Heinrich * @author Jonas Heinrich
* @copyright 2020 Jonas Heinrich <onny@project-insanity.org> * @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Podcast App * Podcast App
* *
* @author Jonas Heinrich * @author Jonas Heinrich
* @copyright 2020 Jonas Heinrich <onny@project-insanity.org> * @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
...@@ -95,39 +95,6 @@ class SettingsController extends ApiController { ...@@ -95,39 +95,6 @@ class SettingsController extends ApiController {
return new JSONResponse(['status' => 'success'], Http::STATUS_OK); return new JSONResponse(['status' => 'success'], Http::STATUS_OK);
} }
/**
* set menu state
*
* @param string $menuState
* @return JSONResponse
*
* @NoAdminRequired
*/
public function setMenuState($menuState = ""): JSONResponse {
if ($menuState = 'SEARCH') {
return new JSONResponse(['status' => 'success'], Http::STATUS_OK);
};
$legalArguments = ['TOP', 'RECENT', 'NEW', 'FAVORITES', 'CATEGORIES'];
if (!in_array($menuState, $legalArguments)) {
return new JSONResponse(['status' => 'error'], Http::STATUS_BAD_REQUEST);
}
return $this->setSetting(
'menuState',
$menuState
);
}
/**
* get menu state
*
* @return JSONResponse
*
* @NoAdminRequired
*/
public function getMenuState(): JSONResponse {
return $this->getSetting('menuState', 'menuState', 'TOP');
}
/** /**
* set player volume * set player volume
* *
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Podcast App * Podcast App
* *
* @author Jonas Heinrich * @author Jonas Heinrich
* @copyright 2020 Jonas Heinrich <onny@project-insanity.org> * @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
...@@ -24,33 +24,75 @@ ...@@ -24,33 +24,75 @@
namespace OCA\Podcast\Controller; namespace OCA\Podcast\Controller;
use OCA\Podcast\AppInfo\Application; use OCA\Podcast\AppInfo\Application;
use OCA\Podcast\Service\ShowsService; use OCA\Podcast\Service\ShowService;
use OCA\Podcast\Service\FyydApiService;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest; use OCP\IRequest;
class ShowsController extends Controller { class ShowController extends Controller {
/** @var ShowsService */ /** @var ShowsService */
private $service; private $service;
/** @var FyydApiService */
private $fyydapi;
/** @var string */ /** @var string */
private $userId; private $userId;
use Errors; use Errors;
public function __construct(IRequest $request, public function __construct(IRequest $request,
ShowsService $service, ShowService $service,
FyydApiService $fyydapi,
$userId) { $userId) {
parent::__construct(Application::APP_ID, $request); parent::__construct(Application::APP_ID, $request);
$this->service = $service; $this->service = $service;
$this->fyydapi = $fyydapi;
$this->userId = $userId; $this->userId = $userId;
} }
/** /**
* @NoAdminRequired * @NoAdminRequired
*/ */
public function index(): DataResponse { public function index(int $podcast_id = null, string $category = null,
return new DataResponse($this->service->findAll($this->userId)); int $count = 20, int $page = 0): DataResponse {
$data = $this->service->findAll($this->userId);
if ($category) {
$list = $this->fyydapi->queryCategory($category, $count, $page);
return new DataResponse($list);
} else if ($podcast_id) {
$list = $this->fyydapi->queryPodcast($podcast_id);
foreach($data as $localEpisode) {
if ($localEpisode->getId() === $list['data']['id']) {
$list['data']['dateadded'] = intval($localEpisode->getDateadded());
}
}
return new DataResponse($list);
}
$data = array_slice($data, $page * $count, $count);
if (count($data) === $count) {
$nextPage = $page + 1;
} else {
$nextPage = null;
};
$response = [
"meta" => [
"paging" => [
"next_page" => $nextPage,
],
],
"data" => $data,
];
return new DataResponse($response);
} }
/** /**
...@@ -65,16 +107,23 @@ class ShowsController extends Controller { ...@@ -65,16 +107,23 @@ class ShowsController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
*/ */
public function create(int $id, string $title, string $htmlURL, string $smallImageURL, string $categories, string $lastpub, string $description, string $author): DataResponse { public function create(int $id, string $smallImageURL, string $author,
return new DataResponse($this->service->create($id, $title, $htmlURL, $smallImageURL, $categories, $lastpub, $description, $author, $this->userId)); string $title, string $lastpub, int $dateadded, string $homepage,
string $feedurl): DataResponse {
return new DataResponse($this->service->create($id, $smallImageURL, $author,
$title, $lastpub, $dateadded, $homepage, $feedurl, $this->userId));
} }
/** /**
* @NoAdminRequired * @NoAdminRequired
*/ */
public function update(int $id, string $title, string $htmlURL, string $smallImageURL, string $categories, string $lastpub, string $description, string $author): DataResponse { public function update(int $id, string $smallImageURL, string $author,
return $this->handleNotFound(function () use ($id, $title, $htmlURL, $smallImageURL, $categories, $lastpub, $description, $author) { string $title, string $lastpub, int $dateadded, string $homepage,
return $this->service->update($id, $title, $htmlURL, $smallImageURL, $categories, $lastpub, $description, $author, $this->userId); string $feedurl): DataResponse {
return $this->handleNotFound(function () use ($id, $smallImageURL, $author,
$title, $lastpub, $dateadded, $homepage, $feedurl) {
return $this->service->update($id, $smallImageURL, $author, $title, $lastpub,
$dateadded, $homepage, $feedurl, $this->userId);
}); });
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Podcast App * Podcast App
* *
* @author Jonas Heinrich * @author Jonas Heinrich
* @copyright 2020 Jonas Heinrich <onny@project-insanity.org> * @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
......
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Podcast\Db;
use JsonSerializable;
use OCP\AppFramework\Db\Entity;
class Episode extends Entity implements JsonSerializable {
protected $imgurl;
protected $title;
protected $pubdate;
protected $duration;
protected $playtime;
protected $lastplayed;
protected $enclosure;
protected $description;
protected $podcastid;
protected $userId;
public function jsonSerialize(): array {
return [
'id' => $this->id,
'imgURL' => $this->imgurl,
'title' => $this->title,
'pubdate' => $this->pubdate,
'duration' => $this->duration,
'playtime' => $this->playtime,
'lastplayed' => $this->lastplayed,
'enclosure' => $this->enclosure,
'description' => $this->description,
'podcast_id' => $this->podcastid,
];
}
}
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Podcast\Db;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
class EpisodeMapper extends QBMapper {
public function __construct(IDBConnection $db) {
parent::__construct($db, 'episodes', Episode::class);
}
/**
* @param int $id
* @param string $userId
* @return Entity|Episode
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws DoesNotExistException
*/
public function find(int $id, string $userId): Episode {
/* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from('episodes')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
return $this->findEntity($qb);
}
/**
* @param string $userId
* @return array
*/
public function findAll(string $userId, string $sortBy = null): array {
if ($sortBy) {
if ($sortBy === 'pubdate') {
$sortBy = 'pubdate';
} else {
$sortBy = 'lastplayed';
}
} else {
$sortBy = 'lastplayed';
};
/* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from('episodes')
->orderBy($sortBy, 'DESC')
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
/* For listening view, query only episodes which were already
listened */
if ($sortBy === 'lastplayed') {
$qb->andWhere($qb->expr()->gt('playtime',$qb->createNamedParameter(0)));
};
return $this->findEntities($qb);
}
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Podcast App * Podcast App
* *
* @author Jonas Heinrich * @author Jonas Heinrich
* @copyright 2020 Jonas Heinrich <onny@project-insanity.org> * @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
...@@ -28,25 +28,25 @@ use JsonSerializable; ...@@ -28,25 +28,25 @@ use JsonSerializable;
use OCP\AppFramework\Db\Entity; use OCP\AppFramework\Db\Entity;
class Show extends Entity implements JsonSerializable { class Show extends Entity implements JsonSerializable {
protected $imgurl;
protected $author;
protected $title; protected $title;
protected $htmlurl;
protected $smallimageurl;
protected $categories;
protected $lastpub; protected $lastpub;
protected $description; protected $dateadded;
protected $author; protected $homepage;
protected $feedurl;
protected $userId; protected $userId;
public function jsonSerialize(): array { public function jsonSerialize(): array {
return [ return [
'id' => $this->id, 'id' => $this->id,
'smallImageURL' => $this->imgurl,
'author' => $this->author,
'title' => $this->title, 'title' => $this->title,
'htmlurl' => $this->htmlurl,
'smallimageurl' => $this->smallimageurl,
'categories' => $this->categories,
'lastpub' => $this->lastpub, 'lastpub' => $this->lastpub,
'description' => $this->description, 'dateadded' => $this->dateadded,
'author' => $this->author, 'homepage' => $this->homepage,
'feedurl' => $this->feedurl,
]; ];
} }
} }
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Podcast App * Podcast App
* *
* @author Jonas Heinrich * @author Jonas Heinrich
* @copyright 2020 Jonas Heinrich <onny@project-insanity.org> * @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
...@@ -46,6 +46,7 @@ class ShowMapper extends QBMapper { ...@@ -46,6 +46,7 @@ class ShowMapper extends QBMapper {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from('shows') ->from('shows')
->orderBy('dateadded', 'DESC')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))) ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($userId))); ->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
return $this->findEntity($qb); return $this->findEntity($qb);
...@@ -60,6 +61,7 @@ class ShowMapper extends QBMapper { ...@@ -60,6 +61,7 @@ class ShowMapper extends QBMapper {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from('shows') ->from('shows')
->orderBy('lastpub', 'DESC')
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId))); ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
return $this->findEntities($qb); return $this->findEntities($qb);
} }
......
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Podcast;
use OC;
use OC\HintException;
use OCP\AppFramework\Http\Response;
class ExportResponse extends Response {
private $returnstring;
public function __construct($returnstring) {
parent::__construct();
$user = OC::$server->getUserSession()->getUser();
if (is_null($user)) {
throw new HintException('User not logged in');
}
$userName = $user->getDisplayName();
$productName = OC::$server->getThemingDefaults()->getName();
$dateTime = OC::$server->getDateTimeFormatter();
$export_name = '"' . $productName . ' Podcast Subscriptions (' . $userName . ') (' . $dateTime->formatDate(time()) . ').opml"';
$this->addHeader("Cache-Control", "private");
$this->addHeader("Content-Type", " application/xml");
$this->addHeader("Content-Length", strlen($returnstring));
$this->addHeader("Content-Disposition", "attachment; filename=" . $export_name);
$this->returnstring = $returnstring;
}
public function render() {
return $this->returnstring;
}
}
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
declare(strict_types=1);
namespace OCA\Podcast\Migration;
use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;
class Version000000Date20181013124731 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
if (!$schema->hasTable('shows')) {
$table = $schema->createTable('shows');
$table->addColumn('id', 'integer', [
'notnull' => true,
]);
$table->addColumn('user_id', 'string', [
'notnull' => true,
]);
$table->addColumn('imgurl', 'string');
$table->addColumn('author', 'string');
$table->addColumn('title', 'string');
$table->setPrimaryKey(['id']);
$table->addIndex(['user_id'], 'shows_user_id_index');
}
if (!$schema->hasTable('episodes')) {
$table = $schema->createTable('episodes');
$table->addColumn('id', 'integer', [
'notnull' => true,
]);
$table->addColumn('user_id', 'string', [
'notnull' => true,
]);
$table->addColumn('imgurl', 'string');
$table->addColumn('author', 'string');
$table->addColumn('title', 'string');
$table->addColumn('pubdate', 'string');
$table->addColumn('duration', 'string');
$table->addColumn('playtime', 'string');
$table->addColumn('lastplayed', 'string');
$table->addColumn('enclosure', 'string');
$table->setPrimaryKey(['id']);
$table->addIndex(['user_id'], 'episodes_user_id_index');
}
return $schema;
}
}
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
declare(strict_types=1);
namespace OCA\Podcast\Migration;
use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;
use Doctrine\DBAL\Types\Type;
class Version000100Date20210201162900 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*
* @return void
*/
public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
}
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*
* @return ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->getTable('shows');
$table->addColumn('lastpub', 'string', [
'notnull' => false,
]);
$table->addColumn('dateadded', 'bigint', [
'notnull' => false,
]);
$table = $schema->getTable('episodes');
$table->addColumn('description', 'string', [
'notnull' => false,
]);
$table->addColumn('podcastid', 'integer', [
'notnull' => true,
]);
if ($table->hasColumn('playtime')) {
$table->dropColumn('playtime');
$table->addColumn('playtime', 'integer');
};
if ($table->hasColumn('duration')) {
$table->dropColumn('duration');
$table->addColumn('duration', 'integer');
};
if ($table->hasColumn('lastplayed')) {
$table->dropColumn('lastplayed');
$table->addColumn('lastplayed', 'bigint');
};
if ($table->hasColumn('author')) {
$table->dropColumn('author');
};
return $schema;
}
}
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
declare(strict_types=1);
namespace OCA\Podcast\Migration;
use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;
use Doctrine\DBAL\Types\Type;
class Version000100Date20210315125200 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*
* @return void
*/
public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
}
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*
* @return ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->getTable('shows');
$table->addColumn('homepage', 'string', [
'notnull' => false,
]);
$table->addColumn('feedurl', 'string', [
'notnull' => false,
]);
$table = $schema->getTable('episodes');
return $schema;
}
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Podcast App * Podcast App
* *
* @author Jonas Heinrich * @author Jonas Heinrich
* @copyright 2020 Jonas Heinrich <onny@project-insanity.org> * @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
......
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Podcast\Service;
use Exception;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCA\Podcast\Db\Episode;
use OCA\Podcast\Db\EpisodeMapper;
class EpisodeService {
/** @var EpisodeMapper */
private $mapper;
public function __construct(EpisodeMapper $mapper) {
$this->mapper = $mapper;
}
public function findAll(string $userId, string $sortBy = null): array {
return $this->mapper->findAll($userId, $sortBy);
}
private function handleException(Exception $e): void {
if ($e instanceof DoesNotExistException ||
$e instanceof MultipleObjectsReturnedException) {
throw new EpisodeNotFound($e->getMessage());
} else {
throw $e;
}
}
public function find($id, $userId) {
try {
return $this->mapper->find($id, $userId);
// in order to be able to plug in different storage backends like files
// for instance it is a good idea to turn storage related exceptions
// into service related exceptions so controllers and service users
// have to deal with only one type of exception
} catch (Exception $e) {
$this->handleException($e);
}
}
public function create($id, $imgurl, $title, $pubdate, $duration, $playtime,
$lastplayed, $enclosure, $description, $podcastid, $userId) {
$episode = new Episode();
$episode->setId($id);
$episode->setImgurl($imgurl);
$episode->setTitle($title);
$episode->setPubdate($pubdate);
$episode->setDuration($duration);
$episode->setPlaytime($playtime);
$episode->setLastplayed($lastplayed);
$episode->setEnclosure($enclosure);
$episode->setDescription($description);
$episode->setPodcastid($podcastid);
$episode->setUserId($userId);
return $this->mapper->insert($episode);
}
public function update($id, $imgurl, $title, $pubdate, $duration, $playtime,
$lastplayed, $enclosure, $description, $podcastid, $userId) {
try {
$episode = $this->mapper->find($id, $userId);
$episode->setImgurl($imgurl);
$episode->setTitle($title);
$episode->setPubdate($pubdate);
$episode->setDuration($duration);
$episode->setPlaytime($playtime);
$episode->setLastplayed($lastplayed);
$episode->setEnclosure($enclosure);
$episode->setDescription($description);
$episode->setPodcastid($podcastid);
return $this->mapper->update($episode);
} catch (Exception $e) {
$this->handleException($e);
}
}
public function delete($id, $userId) {
try {
$episode = $this->mapper->find($id, $userId);
$this->mapper->delete($episode);
return $episode;
} catch (Exception $e) {
$this->handleException($e);
}
}
}
<?php
/**
* Podcast App
*
* @author Jonas Heinrich
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
declare(strict_types=1);
namespace OCA\Podcast\Service;
use OCP\IURLGenerator;
use OCP\Http\Client\IClientService;
use function urlencode;
class FyydApiService {
/** @var IClientService */
private $clientService;
/** @var IURLGenerator */
private $url;
public $baseUrl = "https://api.fyyd.de/0.2";
public function __construct(
IClientService $clientService,
IURLGenerator $url
) {
$this->clientService = $clientService;
$this->url = $url;
}
public function queryEpisodes(int $podcast_id, int $count = 20, int $page = 0) {
$url = $this->baseUrl . "/podcast/episodes";
$options['query'] = [
'podcast_id' => $podcast_id,
'count' => $count,
'page' => $page
];
$client = $this->clientService->newClient();
try {
$response = $client->get($url, $options);
} catch (Exception $e) {
$this->logger->error("Could not search for podcasts: " . $e->getMessage());
throw $e;
}
$body = $response->getBody();
$parsed = json_decode($body, true);
return $parsed;
}
public function queryEpisode(int $episode_id) {
$url = $this->baseUrl . "/episode";
$options['query'] = [
'episode_id' => $episode_id,
];
$client = $this->clientService->newClient();
try {
$response = $client->get($url, $options);
} catch (Exception $e) {
$this->logger->error("Could not search for podcasts: " . $e->getMessage());
throw $e;
}
$body = $response->getBody();
$parsed = json_decode($body, true);
return $parsed;
}
public function queryPodcast(int $podcast_id) {
$url = $this->baseUrl . "/podcast";
$options['query'] = [
'podcast_id' => $podcast_id,
];
$client = $this->clientService->newClient();
try {
$response = $client->get($url, $options);
} catch (Exception $e) {
$this->logger->error("Could not search for podcasts: " . $e->getMessage());
throw $e;
}
$body = $response->getBody();
$parsed = json_decode($body, true);
return $parsed;
}
public function queryCategory(string $category, int $count = 20,
int $page = 0) {
if ($category === 'hot') {
$url = $this->baseUrl . "/feature/podcast/hot";
$options['query'] = [
'count' => $count,
'page' => $page,
];
} else if ($category === 'latest') {
$url = $this->baseUrl . "/podcast/latest";
$options['query'] = [
'count' => $count,
'page' => $page,
];
} else {
$url = $this->baseUrl . "/category";
$options['query'] = [
'count' => $count,
'page' => $page,
'category_id' => $category,
];
}
$client = $this->clientService->newClient();
try {
$response = $client->get($url, $options);
} catch (Exception $e) {
$this->logger->error("Could not search for podcasts: " . $e->getMessage());
throw $e;
}
$body = $response->getBody();
$parsed = json_decode($body, true);
return $parsed;
}
}