Adjust EpisodeAction upload to gpodder api, remove String upload
Remove 3rd dimension of POST data by directly accessing request data - a simple EpisodeActions array has to be posted now. This way the api is closer to gpodder. Additionally, removed EpisodeAction upload as String, so it's now incompatible with older versions
This commit is contained in:
parent
91c2dccd3c
commit
795a9253d2
|
@ -22,6 +22,8 @@ class EpisodeActionController extends Controller {
|
||||||
private $userId;
|
private $userId;
|
||||||
private EpisodeActionSaver $episodeActionSaver;
|
private EpisodeActionSaver $episodeActionSaver;
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
string $AppName,
|
string $AppName,
|
||||||
IRequest $request,
|
IRequest $request,
|
||||||
|
@ -33,6 +35,7 @@ class EpisodeActionController extends Controller {
|
||||||
$this->episodeActionRepository = $episodeActionRepository;
|
$this->episodeActionRepository = $episodeActionRepository;
|
||||||
$this->userId = $UserId;
|
$this->userId = $UserId;
|
||||||
$this->episodeActionSaver = $episodeActionSaver;
|
$this->episodeActionSaver = $episodeActionSaver;
|
||||||
|
$this->request = $request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,10 +43,15 @@ class EpisodeActionController extends Controller {
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return JSONResponse
|
||||||
*/
|
*/
|
||||||
public function create($data) {
|
public function create(): JSONResponse {
|
||||||
return $this->episodeActionSaver->saveEpisodeActions($data, $this->userId);
|
|
||||||
|
$episodeActionsArray = $this->filterEpisodesFromRequestParams($this->request->getParams());
|
||||||
|
|
||||||
|
$this->episodeActionSaver->saveEpisodeActions($episodeActionsArray, $this->userId);
|
||||||
|
|
||||||
|
return new JSONResponse(["timestamp" => time()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,4 +75,26 @@ class EpisodeActionController extends Controller {
|
||||||
"timestamp" => time()
|
"timestamp" => time()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $requestParams
|
||||||
|
*
|
||||||
|
* @return array $episodeActionsArray
|
||||||
|
*/
|
||||||
|
public function filterEpisodesFromRequestParams(array $data): array {
|
||||||
|
return array_filter($data, "is_numeric", ARRAY_FILTER_USE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int|null $since
|
||||||
|
*
|
||||||
|
* @return DateTime
|
||||||
|
*/
|
||||||
|
private function createDateTimeFromTimestamp(?int $since): DateTime {
|
||||||
|
return ($since !== null)
|
||||||
|
? (new \DateTime)->setTimestamp($since)
|
||||||
|
: (new \DateTime('-1 week'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,55 +5,6 @@ namespace OCA\GPodderSync\Core\EpisodeAction;
|
||||||
|
|
||||||
class EpisodeActionReader
|
class EpisodeActionReader
|
||||||
{
|
{
|
||||||
|
|
||||||
const EPISODEACTION_IDENTIFIER = 'EpisodeAction{';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $episodeActionsString
|
|
||||||
* @return EpisodeAction[]
|
|
||||||
*/
|
|
||||||
public function fromString(string $episodeActionsString): array
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
$patterns = [
|
|
||||||
'/EpisodeAction{(podcast=\')(?<podcast>.*?)(\', episode=\')(?<episode>.*?)(\', guid=\')(?<guid>.*?)(\', action=)(?<action>.*?)(, timestamp=)(?<timestamp>.*?)(, started=)(?<started>.*?)(, position=)(?<position>.*?)(, total=)(?<total>.*?)}]*/',
|
|
||||||
'/EpisodeAction{(podcast=\')(?<podcast>.*?)(\', episode=\')(?<episode>.*?)(\', action=)(?<action>.*?)(, timestamp=)(?<timestamp>.*?)(, started=)(?<started>.*?)(, position=)(?<position>.*?)(, total=)(?<total>.*?)}]*/',
|
|
||||||
];
|
|
||||||
|
|
||||||
$episodeActions = [];
|
|
||||||
|
|
||||||
$episodeActionStrings = explode(self::EPISODEACTION_IDENTIFIER, $episodeActionsString);
|
|
||||||
array_shift($episodeActionStrings);
|
|
||||||
|
|
||||||
foreach ($episodeActionStrings as $episodeActionString) {
|
|
||||||
foreach ($patterns as $pattern) {
|
|
||||||
preg_match(
|
|
||||||
$pattern,
|
|
||||||
self::EPISODEACTION_IDENTIFIER . $episodeActionString,
|
|
||||||
$matches
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($matches["action"] !== null) {
|
|
||||||
$episodeActions[] = new EpisodeAction(
|
|
||||||
$matches["podcast"],
|
|
||||||
$matches["episode"],
|
|
||||||
$matches["action"],
|
|
||||||
$matches["timestamp"],
|
|
||||||
(int)$matches["started"],
|
|
||||||
(int)$matches["position"],
|
|
||||||
(int)$matches["total"],
|
|
||||||
$matches["guid"] ?? null,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return $episodeActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $episodeActionsArray[]
|
* @param $episodeActionsArray[]
|
||||||
* @return EpisodeAction[]
|
* @return EpisodeAction[]
|
||||||
|
|
|
@ -29,32 +29,27 @@ class EpisodeActionSaver
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string|array $data
|
* @param array $episodeActionsArray
|
||||||
*
|
*
|
||||||
* @return EpisodeActionEntity[]
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function saveEpisodeActions($data, string $userId): array
|
public function saveEpisodeActions($episodeActionsArray, string $userId): void
|
||||||
{
|
{
|
||||||
$episodeActionEntities = [];
|
$episodeActions = $this->episodeActionReader->fromArray($episodeActionsArray);
|
||||||
|
|
||||||
$episodeActions = is_array($data)
|
|
||||||
? $this->episodeActionReader->fromArray($data)
|
|
||||||
: $this->episodeActionReader->fromString($data);
|
|
||||||
|
|
||||||
foreach ($episodeActions as $episodeAction) {
|
foreach ($episodeActions as $episodeAction) {
|
||||||
$episodeActionEntity = $this->hydrateEpisodeActionEntity($episodeAction, $userId);
|
$episodeActionEntity = $this->hydrateEpisodeActionEntity($episodeAction, $userId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$episodeActionEntities[] = $this->episodeActionWriter->save($episodeActionEntity);
|
$this->episodeActionWriter->save($episodeActionEntity);
|
||||||
} catch (UniqueConstraintViolationException $uniqueConstraintViolationException) {
|
} catch (UniqueConstraintViolationException $uniqueConstraintViolationException) {
|
||||||
$episodeActionEntities[] = $this->updateEpisodeAction($episodeActionEntity, $userId);
|
$this->updateEpisodeAction($episodeActionEntity, $userId);
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
if ($exception->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
|
if ($exception->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
|
||||||
$episodeActionEntities[] = $this->updateEpisodeAction($episodeActionEntity, $userId);
|
$this->updateEpisodeAction($episodeActionEntity, $userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $episodeActionEntities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function convertTimestampToUnixEpoch(string $timestamp): string
|
private function convertTimestampToUnixEpoch(string $timestamp): string
|
||||||
|
|
|
@ -7,63 +7,6 @@ use OCA\GPodderSync\Core\EpisodeAction\EpisodeActionReader;
|
||||||
use Test\TestCase;
|
use Test\TestCase;
|
||||||
|
|
||||||
class EpisodeActionReaderTest extends TestCase {
|
class EpisodeActionReaderTest extends TestCase {
|
||||||
public function testCreateFromString(): void {
|
|
||||||
$reader = new EpisodeActionReader();
|
|
||||||
$episodeActions = $reader->fromString('[EpisodeAction{podcast=\'https://feeds.simplecast.com/wEl4UUJZ\', episode=\'https://chrt.fm/track/47G541/injector.simplecastaudio.com/f16c3da7-cf46-4a42-99b7-8467255c6086/episodes/e8e24c01-6157-40e8-9b5a-45d539aeb7e6/audio/128/default.mp3?aid=rss_feed&awCollectionId=f16c3da7-cf46-4a42-99b7-8467255c6086&awEpisodeId=e8e24c01-6157-40e8-9b5a-45d539aeb7e6&feed=wEl4UUJZ\', action=PLAY, timestamp=Tue May 18 23:45:11 GMT+02:00 2021, started=31, position=36, total=2474}]');
|
|
||||||
$episodeAction = $episodeActions[0];
|
|
||||||
$this->assertSame("https://feeds.simplecast.com/wEl4UUJZ", $episodeAction->getPodcast());
|
|
||||||
$this->assertSame("https://chrt.fm/track/47G541/injector.simplecastaudio.com/f16c3da7-cf46-4a42-99b7-8467255c6086/episodes/e8e24c01-6157-40e8-9b5a-45d539aeb7e6/audio/128/default.mp3?aid=rss_feed&awCollectionId=f16c3da7-cf46-4a42-99b7-8467255c6086&awEpisodeId=e8e24c01-6157-40e8-9b5a-45d539aeb7e6&feed=wEl4UUJZ", $episodeAction->getEpisode());
|
|
||||||
$this->assertSame("PLAY", $episodeAction->getAction());
|
|
||||||
$this->assertSame("Tue May 18 23:45:11 GMT+02:00 2021", $episodeAction->getTimestamp());
|
|
||||||
$this->assertNull($episodeAction->getGuid());
|
|
||||||
$this->assertSame(31, $episodeAction->getStarted());
|
|
||||||
$this->assertSame(36, $episodeAction->getPosition());
|
|
||||||
$this->assertSame(2474, $episodeAction->getTotal());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCreateFromStringWithGuid(): void {
|
|
||||||
$reader = new EpisodeActionReader();
|
|
||||||
$episodeActions = $reader->fromString("[EpisodeAction{podcast='https://rss.art19.com/dr-death-s3-miracle-man', episode='https://dts.podtrac.com/redirect.mp3/chrt.fm/track/9EE2G/pdst.fm/e/rss.art19.com/episodes/db0e3500', guid='gid://art19-episode-locator/V0/KtdfKfLndyWetCZ6t2WhUEFOFArDXRExVIb4Z1fh-TU', action=PLAY, timestamp=Mon Aug 23 01:58:56 GMT+02:00 2021, started=47, position=54, total=2252}]");
|
|
||||||
$episodeAction = $episodeActions[0];
|
|
||||||
$this->assertSame("https://rss.art19.com/dr-death-s3-miracle-man", $episodeAction->getPodcast());
|
|
||||||
$this->assertSame("https://dts.podtrac.com/redirect.mp3/chrt.fm/track/9EE2G/pdst.fm/e/rss.art19.com/episodes/db0e3500", $episodeAction->getEpisode());
|
|
||||||
$this->assertSame("PLAY", $episodeAction->getAction());
|
|
||||||
$this->assertSame("Mon Aug 23 01:58:56 GMT+02:00 2021", $episodeAction->getTimestamp());
|
|
||||||
$this->assertSame("gid://art19-episode-locator/V0/KtdfKfLndyWetCZ6t2WhUEFOFArDXRExVIb4Z1fh-TU", $episodeAction->getGuid());
|
|
||||||
$this->assertSame(47, $episodeAction->getStarted());
|
|
||||||
$this->assertSame(54, $episodeAction->getPosition());
|
|
||||||
$this->assertSame(2252, $episodeAction->getTotal());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCreateFromMultipleEpisodesString(): void {
|
|
||||||
$reader = new EpisodeActionReader();
|
|
||||||
$episodeActions = $reader->fromString('[EpisodeAction{podcast=\'https://example.com/feed.xml\', episode=\'https://example.com/episode1.mp3\', action=PLAY, timestamp=Tue May 18 23:45:11 GMT+02:00 2021, started=31, position=36, total=2474},EpisodeAction{podcast=\'https://example.com/feed.xml\', episode=\'https://example.com/episode2.mp3\', action=DOWNLOAD, timestamp=Tue May 18 23:46:42 GMT+02:00 2021, started=31, position=36, total=2474},EpisodeAction{podcast=\'https://example.org/feed.xml\', episode=\'https://chrt.fm/track/47G541/injector.simplecastaudio.com/f16c3da7-cf46-4a42-99b7-8467255c6086/episodes/e8e24c01-6157-40e8-9b5a-45d539aeb7e6/audio/128/default.mp3?aid=rss_feed&awCollectionId=f16c3da7-cf46-4a42-99b7-8467255c6086&awEpisodeId=e8e24c01-6157-40e8-9b5a-45d539aeb7e6&feed=wEl4UUJZ\', action=PLAY, timestamp=Tue May 18 23:45:14 GMT+02:00 2021, started=0, position=211, total=3121}]');
|
|
||||||
|
|
||||||
$this->assertSame("https://example.com/feed.xml", $episodeActions[0]->getPodcast());
|
|
||||||
$this->assertSame("https://example.com/episode1.mp3", $episodeActions[0]->getEpisode());
|
|
||||||
$this->assertSame("PLAY", $episodeActions[0]->getAction());
|
|
||||||
$this->assertSame("Tue May 18 23:45:11 GMT+02:00 2021", $episodeActions[0]->getTimestamp());
|
|
||||||
$this->assertSame(31, $episodeActions[0]->getStarted());
|
|
||||||
$this->assertSame(36, $episodeActions[0]->getPosition());
|
|
||||||
$this->assertSame(2474, $episodeActions[0]->getTotal());
|
|
||||||
|
|
||||||
$this->assertSame("https://example.com/feed.xml", $episodeActions[1]->getPodcast());
|
|
||||||
$this->assertSame("https://example.com/episode2.mp3", $episodeActions[1]->getEpisode());
|
|
||||||
$this->assertSame("DOWNLOAD", $episodeActions[1]->getAction());
|
|
||||||
$this->assertSame("Tue May 18 23:46:42 GMT+02:00 2021", $episodeActions[1]->getTimestamp());
|
|
||||||
$this->assertSame(31, $episodeActions[1]->getStarted());
|
|
||||||
$this->assertSame(36, $episodeActions[1]->getPosition());
|
|
||||||
$this->assertSame(2474, $episodeActions[1]->getTotal());
|
|
||||||
|
|
||||||
$this->assertSame("https://example.org/feed.xml", $episodeActions[2]->getPodcast());
|
|
||||||
$this->assertSame("https://chrt.fm/track/47G541/injector.simplecastaudio.com/f16c3da7-cf46-4a42-99b7-8467255c6086/episodes/e8e24c01-6157-40e8-9b5a-45d539aeb7e6/audio/128/default.mp3?aid=rss_feed&awCollectionId=f16c3da7-cf46-4a42-99b7-8467255c6086&awEpisodeId=e8e24c01-6157-40e8-9b5a-45d539aeb7e6&feed=wEl4UUJZ", $episodeActions[2]->getEpisode());
|
|
||||||
$this->assertSame("PLAY", $episodeActions[2]->getAction());
|
|
||||||
$this->assertSame("Tue May 18 23:45:14 GMT+02:00 2021", $episodeActions[2]->getTimestamp());
|
|
||||||
$this->assertSame(0, $episodeActions[2]->getStarted());
|
|
||||||
$this->assertSame(211, $episodeActions[2]->getPosition());
|
|
||||||
$this->assertSame(3121, $episodeActions[2]->getTotal());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCreateFromArray(): void {
|
public function testCreateFromArray(): void {
|
||||||
$reader = new EpisodeActionReader();
|
$reader = new EpisodeActionReader();
|
||||||
$episodeActions = $reader->fromArray([["podcast" => "https://example.org/feed.xml", "episode" => "https://example.org/episode1.mp3", "action" => "PLAY", "timestamp" => "Sun Oct 03 14:03:17 GMT+02:00 2021", "started" => 0, "position" => 50, "total"=> 3422]]);
|
$episodeActions = $reader->fromArray([["podcast" => "https://example.org/feed.xml", "episode" => "https://example.org/episode1.mp3", "action" => "PLAY", "timestamp" => "Sun Oct 03 14:03:17 GMT+02:00 2021", "started" => 0, "position" => 50, "total"=> 3422]]);
|
||||||
|
|
Loading…
Reference in New Issue