├── README.md ├── LICENSE └── lib └── EpGuidesAPI ├── Episode.php └── Show.php /README.md: -------------------------------------------------------------------------------- 1 | epguides-api 2 | ============ 3 | 4 | PHP API for epguides.com 5 | 6 | Partially based on Python version by Fredrik Carlsen: https://github.com/frecar/epguides-api 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Andrey Rudenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /lib/EpGuidesAPI/Episode.php: -------------------------------------------------------------------------------- 1 | raw_data = $episode_data; 21 | $this->show = $show; 22 | 23 | $this->title = $episode_data['title']; 24 | $this->is_special = (strtolower($episode_data['special']) == 'y') ? true : false; 25 | if ($this->is_special) { 26 | $this->season = null; 27 | $this->episode = null; 28 | $this->number = null; 29 | } else { 30 | $this->season = (is_numeric($episode_data['season'])) ? intval($episode_data['season']) : null; 31 | $this->episode = (is_numeric($episode_data['episode'])) ? intval($episode_data['episode']) : null; 32 | $this->number = (is_numeric($episode_data['number'])) ? intval($episode_data['number']) : null; 33 | } 34 | 35 | // CST timezone. 36 | $timezone = new \DateTimeZone('Canada/Saskatchewan'); 37 | $date = \DateTime::createFromFormat('d/M/y H:i:s', $episode_data['airdate'] . ' 12:00:00', $timezone); 38 | $this->release_date = $date->getTimestamp(); 39 | unset($date); 40 | unset($timezone); 41 | } 42 | 43 | public function getShow() { 44 | return $this->show; 45 | } 46 | 47 | public function getTitle() { 48 | return $this->title; 49 | } 50 | 51 | public function isSpecial() { 52 | return $this->is_special; 53 | } 54 | 55 | public function getSeason() { 56 | return $this->season; 57 | } 58 | 59 | public function getEpisode() { 60 | if ($this->is_special) { 61 | return false; 62 | } 63 | return $this->episode; 64 | } 65 | 66 | public function getNumber() { 67 | if ($this->is_special) { 68 | return false; 69 | } 70 | return $this->number; 71 | } 72 | 73 | public function getReleaseDate() { 74 | return $this->release_date; 75 | } 76 | 77 | public function getNextEpisode() { 78 | $episodes = $this->show->getEpisodes(); 79 | $next_episode = null; 80 | $found = false; 81 | foreach ($episodes as $episode) { 82 | if ($found) { 83 | $next_episode = $episode; 84 | break; 85 | } 86 | if ($episode === $this) { 87 | $found = true; 88 | continue; 89 | } 90 | } 91 | unset($found); 92 | unset($episodes); 93 | 94 | if ($next_episode !== null) { 95 | return $next_episode; 96 | } 97 | 98 | return false; 99 | } 100 | 101 | public function getRawData() { 102 | return $this->raw_data; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/EpGuidesAPI/Show.php: -------------------------------------------------------------------------------- 1 | null, 'csv' => null, 'printable' => null); 11 | private $episodes = array(); 12 | private $remove_specials; 13 | private $remove_other; 14 | private $printable_episodes; 15 | 16 | /** 17 | * Constructor 18 | * 19 | * @param string $epguides_name 20 | * Machine name of tv show can be taken from url on epguides.com. 21 | * @param array $options 22 | * Additional options, like: 23 | * - 'remove_specials': Flag which removes Specials from episodes list, default is true. 24 | * - 'remove_other': Flag which removes other stuff from episodes list, default is true. 25 | */ 26 | public function __construct($epguides_name, $options) { 27 | // Merge in defaults. 28 | $options += array( 29 | 'remove_specials' => true, 30 | 'remove_other' => true, 31 | ); 32 | 33 | $this->epguides_name = $epguides_name; 34 | $this->remove_specials = $options['remove_specials']; 35 | $this->remove_other = $options['remove_other']; 36 | $this->parseData(); 37 | } 38 | 39 | private function parseData() { 40 | // Download show information page. 41 | $result = $this->downloadURL("http://epguides.com/$this->epguides_name/"); 42 | $this->raw_data['page'] = $result; 43 | unset($result); 44 | 45 | // Parse Title and IMDB ID. 46 | $subject = $this->raw_data['page']; 47 | $pattern = '/

