Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create PodcastIndex extension #31

Merged
merged 6 commits into from
Mar 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/.phpunit.result.cache
/.psalm-cache
/clover.xml
/coveralls-upload.json
/docs/html/
/laminas-mkdoc-theme.tgz
/laminas-mkdoc-theme/
/phpunit.xml
/vendor/
/.phpunit.result.cache
24 changes: 24 additions & 0 deletions docs/book/extensions/podcast-index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Podcast Index

The Podcast Index Extension adds support for the [Podcast Index RSS namespace](https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md),
an open source project which consolidates new features for podcasts into a
single namespace.

Channel API methods:

Method | Description
------ | -----------
`isLocked()` | Returns whether the feed is open for importing to new platforms.
`getLockOwner()` | Returns the email address for owner verification.
`getFunding()` | Returns funding information. The output is an object with "url" and "value" properties.

Item API methods:

Method | Description
------ | -----------
`getTranscript()` | Returns transcript information for the entry. The output is an object with "url", "type", "language" and "rel" properties/
`getChapters()` | Returns chapter information for the entry. The output is an object with "url" and "type" properties.
`getSoundbites()` | Returns soundbites for the entry. The output is an array of objects with "title", "startTime" and "duration" properties.

See the [Podcast Index website](https://podcastindex.org) for more information
about the project.
1 change: 1 addition & 0 deletions docs/book/reader.md
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ Slash | Implements support for the Slash RSS 1.0 module.
WellFormedWeb | Implements support for the Well Formed Web CommentAPI 1.0.
Thread | Implements support for Atom Threading Extensions as described in RFC 4685.
Podcast | Implements support for the Podcast 1.0 DTD from Apple.
[PodcastIndex](extensions/podcast-index.md) | Implements support for the Podcast Index 1.0 RSS namespace.
GooglePlayPodcast | Implements support for the Google Play Podcasts 1.0 DTD from Google.

The core extensions are somewhat special since they are extremely common and
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ nav:
- Security: security.md
- Writer: writer.md
- Pubsubhubbub: pubsubhubbub.md
- Extensions:
- 'Podcast Index': extensions/podcast-index.md
site_name: laminas-feed
site_description: 'Consume and generate Atom and RSS feeds, and interact with Pubsubhubbub.'
repo_url: 'https://github.com/laminas/laminas-feed'
Expand Down
132 changes: 129 additions & 3 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@
<InvalidPropertyAssignmentValue occurrences="1">
<code>$entryKey</code>
</InvalidPropertyAssignmentValue>
<MissingConstructor occurrences="30">
<MissingConstructor occurrences="33">
<code>$domDocument</code>
<code>$domDocument</code>
<code>$domDocument</code>
Expand All @@ -803,6 +803,8 @@
<code>$domDocument</code>
<code>$domDocument</code>
<code>$domDocument</code>
<code>$domDocument</code>
<code>$entry</code>
<code>$entry</code>
<code>$entry</code>
<code>$entry</code>
Expand All @@ -823,6 +825,7 @@
<code>$xpath</code>
<code>$xpath</code>
<code>$xpath</code>
<code>$xpath</code>
</MissingConstructor>
<MixedAssignment occurrences="1">
<code>$type</code>
Expand All @@ -846,14 +849,16 @@
<DocblockTypeContradiction occurrences="1">
<code>null === $this-&gt;xpath</code>
</DocblockTypeContradiction>
<MissingConstructor occurrences="14">
<MissingConstructor occurrences="16">
<code>$domDocument</code>
<code>$domDocument</code>
<code>$domDocument</code>
<code>$domDocument</code>
<code>$domDocument</code>
<code>$domDocument</code>
<code>$domDocument</code>
<code>$domDocument</code>
<code>$xpath</code>
<code>$xpath</code>
<code>$xpath</code>
<code>$xpath</code>
Expand Down Expand Up @@ -1441,6 +1446,39 @@
<code>getAttribute</code>
</UndefinedMethod>
</file>
<file src="src/Reader/Extension/PodcastIndex/Entry.php">
<MismatchingDocblockReturnType occurrences="2">
<code>null|object{url: string, type: string, language: string, rel: string}</code>
<code>null|object{url: string, type: string}</code>
</MismatchingDocblockReturnType>
<MixedInferredReturnType occurrences="3">
<code>array&lt;int, object{title: string, startTime: string, duration: string}&gt;</code>
<code>null|object{url: string, type: string, language: string, rel: string}</code>
<code>null|object{url: string, type: string}</code>
</MixedInferredReturnType>
<MixedReturnStatement occurrences="1">
<code>$this-&gt;data['soundbites']</code>
</MixedReturnStatement>
</file>
<file src="src/Reader/Extension/PodcastIndex/Feed.php">
<MismatchingDocblockReturnType occurrences="1">
<code>null|object{url: string, title: string}</code>
</MismatchingDocblockReturnType>
<MixedAssignment occurrences="2">
<code>$locked</code>
<code>$owner</code>
</MixedAssignment>
<MixedInferredReturnType occurrences="3">
<code>?string</code>
<code>bool</code>
<code>null|object{url: string, title: string}</code>
</MixedInferredReturnType>
<MixedReturnStatement occurrences="3">
<code>$this-&gt;data['locked']</code>
<code>$this-&gt;data['owner']</code>
<code>$this-&gt;data['owner']</code>
</MixedReturnStatement>
</file>
<file src="src/Reader/Extension/Slash/Entry.php">
<InvalidOperand occurrences="1">
<code>$hit</code>
Expand Down Expand Up @@ -2428,7 +2466,9 @@
<code>$this</code>
<code>$this</code>
</ImplementedReturnTypeMismatch>
<MissingConstructor occurrences="44">
<MissingConstructor occurrences="52">
<code>$base</code>
<code>$base</code>
<code>$base</code>
<code>$base</code>
<code>$base</code>
Expand All @@ -2451,6 +2491,9 @@
<code>$dom</code>
<code>$dom</code>
<code>$dom</code>
<code>$dom</code>
<code>$dom</code>
<code>$rootElement</code>
<code>$rootElement</code>
<code>$rootElement</code>
<code>$rootElement</code>
Expand All @@ -2462,6 +2505,9 @@
<code>$rootElement</code>
<code>$rootElement</code>
<code>$rootElement</code>
<code>$rootElement</code>
<code>$type</code>
<code>$type</code>
<code>$type</code>
<code>$type</code>
<code>$type</code>
Expand Down Expand Up @@ -2875,6 +2921,33 @@
<code>empty($owners)</code>
</ParadoxicalCondition>
</file>
<file src="src/Writer/Extension/PodcastIndex/Entry.php">
<MixedArgument occurrences="1">
<code>$value</code>
</MixedArgument>
<MixedArrayAssignment occurrences="1">
<code>$this-&gt;data['soundbites'][]</code>
</MixedArrayAssignment>
<MixedAssignment occurrences="1">
<code>$value</code>
</MixedAssignment>
</file>
<file src="src/Writer/Extension/PodcastIndex/Renderer/Entry.php">
<MixedAssignment occurrences="1">
<code>$soundbite</code>
</MixedAssignment>
<MixedMethodCall occurrences="3">
<code>getPodcastIndexChapters</code>
<code>getPodcastIndexSoundbites</code>
<code>getPodcastIndexTranscript</code>
</MixedMethodCall>
</file>
<file src="src/Writer/Extension/PodcastIndex/Renderer/Feed.php">
<MixedMethodCall occurrences="2">
<code>getPodcastIndexFunding</code>
<code>getPodcastIndexLocked</code>
</MixedMethodCall>
</file>
<file src="src/Writer/Extension/Slash/Renderer/Entry.php">
<MixedAssignment occurrences="2">
<code>$count</code>
Expand Down Expand Up @@ -5764,6 +5837,34 @@
<code>getEncoding</code>
</UndefinedInterfaceMethod>
</file>
<file src="test/Reader/Integration/PodcastIndexRss2Test.php">
<MissingPropertyType occurrences="1">
<code>$feedSamplePath</code>
</MissingPropertyType>
<MixedArgument occurrences="6">
<code>$this-&gt;feedSamplePath</code>
<code>$this-&gt;feedSamplePath</code>
<code>$this-&gt;feedSamplePath</code>
<code>$this-&gt;feedSamplePath</code>
<code>$this-&gt;feedSamplePath</code>
<code>$this-&gt;feedSamplePath</code>
</MixedArgument>
<MixedAssignment occurrences="3">
<code>$entry</code>
<code>$entry</code>
<code>$entry</code>
</MixedAssignment>
<MixedMethodCall occurrences="3">
<code>getChapters</code>
<code>getSoundbites</code>
<code>getTranscript</code>
</MixedMethodCall>
<UndefinedInterfaceMethod occurrences="3">
<code>getFunding</code>
<code>getLockOwner</code>
<code>isLocked</code>
</UndefinedInterfaceMethod>
</file>
<file src="test/Reader/Integration/PodcastRss2Test.php">
<MissingClosureParamType occurrences="2">
<code>$errno</code>
Expand Down Expand Up @@ -6341,6 +6442,31 @@
<code>$errstr</code>
</MixedArgument>
</file>
<file src="test/Writer/Extension/PodcastIndex/EntryTest.php">
<InvalidArgument occurrences="8">
<code>ExceptionInterface::class</code>
<code>ExceptionInterface::class</code>
<code>ExceptionInterface::class</code>
<code>ExceptionInterface::class</code>
<code>ExceptionInterface::class</code>
<code>ExceptionInterface::class</code>
<code>ExceptionInterface::class</code>
<code>ExceptionInterface::class</code>
</InvalidArgument>
<MixedInferredReturnType occurrences="1">
<code>array</code>
</MixedInferredReturnType>
</file>
<file src="test/Writer/Extension/PodcastIndex/FeedTest.php">
<InvalidArgument occurrences="3">
<code>ExceptionInterface::class</code>
<code>ExceptionInterface::class</code>
<code>ExceptionInterface::class</code>
</InvalidArgument>
<MixedInferredReturnType occurrences="1">
<code>array</code>
</MixedInferredReturnType>
</file>
<file src="test/Writer/FeedFactoryTest.php">
<InvalidArgument occurrences="1">
<code>'string'</code>
Expand Down
1 change: 1 addition & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0"?>
<psalm
cacheDirectory="./psalm-cache"
totallyTyped="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
Expand Down
116 changes: 116 additions & 0 deletions src/Reader/Extension/PodcastIndex/Entry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

/**
* @see https://github.com/laminas/laminas-feed for the canonical source repository
* @copyright https://github.com/laminas/laminas-feed/blob/master/COPYRIGHT.md
* @license https://github.com/laminas/laminas-feed/blob/master/LICENSE.md New BSD License
*/

namespace Laminas\Feed\Reader\Extension\PodcastIndex;

use Laminas\Feed\Reader\Extension;
use stdClass;

/**
* Describes PodcastIndex data of an entry in a RSS Feed
*/
class Entry extends Extension\AbstractEntry
{
/**
* Get the entry transcript
*
* @psalm-return null|object{url: string, type: string, language: string, rel: string}
*/
public function getTranscript(): ?stdClass
{
if (array_key_exists('transcript', $this->data)) {
return $this->data['transcript'];
}

$transcript = null;

$nodeList = $this->xpath->query($this->getXpathPrefix() . '/podcast:transcript');

if ($nodeList->length > 0) {
$transcript = new stdClass();
$transcript->url = $nodeList->item(0)->getAttribute('url');
$transcript->type = $nodeList->item(0)->getAttribute('type');
$transcript->language = $nodeList->item(0)->getAttribute('language');
$transcript->rel = $nodeList->item(0)->getAttribute('rel');
}

$this->data['transcript'] = $transcript;

return $this->data['transcript'];
}

/**
* Get the entry chapters
*
* @psalm-return null|object{url: string, type: string}
*/
public function getChapters(): ?stdClass
{
if (array_key_exists('chapters', $this->data)) {
return $this->data['chapters'];
}

$chapters = null;

$nodeList = $this->xpath->query($this->getXpathPrefix() . '/podcast:chapters');

if ($nodeList->length > 0) {
$chapters = new stdClass();
$chapters->url = $nodeList->item(0)->getAttribute('url');
$chapters->type = $nodeList->item(0)->getAttribute('type');
}

$this->data['chapters'] = $chapters;

return $this->data['chapters'];
}

/**
* Get the entry soundbites
*
* @return stdClass[]
* @psalm-return array<int, object{title: string, startTime: string, duration: string}>
*/
public function getSoundbites(): array
{
if (array_key_exists('soundbites', $this->data)) {
return $this->data['soundbites'];
}

$soundbites = [];

$nodeList = $this->xpath->query($this->getXpathPrefix() . '/podcast:soundbite');

if ($nodeList->length > 0) {
foreach ($nodeList as $node) {
/** @var \DOMElement $node */
$soundbite = new stdClass();
$soundbite->title = $node->nodeValue;
$soundbite->startTime = $node->getAttribute('startTime');
$soundbite->duration = $node->getAttribute('duration');

$soundbites[] = $soundbite;
}
}

$this->data['soundbites'] = $soundbites;

return $this->data['soundbites'];
}

/**
* Register PodcastIndex namespace
*/
protected function registerNamespaces(): void
{
$this->xpath->registerNamespace(
'podcast',
'https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md'
);
}
}
Loading