├── 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 = '/
(.+)<\/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 |
--------------------------------------------------------------------------------