diff --git a/lib/Core/EpisodeAction/EpisodeActionReader.php b/lib/Core/EpisodeAction/EpisodeActionReader.php index 75a7a42..87aee49 100644 --- a/lib/Core/EpisodeAction/EpisodeActionReader.php +++ b/lib/Core/EpisodeAction/EpisodeActionReader.php @@ -4,22 +4,44 @@ declare(strict_types=1); namespace OCA\GPodderSync\Core\EpisodeAction; class EpisodeActionReader { - public function fromString(string $episodeActionString): EpisodeAction { - preg_match( - '/\[EpisodeAction{(podcast=\')(?.*?)(\', episode=\')(?.*?)(\', action=)(?.*?)(, timestamp=)(?.*?)(, started=)(?.*?)(, position=)(?.*?)(, total=)(?.*?)}]*/', - $episodeActionString, - $matches - ); + /** + * Reads and parses an EpisodeActions string and returns an EpisodeAction array + * + * @param string $episodeActionString + * @return array + */ + public function fromString(string $episodeActionString): array { + + $episodeActions = array(); - return new EpisodeAction( - $matches["podcast"], - $matches["episode"], - $matches["action"], - $matches["timestamp"], - (int)$matches["started"], - (int)$matches["position"], - (int)$matches["total"], - ); + $seek = 0; + + while (strpos($episodeActionString, 'EpisodeAction{', $seek) >= $seek) { + if (($seek = strpos($episodeActionString, 'EpisodeAction{', $seek)) === false) { + continue; + } + + preg_match( + '/EpisodeAction{(podcast=\')(?.*?)(\', episode=\')(?.*?)(\', action=)(?.*?)(, timestamp=)(?.*?)(, started=)(?.*?)(, position=)(?.*?)(, total=)(?.*?)}]*/', + substr($episodeActionString, $seek), + $matches + ); + + // change for next iteration + $seek++; + + array_push($episodeActions, new EpisodeAction( + $matches["podcast"], + $matches["episode"], + $matches["action"], + $matches["timestamp"], + (int)$matches["started"], + (int)$matches["position"], + (int)$matches["total"], + )); + } + + return $episodeActions; } } diff --git a/lib/Core/EpisodeAction/EpisodeActionSaver.php b/lib/Core/EpisodeAction/EpisodeActionSaver.php index dc37879..233e0a0 100644 --- a/lib/Core/EpisodeAction/EpisodeActionSaver.php +++ b/lib/Core/EpisodeAction/EpisodeActionSaver.php @@ -31,30 +31,36 @@ class EpisodeActionSaver /** * @param $data * - * @return EpisodeActionEntity + * @return array */ - public function saveEpisodeAction($data, string $userId): EpisodeActionEntity + public function saveEpisodeAction($data, string $userId): array { - $episodeAction = $this->episodeActionReader->fromString($data); - $episodeActionEntity = new EpisodeActionEntity(); - $episodeActionEntity->setPodcast($episodeAction->getPodcast()); - $episodeActionEntity->setEpisode($episodeAction->getEpisode()); - $episodeActionEntity->setAction($episodeAction->getAction()); - $episodeActionEntity->setPosition($episodeAction->getPosition()); - $episodeActionEntity->setStarted($episodeAction->getStarted()); - $episodeActionEntity->setTotal($episodeAction->getTotal()); - $episodeActionEntity->setTimestamp($this->convertTimestampToDbDateTimeString($episodeAction->getTimestamp())); - $episodeActionEntity->setUserId($userId); + $response = array(); - try { - return $this->episodeActionWriter->save($episodeActionEntity); - } catch (UniqueConstraintViolationException $uniqueConstraintViolationException) { - return $this->updateEpisodeAction($episodeAction, $episodeActionEntity, $userId); - } catch (Exception $exception) { - if ($exception->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { - return $this->updateEpisodeAction($episodeAction, $episodeActionEntity, $userId); - } - } + $episodeActions = $this->episodeActionReader->fromString($data); + + foreach ($episodeActions as $episodeAction) { + $episodeActionEntity = new EpisodeActionEntity(); + $episodeActionEntity->setPodcast($episodeAction->getPodcast()); + $episodeActionEntity->setEpisode($episodeAction->getEpisode()); + $episodeActionEntity->setAction($episodeAction->getAction()); + $episodeActionEntity->setPosition($episodeAction->getPosition()); + $episodeActionEntity->setStarted($episodeAction->getStarted()); + $episodeActionEntity->setTotal($episodeAction->getTotal()); + $episodeActionEntity->setTimestamp($this->convertTimestampToDbDateTimeString($episodeAction->getTimestamp())); + $episodeActionEntity->setUserId($userId); + + try { + array_push($response, $this->episodeActionWriter->save($episodeActionEntity)); + } catch (UniqueConstraintViolationException $uniqueConstraintViolationException) { + array_push($response, $this->updateEpisodeAction($episodeAction, $episodeActionEntity, $userId)); + } catch (Exception $exception) { + if ($exception->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + array_push($response, $this->updateEpisodeAction($episodeAction, $episodeActionEntity, $userId)); + } + } + } + return $response; } /** diff --git a/tests/Unit/Core/EpisodeAction/EpisodeActionReaderTest.php b/tests/Unit/Core/EpisodeAction/EpisodeActionReaderTest.php index 93ec74f..914d2ef 100644 --- a/tests/Unit/Core/EpisodeAction/EpisodeActionReaderTest.php +++ b/tests/Unit/Core/EpisodeAction/EpisodeActionReaderTest.php @@ -9,7 +9,8 @@ use Test\TestCase; class EpisodeActionReaderTest extends TestCase { public function testCreateFromString(): void { $reader = new EpisodeActionReader(); - $episodeAction = $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}]'); + $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()); @@ -20,4 +21,33 @@ class EpisodeActionReaderTest extends TestCase { } + 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()); + } + }