([\w\s.&:\']*)[\w)(]*<\/a>/'; 48 | preg_match($pattern, $subject, $matches); 49 | unset($subject); 50 | unset($pattern); 51 | if ((!isset($matches[1])) || (!isset($matches[2]))) { 52 | throw new \Exception('Unable to parse title and IMDB ID.'); 53 | } 54 | $this->imdb_id = trim($matches[1]); 55 | $this->title = trim($matches[2]); 56 | unset($matches); 57 | 58 | // Parse EPGuides ID and CSV link. 59 | $subject = $this->raw_data['page']; 60 | $pattern = '/epguides_id = $matches[2]; 69 | unset($matches); 70 | 71 | // Download episodes list. 72 | $result = $this->downloadURL($csv_link); 73 | 74 | // Cleanup CSV. 75 | $subject = $result; 76 | $pattern = '/
(.+)<\/pre>/s';
 77 |     preg_match($pattern, $subject, $matches);
 78 |     unset($subject);
 79 |     unset($pattern);
 80 |     if (!isset($matches[1])) {
 81 |       throw new \Exception('Unable to parse CSV.');
 82 |     }
 83 |     $tmp_csv = trim($matches[1]);
 84 |     unset($result);
 85 |     unset($matches);
 86 | 
 87 |     // Parse CSV data.
 88 |     $tmp_csv = $this->parseCSV($tmp_csv);
 89 |     $this->raw_data['csv'] = $tmp_csv;
 90 |     unset($tmp_csv);
 91 | 
 92 |     // If "Remove other" flag is set, then we have to download printable
 93 |     // version from tvrage.com.
 94 |     if ($this->remove_other) {
 95 |       $this->raw_data['printable'] = $this->downloadURL("http://www.tvrage.com/shows/id-$this->epguides_id/printable");
 96 | 
 97 |       $subject = $this->raw_data['printable'];
 98 |       $pattern = '/>[\d]+ :([\d]{2})x([\d]{2}) - (.*)<\//U';
 99 |       preg_match_all($pattern, $subject, $matches);
100 |       unset($subject);
101 |       unset($pattern);
102 |       if (empty($matches[1])) {
103 |         throw new \Exception('Unable to parse printable version from tvrage.com.');
104 |       }
105 |       $this->printable_episodes = array();
106 |       foreach ($matches[1] as $key => $tmp_item) {
107 |         $season = intval($matches[1][$key]);
108 |         $episode = intval($matches[2][$key]);
109 |         $title = trim($matches[3][$key]);
110 |         $this->printable_episodes[$season][$episode] = $title;
111 |       }
112 |       dump($this->printable_episodes);
113 |       unset($matches);
114 |     }
115 |   }
116 | 
117 |   private function parseCSV($CSVData) {
118 |     $rows = explode("\n", $CSVData);
119 | 
120 |     $headers = array_shift($rows);
121 |     $headers = str_getcsv($headers);
122 |     foreach ($headers as &$header) {
123 |       $header = trim($header, "? \t\n\r\0\x0B");
124 |     }
125 | 
126 |     $parsed_rows = array();
127 |     foreach ($rows as $row) {
128 |       $csv_row = str_getcsv($row);
129 |       $csv_row = array_combine($headers, array_values($csv_row));
130 |       $parsed_rows[] = $csv_row;
131 |       unset($csv_row);
132 |     }
133 |     unset($headers);
134 |     unset($rows);
135 | 
136 |     return $parsed_rows;
137 |   }
138 | 
139 |   private function downloadURL($url) {
140 |     $options = array(
141 |       CURLOPT_URL => $url,
142 |       CURLOPT_HEADER => 0,
143 |       CURLOPT_RETURNTRANSFER => true,
144 |       CURLOPT_TIMEOUT => 4,
145 |       CURLOPT_FOLLOWLOCATION => true,
146 |     );
147 | 
148 |     $ch = curl_init();
149 |     curl_setopt_array($ch, $options);
150 |     $result = curl_exec($ch);
151 |     if(!$result) {
152 |       throw new \Exception('CURL Error: ' . curl_error($ch));
153 |     }
154 |     curl_close($ch);
155 |     return $result;
156 |   }
157 | 
158 |   public function getEpGuidesName() {
159 |     return $this->epguides_name;
160 |   }
161 | 
162 |   public function getEpGuidesID() {
163 |     return $this->epguides_id;
164 |   }
165 | 
166 |   public function getTitle() {
167 |     return $this->title;
168 |   }
169 | 
170 |   public function getRawData() {
171 |     return $this->raw_data;
172 |   }
173 | 
174 |   public function getIMDB() {
175 |     return $this->imdb_id;
176 |   }
177 | 
178 |   /**
179 |    * Get array of episodes sorted by release date.
180 |    *
181 |    * @return Episode[]
182 |    *   Array of Episodes.
183 |    */
184 |   public function getEpisodes() {
185 |     if (!empty($this->episodes)) {
186 |       return $this->episodes;
187 |     }
188 | 
189 |     $episodes = array();
190 |     foreach ($this->raw_data['csv'] as $episode_data) {
191 |       $episode = new Episode($this, $episode_data);
192 | 
193 |       // Remove Specials.
194 |       if ($this->remove_specials && $episode->isSpecial()) {
195 |         unset($episode);
196 |         continue;
197 |       }
198 | 
199 |       // Remove other.
200 |       if ($this->remove_specials && (!isset($this->printable_episodes[$episode->getSeason()][$episode->getEpisode()]))) {
201 |         unset($episode);
202 |         continue;
203 |       }
204 | 
205 |       $episodes[] = $episode;
206 |     }
207 | 
208 |     // Sort episodes by release date.
209 |     uasort($episodes, array($this, 'sorterCallback'));
210 |     $episodes = array_values($episodes);
211 | 
212 |     $this->episodes = $episodes;
213 |     return $episodes;
214 |   }
215 | 
216 |   private function sorterCallback(Episode $ep1, Episode $ep2) {
217 |     if ($ep1->getReleaseDate() == $ep2->getReleaseDate()) {
218 |       if ($ep1->isSpecial() || $ep2->isSpecial()) {
219 |         // If one of episodes is special - do nothing.
220 |         return 0;
221 |       }
222 |       // If time is equal, then compare seasons.
223 |       if ($ep1->getSeason() == $ep2->getSeason()) {
224 |         // If seasons are equal, then compare episodes.
225 |         if ($ep1->getEpisode() == $ep2->getEpisode()) {
226 |           // If episodes are equal - do nothing, since "number" is not based on
227 |           // time, so it's not representative.
228 |           return 0;
229 |         }
230 |         return ($ep1->getEpisode() < $ep2->getEpisode()) ? -1 : 1;
231 |       }
232 |       return ($ep1->getSeason() < $ep2->getSeason()) ? -1 : 1;
233 |     }
234 |     return ($ep1->getReleaseDate() < $ep2->getReleaseDate()) ? -1 : 1;
235 |   }
236 | }
237 | 


--------------------------------------------------------------------------------