<?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
]
;
}
}
}