diff --git a/formats/M3uFormat.php b/formats/M3uFormat.php new file mode 100644 index 00000000000..50d75c2bd26 --- /dev/null +++ b/formats/M3uFormat.php @@ -0,0 +1,94 @@ +item_duration = null; + $this->item_title = null; + $this->item_url = null; + $this->item_bytes = null; + } + private function itemIsEmpty(): bool + { + return $this->item_url === null; + } + private function itemRender(): string + { + if ($this->itemIsEmpty()) { + return ''; + } + $text = "\n"; + $commentParts = []; + if ($this->item_duration !== null && $this->item_duration > 0) { + $commentParts[] = $this->item_duration; + } + if ($this->item_title !== null) { + $commentParts[] = $this->item_title; + } + + if (count($commentParts) !== 0) { + $text .= '#EXTINF:' . implode(',', $commentParts) . "\n"; + } + + $text .= $this->item_url . "\n"; + return $text; + } + + public function stringify() + { + $contents = "#EXTM3U\n"; + + foreach ($this->getItems() as $item) { + $this->resetItem(); + $itemArray = $item->toArray(); + + if (isset($itemArray['enclosure'])) { + $this->item_url = $itemArray['enclosure']['url']; + $this->item_bytes = $itemArray['enclosure']['length']; + if (isset($itemArray['itunes']) && isset($itemArray['itunes']['duration'])) { + $this->item_duration = self::parseDuration($itemArray['itunes']['duration']); + } + } + if (isset($itemArray['title'])) { + $item->item_title = $itemArray['title']; + } + if (! $this->itemIsEmpty()) { + $contents .= $this->itemRender(); + } else { + foreach ($item->enclosures as $url) { + $this->resetItem(); + $this->item_url = $url; + if (isset($itemArray['title'])) { + $this->item_title = $itemArray['title']; + } + $contents .= $this->itemRender(); + } + } + } + return mb_convert_encoding($contents, $this->getCharset(), 'UTF-8'); + } + /* + * parseDuration converts a string like "00:4:20" to 260 + * allowing to convert duration as used in the itunes:duration tag to the number of seconds + */ + private static function parseDuration(string $duration_string): int + { + $seconds = 0; + $parts = explode(':', $duration_string); + for ($i = 0; $i < count($parts); $i++) { + $seconds += intval($parts[count($parts) - $i - 1]) * pow(60, $i); + } + return $seconds; + } +} diff --git a/tests/Formats/M3uFormatTest.php b/tests/Formats/M3uFormatTest.php new file mode 100644 index 00000000000..22743e6674c --- /dev/null +++ b/tests/Formats/M3uFormatTest.php @@ -0,0 +1,29 @@ +formatData('M3u', $this->loadSample($path)); + + $expected = file_get_contents(self::PATH_EXPECTED . $name . '.m3u'); + $this->assertEquals($expected, $data); + } +} + diff --git a/tests/Formats/samples/expectedM3uFormat/feed.common.m3u b/tests/Formats/samples/expectedM3uFormat/feed.common.m3u new file mode 100644 index 00000000000..801996076ae --- /dev/null +++ b/tests/Formats/samples/expectedM3uFormat/feed.common.m3u @@ -0,0 +1,4 @@ +#EXTM3U + +#EXTINF:Atom draft-07 snapshot +http://example.org/audio/ph34r_my_podcast.mp3 diff --git a/tests/Formats/samples/expectedM3uFormat/feed.empty.m3u b/tests/Formats/samples/expectedM3uFormat/feed.empty.m3u new file mode 100644 index 00000000000..fcd718794a8 --- /dev/null +++ b/tests/Formats/samples/expectedM3uFormat/feed.empty.m3u @@ -0,0 +1 @@ +#EXTM3U diff --git a/tests/Formats/samples/expectedM3uFormat/feed.emptyItems.m3u b/tests/Formats/samples/expectedM3uFormat/feed.emptyItems.m3u new file mode 100644 index 00000000000..fcd718794a8 --- /dev/null +++ b/tests/Formats/samples/expectedM3uFormat/feed.emptyItems.m3u @@ -0,0 +1 @@ +#EXTM3U diff --git a/tests/Formats/samples/expectedM3uFormat/feed.microblog.m3u b/tests/Formats/samples/expectedM3uFormat/feed.microblog.m3u new file mode 100644 index 00000000000..fcd718794a8 --- /dev/null +++ b/tests/Formats/samples/expectedM3uFormat/feed.microblog.m3u @@ -0,0 +1 @@ +#EXTM3U