1<?php 2/** 3 * This contains variables and functions related to the Program class 4 * 5 * @license GPL 6 * 7 * @package MythWeb 8 * @subpackage TV 9 * 10 **/ 11 12// Reasons a recording wouldn't be happening (from libs/libmythtv/programinfo.h) 13 $RecStatus_Types = array( 14 '-8' => 'TunerBusy', 15 '-7' => 'LowDiskSpace', 16 '-6' => 'Cancelled', 17 '-5' => 'Deleted', 18 '-4' => 'Aborted', 19 '-3' => 'Recorded', 20 '-2' => 'Recording', 21 '-1' => 'WillRecord', 22 0 => 'Unknown', 23 1 => 'DontRecord', 24 2 => 'PreviousRecording', 25 3 => 'CurrentRecording', 26 4 => 'EarlierShowing', 27 5 => 'TooManyRecordings', 28 6 => 'NotListed', 29 7 => 'Conflict', 30 8 => 'LaterShowing', 31 9 => 'Repeat', 32 10 => 'Inactive', 33 11 => 'NeverRecord' 34 ); 35 36 $RecStatus_Reasons = array( 37 'TunerBusy' => t('recstatus: tunerbusy'), 38 'LowDiskSpace' => t('recstatus: lowdiskspace'), 39 'Cancelled' => t('recstatus: cancelled'), 40 'Deleted' => t('recstatus: deleted'), 41 'Aborted' => t('recstatus: stopped'), 42 'Recorded' => t('recstatus: recorded'), 43 'Recording' => t('recstatus: recording'), 44 'WillRecord' => t('recstatus: willrecord'), 45 'Unknown' => t('recstatus: unknown'), 46 'DontRecord' => t('recstatus: manualoverride'), 47 'PreviousRecording' => t('recstatus: previousrecording'), 48 'CurrentRecording' => t('recstatus: currentrecording'), 49 'EarlierShowing' => t('recstatus: earliershowing'), 50 'TooManyRecordings' => t('recstatus: toomanyrecordings'), 51 'NotListed' => t('recstatus: notlisted'), 52 'Conflict' => t('recstatus: conflict'), 53 'Repeat' => t('recstatus: repeat'), 54 'LaterShowing' => t('recstatus: latershowing'), 55 'Inactive' => t('recstatus: inactive'), 56 'NeverRecord' => t('recstatus: neverrecord'), 57 // A special category for mythweb, since this feature doesn't exist in the backend 58 'ForceRecord' => t('recstatus: force_record'), 59 ); 60 61/** 62 * a shortcut to load_all_program_data's single-program query 63 **/ 64 function &load_one_program($start_time, $chanid, $manualid) { 65 if ($manualid) 66 $program =& load_all_program_data($start_time, $start_time, $chanid, true, 'program.manualid='.intval($manualid)); 67 else 68 $program =& load_all_program_data($start_time, $start_time, $chanid, true); 69 if (!is_object($program) || strcasecmp(get_class($program), 'program')) 70 return NULL; 71 return $program; 72 } 73 74/** 75 * loads all program data for the specified time range. 76 * Set $single_program to true if you only want information about programs that 77 * start exactly at $start_time (used by program_detail.php) 78 **/ 79 function &load_all_program_data($start_time, $end_time, $chanid = false, $single_program = false, $extra_query = '', $distinctTitle = false) { 80 global $db; 81 // Don't allow negative timestamps; it confuses MySQL 82 if ($start_time < 0) 83 $start_time = 0; 84 if ($end_time < 0) 85 $end_time = 0; 86 // Make a local hash of channel chanid's with references to the actual 87 // channel data (Channels are not indexed by anything in particular, so 88 // that the user can sort by chanid or channum). 89 $channel_hash = array(); 90 // An array (that later gets converted to a string) containing the id's of channels we want to load 91 if ($chanid) 92 $these_channels[] = $chanid; 93 else 94 $these_channels = Channel::getChannelList(); 95 // convert $these_channels into a string so it'll go straight into the query 96 if (!count($these_channels)) 97 trigger_error("load_all_program_data() attempted with out any channels", FATAL); 98 $these_channels = implode(',', $these_channels); 99 // Build the sql query, and execute it 100 // The weird stuff with pr1 and pr2 is to eliminate the mutiple ratings 101 // per program which causes duplicates to be found. 102 // This code selects the "rater" with the highest name alphabetically, 103 // so for example where raters available for a program are CHVRS ClassInd and VCHIP, 104 // it selects VCHIP. 105 $query = 'SELECT DISTINCT program.*, 106 UNIX_TIMESTAMP(program.starttime) AS starttime_unix, 107 UNIX_TIMESTAMP(program.endtime) AS endtime_unix, 108 IFNULL(pr1.`system`, "") AS rater, 109 IFNULL(pr1.rating, "") AS rating, 110 channel.callsign, 111 channel.channum 112 FROM program USE INDEX (id_start_end) 113 LEFT JOIN programrating pr1 114 on program.chanid = pr1.chanid 115 and program.starttime = pr1.starttime 116 LEFT OUTER JOIN programrating pr2 117 on program.chanid = pr2.chanid 118 and program.starttime = pr2.starttime 119 and pr2.`system` > pr1.`system` 120 LEFT JOIN channel on channel.chanid = program.chanid 121 LEFT JOIN credits 122 on program.chanid = credits.chanid 123 and program.starttime = credits.starttime 124 LEFT JOIN people USING (person) 125 WHERE pr2.`system` is null and '; 126 // Only loading a single channel worth of information 127 if ($chanid > 0) 128 $query .= ' program.chanid='.$db->escape($chanid); 129 // Loading a group of channels (probably all of them) 130 else 131 $query .= ' program.chanid IN ('.$these_channels.')'; 132 // Requested start time is the same as the end time - don't bother with fancy calculations 133 if ($start_time == $end_time) 134 $query .= ' AND program.starttime = FROM_UNIXTIME('.$db->escape($start_time).')'; 135 // We're looking at a time range 136 else 137 $query .= ' AND (program.endtime > FROM_UNIXTIME(' .$db->escape($start_time).')' 138 .' AND program.starttime < FROM_UNIXTIME('.$db->escape($end_time) .')' 139 .' AND program.starttime != program.endtime)'; 140 // The extra query, if there is one 141 if ($extra_query) 142 $query .= ' AND '.$extra_query; 143 // Group and sort 144 // FIXME reenable with e.g. ANY_VALUE or rewrite to use the Service API 145 // if (!$distinctTitle) 146 // $query .= "\nGROUP BY channel.callsign, program.chanid, program.starttime"; 147 // else 148 // $query .= "\nGROUP BY program.title"; 149 $query .= " ORDER BY program.starttime"; 150 // Limit 151 if ($single_program) 152 $query .= "\n LIMIT 1"; 153 // Query 154 $sh = $db->query($query); 155 // No results 156 if ($sh->num_rows() < 1) { 157 $sh->finish(); 158 return array(); 159 } 160 // Build two separate queries for optimized selecting of recstatus 161 $sh2 = $db->prepare('SELECT recstatus 162 FROM oldrecorded 163 WHERE recstatus IN (-3, 11) 164 AND programid = ? 165 AND seriesid = ? 166 AND future = 0 167 LIMIT 1'); 168 $sh3 = $db->prepare('SELECT recstatus 169 FROM oldrecorded 170 WHERE recstatus IN (-3, 11) 171 AND title = ? 172 AND subtitle = ? 173 AND description = ? 174 AND future = 0 175 LIMIT 1'); 176 // Load in all of the programs (if any?) 177 $these_programs = array(); 178 $scheduledRecordings = Schedule::findScheduled(); 179 while ($data = $sh->fetch_assoc()) { 180 if (!$data['chanid']) 181 continue; 182 // This program has already been loaded, and is attached to a recording schedule 183 if (!empty($data['title']) && $scheduledRecordings[$data['callsign']][$data['starttime_unix']][0]->title == $data['title']) { 184 $program =& $scheduledRecordings[$data['callsign']][$data['starttime_unix']][0]; 185 // merge in data fetched from DB 186 $program->merge(new Program($data)); 187 } 188 // Otherwise, create a new instance of the program 189 else { 190 // Load the recstatus now that we can use an index 191 if ($data['programid'] && $data['seriesid']) { 192 $sh2->execute($data['programid'], $data['seriesid']); 193 list($data['recstatus']) = $sh2->fetch_row(); 194 } 195 elseif ($data['category_type'] == 'movie' || ($data['title'] && $data['subtitle'] && $data['description'])) { 196 $sh3->execute($data['title'], $data['subtitle'], $data['description']); 197 list($data['recstatus']) = $sh3->fetch_row(); 198 } 199 // Create a new instance 200 $program =& Program::find($data); 201 } 202 // Add this program to the channel hash, etc. 203 $these_programs[] =& $program; 204 $channel_hash[$data['chanid']] = new stdClass(); 205 $channel_hash[$data['chanid']]->programs[] =& $program; 206 // Cleanup 207 unset($program); 208 } 209 // Cleanup 210 $sh3->finish(); 211 $sh2->finish(); 212 $sh->finish(); 213 // If channel-specific information was requested, return an array of those programs, or just the first/only one 214 if ($chanid && $single_program) 215 return $these_programs[0]; 216 // Just in case, return an array of all programs found 217 return $these_programs; 218 } 219