Source of file Parser.php
Size: 12,700 Bytes - Last Modified: 2020-12-04T01:41:26+00:00
/home/vagrant/Code/projects/podcast-feed-parser/src/Parser.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 | <?php namespace Lukaswhite\PodcastFeedParser; use Lukaswhite\PodcastFeedParser\Exceptions\FileNotFoundException; use Lukaswhite\PodcastFeedParser\Exceptions\InvalidXmlException; use Lukaswhite\PodcastFeedParser\Rawvoice\Subscribe; /** * Class Parser * * Parse a podcast feed. * * @package Lukaswhite\PodcastFeedParser */ class Parser { /** * Class constants for the various namespaces */ const NS_ITUNES = 'http://www.itunes.com/dtds/podcast-1.0.dtd'; const NS_GOOGLE_PLAY = 'http://www.google.com/schemas/play-podcasts/1.0'; const NS_ATOM = 'http://www.w3.org/2005/Atom'; const NS_SYNDICATION = 'http://purl.org/rss/1.0/modules/syndication/'; const NS_RAWVOICE = 'http://www.rawvoice.com/rawvoiceRssModule/'; /** * The raw feed content * * @var string */ protected $content; /** * @var \SimplePie */ protected $sp; /** * @param string $content * @return $this * @throws InvalidXmlException */ public function setContent(string $content): self { try { simplexml_load_string($content); } catch (\Exception $e) { throw new InvalidXmlException('The feed does not appear to be valid XML'); } $this->content = $content; return $this; } /** * @param string $filepath * @return self * @throws FileNotFoundException * @throws InvalidXmlException */ public function load(string $filepath): self { if (!file_exists($filepath)) { throw new FileNotFoundException('The file could not be found'); } $this->setContent(file_get_contents($filepath)); return $this; } /** * Run the parser and return an object that represents the parsed podcast. * * @return Podcast * @throws \Exception */ public function run(): Podcast { $this->sp = new \SimplePie(); $this->sp->set_raw_data($this->content); $this->sp->init(); $podcast = new Podcast(); $podcast->setTitle($this->sp->get_title()) ->setDescription($this->sp->get_description()) ->setLanguage($this->sp->get_language()) ->setCopyright($this->sp->get_copyright()) ->setLink($this->sp->get_link()); $this->parseRssTags($podcast); $this->parseAtomTags($podcast); $this->parseSyndicationFields($podcast); $this->parseRawvoiceFields($podcast); if ($this->sp->get_author()) { $podcast->setAuthor($this->sp->get_author()->get_name()); } $iTunesType = $this->sp->get_channel_tags(self::NS_ITUNES, 'type'); if ($iTunesType && count($iTunesType)) { $podcast->setType($iTunesType[0]['data']); } $editor = $this->sp->get_channel_tags('', 'managingEditor'); if ($editor && count($editor)) { $podcast->setManagingEditor($editor[0]['data']); } if ( $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'subtitle')) { $podcast->setSubtitle( $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'subtitle')['data'] ); } if ( $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'explicit')) { $podcast->setExplicit( $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'explicit')['data'] ); } if ( $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'new-feed-url')) { $podcast->setNewFeedUrl( $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'new-feed-url')['data'] ); } $image = $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'image'); if ( $image ) { $artwork = new Artwork(); $artwork->setUri( $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'image')['attribs']['']['href'] ); $podcast->setArtwork($artwork); } if ( $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'owner')) { $ownerData = $this->getSingleNamespacedChannelItem(self::NS_ITUNES, 'owner'); $owner = new Owner(); if (isset($ownerData['child'])&& isset($ownerData['child'][self::NS_ITUNES])&& isset($ownerData['child'][self::NS_ITUNES]['name'])) { $owner->setName($ownerData['child'][self::NS_ITUNES]['name'][0]['data']); } if (isset($ownerData['child'])&& isset($ownerData['child'][self::NS_ITUNES])&& isset($ownerData['child'][self::NS_ITUNES]['email'])) { $owner->setEmail($ownerData['child'][self::NS_ITUNES]['email'][0]['data']); } $podcast->setOwner($owner); } $itunesCategories = $this->sp->get_channel_tags(self::NS_ITUNES, 'category'); if ($itunesCategories && count($itunesCategories)) { foreach($itunesCategories as $categoryData) { $category = new Category(); $category->setType(Category::ITUNES) ->setName($categoryData['attribs']['']['text']); if(isset($categoryData['child'])&&is_array($categoryData['child'])) { foreach($categoryData['child'][self::NS_ITUNES]['category'] as $subCategoryData) { $category->addSubCategory( ( new Category() ) ->setType(Category::ITUNES) ->setName($subCategoryData['attribs']['']['text']) ); } } $podcast->addCategory($category); } } $googlePlayCategories = $this->sp->get_channel_tags(self::NS_GOOGLE_PLAY, 'category'); if ($googlePlayCategories && count($googlePlayCategories)) { foreach($googlePlayCategories as $categoryData) { $category = new Category(); $category->setType(Category::GOOGLE_PLAY) ->setName($categoryData['attribs']['']['text']); $podcast->addCategory($category); } } // Now add the episodes foreach ($this->sp->get_items() as $item) { $podcast->addEpisode($this->parseEpisodeItem($item)); } return $podcast; } /** * @param Podcast $podcast * @throws \Exception */ protected function parseRssTags(Podcast $podcast) { $generator = $this->sp->get_channel_tags('', 'generator'); if ($generator && count($generator)) { $podcast->setGenerator($generator[0]['data']); } $lastBuildDate = $this->sp->get_channel_tags('', 'lastBuildDate'); if ($lastBuildDate && count($lastBuildDate)) { $podcast->setLastBuildDate((new \DateTime())->setTimestamp(strtotime($lastBuildDate[0]['data']))); } } /** * @param Podcast $podcast */ protected function parseAtomTags(Podcast $podcast) { $atomLinks = $this->sp->get_channel_tags(self::NS_ATOM, 'link'); if($atomLinks && count($atomLinks)) { foreach ($atomLinks as $atomLink) { $link = new Link($atomLink['attribs']['']['href']); if (isset($atomLink['attribs']['']['rel'])) { $link->setRel($atomLink['attribs']['']['rel']); } if (isset($atomLink['attribs']['']['type'])) { $link->setType($atomLink['attribs']['']['type']); } $podcast->addAtomLink($link); } } } /** * @param Podcast $podcast * @throws \Exception */ protected function parseSyndicationFields(Podcast $podcast) { $updatePeriod = $this->sp->get_channel_tags(self::NS_SYNDICATION, 'updatePeriod'); if($updatePeriod&&count($updatePeriod)) { $podcast->setUpdatePeriod($updatePeriod[0]['data']); } $updateFrequency = $this->sp->get_channel_tags(self::NS_SYNDICATION, 'updateFrequency'); if($updateFrequency&&count($updateFrequency)) { $podcast->setUpdateFrequency(intval($updateFrequency[0]['data'])); } $updateBase = $this->sp->get_channel_tags(self::NS_SYNDICATION, 'updateBase'); if($updateBase&&count($updateBase)) { $podcast->setUpdateBase((new \DateTime())->setTimestamp(strtotime($updateBase[0]['data']))); } } /** * @param Podcast $podcast * @throws \Exception */ protected function parseRawvoiceFields(Podcast $podcast) { $rating = $this->sp->get_channel_tags(self::NS_RAWVOICE, 'rating'); if($rating&&count($rating)) { $podcast->setRawvoiceRating($rating[0]['data']); } $location = $this->sp->get_channel_tags(self::NS_RAWVOICE, 'location'); if($location&&count($location)) { $podcast->setRawvoiceLocation($location[0]['data']); } $frequency = $this->sp->get_channel_tags(self::NS_RAWVOICE, 'frequency'); if($frequency&&count($frequency)) { $podcast->setRawvoiceFrequency($frequency[0]['data']); } $subscribe = $this->sp->get_channel_tags(self::NS_RAWVOICE, 'subscribe'); if($subscribe&&count($subscribe)) { $links = new Subscribe(); foreach($subscribe[0]['attribs'][''] as $platform => $link) { $links->addLink($platform,$link); } $podcast->setRawvoiceSubscribe($links); } } /** * @param \SimplePie_Item $item * @return Episode * @throws \Exception */ protected function parseEpisodeItem(\SimplePie_Item $item) { $episode = new Episode(); $episode->setTitle($item->get_title()) ->setDescription($item->get_description()) ->setLink($item->get_link()) ->setPublishedDate(new \DateTime($item->get_date())); $guid = $item->get_item_tags('', 'guid'); if ($guid && count($guid)) { $episode->setGuid($guid[0]['data']); } $subtitle = $item->get_item_tags(self::NS_ITUNES, 'subtitle'); if ($subtitle && count($subtitle)) { $episode->setSubtitle($subtitle[0]['data']); } $explicit = $item->get_item_tags(self::NS_ITUNES, 'explicit'); if ( $explicit && count($explicit)) { $episode->setExplicit($explicit[0]['data']); } $episodeNumber = $item->get_item_tags(self::NS_ITUNES, 'episode'); if ( $episodeNumber && count($episodeNumber)) { $episode->setEpisodeNumber(intval($episodeNumber[0]['data'])); } $season = $item->get_item_tags(self::NS_ITUNES, 'season'); if ( $season && count($season)) { $episode->setSeason(intval($season[0]['data'])); } $episodeType = $item->get_item_tags(self::NS_ITUNES, 'episodeType'); if ( $episodeType && count($episodeType)) { $episode->setType($episodeType[0]['data']); } $image = $item->get_item_tags(self::NS_ITUNES, 'image'); if ( $image && count($image)) { $artwork = new Artwork(); $artwork->setUri( $image[0]['attribs']['']['href'] ); $episode->setArtwork($artwork); } $enclosure = $item->get_enclosure(); if ( $enclosure && $enclosure->get_link()) { $media = new Media(); $media->setUri($enclosure->get_link()) ->setMimeType($enclosure->get_type()) ->setLength($enclosure->get_length()); $episode->setMedia($this->getFile($item)); } return $episode; } /** * @param \SimplePie_Item $item * @return Media */ protected function getFile(\SimplePie_Item $item): Media { $enclosure = $item->get_enclosure(); $media = new Media(); $media->setUri($enclosure->get_link()) ->setMimeType($enclosure->get_type()) ->setLength($enclosure->get_length()); return $media; } /** * @param $namespace * @param $name * @param null $item * @return mixed */ protected function getSingleNamespacedChannelItem($namespace, $name, $item = null ) { $items = $this->sp->get_channel_tags($namespace, $name); if ( $items && count( $items ) ) { return $items[0]; } } } |