Skip to content

Commit

Permalink
Merge pull request #68 from ben-xo/feature/itunes-season-tag
Browse files Browse the repository at this point in the history
v1.38 option to output <itunes:season> from TPOS tag
  • Loading branch information
ben-xo authored Feb 25, 2023
2 parents cbdf706 + 0691d45 commit 178c977
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 68 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ jobs:
build:
strategy:
matrix:
operating-system: [ubuntu-latest, macos-10.15]
php-versions: ['7.3', '7.4', '8.0', '8.1']
operating-system: [ubuntu-latest, macos-11]
php-versions: ['7.3', '7.4', '8.0', '8.1', '8.2', '8.3']
runs-on: ${{ matrix.operating-system }}
steps:
- name: Setup PHP and extensions
Expand All @@ -18,7 +18,7 @@ jobs:
env:
fail-fast: true
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Composer Install
uses: ramsey/composer-install@v2
with:
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Changelog
=========

1.38 2023-01-05 * Add <itunes:type> defaulting to "episodic". The ITUNES_TYPE
option in dir2cast.ini will let you set the feed to
<itunes:type>serial<itunes:type> set, and then,
for each episode, the "Part Of A Set" tag (TPOS), if filled,
will be used to output an <itunes:season> tag, and the
"Track Number" tag (TRCK), if filled, will be used to output
an <itunes:episode> tag. See the .ini for usage info.
Suggested by @EdwarDDay (#65)
* Fix deprecation warning in PHP 8.2, and tested up to PHP 8.3

1.37 2022-10-27 * Errors now return an HTTP status code 500 by default.
* If the error is due to no content, or a bad URL passed to
?dir=, then it will be a 404 and no information about
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[![Testing dir2cast](https://github.com/ben-xo/dir2cast/actions/workflows/testing.yml/badge.svg)](https://github.com/ben-xo/dir2cast/actions/workflows/testing.yml)


dir2cast by Ben XO v1.37 (2022-10-27)
dir2cast by Ben XO v1.38 (2023-01-05)
================================================================================

https://github.com/ben-xo/dir2cast/
Expand Down
44 changes: 34 additions & 10 deletions dir2cast.ini
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@
; The full filesystem path to the MP3 folder
; Set this if you *do not* want the folder to be passed in the URL.
; (This defaults to the same folder as the script)
;MP3_DIR = /home/ben_xo/public_html/my_mp3_folder
;MP3_DIR = "/home/ben_xo/public_html/my_mp3_folder"

; The base to look for folders if they are specified in the URL
; Set this if you *do* want the folder passed in the URL, but the passed
; folders are not subfolders of where you installed dir2cast.php.
; (This defaults to the same folder as the script)
;MP3_BASE = /home/ben_xo/public_html/
;MP3_BASE = "/home/ben_xo/public_html/"

; The URL of the MP3 folder
; This defaults to the directory of the script.
; dir2cast can usually work this out for you, but under some circumstances
; it will fail. If your MP3 URLs are all wrong, try putting this in manually.
;MP3_URL = http://www.example.foo/my_mp3_folder/
;MP3_URL = "http://www.example.foo/my_mp3_folder/"

; Uncomment this if you want to check in every sub-folder for new files as well.
;RECURSIVE_DIRECTORY_ITERATOR = true
Expand All @@ -70,7 +70,7 @@

; Email of the Author of the podcast for iTunes
; This defaults to empty
;ITUNES_OWNER_EMAIL = [email protected]
;ITUNES_OWNER_EMAIL = "[email protected]"

; URL of the feed's home page (this is NOT where the MP3s are! It is
; just the link to your "about" page).
Expand Down Expand Up @@ -101,7 +101,8 @@
; See https://github.com/simplepie/simplepie-ng/wiki/Spec:-iTunes-Podcast-RSS
; Valid values are "yes", "explicit", "true" or "no", "clean", "false"
;
; If you don't set this, it will not appear in the feed at all!
; If you don't set this, it will not appear in the feed at all, and Apple
; Podcasts may reject your feed!
;ITUNES_EXPLICIT = "no"


Expand Down Expand Up @@ -157,16 +158,39 @@
;
;ITUNES_SUBTITLE_SUFFIX = ""

; Whether to output the <itunes:episode> and <itunes:season> tags
;
; Set the <itunes:type> tag. If you set this to "serial", it will
; use the content of the ID3 "TRCK" and "TPOS" fields (also known as
; "track number", and "part of a set" (or sometimes "disc number"),
; respectively, as content of the <itunes:episode> and <itunes:season> tags.
;
; The TRCK and TPOS values should be non-zero positive integers (1, 2, 3, etc)
;
; NOTE: these are NOT used for ordering within the RSS feed. This is
; still done by file date so it's up to you to make the episode order
; and the file date order match by uploading them in season/episode order.
;
; The default value is "episodic", and no <itunes:episode> or <itunes:season>
; tags will be output in the feed.
;
; If you don't want <itunes:type> to appear in the feed at all, set this to ""
;
; Any value that is not "" or "serial" will be treated as "episodic"
;ITUNES_TYPE = "episodic"

; *** CHECK THESE ARE OK. ***

; Language of the feed
; This defaults to en-us (US English). This must be something recognised by
; the RSS standard.
;LANGUAGE = en-us
; the RSS standard. Apple Podcasts only supports values from the ISO 639 list
; (two-letter language codes, with some possible modifiers, such as "en-us").
; See https://www.loc.gov/standards/iso639-2/php/code_list.php
;LANGUAGE = "en-us"

; Where to cache RSS feeds (this must be writable by the web server)
; This defaults to a folder called 'temp' alongside the script
;TMP_DIR = /tmp
;TMP_DIR = "/tmp"

; Number of items to show in the feed
; This defaults to 10
Expand Down Expand Up @@ -228,8 +252,8 @@
; generated, or from a file with the same name with .txt extension) then
; set this parameter to 'summary'. Otherwise it will get its description from
; comment tag embedded in the file.
;DESCRIPTION_SOURCE=comment
;DESCRIPTION_SOURCE = "comment"

; If you want to have HTML in your <description> tag set this parameter.
; Otherwise the content of the description will be escaped with htmlspecialchars()
;DESCRIPTION_HTML=
;DESCRIPTION_HTML =
57 changes: 55 additions & 2 deletions dir2cast.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
/* DEFAULTS *********************************************/

// error handler needs these, so let's set them now.
define('VERSION', '1.37');
define('VERSION', '1.38');
define('DIR2CAST_HOMEPAGE', 'https://github.com/ben-xo/dir2cast/');
define('GENERATOR', 'dir2cast ' . VERSION . ' by Ben XO (' . DIR2CAST_HOMEPAGE . ')');

Expand Down Expand Up @@ -173,7 +173,7 @@ public function appendToItem(DOMElement $d, DOMDocument $doc, RSS_Item $item)
}

unset($this->getid3);

if(!empty($info['comments']))
{
if(!empty($info['comments']['title'][0]))
Expand All @@ -184,6 +184,10 @@ public function appendToItem(DOMElement $d, DOMDocument $doc, RSS_Item $item)
$item->setID3Album( $info['comments']['album'][0] );
if(!empty($info['comments']['comment'][0]))
$item->setID3Comment( $info['comments']['comment'][0] );
if(!empty($info['comments']['track_number'][0]))
$item->setID3Track( $info['comments']['track_number'][0] );
if(!empty($info['comments']['part_of_a_set'][0]))
$item->setID3PartOfASet( $info['comments']['part_of_a_set'][0] );

if(self::$AUTO_SAVE_COVER_ART)
{
Expand Down Expand Up @@ -332,6 +336,7 @@ public function id()
}

static $ITUNES_SUBTITLE_SUFFIX = '';
static $ITUNES_TYPE = "episodic";

protected $owner_name, $owner_email, $image_href, $explicit;
protected $categories = array();
Expand Down Expand Up @@ -391,6 +396,12 @@ public function appendToChannel(DOMElement $channel, DOMDocument $doc)
$channel->appendChild( $doc->createElement('itunes:image') )
->setAttribute('href', $this->image_href);
}

if(strlen(iTunes_Podcast_Helper::$ITUNES_TYPE))
{
$channel->appendChild( $doc->createElement('itunes:type') )
->appendChild( new DOMText( iTunes_Podcast_Helper::$ITUNES_TYPE == "serial" ? "serial" : "episodic" ) );
}
}

