astrXbian/www/jukebox/includes/podcastfunctions.php

1316 lines
58 KiB
PHP

<?php
function parse_rss_feed($url, $id = false, $lastpubdate = null, $gettracks = true) {
global $prefs;
$url = preg_replace('#^itpc://#', 'http://', $url);
$url = preg_replace('#^feed://#', 'http://', $url);
logger::shout("PARSE_RSS", "Parsing Feed ".$url);
$d = new url_downloader(array('url' => $url));
if (!$d->get_data_to_string()) {
header('HTTP/1.0 404 Not Found');
print "Feed Not Found";
logger::fail("PARSE_RSS", " Failed to Download ".$url);
exit;
}
// For debugging
// file_put_contents('prefs/temp/feed.xml', $d->get_data());
if ($id) {
if (!is_dir('prefs/podcasts/'.$id)) {
mkdir('prefs/podcasts/'.$id, 0755);
}
file_put_contents('prefs/podcasts/'.$id.'/feed.xml', $d->get_data());
}
$feed = simplexml_load_string($d->get_data());
logger::trace("PARSE_RSS", " Our LastPubDate is ".$lastpubdate);
// Begin RSS Parse
$podcast = array();
$podcast['FeedURL'] = $url;
$domain = preg_replace('#^(http://.*?)/.*$#', '$1', $url);
$ppg = $feed->channel->children('ppg', TRUE);
$m = $feed->channel->children('itunes', TRUE);
$sy = $feed->channel->children('sy', TRUE);
// Automatic Refresh
if ($ppg && $ppg->seriesDetails) {
switch ($ppg->seriesDetails[0]->attributes()->frequency) {
case "hourly":
$podcast['RefreshOption'] = REFRESHOPTION_HOURLY;
break;
case "daily":
$podcast['RefreshOption'] = REFRESHOPTION_DAILY;
break;
case "weekly":
$podcast['RefreshOption'] = REFRESHOPTION_WEEKLY;
break;
case "monthly":
$podcast['RefreshOption'] = REFRESHOPTION_MONTHLY;
break;
default:
$podcast['RefreshOption'] = REFRESHOPTION_NEVER;
break;
}
} else if ($sy && $sy->updatePeriod) {
switch ($sy->updatePeriod) {
case "hourly":
$podcast['RefreshOption'] = REFRESHOPTION_HOURLY;
break;
case "daily":
$podcast['RefreshOption'] = REFRESHOPTION_DAILY;
break;
case "weekly":
$podcast['RefreshOption'] = REFRESHOPTION_WEEKLY;
break;
case "monthly":
$podcast['RefreshOption'] = REFRESHOPTION_MONTHLY;
break;
default:
$podcast['RefreshOption'] = REFRESHOPTION_NEVER;
break;
}
} else {
$podcast['RefreshOption'] = $prefs['default_podcast_refresh_mode'];
}
// Episode Expiry
if ($ppg && $ppg->seriesDetails && $ppg->seriesDetails[0]->attributes()->daysLive) {
$podcast['DaysLive'] = $ppg->seriesDetails[0]->attributes()->daysLive;
} else {
$podcast['DaysLive'] = -1;
}
// Image
if ($feed->channel->image) {
$podcast['Image'] = html_entity_decode($feed->channel->image->url);
logger::log("PARSE_RSS", " Image is ".$podcast['Image']);
} else if ($m && $m->image) {
$podcast['Image'] = $m->image[0]->attributes()->href;
logger::log("PARSE_RSS", " Image is ".$podcast['Image']);
} else {
$podcast['Image'] = "newimages/podcast-logo.svg";
logger::trace("PARSE_RSS", " No Image Found");
}
if (preg_match('#^/#', $podcast['Image'])) {
// Image link with a relative URL. Duh.
$podcast['Image'] = $domain.$image;
}
// Artist
if ($m && $m->author) {
$podcast['Artist'] = (string) $m->author;
} else {
$podcast['Artist'] = '';
}
logger::log("PARSE_RSS", " Artist is ".$podcast['Artist']);
// Category
$cats = array();
if ($m && $m->category) {
for ($i = 0; $i < count($m->category); $i++) {
$cat = html_entity_decode((string) $m->category[$i]->attributes()->text);
if (!in_array($cat, $cats)) {
$cats[] = $cat;
}
}
}
$spaz = array_diff($cats, array('Podcasts'));
natsort($spaz);
$podcast['Category'] = implode(', ', $spaz);
logger::log("PARSE_RSS", " Category is ".$podcast['Category']);
// Title
$podcast['Title'] = (string) $feed->channel->title;
if ($id !== false) {
$albumimage = new baseAlbumImage(array(
'artist' => 'PODCAST',
'albumpath' => $id,
'album' => $podcast['Title']
));
if ($albumimage->get_image_if_exists() === null) {
logger::mark("PODCASTS", "Replacing missing podcast image");
download_image($podcast['Image'], $id, $podcast['Title']);
}
}
// Description
$podcast['Description'] = (string) $feed->channel->description;
// Tracks
$podcast['tracks'] = array();
$podcast['LastPubDate'] = $lastpubdate;
if ($gettracks) {
foreach($feed->channel->item as $item) {
$track = array();
$m = $item->children('media', TRUE);
// Track Title
$track['Title'] = (string) $item->title;
logger::log("PARSE_RSS", " Found track ".$track['Title']);
// Track URI
$uri = null;
if ($m && $m->content) {
foreach ($m->content as $c) {
if (preg_match('/audio/',(string) $c->attributes()->type)) {
$uri = (string) $c->attributes()->url;
break;
}
}
}
if ($item->enclosure && $uri == null) {
$uri = (string) $item->enclosure->attributes()->url;
}
if ($item->link && $uri == null) {
$uri = (string) $item->link;
}
$track['Link'] = $uri;
logger::log("PARSE_RSS", " Track URI is ".$uri);
if ($item->guid) {
$track['GUID'] = $item->guid;
} else {
$track['GUID'] = $uri;
}
if ($uri == null) {
logger::fail("PARSE_RSS", " Could Not Find URI for track!");
continue;
}
// Track Duration
$track['Duration'] = 0;
if ($m && $m->content) {
if ($m->content[0]->attributes()->duration) {
$track['Duration'] = (string) $m->content[0]->attributes()->duration;
}
}
$m = $item->children('itunes', TRUE);
if ($track['Duration'] == 0 && $m && $m->duration) {
$track['Duration'] = (string) $m->duration;
}
if (preg_match('/:/', $track['Duration'])) {
$timesplit = explode(':', $track['Duration']);
$timefactors = array(1, 60, 3600, 86400);
$hms = array_reverse($timesplit);
$time = 0;
foreach ($hms as $s) {
$mf = array_shift($timefactors);
if (is_numeric($s)) {
$time += ($s * $mf);
} else {
logger::warn("PARSE_RSS", " Non-numeric duration field encountered in podcast! -",$track['Duration']);
$time = 0;
break;
}
}
$track['Duration'] = $time;
}
// Track Author
if ($m && $m->author) {
$track['Artist'] = (string) $m->author;
} else {
$track['Artist'] = $podcast['Artist'];
}
// Track Publication Date
$t = strtotime((string) $item->pubDate);
logger::log("PARSE_RSS", " Track PubDate is ",(string) $item->pubDate,"(".$t.")");
if ($t === false) {
logger::warn("PARSE_RSS", " ERROR - Could not parse episode Publication Date",(string) $item->pubDate);
} else if ($t > $podcast['LastPubDate']) {
logger::log("PARSE_RSS", " This is a new episode");
}
if ($t === false || $podcast['LastPubDate'] === null || $t > $podcast['LastPubDate']) {
$podcast['LastPubDate'] = $t;
}
$track['PubDate'] = $t;
if ($item->enclosure && $item->enclosure->attributes()) {
$track['FileSize'] = $item->enclosure->attributes()->length;
} else {
$track['FileSize'] = 0;
}
if ($m && $m->summary) {
$track['Description'] = $m->summary;
} else {
$track['Description'] = $item->description;
}
$podcast['tracks'][] = $track;
}
}
if ($lastpubdate !== null) {
if ($podcast['LastPubDate'] !== false && $podcast['LastPubDate'] == $lastpubdate) {
logger::mark("PARSE_RSS", "Podcast has not been updated since last refresh");
return false;
}
}
return $podcast;
}
function getNewPodcast($url, $subbed = 1, $gettracks = true) {
global $mysqlc, $prefs;
logger::mark("PODCASTS", "Getting podcast",$url);
$newpodid = null;
$podcast = parse_rss_feed($url, false, null, $gettracks);
$r = check_if_podcast_is_subscribed(array( 'feedUrl' => $podcast['FeedURL'],
'collectionName' => $podcast['Title'],
'artistName' => $podcast['Artist']));
if (count($r) > 0) {
foreach ($r as $a) {
logger::fail("PODCASTS", " Already subscribed to podcast",$a['Title']);
}
header('HTTP/1.0 404 Not Found');
print 'You are already to subscrtibed to '.$podcast['Title'];
exit(0);
}
logger::mark("PODCASTS", "Adding New Podcast",$podcast['Title']);
$lastupdate = calculate_best_update_time($podcast);
if (sql_prepare_query(true, null, null, null,
"INSERT INTO Podcasttable
(FeedURL, LastUpdate, Image, Title, Artist, RefreshOption, SortMode, DisplayMode, DaysLive, Description, Version, Subscribed, LastPubDate, Category)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
$podcast['FeedURL'],
calculate_best_update_time($podcast),
$podcast['Image'],
$podcast['Title'],
$podcast['Artist'],
$podcast['RefreshOption'],
$prefs['default_podcast_sort_mode'],
$prefs['default_podcast_display_mode'],
$podcast['DaysLive'],
$podcast['Description'],
ROMPR_PODCAST_TABLE_VERSION,
$subbed,
$podcast['LastPubDate'],
$podcast['Category']))
{
$newpodid = $mysqlc->lastInsertId();
if (is_dir('prefs/podcasts/'.$newpodid)) {
rrmdir('prefs/podcasts/'.$newpodid);
}
mkdir('prefs/podcasts/'.$newpodid, 0755);
download_image($podcast['Image'], $newpodid, $podcast['Title']);
if ($subbed == 1) {
foreach ($podcast['tracks'] as $track) {
if (sql_prepare_query(true, null, null, null,
"INSERT INTO PodcastTracktable
(PODindex, Title, Artist, Duration, PubDate, FileSize, Description, Link, Guid, New)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
$newpodid, $track['Title'], $track['Artist'], $track['Duration'], $track['PubDate'],
$track['FileSize'], $track['Description'], $track['Link'], $track['GUID'], 1))
{
logger::log("PODCASTS", " Added Track ".$track['Title']);
} else {
logger::fail("PODCASTS", " FAILED Adding Track ".$track['Title']);
}
}
}
}
return $newpodid;
}
function calculate_best_update_time($podcast) {
// Note: this returns a value for LastUpdate, since that is what refresh is based on.
// The purpose of this is try to get the refresh in sync with the podcast's publication date.
if ($podcast['LastPubDate'] === null) {
logger::log("PODCASTS", $podcast['Title'],"last pub date is null");
return time();
}
switch ($podcast['RefreshOption']) {
case REFRESHOPTION_NEVER:
case REFRESHOPTION_HOURLY:
case REFRESHOPTION_DAILY:
return time();
break;
}
logger::log("PODCASTS", "Working out best update time for ".$podcast['Title']);
$dt = new DateTime(date('c', $podcast['LastPubDate']));
logger::log("PODCASTS", " Last Pub Date is ".$podcast['LastPubDate'].' ('.$dt->format('c').')');
logger::log("PODCASTS", " Podcast Refresh interval is ".$podcast['RefreshOption']);
while ($dt->getTimestamp() < time()) {
switch ($podcast['RefreshOption']) {
case REFRESHOPTION_WEEKLY:
$dt->modify('+1 week');
break;
case REFRESHOPTION_MONTHLY:
$dt->modify('+1 month');
break;
default:
logger::error("PODCASTS", " Unknown refresh option",$podcast['RefreshOption'],"for podcast ID",$podcast['podid']);
return time();
break;
}
}
logger::log("PODCASTS", " Worked out update time based on pubDate and RefreshOption: ".$dt->format('r').' ('.$dt->getTImestamp().')');
logger::log("PODCASTS", " Give it an hour's grace");
$dt->modify('+1 hour');
switch ($podcast['RefreshOption']) {
case REFRESHOPTION_WEEKLY:
$dt->modify('-1 week');
break;
case REFRESHOPTION_MONTHLY:
$dt->modify('-1 month');
break;
}
logger::log("PODCASTS", " Therefore setting lastupdate to: ".$dt->format('r').' ('.$dt->getTImestamp().')');
return $dt->getTimestamp();
}
function download_image($url, $podid, $title) {
$albumimage = new albumImage(array(
'artist' => 'PODCAST',
'albumpath' => $podid,
'album' => $title,
'source' => $url
));
if ($albumimage->get_image_if_exists() === null) {
$albumimage->download_image();
$albumimage->update_image_database();
}
}
function check_podcast_upgrade($podetails, $podid, $podcast) {
if ($podetails->Version < ROMPR_PODCAST_TABLE_VERSION) {
if ($podcast === false) {
logger::blurt("PODCASTS", "Podcast needs to be upgraded, must re-parse the feed");
$podcast = parse_rss_feed($podetails->FeedURL, $podid, null);
}
upgrade_podcast($podid, $podetails, $podcast);
}
}
function refreshPodcast($podid) {
global $prefs;
check_refresh_pid();
logger::shout("PODCASTS", "---------------------------------------------------");
logger::shout("PODCASTS", "Refreshing podcast ",$podid);
$result = generic_sql_query("SELECT * FROM Podcasttable WHERE PODindex = ".$podid, false, PDO::FETCH_OBJ);
if (count($result) > 0) {
$podetails = $result[0];
logger::log("PODCASTS", " Podcast title is ".$podetails->Title);
} else {
logger::error("PODCASTS", "ERROR Looking up podcast ".$podid);
return $podid;
}
$podcast = parse_rss_feed($podetails->FeedURL, $podid, $podetails->LastPubDate);
if ($podetails->Subscribed == 1 && $prefs['podcast_mark_new_as_unlistened']) {
generic_sql_query("UPDATE PodcastTracktable SET New = 0 WHERE PODindex = ".$podetails->PODindex);
}
if ($podcast === false) {
check_podcast_upgrade($podetails, $podid, $podcast);
// Podcast pubDate has not changed, hence we didn't re-parse the feed.
// Still calculate the best next update time
sql_prepare_query(true, null, null, null, "UPDATE Podcasttable SET LastUpdate = ? WHERE PODindex = ?",
calculate_best_update_time(
array(
'LastPubDate' => $podetails->LastPubDate,
'RefreshOption' => $podetails->RefreshOption,
'Title' => $podetails->Title
)
),
$podid);
// Still check to keep (days to keep still needs to be honoured)
if (check_tokeep($podetails, $podid) || $prefs['podcast_mark_new_as_unlistened']) {
return $podid;
} else {
return false;
}
}
check_podcast_upgrade($podetails, $podid, $podcast);
if ($podetails->Subscribed == 0) {
sql_prepare_query(true, null, null, null, "UPDATE Podcasttable SET Description = ?, DaysLive = ?, RefreshOption = ?, LastUpdate = ?, LastPubDate = ? WHERE PODindex = ?",
$podcast['Description'],
$podcast['DaysLive'],
$podcast['RefreshOption'],
calculate_best_update_time($podcast),
$podcast['LastPubDate'],
$podid);
sql_prepare_query(true, null, null, null, "UPDATE PodcastTracktable SET New=?, JustUpdated=?, Listened = 0 WHERE PODindex=?", 1, 0, $podid);
} else {
sql_prepare_query(true, null, null, null, "UPDATE PodcastTracktable SET New=?, JustUpdated=? WHERE PODindex=?", 0, 0, $podid);
sql_prepare_query(true, null, null, null, "UPDATE Podcasttable SET Description=?, LastUpdate=?, DaysLive=?, LastPubDate=? WHERE PODindex=?",
$podcast['Description'],
calculate_best_update_time($podcast),
$podcast['DaysLive'],
$podcast['LastPubDate'],
$podid);
}
download_image($podcast['Image'], $podid, $podetails->Title);
foreach ($podcast['tracks'] as $track) {
$trackid = sql_prepare_query(false, null, 'PODTrackindex' , null, "SELECT PODTrackindex FROM PodcastTracktable WHERE Guid=? AND PODindex = ?", $track['GUID'], $podid);
if ($trackid !== null) {
logger::trace("PODCASTS", " Found existing track ".$track['Title']);
sql_prepare_query(true, null, null, null, "UPDATE PodcastTracktable SET JustUpdated=?, Duration=?, Link=? WHERE PODTrackindex=?",1,$track['Duration'], $track['Link'], $trackid);
} else {
if (sql_prepare_query(true, null, null, null,
"INSERT INTO PodcastTracktable
(JustUpdated, PODindex, Title, Artist, Duration, PubDate, FileSize, Description, Link, Guid, New)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
1, $podid, $track['Title'], $track['Artist'], $track['Duration'], $track['PubDate'],
$track['FileSize'], $track['Description'], $track['Link'], $track['GUID'], 1))
{
logger::log("PODCASTS", " Added Track ".$track['Title']);
} else {
logger::fail("PODCASTS", " FAILED Adding Track ".$track['Title']);
}
}
}
check_tokeep($podetails, $podid);
clear_refresh_pid();
return $podid;
}
function check_tokeep($podetails, $podid) {
$retval = false;
// Remove tracks that are no longer in the feed and haven't been downloaded
if ($podetails->Subscribed == 1) {
sql_prepare_query(true, null, null, null, "DELETE FROM PodcastTracktable WHERE PODindex=? AND JustUpdated=? AND Downloaded=?",$podid, 0, 0);
// Remove tracks that have been around longer than DaysToKeep - honoring KeepDownloaded
if ($podetails->DaysToKeep > 0) {
$oldesttime = time() - ($podetails->DaysToKeep * 86400);
$numthen = simple_query("COUNT(PODTrackindex)", "PodcastTracktable", 'Deleted = 0 AND PODindex', $podid, 0);
$qstring = "UPDATE PodcastTracktable SET Deleted=1 WHERE PODindex = ".$podid." AND PubDate < ".$oldesttime." AND Deleted = 0";
if ($podetails->KeepDownloaded == 1) {
$qstring .= " AND Downloaded = 0";
}
generic_sql_query($qstring, true);
$numnow = simple_query("COUNT(PODTrackindex)", "PodcastTracktable", 'Deleted = 0 AND PODindex', $podid, 0);
if ($numnow != $numthen) {
logger::log("PODCASTS", " Old episodes were removed from podcast ID ".$podid);
$retval = true;
}
}
// Remove tracks where there are more than NumToKeep - honoring KeepDownloaded
if ($podetails->NumToKeep > 0) {
$getrid = 0;
$qstring = "SELECT COUNT(PODTrackindex) AS num FROM PodcastTracktable WHERE PODindex=".$podid." AND Deleted = 0";
if ($podetails->KeepDownloaded == 1) {
$qstring .= " AND Downloaded = 0";
}
$num = generic_sql_query($qstring, false, null, 'num', 0);
$getrid = $num - $podetails->NumToKeep;
logger::log("PODCASTS", " Num To Keep is ".$podetails->NumToKeep." and there are ".$num." episodes that can be pruned. Removing ".$getrid);
if ($getrid > 0) {
$qstring = "SELECT PODTrackindex FROM PodcastTracktable WHERE PODindex=".$podid." AND Deleted = 0";
if ($podetails->KeepDownloaded == 1) {
$qstring .= " AND Downloaded=0";
}
$qstring .= " ORDER BY PubDate ASC LIMIT ".$getrid;
$pods = sql_get_column($qstring, 0);
foreach ($pods as $i) {
logger::trace("PODCASTS", " Removing Track ".$i);
generic_sql_query("UPDATE PodcastTracktable SET Deleted=1 WHERE PODTrackindex=".$i, true);
$retval = true;
}
}
}
}
return $retval;
}
function upgrade_podcast($podid, $podetails, $podcast) {
$v = $podetails->Version;
while ($v < ROMPR_PODCAST_TABLE_VERSION) {
switch ($v) {
case 1:
logger::mark("PODCASTS", "Updating Podcast ".$podetails->Title." to version 2");
foreach ($podcast['tracks'] as $track) {
$t = sql_prepare_query(false, PDO::FETCH_OBJ, null, null, "SELECT * FROM PodcastTracktable WHERE Link=? OR OrigLink=?", $track['Link'], $track['Link']);
foreach($t as $result) {
logger::log("PODCASTS", " Updating Track ".$result->Title);
logger::trace("PODCASTS", " GUID is ".$track['GUID']);
$dlfilename = null;
if ($result->Downloaded == 1) {
$dlfilename = basename($result->Link);
logger::log("PODCASTS", " Track has been downloaded to ".$dlfilename);
}
sql_prepare_query(true, null, null, null, "UPDATE PodcastTracktable SET Link = ?, Guid = ?, Localfilename = ?, OrigLink = NULL WHERE PODTrackindex = ?", $track['Link'], $track['GUID'], $dlfilename, $result->PODTrackindex);
}
}
generic_sql_query("UPDATE Podcasttable SET Version = 2 WHERE PODindex = ".$podid, true);
$v++;
break;
case 2:
// This will have been done by the function below
$v++;
break;
case 3:
logger::mark("PODCASTS", "Updating Podcast ".$podetails->Title." to version 4");
sql_prepare_query(true, null, null, null, "UPDATE Podcasttable SET Version = ?, Category = ? WHERE PODindex = ?", 4, $podcast['Category'], $podid);
$v++;
break;
}
}
}
function upgrade_podcasts_to_version() {
$pods = generic_sql_query('SELECT * FROM Podcasttable WHERE Subscribed = 1 AND Version < '.ROMPR_PODCAST_TABLE_VERSION);
foreach ($pods as $podcast) {
$v = $podcast['Version'];
while ($v < ROMPR_PODCAST_TABLE_VERSION) {
switch ($v) {
case 2;
logger::mark("PODCASTS", " Updating Podcast ".$podcast['Title']." to version 3");
$newest_track = generic_sql_query("SELECT PubDate FROM PodcastTracktable WHERE PODindex = ".$podcast['PODindex']." ORDER BY PubDate DESC LIMIT 1");
$podcast['LastPubDate'] = $newest_track[0]['PubDate'];
logger::log("PODCASTS", " Last episode for this podcast was published on ".date('c', $podcast['LastPubDate']));
switch($podcast['RefreshOption']) {
case REFRESHOPTION_WEEKLY:
case REFRESHOPTION_MONTHLY:
$podcast['LastUpdate'] = calculate_best_update_time($podcast);
break;
}
generic_sql_query("UPDATE Podcasttable SET LastUpdate = ".$podcast['LastUpdate'].", LastPubDate = ".$podcast['LastPubDate'].", Version = 3 WHERE PODindex = ".$podcast['PODindex']);
$v++;
break;
case 3;
// Upgrade to version 4 can only happen after feed has been re-parsed
$v++;
break;
}
}
}
}
function outputPodcast($podid, $do_searchbox = true) {
$result = generic_sql_query("SELECT * FROM Podcasttable WHERE PODindex = ".$podid, false, PDO::FETCH_OBJ);
foreach ($result as $obj) {
doPodcast($obj, $do_searchbox);
}
}
function doPodcast($y, $do_searchbox) {
if ($y->Subscribed == 0) {
logger::mark("PODCASTS", "Getting feed for unsubscribed podcast ".$y->FeedURL);
refreshPodcast($y->PODindex);
$a = generic_sql_query("SELECT * FROM Podcasttable WHERE PODindex = ".$y->PODindex, false, PDO::FETCH_OBJ);
if (count($a) > 0) {
$y = $a[0];
} else {
logger::fail("PODCASTS", "ERROR looking up podcast",$y->FeedURL);
return;
}
}
$aa = $y->Artist;
if ($aa != '') {
$aa = $aa . ' - ';
}
$pm = $y->PODindex;
trackControlHeader('','','podcast_'. $pm,array(array('Image' => $y->Image)));
print '<div class="whatdoicallthis">'.format_text($y->Description).'</div>';
if ($y->Subscribed == 1) {
print '<div class="containerbox bumpad">';
print '<i title="'.get_int_text("podcast_configure").'" class="icon-cog-alt podicon '.
'clickicon openmenu fixed tooltip" name="podconf_'.$pm.'"></i>';
print '<i title="'.get_int_text("podcast_refresh").'" class="icon-refresh podicon podaction podcast clickable '.
'clickicon fixed tooltip" name="refresh_'.$pm.'"></i>';
print '<i title="'.get_int_text("podcast_download_all").'" class="icon-download podicon '.
'clickable clickicon podgroupload podcast fixed tooltip" name="podgroupload_'.$pm.'"></i>';
print '<i title="'.get_int_text("podcast_mark_all").'" class="icon-headphones podicon podcast podaction '.
'clickable clickicon fixed tooltip" name="channellistened_'.$pm.'"></i>';
print '<i title="'.get_int_text("podcast_undelete").'" class="icon-trash podicon podcast podaction oneeighty '.
'clickable clickicon fixed tooltip" name="channelundelete_'.$pm.'"></i>';
print '<i title="'.get_int_text("podcast_removedownloaded").'" class="icon-download podicon podcast podaction oneeighty '.
'clickable clickicon fixed tooltip" name="removedownloaded_'.$pm.'"></i>';
print '<div class="expand"></div>';
print '<i title="'.get_int_text("podcast_delete").'" class="icon-cancel-circled podicon '.
'clickable clickicon podremove podcast fixed tooltip" name="podremove_'.$pm.'"></i>';
print '</div>';
print '<div class="marged whatdoicallthis toggledown invisible podconfigpanel" id="podconf_'.$pm.'">';
print '<div class="containerbox vertical podoptions">';
print '<div class="containerbox fixed dropdown-container"><div class="divlabel">'.
get_int_text("podcast_display").'</div>';
print '<div class="selectholder">';
print '<select name="DisplayMode" onchange="podcasts.changeOption(event)">';
$options = '<option value="'.DISPLAYMODE_ALL.'">'.get_int_text("podcast_display_all").'</option>'.
'<option value="'.DISPLAYMODE_NEW.'">'.get_int_text("podcast_display_onlynew").'</option>'.
'<option value="'.DISPLAYMODE_UNLISTENED.'">'.get_int_text("podcast_display_unlistened").'</option>'.
'<option value="'.DISPLAYMODE_DOWNLOADEDNEW.'">'.get_int_text("podcast_display_downloadnew").'</option>'.
'<option value="'.DISPLAYMODE_DOWNLOADED.'">'.get_int_text("podcast_display_downloaded").'</option>';
print preg_replace('/(<option value="'.$y->DisplayMode.'")/', '$1 selected', $options);
print '</select>';
print '</div></div>';
print '<div class="containerbox fixed dropdown-container"><div class="divlabel">'.
get_int_text("podcast_refresh").'</div>';
print '<div class="selectholder">';
print '<select name="RefreshOption" onchange="podcasts.changeOption(event)">';
$options = '<option value="'.REFRESHOPTION_NEVER.'">'.get_int_text("podcast_refresh_never").'</option>'.
'<option value="'.REFRESHOPTION_HOURLY.'">'.get_int_text("podcast_refresh_hourly").'</option>'.
'<option value="'.REFRESHOPTION_DAILY.'">'.get_int_text("podcast_refresh_daily").'</option>'.
'<option value="'.REFRESHOPTION_WEEKLY.'">'.get_int_text("podcast_refresh_weekly").'</option>'.
'<option value="'.REFRESHOPTION_MONTHLY.'">'.get_int_text("podcast_refresh_monthly").'</option>';
print preg_replace('/(<option value="'.$y->RefreshOption.'")/', '$1 selected', $options);
print '</select>';
print '</div></div>';
print '<div class="containerbox fixed dropdown-container"><div class="divlabel">'.
get_int_text("podcast_expire").'</div>';
print '<div class="selectholder">';
print '<select title="'.get_int_text("podcast_expire_tooltip").
'" name="DaysToKeep" class="tooltip" onchange="podcasts.changeOption(event)">';
$options = '<option value="0">'.get_int_text("podcast_expire_never").'</option>'.
'<option value="7">'.get_int_text("podcast_expire_week").'</option>'.
'<option value="14">'.get_int_text("podcast_expire_2week").'</option>'.
'<option value="30">'.get_int_text("podcast_expire_month").'</option>'.
'<option value="60">'.get_int_text("podcast_expire_2month").'</option>'.
'<option value="182">'.get_int_text("podcast_expire_6month").'</option>'.
'<option value="365">'.get_int_text("podcast_expire_year").'</option>';
print preg_replace('/(<option value="'.$y->DaysToKeep.'")/', '$1 selected', $options);
print '</select>';
print '</div></div>';
print '<div class="containerbox fixed dropdown-container"><div class="divlabel">'.
get_int_text("podcast_keep").'</div>';
print '<div class="selectholder">';
print '<select title="'.get_int_text("podcast_keep_tooltip").
'" name="NumToKeep" class="tooltip" onchange="podcasts.changeOption(event)">';
$options = '<option value="0">'.get_int_text("podcast_keep_0").'</option>'.
'<option value="1">1</option>'.
'<option value="5">5</option>'.
'<option value="10">10</option>'.
'<option value="25">25</option>'.
'<option value="50">50</option>'.
'<option value="100">100</option>'.
'<option value="200">200</option>';
print preg_replace('/(<option value="'.$y->NumToKeep.'")/', '$1 selected', $options);
print '</select>';
print '</div></div>';
print '<div class="containerbox fixed dropdown-container"><div class="divlabel">'.
get_int_text("podcast_sortmode").'</div>';
print '<div class="selectholder">';
print '<select name="SortMode" onchange="podcasts.changeOption(event)">';
$options = '<option value="'.SORTMODE_NEWESTFIRST.'">'.get_int_text("podcast_newestfirst").'</option>'.
'<option value="'.SORTMODE_OLDESTFIRST.'">'.get_int_text("podcast_oldestfirst").'</option>';
print preg_replace('/(<option value="'.$y->SortMode.'")/', '$1 selected', $options);
print '</select>';
print '</div></div>';
print '</div>';
print '<div class="containerbox fixed bumpad styledinputs">';
print '<input type="checkbox" class="topcheck" id="podkd"';
if ($y->KeepDownloaded == 1) {
print ' checked';
}
print '><label for="podkd" class="tooltip" title="'.get_int_text("podcast_kd_tooltip").
'" name="KeepDownloaded" onclick="podcasts.changeOption(event)">'.
get_int_text("podcast_keep_downloaded").'</label></div>';
// print '<div class="containerbox fixed bumpad styledinputs">';
// print '<input type="checkbox" class="topcheck podautodown" id="podad"';
// if ($y->AutoDownload == 1) {
// print ' checked';
// }
// print '><label for="podad" name="AutoDownload" onclick="podcasts.changeOption(event)">'.
// get_int_text("podcast_auto_download").'</label></div>';
print '<div class="containerbox fixed bumpad styledinputs">';
print '<input type="checkbox" class="topcheck" id="podhd"';
if ($y->HideDescriptions == 1) {
print ' checked';
}
print '><label for="podhd" name="HideDescriptions" onclick="podcasts.changeOption(event)">'.
get_int_text("podcast_hidedescriptions").'</label></div>';
print '</div>';
}
if ($do_searchbox) {
print '<div class="containerbox noselection dropdown-container"><div class="expand">
<input class="enter clearbox" name="podsearcher_'.$y->PODindex.'" type="text" ';
if (array_key_exists('searchterm', $_REQUEST)) {
print 'value="'.urldecode($_REQUEST['searchterm']).'" ';
}
print '/></div><button class="fixed searchbutton iconbutton" onclick="podcasts.searchinpodcast('.$y->PODindex.')"></button></div>';
}
print '<div class="clearfix bumpad"></div>';
if (array_key_exists('searchterm', $_REQUEST)) {
$extrabit = ' AND (Title LIKE "%'.urldecode($_REQUEST['searchterm']).'%" OR Description LIKE "%'.urldecode($_REQUEST['searchterm']).'%")';
} else {
$extrabit = '';
}
$qstring = 'SELECT * FROM PodcastTracktable WHERE PODindex = '.$y->PODindex.' AND Deleted = 0'.$extrabit.' ORDER BY PubDate ';
if ($y->SortMode == SORTMODE_OLDESTFIRST) {
$qstring .= "ASC";
} else {
$qstring .= "DESC";
}
logger::debug("PODCASTS", $qstring);
$result = generic_sql_query($qstring, false, PDO::FETCH_OBJ);
foreach ($result as $episode) {
format_episode($y, $episode, $pm);
}
}
function format_episode(&$y, &$item, $pm) {
if ($item->Deleted == 1) {
return;
}
if ($y->DisplayMode == DISPLAYMODE_DOWNLOADEDNEW && ($item->Downloaded == 0 && $item->New == 0))
{
return;
}
if ($y->DisplayMode == DISPLAYMODE_NEW && $item->New == 0) {
return;
}
if ($y->DisplayMode == DISPLAYMODE_UNLISTENED && $item->Listened == 1) {
// Track cannot be new and unlistened, that can't happen because it makes no sense
return;
}
if ($y->DisplayMode == DISPLAYMODE_DOWNLOADED && $item->Downloaded == 0) {
return;
}
print '<div class="item podcastitem">';
if ($item->Downloaded == 1 && $y->Version > 1) {
print '<div class="containerbox clicktrack playable draggable dropdown-container" name="'.get_base_url().$item->Localfilename.'">';
} else {
print '<div class="containerbox clicktrack playable draggable dropdown-container" name="'.$item->Link.'">';
}
if ($y->Subscribed == 1) {
if ($item->New == 1) {
print '<i title="'.get_int_text("podcast_tooltip_new").
'" class="icon-sun fixed newpodicon tooltip"></i>';
} else if ($item->Listened == 0) {
print '<i title="'.get_int_text("podcast_tooltip_notnew").
'" class="icon-unlistened fixed oldpodicon tooltip"></i>';
}
}
print '<div class="podtitle expand">'.htmlspecialchars(html_entity_decode($item->Title)).'</div>';
print '<i class="fixed icon-no-response-playbutton podicon"></i>';
print '</div>';
if ($item->Progress > 0) {
print '<input type="hidden" class="resumepos" value="'.$item->Progress.'" />';
print '<input type="hidden" class="length" value="'.$item->Duration.'" />';
}
$pee = date(DATE_RFC2822, $item->PubDate);
$pee = preg_replace('/ \+\d\d\d\d$/','',$pee);
print '<div class="whatdoicallthis padright containerbox dropdown-container podtitle notbold">';
if ($y->HideDescriptions == 0) {
$class = 'icon-toggle-open';
} else {
$class = 'icon-toggle-closed';
}
print '<i class="'.$class.' menu mh fixed openmenu" name="poddesc_'.$item->PODTrackindex.'"></i>';
print '<div class="expand"><i>'.$pee.'</i></div>';
if ($item->Duration != 0) {
print '<div class="fixed">'.format_time($item->Duration).'</div>';
}
print '</div>';
if ($y->HideDescriptions == 0) {
$class = 'whatdoicallthis toggledown';
} else {
$class = 'invisible whatdoicallthis toggledown';
}
print '<div id="poddesc_'.$item->PODTrackindex.'" class="'.$class.'">'.format_text(fixup_links($item->Description)).'</div>';
// Usually very inaccurate
// if ($item->FileSize > 0) {
// print '<div class="fsize">'.format_bytes($item->FileSize).'Bytes</div>';
// }
if ($y->Subscribed == 1) {
print '<div class="clearfix" name="podcontrols_'.$pm.'">';
if ($item->Downloaded == 1) {
print '<i class="icon-floppy podicon tleft tooltip" title="'.
get_int_text("podcast_tooltip_downloaded").'"></i>';
} else {
if ($item->New == 1) {
$extraclass = ' podnewdownload';
} else {
$extraclass = '';
}
print '<i class="icon-download podicon clickable clickicon tleft podcast poddownload'.$extraclass.' tooltip" title="'.
get_int_text("podcast_tooltip_download").'" name="poddownload_'.$item->PODTrackindex.'"></i>';
}
if ($item->Listened == 0) {
print '<i class="icon-headphones podicon clickable clickicon tleft podcast podmarklistened tooltip" title="'.
get_int_text("podcast_tooltip_mark").'" name="podmarklistened_'.$item->PODTrackindex.'"></i>';
}
print '<i class="icon-cancel-circled podicon clickable clickicon tright podtrackremove podcast tooltip" title="'.
get_int_text("podcast_tooltip_delepisode").'" name="podtrackremove_'.$item->PODTrackindex.'" ></i>';
print '</div>';
}
print '</div>';
}
function doPodcastHeader($y) {
$i = getDomain($y->Image);
if ($i == "http" || $i == "https") {
$img = "getRemoteImage.php?url=".$y->Image;
} else {
$img = $y->Image;
}
$aname = htmlspecialchars(html_entity_decode($y->Artist));
if ($y->Category) {
$aname .= '<br /><span class="playlistrow2">'.htmlspecialchars($y->Category).'</span>';
}
$html = albumHeader(array(
'id' => 'podcast_'.$y->PODindex,
'Image' => $img,
'Searched' => 1,
'AlbumUri' => null,
'Year' => null,
'Artistname' => $aname,
'Albumname' => htmlspecialchars(html_entity_decode($y->Title)),
'why' => null,
'ImgKey' => 'none',
'class' => 'podcast'
));
$extra = '<div class="fixed">';
if ($y ->Subscribed == 1) {
$uc = get_podcast_counts($y->PODindex);
$extra .= '<span id="podnumber_'.$y->PODindex.'"';
if ($uc['new'] > 0) {
$extra .= ' class="newpod">'.$uc['new'].'</span>';
} else {
$extra .= '></span>';
}
if ($uc['unlistened'] > 0) {
$extra .= '<span class="unlistenedpod">'.$uc['unlistened'].'</span>';
} else {
$extra .= '<span></span>';
}
} else {
$extra .= '<i class="clickicon clickable clickpodsubscribe podcast icon-rss podicon tooltip" title="Subscribe to this podcast"></i><input type="hidden" value="'.$y->PODindex.'" />';
}
$extra .= '</div>';
// phpQuery is something like 160K of extra code. Just to do this.
// The fact that I'm willing to include it indicates just how crap php's DOMDocument is
// phpQuery barfs at our '&rompr_resize_size' because it's expecting an HTML entity after &
$html = preg_replace('/&rompr_/','&amp;rompr_', $html);
$out = addPodcastCounts($html, $extra);
$h = $out->html();
$html = preg_replace('/&amp;rompr_/','&rompr_', $h);
print $html;
print '<div id="podcast_'.$y->PODindex.'" class="indent dropmenu padright"><div class="configtitle textcentre"><b>'.get_int_text('label_loading').'</b></div></div>';
}
function removePodcast($podid) {
logger::mark("PODCASTS", "Removing podcast ".$podid);
if (is_dir('prefs/podcasts/'.$podid)) {
rrmdir('prefs/podcasts/'.$podid);
}
generic_sql_query("DELETE FROM Podcasttable WHERE PODindex = ".$podid, true);
generic_sql_query("DELETE FROM PodcastTracktable WHERE PODindex = ".$podid, true);
}
function markAsListened($url) {
$podid = false;
$pods = sql_prepare_query(false, PDO::FETCH_OBJ, null, null, "SELECT PODindex, PODTrackindex FROM PodcastTracktable WHERE Link = ? OR Localfilename = ?", $url, basename($url));
foreach ($pods as $pod) {
$podid = $pod->PODindex;
logger::mark("PODCASTS", "Marking track",$pod->PODTrackindex,"from podcast",$podid,"as listened");
sql_prepare_query(true, null, null, null, "UPDATE PodcastTracktable SET Listened = 1, New = 0, Progress = 0 WHERE PODTrackindex=?",$pod->PODTrackindex);
}
return $podid;
}
function deleteTrack($trackid, $channel) {
logger::mark("PODCASTS", "Marking track",$trackid,"from podcast",$channel,"as deleted");
generic_sql_query("UPDATE PodcastTracktable SET Deleted = 1 WHERE PODTrackindex = ".$trackid, true);
if (is_dir('prefs/podcasts/'.$channel.'/'.$trackid)) {
rrmdir('prefs/podcasts/'.$channel.'/'.$trackid);
}
return $channel;
}
function markKeyAsListened($trackid, $channel) {
logger::mark("PODCASTS", "Marking track",$trackid,"from podcast",$channel,"as listened");
generic_sql_query("UPDATE PodcastTracktable SET Listened = 1, New = 0, Progress = 0 WHERE PODTrackindex = ".$trackid, true);
return $channel;
}
function changeOption($option, $val, $channel) {
logger::log("PODCASTS", "Changing Option",$option,"to",$val,"on channel",$channel);
if ($val === 'true') {
$val = 1;
}
if ($val === 'false') {
$val = 0;
}
generic_sql_query("UPDATE Podcasttable SET ".$option."=".$val." WHERE PODindex=".$channel, true);
if ($option == 'DaysToKeep' || $option == 'NumToKeep') {
refreshPodcast($channel);
}
if ($option == 'RefreshOption') {
$podcast = generic_sql_query("SELECT * FROM Podcasttable WHERE PODindex = ".$channel, false, PDO::FETCH_ASSOC);
$dt = new DateTime(date('c', $podcast[0]['LastUpdate']));
logger::log("PODCASTS", "Changed Refresh Option for podcast ".$channel.". Last Update Was ".$dt->format('c'));
switch($podcast[0]['RefreshOption']) {
case REFRESHOPTION_HOURLY:
$dt->modify('+1 hour');
break;
case REFRESHOPTION_DAILY:
$dt->modify('+24 hours');
break;
case REFRESHOPTION_WEEKLY:
$dt->modify('+1 week');
break;
case REFRESHOPTION_MONTHLY:
$dt->modify('+1 month');
break;
default:
$dt->modify('+10 years');
break;
}
$updatetime = $dt->getTimestamp();
if ($updatetime <= time()) {
refreshPodcast($channel);
} else {
generic_sql_query("UPDATE Podcasttable SET LastUpdate = ".calculate_best_update_time($podcast[0])." WHERE PODindex = ".$channel);
}
}
return $channel;
}
function markChannelAsListened($channel) {
generic_sql_query("UPDATE PodcastTracktable SET Listened = 1, New = 0, Progress = 0 WHERE PODindex = ".$channel, true);
return $channel;
}
function mark_all_episodes_listened() {
generic_sql_query("UPDATE PodcastTracktable SET Listened = 1, New = 0, Progress = 0 WHERE PODindex IN (SELECT PODindex FROM Podcasttable WHERE Subscribed = 1)");
return false;
}
function undeleteFromChannel($channel) {
generic_sql_query("UPDATE PodcastTracktable SET Downloaded=0 WHERE PODindex=".$channel." AND Deleted=1", true);
generic_sql_query("UPDATE PodcastTracktable SET Deleted=0 WHERE PODindex=".$channel." AND Deleted=1", true);
return $channel;
}
function undelete_all() {
generic_sql_query("UPDATE PodcastTracktable SET Downloaded = 0 WHERE PODindex IN (SELECT PODindex FROM Podcasttable WHERE Subscribed = 1) AND Deleted = 1", true);
generic_sql_query("UPDATE PodcastTracktable SET Deleted = 0 WHERE PODindex IN (SELECT PODindex FROM Podcasttable WHERE Subscribed = 1) AND Deleted = 1", true);
return false;
}
function remove_all_downloaded() {
$pods = glob('prefs/podcasts/*');
foreach ($pods as $channel) {
removeDownloaded(basename($channel));
}
return false;
}
function removeDownloaded($channel) {
if (is_dir('prefs/podcasts/'.$channel)) {
$things = glob('prefs/podcasts/'.$channel.'/*');
foreach ($things as $thing) {
if (is_dir($thing) && basename($thing) != 'albumart') {
rrmdir($thing);
}
}
}
generic_sql_query("UPDATE PodcastTracktable SET Downloaded=0, Localfilename=NULL WHERE PODindex=".$channel, true);
return $channel;
}
function downloadTrack($key, $channel) {
logger::mark("PODCASTS", "Downloading track",$key,"from podcast",$channel);
$url = null;
$filesize = 0;
$result = generic_sql_query("SELECT Link, FileSize FROM PodcastTracktable WHERE PODTrackindex = " . intval($key), false, PDO::FETCH_OBJ);
foreach ($result as $obj) {
$url = $obj->Link;
$filesize = $obj->FileSize;
}
if ($url === null) {
logger::fail("PODCASTS", " Failed to find URL for podcast",$channel);
return $channel;
}
// The file size reported in the RSS is often VERY inaccurate. Probably based on raw audio prior to converting to MP3
// To make the progress bars look better in the GUI we attempt to read the actual filesize
$filesize = getRemoteFilesize($url, $filesize);
if (is_dir('prefs/podcasts/'.$channel.'/'.$key) || mkdir ('prefs/podcasts/'.$channel.'/'.$key, 0755, true)) {
$filename = basename($url);
$filename = preg_replace('/\?.*$/','',$filename);
$fp = fopen('prefs/monitor.xml', 'w');
if ($fp === false) {
logger::warn("PODCASTS", "Failed to open monitor.xml");
return $channel;
}
$xml = '<?xml version="1.0" encoding="utf-8"?><download><filename>';
$xml = $xml . 'prefs/podcasts/'.$channel.'/'.$key.'/'.$filename;
$xml = $xml . '</filename><filesize>'.$filesize.'</filesize></download>';
$fp = fopen('prefs/monitor.xml', 'w');
fwrite($fp, $xml);
fclose($fp);
logger::log("PODCASTS", "Downloading To prefs/podcasts/".$channel.'/'.$key.'/'.$filename);
$d = new url_downloader(array('url' => $url));
if ($d->get_data_to_file('prefs/podcasts/'.$channel.'/'.$key.'/'.$filename, true)) {
sql_prepare_query(true, null, null, null, "UPDATE PodcastTracktable SET Downloaded=?, Localfilename=? WHERE PODTrackindex=?", 1, '/prefs/podcasts/'.$channel.'/'.$key.'/'.$filename, $key);
} else {
header('HTTP/1.0 404 Not Found');
system (escapeshellarg('rm -fR prefs/podcasts/'.$channel.'/'.$key));
}
} else {
logger::warn("PODCASTS", 'Failed to create directory prefs/podcasts/'.$channel.'/'.$key);
return $channel;
}
return $channel;
}
function get_podcast_counts($podid) {
if ($podid !== null) {
$ext = ' AND PODindex = '.$podid;
} else {
$ext = '';
}
$qstring = "SELECT COUNT(PODTrackindex) AS num FROM PodcastTracktable JOIN Podcasttable USING (PODindex) WHERE Subscribed = 1 AND New = 1 AND Listened = 0 AND Deleted = 0";
$results['new'] = generic_sql_query($qstring.$ext, false, null, 'num', 0);
$qstring = "SELECT COUNT(PODTrackindex) AS num FROM PodcastTracktable JOIN Podcasttable USING (PODindex) WHERE Subscribed = 1 AND New = 0 AND Listened = 0 AND Deleted = 0";
$results['unlistened'] = generic_sql_query($qstring.$ext, false, null, 'num', 0);
return $results;
}
function get_all_counts() {
$counts = array();
$counts['totals'] = get_podcast_counts(null);
$result = generic_sql_query("SELECT PODindex FROM Podcasttable WHERE Subscribed = 1", false, PDO::FETCH_OBJ);
foreach ($result as $obj) {
$counts[$obj->PODindex] = get_podcast_counts($obj->PODindex);
}
return $counts;
}
function check_podcast_refresh() {
check_refresh_pid();
$tocheck = array();
$nextupdate_seconds = 2119200;
$result = generic_sql_query("SELECT PODindex, LastUpdate, RefreshOption FROM Podcasttable WHERE RefreshOption > 0 AND Subscribed = 1", false, PDO::FETCH_OBJ);
foreach ($result as $obj) {
$tocheck[] = array('podid' => $obj->PODindex, 'lastupdate' => $obj->LastUpdate, 'refreshoption' => $obj->RefreshOption);
}
$updated = array('nextupdate' => $nextupdate_seconds, 'updated' => array());
$now = time();
foreach ($tocheck as $pod) {
$dt = new DateTime(date('c', $pod['lastupdate']));
logger::mark("PODCASTS", "Checking for refresh to podcast",$pod['podid'],'refreshoption is',$pod['refreshoption'],"LastUpdate is",$dt->format('c'));
switch($pod['refreshoption']) {
case REFRESHOPTION_HOURLY:
$dt->modify('+1 hour');
$tempnextupdate = 3600;
break;
case REFRESHOPTION_DAILY:
$dt->modify('+24 hours');
$tempnextupdate = 86400;
break;
case REFRESHOPTION_WEEKLY:
$dt->modify('+1 week');
$tempnextupdate = 604800;
break;
case REFRESHOPTION_MONTHLY:
$dt->modify('+1 month');
// Seconds in a month is roughly 2419200, but this value is TOO BIG
// for Javascript's setTimeout which is 32 bit signed milliseconds.
$tempnextupdate = 2119200;
break;
default:
logger::log("PODCASTS", "Not automatic update option for podcast id ".$pod['podid']);
continue 2;
}
$updatetime = $dt->getTimestamp();
logger::trace("PODCASTS", " lastupdate is",$pod['lastupdate'],"update time is",$updatetime,"current time is",$now);
if ($updatetime <= $now) {
$retval = refreshPodcast($pod['podid']);
if ($retval !== false) {
$updated[] = $retval;
}
if ($tempnextupdate < $nextupdate_seconds) {
$nextupdate_seconds = $tempnextupdate;
}
} else {
$a = $updatetime - $now;
if ($a < $nextupdate_seconds) {
$nextupdate_seconds = $a;
}
}
}
logger::log("PODCASTS", "Next update is required in",$nextupdate_seconds,"seconds");
$updated['nextupdate'] = $nextupdate_seconds;
clear_refresh_pid();
return $updated;
}
function search_itunes($term) {
global $prefs;
logger::mark("PODCASTS", "Searching iTunes for '".$term."'");
generic_sql_query("DELETE FROM PodcastTracktable WHERE PODindex IN (SELECT PODindex FROM Podcasttable WHERE Subscribed = 0)", true);
generic_sql_query("DELETE FROM Podcasttable WHERE Subscribed = 0", true);
$d = new url_downloader(array('url' => 'https://itunes.apple.com/search?term='.$term.'&entity=podcast'));
if ($d->get_data_to_string()) {
$pods = json_decode(trim($d->get_data()), true);
foreach ($pods['results'] as $podcast) {
if (array_key_exists('feedUrl', $podcast)) {
// Bloody hell they can't even be consistent!
$podcast['feedURL'] = $podcast['feedUrl'];
}
if (array_key_exists('feedURL', $podcast)) {
$r = check_if_podcast_is_subscribed($podcast);
if (count($r) > 0) {
foreach ($r as $a) {
logger::log("PODCASTS", " Search found EXISTING podcast ".$a['Title']);
}
continue;
}
if (array_key_exists('artworkUrl600', $podcast) && $podcast['artworkUrl600'] != '' && $podcast['artworkUrl600'] != null) {
$img = 'getRemoteImage.php?url='.$podcast['artworkUrl600'];
} else {
$img = 'newimages/podcast-logo.svg';
}
logger::log("PODCASTS", "Search found podcast : ".$podcast['collectionName']);
// IMPORTANT NOTE. We do NOT set LastPubDate here, because that would prevent the podcasts from being refreshed
// if we subscribe to it. (If it hasn't been browsed then we need to refresh it to get all the episodes)
// LastPubDate will get set by refreshPodcast if we subscribe
sql_prepare_query(true, null, null, null,
"INSERT INTO Podcasttable
(FeedURL, LastUpdate, Image, Title, Artist, RefreshOption, SortMode, DisplayMode, DaysLive, Description, Version, Subscribed, Category)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
$podcast['feedUrl'],
time(),
$img,
$podcast['collectionName'],
$podcast['artistName'],
$prefs['default_podcast_refresh_mode'],
$prefs['default_podcast_sort_mode'],
$prefs['default_podcast_display_mode'],
0,
'',
ROMPR_PODCAST_TABLE_VERSION,
0,
implode(', ', array_diff($podcast['genres'], array('Podcasts')))
);
}
}
}
}
function subscribe($index) {
refreshPodcast($index);
generic_sql_query("UPDATE Podcasttable SET Subscribed = 1 WHERE PODindex = ".$index, true);
}
function check_if_podcast_is_subscribed($podcast) {
return sql_prepare_query(false, PDO::FETCH_ASSOC, null, null, "SELECT Title FROM Podcasttable WHERE Subscribed = 1 AND (FeedURL = ? OR (Title = ? AND Artist = ?))", $podcast['feedUrl'], $podcast['collectionName'], $podcast['artistName']);
}
function setPlaybackProgress($progress, $uri) {
$podid = false;
$pod = sql_prepare_query(false, PDO::FETCH_OBJ, null, null, "SELECT PODindex, PODTrackindex FROM PodcastTracktable WHERE Link = ? OR LocalFilename = ?", $uri, $uri);
foreach ($pod as $podcast) {
$podid = $podcast->PODindex;
logger::log("PODCASTS", "Updating Playback Progress for track",$podcast->PODTrackindex,"in podcast",$podid,"to",$progress);
generic_sql_query("UPDATE PodcastTracktable SET Progress = ".$progress." WHERE PODTrackindex = ".$podcast->PODTrackindex);
}
return $podid;
}
function refresh_all_podcasts() {
check_refresh_pid();
$result = generic_sql_query("SELECT PODindex FROM Podcasttable WHERE Subscribed = 1", false, PDO::FETCH_OBJ);
foreach ($result as $obj) {
refreshPodcast($obj->PODindex);
}
clear_refresh_pid();
return false;
}
function checkListened($title, $album, $artist) {
logger::mark("PODCASTS", "Checking Podcast",$album,"for track",$title);
$podid = false;
$pods = sql_prepare_query(false, PDO::FETCH_OBJ, null, null,
"SELECT PODindex, PODTrackindex FROM Podcasttable JOIN PodcastTracktable USING (PODindex)
WHERE
-- Podcasttable.Artist = ? AND
Podcasttable.Title = ? AND
PodcastTracktable.Title = ?",
// $artist,
$album,
$title);
foreach ($pods as $pod) {
$podid = $pod->PODindex;
logger::log("PODCASTS", "Marking",$pod->PODTrackindex,"from",$podid,"as listened");
sql_prepare_query(true, null, null, null, "UPDATE PodcastTracktable SET Listened = 1, New = 0, Progress = 0 WHERE PODTrackindex=?",$pod->PODTrackindex);
}
return $podid;
}
function check_refresh_pid() {
// $pid = getmypid();
// $rpid = simple_query('Value', 'Statstable', 'Item', 'PodUpPid', null);
// if ($rpid === null) {
// header('HTTP/1.1 500 Internal Server Error');
// exit(0);
// } else if ($rpid != 0) {
// header('HTTP/1.1 412 Precondition Failed');
// exit(0);
// }
// generic_sql_query("UPDATE Statstable SET Value = '.$pid.' WHERE Item = 'PodUpPid'");
}
function clear_refresh_pid() {
// generic_sql_query("UPDATE Statstable SET Value = 0 WHERE Item = 'PodUpPid'");
}
?>