1<?php
2
3class TheTVDBBridge extends BridgeAbstract {
4
5	const MAINTAINER = 'Astyan';
6	const NAME = 'TheTVDB';
7	const URI = 'http://thetvdb.com/';
8	const APIURI = 'https://api.thetvdb.com/';
9	const CACHE_TIMEOUT = 43200; // 12h
10	const DESCRIPTION = 'Returns latest episodes of a serie with theTVDB api. You can contribute to theTVDB.';
11	const PARAMETERS = array(
12		array(
13			'serie_id' => array(
14				'type' => 'number',
15				'name' => 'ID',
16				'required' => true,
17			),
18			'nb_episode' => array(
19				'type' => 'number',
20				'name' => 'Number of episodes',
21				'defaultValue' => 10,
22				'required' => true,
23			),
24		)
25	);
26	const APIACCOUNT = 'RSSBridge';
27	const APIKEY = '76DE1887EA401C9A';
28	const APIUSERKEY = 'B52869AC6005330F';
29
30	private function getApiUri(){
31		return self::APIURI;
32	}
33
34	private function getToken(){
35		//login and get token, don't use curlJob to do less adaptations
36		$login_array = array(
37			'apikey' => self::APIKEY,
38			'username' => self::APIACCOUNT,
39			'userkey' => self::APIUSERKEY
40		);
41
42		$login_json = json_encode($login_array);
43		$ch = curl_init($this->getApiUri() . 'login');
44		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
45		curl_setopt($ch, CURLOPT_POSTFIELDS, $login_json);
46		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
47		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
48				'Content-Type: application/json',
49				'Accept: application/json'
50			)
51		);
52
53		curl_setopt($ch, CURLOPT_TIMEOUT, 5);
54		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
55		$result = curl_exec($ch);
56		curl_close($ch);
57		$token_json = (array)json_decode($result);
58		if(isset($token_json['Error'])) {
59			throw new Exception($token_json['Error']);
60			die;
61		}
62		$token = $token_json['token'];
63		return $token;
64	}
65
66	private function curlJob($token, $url){
67		$token_header = 'Authorization: Bearer ' . $token;
68		$ch = curl_init($url);
69		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
70		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
71		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
72				'Accept: application/json',
73				$token_header
74			)
75		);
76		curl_setopt($ch, CURLOPT_TIMEOUT, 5);
77		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
78		$result = curl_exec($ch);
79		curl_close($ch);
80		$result_array = (array)json_decode($result);
81		if(isset($result_array['Error'])) {
82			throw new Exception($result_array['Error']);
83			die;
84		}
85		return $result_array;
86	}
87
88	private function getLatestSeasonNumber($token, $serie_id){
89		// get the last season
90		$url = $this->getApiUri() . 'series/' . $serie_id . '/episodes/summary';
91		$summary = $this->curlJob($token, $url);
92		return max($summary['data']->airedSeasons);
93	}
94
95	private function getSerieName($token, $serie_id){
96		$url = $this->getApiUri() . 'series/' . $serie_id;
97		$serie = $this->curlJob($token, $url);
98		return $serie['data']->seriesName;
99	}
100
101	private function getSeasonEpisodes($token,
102	$serie_id,
103	$season,
104	$seriename,
105	&$episodelist,
106	$nbepisodemin,
107	$page = 1){
108		$url = $this->getApiUri()
109		. 'series/'
110		. $serie_id
111		. '/episodes/query?airedSeason='
112		. $season
113		. '?page='
114		. $page;
115
116		$episodes = $this->curlJob($token, $url);
117		// we don't check the number of page because we assume there is less
118		//than 100 episodes in every season
119		$episodes = (array)$episodes['data'];
120		$episodes = array_slice($episodes, -$nbepisodemin, $nbepisodemin);
121		foreach($episodes as $episode) {
122			$episodedata = array();
123			$episodedata['uri'] = $this->getURI()
124			. '?tab=episode&seriesid='
125			. $serie_id
126			. '&seasonid='
127			. $episode->airedSeasonID
128			. '&id='
129			. $episode->id;
130
131			// check if the absoluteNumber exist
132			if(isset($episode->absoluteNumber)) {
133				$episodedata['title'] = 'S'
134				. $episode->airedSeason
135				. 'E'
136				. $episode->airedEpisodeNumber
137				. '('
138				. $episode->absoluteNumber
139				. ') : '
140				. $episode->episodeName;
141			} else {
142				$episodedata['title'] = 'S'
143				. $episode->airedSeason
144				. 'E'
145				. $episode->airedEpisodeNumber
146				. ' : '
147				. $episode->episodeName;
148			}
149			$episodedata['author'] = $seriename;
150			$date = DateTime::createFromFormat(
151				'Y-m-d H:i:s',
152				$episode->firstAired . ' 00:00:00'
153			);
154
155			$episodedata['timestamp'] = $date->getTimestamp();
156			$episodedata['content'] = $episode->overview;
157			$episodelist[] = $episodedata;
158		}
159	}
160
161	public function getIcon() {
162		return self::URI . 'application/themes/thetvdb/images/logo.png';
163	}
164
165	public function collectData(){
166		$serie_id = $this->getInput('serie_id');
167		$nbepisode = $this->getInput('nb_episode');
168		$episodelist = array();
169		$token = $this->getToken();
170		$maxseason = $this->getLatestSeasonNumber($token, $serie_id);
171		$seriename = $this->getSerieName($token, $serie_id);
172		$season = $maxseason;
173		while(sizeof($episodelist) < $nbepisode && $season >= 1) {
174			$nbepisodetmp = $nbepisode - sizeof($episodelist);
175			$this->getSeasonEpisodes(
176				$token,
177				$serie_id,
178				$season,
179				$seriename,
180				$episodelist,
181				$nbepisodetmp
182			);
183
184			$season = $season - 1;
185		}
186		// add the 10 last specials episodes
187		try { // catch to avoid error if empty
188			$this->getSeasonEpisodes(
189				$token,
190				$serie_id,
191				0,
192				$seriename,
193				$episodelist,
194				$nbepisode
195			);
196		} catch(Exception $e) {
197			unset($e);
198		}
199		// sort and keep the 10 last episodes, works bad with the netflix serie
200		// (all episode lauch at once)
201		usort(
202			$episodelist,
203			function ($a, $b){
204				return $a['timestamp'] < $b['timestamp'];
205			}
206		);
207		$this->items = array_slice($episodelist, 0, $nbepisode);
208	}
209}
210