public function appendToItem(DOMElement $item_element, DOMDocument $doc, RSS_Item $item)
Expand Down Expand Up @@ -426,6 +437,22 @@ public function appendToItem(DOMElement $item_element, DOMDocument $doc, RSS_Ite
{
$elements['subtitle'] = $itunes_subtitle . iTunes_Podcast_Helper::$ITUNES_SUBTITLE_SUFFIX;
}

if(iTunes_Podcast_Helper::$ITUNES_TYPE == "serial")
{

$episode = $item->getEpisode();
if($episode !== '')
{
$elements['episode'] = $episode;
}

$season = $item->getSeason();
if($season !== '')
{
$elements['season'] = $season;
}
}

foreach($elements as $key => $val)
if(!empty($val))
Expand Down Expand Up @@ -919,6 +946,28 @@ public function getSubtitle()
return $subtitle;
}

public function getEpisode()
{
$episode = parent::getEpisode();
if(!$episode)
{
// use track tag as season if there's no override
$episode = $this->getID3Track();
}
return $episode;
}

public function getSeason()
{
$season = parent::getSeason();
if(!$season)
{
// use part_of_a_set tag as season if there's no override
$season = $this->getID3PartOfASet();
}
return $season;
}

/**
* Version number used in the saved cache files. If the used fields change, increment this number.
* @var integer
Expand Down Expand Up @@ -1956,6 +2005,9 @@ public static function defaults(array $SERVER)
if(!defined('ITUNES_SUBTITLE_SUFFIX'))
define('ITUNES_SUBTITLE_SUFFIX', '');

if(!defined('ITUNES_TYPE'))
define('ITUNES_TYPE', "episodic");

if(!defined('DESCRIPTION_SOURCE'))
define('DESCRIPTION_SOURCE', 'comment');

Expand Down Expand Up @@ -1986,6 +2038,7 @@ public static function defaults(array $SERVER)
Cached_Dir_Podcast::$MIN_CACHE_TIME = MIN_CACHE_TIME;
getID3_Podcast_Helper::$AUTO_SAVE_COVER_ART = AUTO_SAVE_COVER_ART;
iTunes_Podcast_Helper::$ITUNES_SUBTITLE_SUFFIX = ITUNES_SUBTITLE_SUFFIX;
iTunes_Podcast_Helper::$ITUNES_TYPE = ITUNES_TYPE;

// Set up up factory settings for RSS Items
RSS_File_Item::$FILES_URL = MP3_URL; // TODO: rename this to MEDIA_URL
Expand Down
70 changes: 70 additions & 0 deletions test/ITunesPodcastSeasonTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php declare(strict_types=1);

use PHPUnit\Framework\TestCase;

class ITunesPodcastSeasonTest extends MixedMediaExampleTest
{
public static function setUpBeforeClass(): void
{
prepare_testing_dir();

copy('../fixtures/id3v1_artist_album_title.mp3', '1.mp3');
copy('../fixtures/id3v2_artist_album_title.mp3', '2.mp3');
copy('../fixtures/tagged.mp4', '3.mp4');
copy('../fixtures/id3v2_comment.mp3', '4.mp3');
copy('../fixtures/id3v2_artist_title_partofaset.mp3', '5.mp3');
copy('../fixtures/id3v2_artist_title_track.mp3', '6.mp3');

$now = time();
touch('1.mp3', $now);
touch('2.mp3', $now+50);
touch('3.mp4', $now+100);
touch('4.mp3', $now+150);
touch('5.mp3', $now+200);
touch('6.mp3', $now+250);
MixedMediaExampleTest::$filemtime = $now;

file_put_contents('./dir2cast.ini', "ITUNES_TYPE = serial\n");

MixedMediaExampleTest::$output = '';
exec('php dir2cast.php --media-url=https://www.example.com/podcast/ --output=out.xml --min-file-age=0', MixedMediaExampleTest::$output, MixedMediaExampleTest::$returncode);
}

public function test_itunes_type()
{
// generated valid XML
$data = simplexml_load_string(file_get_contents(self::$file));
$itdtd = "http://www.itunes.com/dtds/podcast-1.0.dtd";

// assert itunes:type = serial
$this->assertEquals('serial', $data->channel->children($itdtd)->type);
}

public function test_itunes_season()
{
// generated valid XML
$data = simplexml_load_string(file_get_contents(self::$file));
$itdtd = "http://www.itunes.com/dtds/podcast-1.0.dtd";
$this->assertEmpty($data->channel->item[0]->children($itdtd)->season);
$this->assertEquals('Season 1', $data->channel->item[1]->children($itdtd)->season);
$this->assertEmpty($data->channel->item[2]->children($itdtd)->season);
$this->assertEmpty($data->channel->item[3]->children($itdtd)->season);
$this->assertEmpty($data->channel->item[4]->children($itdtd)->season);
$this->assertEmpty($data->channel->item[5]->children($itdtd)->season);
}

public function test_itunes_episode()
{
// generated valid XML
$data = simplexml_load_string(file_get_contents(self::$file));
$itdtd = "http://www.itunes.com/dtds/podcast-1.0.dtd";
$this->assertEquals('1', $data->channel->item[0]->children($itdtd)->episode);
$this->assertEmpty($data->channel->item[1]->children($itdtd)->episode);
$this->assertEmpty($data->channel->item[2]->children($itdtd)->episode);
$this->assertEmpty($data->channel->item[3]->children($itdtd)->episode);
$this->assertEmpty($data->channel->item[4]->children($itdtd)->episode);
$this->assertEmpty($data->channel->item[5]->children($itdtd)->episode);
}


}
11 changes: 11 additions & 0 deletions test/Media_RSS_ItemTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public function getID3Comment()
return '';
}

public function getID3PartOfASet()
{
return '';
}

protected $media_rss_item_class = 'Media_RSS_Item';

public function newRSSItem()
Expand All @@ -67,6 +72,7 @@ public function newRSSItem()
$item->setID3Title($this->getID3Title());
$item->setID3Artist($this->getID3Artist());
$item->setID3Comment($this->getID3Comment());
$item->setID3PartOfASet($this->getID3PartOfASet());
return $item;
}

Expand Down Expand Up @@ -136,6 +142,11 @@ public function test_summary_from_description_when_summary_not_set_and_descripti
$this->assertEquals('', $item->getSummary());
}

public function test_season_from_part_of_set_tag_by_default() {
$item = $this->newRSSItem();
$this->assertEquals($this->getID3PartOfASet(), $item->getSeason());
}

public function tearDown(): void
{
file_exists($this->filename) && unlink($this->filename);
Expand Down
Loading

0 comments on commit 178c977

Please sign in to comment.