mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-09-01 02:38:55 +00:00
Update TVMaze support, it is working now
This commit is contained in:
@@ -11,7 +11,7 @@ At the current version this wrapper supports all of TVMaze's endpoints except fo
|
||||
|
||||
Pre-reqs
|
||||
--------
|
||||
Before attempting to use this wrapper make sure you require 'TVMazeIncludes.php'; at the top of your php file.
|
||||
- Before attempting to use this wrapper make sure you require 'TVMazeIncludes.php'; at the top of your php file.
|
||||
|
||||
Supported Methods
|
||||
-----------------
|
||||
@@ -42,8 +42,5 @@ getCrewCreditsByID -> Return an array of all the positions a particular actor ha
|
||||
Open Source Projects using this
|
||||
-------------------------------
|
||||
nZEDb
|
||||
Website Link: http://www.nzedb.com
|
||||
Website Link: http://www.nzedb.com
|
||||
Github Link: https://github.com/nZEDb/nZEDb
|
||||
|
||||
newznab-tmux
|
||||
Github Link: https://github.com/DariusIII/newznab-tmux
|
||||
|
||||
@@ -21,7 +21,7 @@ class Client {
|
||||
*/
|
||||
public function __construct($options = array())
|
||||
{
|
||||
$this->embed = $options['embed'];
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,13 +32,14 @@ class Client {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function search($show_name){
|
||||
$url = self::APIURL . "/search/shows?q=" . $show_name;
|
||||
function search($show_name)
|
||||
{
|
||||
$url = self::APIURL . "/search/shows?q=" . urlencode($show_name);
|
||||
|
||||
$shows = $this->getFile($url);
|
||||
|
||||
$relevant_shows = array();
|
||||
foreach($shows as $series){
|
||||
foreach($shows as $series) {
|
||||
$TVShow = new TVShow($series['show']);
|
||||
array_push($relevant_shows, $TVShow);
|
||||
}
|
||||
@@ -46,20 +47,20 @@ class Client {
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes in a show name with optional modifiers (episodes)
|
||||
* Outputs array of the MOST related shows for that given name
|
||||
* Takes in a show name with optional modifiers (akas)
|
||||
* Outputs array of the MOST related show for that given name
|
||||
*
|
||||
* @param $show_name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function singleSearch($show_name){
|
||||
|
||||
$url = self::APIURL."/singlesearch/shows?q=".$show_name.'&embed=episodes';
|
||||
function singleSearch($show_name)
|
||||
{
|
||||
$url = self::APIURL . "/singlesearch/shows?q=" . urlencode($show_name) . '&embed=akas';
|
||||
$shows = $this->getFile($url);
|
||||
|
||||
$episode_list = array();
|
||||
foreach($shows['_embedded']['episodes'] as $episode){
|
||||
foreach($shows['_embedded']['episodes'] as $episode) {
|
||||
$ep = new Episode($episode);
|
||||
print_r($episode);
|
||||
array_push($episode_list, $ep);
|
||||
@@ -79,7 +80,8 @@ class Client {
|
||||
*
|
||||
* @return TVShow
|
||||
*/
|
||||
function getShowBySiteID($site, $ID){
|
||||
function getShowBySiteID($site, $ID)
|
||||
{
|
||||
$site = strtolower($site);
|
||||
$url = self::APIURL . '/lookup/shows?' . $site . '=' . $ID;
|
||||
$show = $this->getFile($url);
|
||||
@@ -94,14 +96,15 @@ class Client {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getPersonByName($name){
|
||||
function getPersonByName($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
$url = self::APIURL . '/search/people?q=' . $name;
|
||||
$person = $this->getFile($url);
|
||||
|
||||
$people = array();
|
||||
foreach($person as $peeps){
|
||||
array_push($people, new Actor($peeps['person']));
|
||||
foreach($person as $peeps) {
|
||||
array_push($people, new Actor($peeps['person']));
|
||||
}
|
||||
|
||||
return $people;
|
||||
@@ -115,21 +118,21 @@ class Client {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getSchedule($country=null, $date=null){
|
||||
if($country != null && $date != null){
|
||||
function getSchedule($country=null, $date=null) {
|
||||
if($country != null && $date != null) {
|
||||
$url = self::APIURL . '/schedule?country=' . $country .'&date='. $date;
|
||||
}else if($country == null && $date != null){
|
||||
} else if ($country == null && $date != null) {
|
||||
$url = self::APIURL . '/schedule?date=' . $date;
|
||||
}else if($country != null && $date == null){
|
||||
} else if ($country != null && $date == null) {
|
||||
$url = self::APIURL . '/schedule?country=' . $country;
|
||||
}else{
|
||||
} else {
|
||||
$url = self::APIURL . '/schedule';
|
||||
}
|
||||
|
||||
$schedule = $this->getFile($url);
|
||||
|
||||
$show_list = array();
|
||||
foreach($schedule as $episode){
|
||||
foreach($schedule as $episode) {
|
||||
$ep = new Episode($episode);
|
||||
$show = new TVShow($episode['show']);
|
||||
array_push($show_list, $show, $ep);
|
||||
@@ -146,17 +149,18 @@ class Client {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getShowByShowID($ID, $embed_cast=null){
|
||||
if($embed_cast === true){
|
||||
function getShowByShowID($ID, $embed_cast=null)
|
||||
{
|
||||
if($embed_cast === true) {
|
||||
$url = self::APIURL . '/shows/'. $ID . '?embed=cast';
|
||||
}else{
|
||||
} else {
|
||||
$url = self::APIURL . '/shows/' . $ID;
|
||||
}
|
||||
|
||||
$show = $this->getFile($url);
|
||||
|
||||
$cast = array();
|
||||
foreach($show['_embedded']['cast'] as $person){
|
||||
foreach($show['_embedded']['cast'] as $person) {
|
||||
$actor = new Actor($person['person']);
|
||||
$character = new Character($person['character']);
|
||||
array_push($cast, array($actor, $character));
|
||||
@@ -174,14 +178,15 @@ class Client {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getEpisodesByShowID($ID){
|
||||
function getEpisodesByShowID($ID)
|
||||
{
|
||||
|
||||
$url = self::APIURL . '/shows/' . $ID . '/episodes';
|
||||
|
||||
$episodes = $this->getFile($url);
|
||||
|
||||
$allEpisodes = array();
|
||||
foreach($episodes as $episode){
|
||||
foreach($episodes as $episode) {
|
||||
$ep = new Episode($episode);
|
||||
array_push($allEpisodes, $ep);
|
||||
}
|
||||
@@ -208,6 +213,29 @@ class Client {
|
||||
return $episode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns episodes for a given show ID and ISO 8601 airdate
|
||||
*
|
||||
* @param $ID
|
||||
* @param $season
|
||||
* @param $episode
|
||||
*
|
||||
* @return Episode|mixed
|
||||
*/
|
||||
function getEpisodesByAirdate($ID, $airdate)
|
||||
{
|
||||
$url = self::APIURL . '/shows/' . $ID . '/episodesbydate?date=' . date('Y-m-d', strtotime($airdate));
|
||||
$episodes = $this->getFile($url);
|
||||
|
||||
$allEpisodes = array();
|
||||
foreach($episodes as $episode) {
|
||||
$ep = new Episode($episode);
|
||||
array_push($allEpisodes, $ep);
|
||||
}
|
||||
|
||||
return $allEpisodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes in a show ID and outputs all of the cast members in the form (actor, character)
|
||||
*
|
||||
@@ -215,12 +243,13 @@ class Client {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getCastByShowID($ID){
|
||||
function getCastByShowID($ID)
|
||||
{
|
||||
$url = self::APIURL . '/shows/' . $ID . '/cast';
|
||||
$people = $this->getFile($url);
|
||||
|
||||
$cast = array();
|
||||
foreach($people as $person){
|
||||
foreach($people as $person) {
|
||||
$actor = new Actor($person['person']);
|
||||
$character = new Character($person['character']);
|
||||
array_push($cast, array($actor, $character));
|
||||
@@ -236,7 +265,8 @@ class Client {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getAllShowsByPage($page=null){
|
||||
function getAllShowsByPage($page=null)
|
||||
{
|
||||
if($page == null){
|
||||
$url = self::APIURL . '/shows';
|
||||
}else{
|
||||
@@ -260,7 +290,8 @@ class Client {
|
||||
*
|
||||
* @return Actor
|
||||
*/
|
||||
function getPersonByID($ID){
|
||||
function getPersonByID($ID)
|
||||
{
|
||||
$url = self::APIURL . '/people/' . $ID;
|
||||
$show = $this->getFile($url);
|
||||
return new Actor($show);
|
||||
@@ -273,12 +304,13 @@ class Client {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getCastCreditsByID($ID){
|
||||
function getCastCreditsByID($ID)
|
||||
{
|
||||
$url = self::APIURL . '/people/' . $ID . '/castcredits?embed=show';
|
||||
$castCredit = $this->getFile($url);
|
||||
|
||||
$shows_appeared = array();
|
||||
foreach($castCredit as $series){
|
||||
foreach($castCredit as $series) {
|
||||
$TVShow = new TVShow($series['_embedded']['show']);
|
||||
array_push($shows_appeared, $TVShow);
|
||||
}
|
||||
@@ -292,12 +324,13 @@ class Client {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getCrewCreditsByID($ID){
|
||||
function getCrewCreditsByID($ID)
|
||||
{
|
||||
$url = self::APIURL . '/people/' . $ID . '/crewcredits?embed=show';
|
||||
$crewCredit = $this->getFile($url);
|
||||
|
||||
$shows_appeared = array();
|
||||
foreach($crewCredit as $series){
|
||||
foreach($crewCredit as $series) {
|
||||
$position = $series['type'];
|
||||
$TVShow = new TVShow($series['_embedded']['show']);
|
||||
array_push($shows_appeared, array($position, $TVShow));
|
||||
@@ -312,9 +345,17 @@ class Client {
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getFile($url){
|
||||
$json = file_get_contents($url);
|
||||
$response = json_decode($json, TRUE);
|
||||
private function getFile($url)
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
$result = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$response = json_decode($result, TRUE);
|
||||
|
||||
if ($response) {
|
||||
return $response;
|
||||
@@ -322,7 +363,6 @@ class Client {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
@@ -9,10 +9,11 @@
|
||||
namespace libs\JPinkney\TVMaze;
|
||||
|
||||
//Check back here if we can move the episode data to the episode class later
|
||||
|
||||
/**
|
||||
* Class TVShow
|
||||
*
|
||||
* @package JPinkney\TVMaze
|
||||
* @package libs\JPinkney\TVMaze
|
||||
*/
|
||||
class TVShow extends TVProduction{
|
||||
|
||||
@@ -81,6 +82,11 @@ class TVShow extends TVProduction{
|
||||
*/
|
||||
public $airDay;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $country;
|
||||
|
||||
/**
|
||||
* @param $show_data
|
||||
*/
|
||||
@@ -96,9 +102,11 @@ class TVShow extends TVProduction{
|
||||
$this->weight = $show_data['weight'];
|
||||
$this->network_array = $show_data['network'];
|
||||
$this->network = $show_data['network']['name'];
|
||||
$this->country = $show_data['network']['country']['code'];
|
||||
$this->webChannel = $show_data['webChannel'];
|
||||
$this->externalIDs = $show_data['externals'];
|
||||
$this->summary = strip_tags($show_data['summary']);
|
||||
$this->akas = (isset($show_data['_embedded']['akas']) ? $show_data['_embedded']['akas'] : null);
|
||||
|
||||
$current_date = date("Y-m-d");
|
||||
foreach($show_data['_embedded']['episodes'] as $episode){
|
||||
@@ -120,7 +128,8 @@ class TVShow extends TVProduction{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function isEmpty(){
|
||||
function isEmpty()
|
||||
{
|
||||
return($this->id == null || $this->id == 0 && $this->url == null && $this->name == null);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ class Releases
|
||||
WHERE r.nzbstatus = %d
|
||||
AND r.passwordstatus %s
|
||||
%s %s %s %s',
|
||||
($groupName != '' ? 'INNER JOIN groups g ON g.id = r.groupid' : ''),
|
||||
($groupName != '' ? 'LEFT JOIN groups g ON g.id = r.groupid' : ''),
|
||||
NZB::NZB_ADDED,
|
||||
$this->showPasswords,
|
||||
($groupName != '' ? sprintf(' AND g.name = %s', $this->pdo->escapeString($groupName)) : ''),
|
||||
@@ -214,7 +214,7 @@ class Releases
|
||||
(
|
||||
SELECT r.*, g.name AS group_name
|
||||
FROM releases r
|
||||
INNER JOIN groups g ON g.id = r.groupid
|
||||
LEFT JOIN groups g ON g.id = r.groupid
|
||||
WHERE r.nzbstatus = %d
|
||||
AND r.passwordstatus %s
|
||||
%s %s %s %s
|
||||
@@ -1209,7 +1209,7 @@ class Releases
|
||||
CONCAT(cp.title, ' > ', c.title) AS category_name,
|
||||
CONCAT(cp.id, ',', c.id) AS category_ids,
|
||||
g.name AS group_name,
|
||||
v.title AS showtitle, v.tvdb, v.trakt, v.tvrage, v.source,
|
||||
v.title AS showtitle, v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.source,
|
||||
tvi.summary, tvi.image,
|
||||
tve.title, tve.firstaired, tve.se_complete
|
||||
FROM releases r
|
||||
@@ -1570,7 +1570,7 @@ class Releases
|
||||
return $this->pdo->query(
|
||||
"SELECT r.videos_id, r.guid, r.name, r.searchname, r.size, r.completion,
|
||||
r.postdate, r.categoryid, r.comments, r.grabs,
|
||||
v.id AS tvid, v.title AS tvtitle, v.tvdb, v.tvrage,
|
||||
v.id AS tvid, v.title AS tvtitle, v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.imdb, v.tmdb,
|
||||
tvi.image
|
||||
FROM releases r
|
||||
INNER JOIN videos v ON r.videos_id = v.id
|
||||
|
||||
@@ -14,6 +14,7 @@ use newznab\Nfo;
|
||||
use newznab\Sharing;
|
||||
//use newznab\processing\tv\TvRage;
|
||||
use newznab\processing\tv\TVDB;
|
||||
use newznab\processing\tv\TVMaze;
|
||||
use newznab\XXX;
|
||||
use newznab\ReleaseFiles;
|
||||
use newznab\db\Settings;
|
||||
@@ -260,6 +261,7 @@ class PostProcess
|
||||
if ($processTV > 0) {
|
||||
(new TVDB(['Echo' => $this->echooutput, 'Settings' => $this->pdo]))->processTVDB($groupID, $guidChar, $processTV);
|
||||
//(new TvRage(['Echo' => $this->echooutput, 'Settings' => $this->pdo]))->processTvRage($groupID, $guidChar, $processTV);
|
||||
(new TVMaze(['Echo' => $this->echooutput, 'Settings' => $this->pdo]))->processTVMaze($groupID, $guidChar, $processTV);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,12 @@ abstract class TV extends Videos
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $rageqty;
|
||||
public $tvqty;
|
||||
|
||||
/**
|
||||
* @string Path to Save Images
|
||||
*/
|
||||
public $imgSavePath;
|
||||
|
||||
/**
|
||||
* @param array $options Class instances / Echo to CLI.
|
||||
@@ -55,6 +60,7 @@ abstract class TV extends Videos
|
||||
$this->echooutput = ($options['Echo'] && NN_ECHOCLI);
|
||||
$this->catWhere = 'categoryid BETWEEN 5000 AND 5999 AND categoryid NOT IN (5070)';
|
||||
$this->tvqty = ($this->pdo->getSetting('maxrageprocessed') != '') ? $this->pdo->getSetting('maxrageprocessed') : 75;
|
||||
$this->imgSavePath = NN_COVERS . 'tvshows' . DS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,7 +197,7 @@ abstract class TV extends Videos
|
||||
*/
|
||||
public function add($showArr = array())
|
||||
{
|
||||
if ($showArr['country'] !== '') {
|
||||
if ($showArr['country'] !== '' && strlen($showArr['country']) > 2) {
|
||||
$showArr['country'] = $this->countryCode($showArr['country']);
|
||||
}
|
||||
|
||||
@@ -534,8 +540,7 @@ abstract class TV extends Videos
|
||||
sprintf('
|
||||
SELECT id
|
||||
FROM countries
|
||||
WHERE country = %s
|
||||
OR iso3 = %1\$s',
|
||||
WHERE country = %1\$s',
|
||||
$this->pdo->escapeString($country)
|
||||
)
|
||||
);
|
||||
@@ -859,4 +864,42 @@ abstract class TV extends Videos
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks API response returns have all REQUIRED attributes set
|
||||
* Returns true or false
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function checkRequired($array = array(), $type)
|
||||
{
|
||||
$required = ['failedToMatchType'];
|
||||
|
||||
switch ($type) {
|
||||
case 'tvdbS':
|
||||
$required = ['id', 'name', 'overview', 'firstAired'];
|
||||
break;
|
||||
case 'tvdbE':
|
||||
$required = ['name', 'season', 'number', 'firstAired', 'overview'];
|
||||
break;
|
||||
case 'tvmazeS':
|
||||
$required = ['id', 'name', 'summary', 'premiered', 'country'];
|
||||
break;
|
||||
case 'tvmazeE':
|
||||
$required = ['name', 'season', 'number', 'airdate', 'summary'];
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_array($required)) {
|
||||
foreach ($required as $req) {
|
||||
if (!isset($array->$req)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,6 @@ class TVDB extends TV
|
||||
*/
|
||||
public $fanartUrl;
|
||||
|
||||
/**
|
||||
* @string Path to Save Images
|
||||
*/
|
||||
public $imgSavePath;
|
||||
|
||||
/**
|
||||
* @string The Timestamp of the TVDB Server
|
||||
*/
|
||||
@@ -57,7 +52,6 @@ class TVDB extends TV
|
||||
$this->client = new Client(self::TVDB_URL, self::TVDB_API_KEY);
|
||||
$this->posterUrl = self::TVDB_URL . DS . 'banners/_cache/posters/%s-1.jpg';
|
||||
$this->fanartUrl = self::TVDB_URL . DS . 'banners/_cache/fanart/original/%s-1.jpg';
|
||||
$this->imgSavePath = NN_COVERS . 'tvshows' . DS;
|
||||
|
||||
$this->serverTime = $this->client->getServerTime();
|
||||
$this->timeZone = new \DateTimeZone('UTC');
|
||||
@@ -73,7 +67,7 @@ class TVDB extends TV
|
||||
* @param $processTV
|
||||
* @param bool|false $local
|
||||
*/
|
||||
public function processTVDB ($groupID, $guidChar, $processTV, $local = false)
|
||||
public function processTVDB($groupID, $guidChar, $processTV, $local = false)
|
||||
{
|
||||
$res = $this->getTvReleases($groupID, $guidChar, $processTV, parent::PROCESS_TVDB);
|
||||
|
||||
@@ -110,16 +104,16 @@ class TVDB extends TV
|
||||
|
||||
// If it doesnt exist locally and lookups are allowed lets try to get it.
|
||||
if ($this->echooutput) {
|
||||
echo $this->pdo->log->primaryOver("Video ID for ") .
|
||||
$this->pdo->log->headerOver($release['cleanname']) .
|
||||
$this->pdo->log->primary(" not found in local db, checking web.");
|
||||
echo $this->pdo->log->primaryOver("Video ID for ") .
|
||||
$this->pdo->log->headerOver($release['cleanname']) .
|
||||
$this->pdo->log->primary(" not found in local db, checking web.");
|
||||
}
|
||||
|
||||
// Get the show from TVDB
|
||||
$tvdbShow = $this->getShowInfo((string)$release['cleanname']);
|
||||
|
||||
if (is_array($tvdbShow)) {
|
||||
$tvdbShow['country'] = (isset($release['country']) && strlen($release['country']) == 2
|
||||
$tvdbShow['country'] = (isset($release['country']) && $release['country'] !== 2
|
||||
? (string)$release['country']
|
||||
: ''
|
||||
);
|
||||
@@ -127,9 +121,9 @@ class TVDB extends TV
|
||||
$tvdbid = (int)$tvdbShow['tvdbid'];
|
||||
}
|
||||
} else if ($this->echooutput) {
|
||||
echo $this->pdo->log->primaryOver("Video ID for ") .
|
||||
$this->pdo->log->headerOver($release['cleanname']) .
|
||||
$this->pdo->log->primary(" found in local db, attempting episode match.");
|
||||
echo $this->pdo->log->primaryOver("Video ID for ") .
|
||||
$this->pdo->log->headerOver($release['cleanname']) .
|
||||
$this->pdo->log->primary(" found in local db, attempting episode match.");
|
||||
}
|
||||
|
||||
if (is_numeric($videoId) && $videoId > 0 && is_numeric($tvdbid) && $tvdbid > 0) {
|
||||
@@ -210,13 +204,14 @@ class TVDB extends TV
|
||||
$highestMatch = 0;
|
||||
try {
|
||||
$response = (array)$this->client->getSeries($cleanName, 'en');
|
||||
} catch (\Exception $error) { }
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
if (is_array($response)) {
|
||||
foreach ($response as $show) {
|
||||
if ($this->checkRequired($show, 1)) {
|
||||
if ($this->checkRequired($show, 'tvdbS')) {
|
||||
// Check for exact title match first and then terminate if found
|
||||
if ($show->name === $cleanName) {
|
||||
$highest = $show;
|
||||
@@ -248,6 +243,7 @@ class TVDB extends TV
|
||||
$return = $this->formatShowArr($highest);
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -255,7 +251,7 @@ class TVDB extends TV
|
||||
* Retrieves the poster art for the processed show
|
||||
*
|
||||
* @param int $videoId -- the local Video ID
|
||||
* @param int $showId -- the TVDB ID
|
||||
* @param int $showId -- the TVDB ID
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
@@ -280,11 +276,11 @@ class TVDB extends TV
|
||||
* Gets the specific episode info for the parsed release after match
|
||||
* Returns a formatted array of episode data or false if no match
|
||||
*
|
||||
* @param integer $tvdbid
|
||||
* @param integer $season
|
||||
* @param integer $episode
|
||||
* @param string $airdate
|
||||
* @param integer $videoId
|
||||
* @param integer $tvdbid
|
||||
* @param integer $season
|
||||
* @param integer $episode
|
||||
* @param string $airdate
|
||||
* @param integer $videoId
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
@@ -312,16 +308,17 @@ class TVDB extends TV
|
||||
sleep(1);
|
||||
|
||||
if (is_object($response)) {
|
||||
if ($this->checkRequired($response, 2)) {
|
||||
if ($this->checkRequired($response, 'tvdbE')) {
|
||||
$return = $this->formatEpisodeArr($response);
|
||||
}
|
||||
} else if (is_array($response) && isset($response['episodes']) && $videoId > 0) {
|
||||
foreach($response['episodes'] as $singleEpisode) {
|
||||
if ($this->checkRequired($singleEpisode, 2)) {
|
||||
foreach ($response['episodes'] as $singleEpisode) {
|
||||
if ($this->checkRequired($singleEpisode, 'tvdbE')) {
|
||||
$this->addEpisode($videoId, $this->formatEpisodeArr($singleEpisode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -338,7 +335,7 @@ class TVDB extends TV
|
||||
$show->firstAired->setTimezone($this->timeZone);
|
||||
preg_match('/tt(?P<imdbid>\d{6,7})$/i', $show->imdbId, $imdb);
|
||||
|
||||
return [
|
||||
return [
|
||||
'tvdbid' => (int)$show->id,
|
||||
'column' => 'tvdb',
|
||||
'siteid' => (int)$show->id,
|
||||
@@ -348,10 +345,10 @@ class TVDB extends TV
|
||||
'publisher' => (string)$show->network,
|
||||
'source' => (int)parent::SOURCE_TVDB,
|
||||
'imdbid' => (int)(isset($imdb['imdbid']) ? $imdb['imdbid'] : 0),
|
||||
'traktid' => 0,
|
||||
'tvrageid' => 0,
|
||||
'tvmazeid' => 0,
|
||||
'tmdbid' => 0
|
||||
'traktid' => 0,
|
||||
'tvrageid' => 0,
|
||||
'tvmazeid' => 0,
|
||||
'tmdbid' => 0
|
||||
];
|
||||
}
|
||||
|
||||
@@ -376,36 +373,4 @@ class TVDB extends TV
|
||||
'summary' => (string)$episode->overview
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks API response returns have all REQUIRED attributes set
|
||||
* Returns true or false
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function checkRequired($array = array(), $type)
|
||||
{
|
||||
$required = false;
|
||||
|
||||
switch ($type) {
|
||||
case 1:
|
||||
$required = ['id', 'name', 'overview', 'firstAired'];
|
||||
break;
|
||||
case 2:
|
||||
$required = ['name', 'season', 'number', 'firstAired', 'overview'];
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_array($required)) {
|
||||
foreach ($required as $req) {
|
||||
if (!isset($array->$req)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace newznab\processing\tv;
|
||||
|
||||
use \libs\JPinkney\TVMaze\Client;
|
||||
use newznab\ReleaseImage;
|
||||
|
||||
/**
|
||||
* Class TVMaze
|
||||
@@ -9,6 +11,8 @@ use \libs\JPinkney\TVMaze\Client;
|
||||
*/
|
||||
class TVMaze extends TV
|
||||
{
|
||||
const MATCH_PROBABILITY = 75;
|
||||
|
||||
/**
|
||||
* Client for TVMaze API
|
||||
*
|
||||
@@ -16,6 +20,11 @@ class TVMaze extends TV
|
||||
*/
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* @var string The URL for the medium sized image for poster
|
||||
*/
|
||||
private $posterUrl;
|
||||
|
||||
/**
|
||||
* Construct. Instanciate TVMaze Client Class
|
||||
*
|
||||
@@ -43,41 +52,335 @@ class TVMaze extends TV
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve info of TV episode from site using its API.
|
||||
* Main processing director function for TVMaze
|
||||
* Calls work query function and initiates processing
|
||||
*
|
||||
* @param integer $siteId
|
||||
* @param integer $series
|
||||
* @param integer $episode
|
||||
*
|
||||
* @return array|false False on failure, an array of information fields otherwise.
|
||||
* @param $groupID
|
||||
* @param $guidChar
|
||||
* @param $processTV
|
||||
* @param bool|false $local
|
||||
*/
|
||||
public function getEpisodeInfo($siteId, $series, $episode)
|
||||
public function processTVMaze ($groupID, $guidChar, $processTV, $local = false)
|
||||
{
|
||||
return false;
|
||||
$res = $this->getTvReleases($groupID, $guidChar, $processTV, parent::PROCESS_TVMAZE);
|
||||
|
||||
$tvcount = $res->rowCount();
|
||||
|
||||
if ($this->echooutput && $tvcount > 1) {
|
||||
echo $this->pdo->log->header("Processing TVMaze lookup for " . number_format($tvcount) . " release(s).");
|
||||
}
|
||||
|
||||
if ($res instanceof \Traversable) {
|
||||
foreach ($res as $row) {
|
||||
|
||||
$tvmazeid = false;
|
||||
$this->posterUrl = '';
|
||||
|
||||
// Clean the show name for better match probability
|
||||
$release = $this->parseNameEpSeason($row['searchname']);
|
||||
if (is_array($release) && $release['name'] != '') {
|
||||
|
||||
// Find the Video ID if it already exists by checking the title.
|
||||
$videoId = $this->getByTitle($release['cleanname']);
|
||||
|
||||
if ($videoId !== false) {
|
||||
$tvmazeid = $this->getSiteByID('tvmaze', $videoId);
|
||||
}
|
||||
|
||||
// Force local lookup only
|
||||
if ($local == true) {
|
||||
$lookupSetting = false;
|
||||
} else {
|
||||
$lookupSetting = true;
|
||||
}
|
||||
|
||||
if ($tvmazeid === false && $lookupSetting) {
|
||||
|
||||
// If it doesnt exist locally and lookups are allowed lets try to get it.
|
||||
if ($this->echooutput) {
|
||||
echo $this->pdo->log->primaryOver("Video ID for ") .
|
||||
$this->pdo->log->headerOver($release['cleanname']) .
|
||||
$this->pdo->log->primary(" not found in local db, checking web.");
|
||||
}
|
||||
|
||||
// Get the show from TVDB
|
||||
$tvmazeShow = $this->getShowInfo((string)$release['cleanname']);
|
||||
|
||||
if (is_array($tvmazeShow)) {
|
||||
$videoId = $this->add($tvmazeShow);
|
||||
$tvmazeid = (int)$tvmazeShow['tvmazeid'];
|
||||
}
|
||||
} else if ($this->echooutput) {
|
||||
echo $this->pdo->log->primaryOver("Video ID for ") .
|
||||
$this->pdo->log->headerOver($release['cleanname']) .
|
||||
$this->pdo->log->primary(" found in local db, attempting episode match.");
|
||||
}
|
||||
|
||||
if (is_numeric($videoId) && $videoId > 0 && is_numeric($tvmazeid) && $tvmazeid > 0) {
|
||||
// Now that we have valid video and tvmaze ids, try to get the poster
|
||||
$this->getPoster($videoId, $tvmazeid);
|
||||
|
||||
$seasonNo = preg_replace('/^S0*/i', '', $release['season']);
|
||||
$episodeNo = preg_replace('/^E0*/i', '', $release['episode']);
|
||||
|
||||
if ($episodeNo === 'all') {
|
||||
// Set the video ID and leave episode 0
|
||||
$this->setVideoIdFound($videoId, $row['id'], 0);
|
||||
echo $this->pdo->log->primary("Found TVDB Match for Full Season!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Download all episodes if new show to reduce API/bandwidth usage
|
||||
if ($this->countEpsByVideoID($videoId) === false) {
|
||||
$this->getEpisodeInfo($tvmazeid, -1, -1, '', $videoId);
|
||||
}
|
||||
|
||||
// Check if we have the episode for this video ID
|
||||
$episode = $this->getBySeasonEp($videoId, $seasonNo, $episodeNo, $release['airdate']);
|
||||
|
||||
if ($episode === false && $lookupSetting) {
|
||||
// Send the request for the episode to TVDB
|
||||
$tvmazeEpisode = $this->getEpisodeInfo(
|
||||
$tvmazeid,
|
||||
$seasonNo,
|
||||
$episodeNo,
|
||||
$release['airdate']
|
||||
);
|
||||
|
||||
if ($tvmazeEpisode) {
|
||||
$episode = $this->addEpisode($videoId, $tvmazeEpisode);
|
||||
}
|
||||
}
|
||||
|
||||
if ($episode !== false && is_numeric($episode) && $episode > 0) {
|
||||
// Mark the releases video and episode IDs
|
||||
$this->setVideoIdFound($videoId, $row['id'], $episode);
|
||||
if ($this->echooutput) {
|
||||
echo $this->pdo->log->primary("Found TVMaze Match!");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} //Processing failed, set the episode ID to the next processing group
|
||||
$this->setVideoNotFound(parent::PROCESS_IMDB, $row['id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Calls the API to perform initial show name match to TVDB title
|
||||
* Returns a formatted array of show data or false if no match
|
||||
*
|
||||
* @param $cleanName
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
protected function getShowInfo($cleanName)
|
||||
{
|
||||
$return = $response = false;
|
||||
|
||||
try {
|
||||
//Try for the best match with AKAs embedded
|
||||
$response = $this->client->singleSearch($cleanName);
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
if (is_array($response)) {
|
||||
$return = $this->processResponse($response, $cleanName);
|
||||
}
|
||||
if ($return === false) {
|
||||
try {
|
||||
//Try for the best match via full search (no AKAs can be returned)
|
||||
$response = $this->client->search($cleanName);
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
if (is_array($response)) {
|
||||
foreach ($response as $show) {
|
||||
$return = $this->processResponse($show, $cleanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve poster image for TV episode from site using its API.
|
||||
* @param $show
|
||||
* @param $cleanName
|
||||
*
|
||||
* @param integer $videoId ID from videos table.
|
||||
* @param integer $siteId ID that this site uses for the programme.
|
||||
* @return array|bool
|
||||
*/
|
||||
private function processResponse ($show, $cleanName)
|
||||
{
|
||||
$return = false;
|
||||
|
||||
if ($this->checkRequired($show, 'tvmazeS')) {
|
||||
// Check for exact title match first and then terminate if found
|
||||
if ($show->name === $cleanName) {
|
||||
$return = $this->formatShowArr($show);
|
||||
} else {
|
||||
$return = $this->matchShowInfo($show, $cleanName);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
private function matchShowInfo($show, $cleanName)
|
||||
{
|
||||
$return = false;
|
||||
$highestMatch = 0;
|
||||
|
||||
// Check each show title for similarity and then find the highest similar value
|
||||
$matchPercent = $this->checkMatch($show->name, $cleanName, self::MATCH_PROBABILITY);
|
||||
|
||||
// If new match has a higher percentage, set as new matched title
|
||||
if ($matchPercent > $highestMatch) {
|
||||
$highestMatch = $matchPercent;
|
||||
$highest = $show;
|
||||
}
|
||||
|
||||
// Check for show aliases and try match those too
|
||||
if (is_array($show->akas) && !empty($show->akas)) {
|
||||
foreach ($show->akas as $key => $name) {
|
||||
$matchPercent = $this->checkMatch($name, $cleanName, $matchPercent);
|
||||
if ($matchPercent > $highestMatch) {
|
||||
$highestMatch = $matchPercent;
|
||||
$highest = $show;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($highest)) {
|
||||
$return = $this->formatShowArr($highest);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the poster art for the processed show
|
||||
*
|
||||
* @param int $videoId -- the local Video ID
|
||||
* @param int $showId -- the TVDB ID
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getPoster($videoId, $siteId)
|
||||
protected function getPoster($videoId, $showId = 0)
|
||||
{
|
||||
return false;
|
||||
$ri = new ReleaseImage($this->pdo);
|
||||
|
||||
// Try to get the Poster
|
||||
$hascover = $ri->saveImage($videoId, sprintf($this->posterUrl), $this->imgSavePath, '', '');
|
||||
|
||||
// Mark it retrieved if we saved an image
|
||||
if ($hascover == 1) {
|
||||
$this->setCoverFound($videoId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve info of TV programme from site using it's API.
|
||||
* Gets the specific episode info for the parsed release after match
|
||||
* Returns a formatted array of episode data or false if no match
|
||||
*
|
||||
* @param string $name Title of programme to look up. Usually a cleaned up version from releases table.
|
||||
* @param integer $tvmazeid
|
||||
* @param integer $season
|
||||
* @param integer $episode
|
||||
* @param string $airdate
|
||||
* @param integer $videoId
|
||||
*
|
||||
* @return array|false False on failure, an array of information fields otherwise.
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getShowInfo($name)
|
||||
protected function getEpisodeInfo($tvmazeid, $season, $episode, $airdate = '', $videoId = 0)
|
||||
{
|
||||
return false;
|
||||
$return = $response = false;
|
||||
|
||||
if ($airdate !== '') {
|
||||
try {
|
||||
$response = $this->client->getEpisodesByAirdate($tvmazeid, $airdate);
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
} else if ($videoId > 0) {
|
||||
try {
|
||||
$response = $this->client->getEpisodesByShowID($tvmazeid);
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$response = $this->client->getEpisodeByNumber($tvmazeid, $season, $episode);
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
//Handle Single Episode Lookups
|
||||
if (is_object($response)) {
|
||||
if ($this->checkRequired($response, 'tvmazeE')) {
|
||||
$return = $this->formatEpisodeArr($response);
|
||||
}
|
||||
} else if (is_array($response)) {
|
||||
//Handle new show/all episodes
|
||||
if ($videoId > 0) {
|
||||
foreach ($response as $singleEpisode) {
|
||||
if ($this->checkRequired($singleEpisode, 'tvmazeE')) {
|
||||
$this->addEpisode($videoId, $this->formatEpisodeArr($singleEpisode));
|
||||
}
|
||||
}
|
||||
//Handle airdate lookups -- return first response
|
||||
} else {
|
||||
if ($this->checkRequired($response[0], 'tvmazeE')) {
|
||||
$return = $this->formatEpisodeArr($response[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns API show response values to a formatted array for insertion
|
||||
* Returns the formatted array
|
||||
*
|
||||
* @param $show
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function formatShowArr($show)
|
||||
{
|
||||
$this->posterUrl = (string)(isset($show->mediumImage) ? $show->mediumImage : '');
|
||||
|
||||
return [
|
||||
'tvmazeid' => (int)$show->id,
|
||||
'column' => 'tvmaze',
|
||||
'siteid' => (int)$show->id,
|
||||
'title' => (string)$show->name,
|
||||
'summary' => (string)$show->summary,
|
||||
'started' => (string)$show->premiered,
|
||||
'publisher' => (string)$show->network,
|
||||
'country' => (string)$show->country,
|
||||
'source' => (int)parent::SOURCE_TVMAZE,
|
||||
'imdbid' => 0,
|
||||
'tvdbid' => (int)(isset($show->externalIDs['thetvdb']) ? $show->externalIDs['thetvdb'] : 0),
|
||||
'traktid' => 0,
|
||||
'tvrageid' => (int)(isset($show->externalIDs['tvrage']) ? $show->externalIDs['tvrage'] : 0),
|
||||
'tmdbid' => 0
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns API episode response values to a formatted array for insertion
|
||||
* Returns the formatted array
|
||||
*
|
||||
* @param $episode
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function formatEpisodeArr($episode)
|
||||
{
|
||||
return [
|
||||
'title' => (string)$episode->name,
|
||||
'series' => (int)$episode->season,
|
||||
'episode' => (int)$episode->number,
|
||||
'se_complete' => (string)'S' . sprintf('%02d', $episode->season) . 'E' . sprintf('%02d', $episode->number),
|
||||
'firstaired' => (string)$episode->airdate,
|
||||
'summary' => (string)$episode->summary
|
||||
];
|
||||
}
|
||||
}
|
||||
+3
-19
@@ -45,25 +45,9 @@ if (isset($_GET["id"]))
|
||||
$page->userdata['categoryexclusions']);
|
||||
$failed = $df->getFailedCount($data['guid']);
|
||||
|
||||
$criteria = '';
|
||||
if ($data['videos_id'] != 0) {
|
||||
$$showInfo = '';
|
||||
if ($data['videos_id'] > 0) {
|
||||
$showInfo = (new Videos(['Settings' => $page->settings]))->getByVideoID($data['videos_id']);
|
||||
if (count($showInfo) > 0) {
|
||||
$criteria = ['title' => '', 'summary' => '', 'countries_id' => '', 'image' => '', 'id' => ''];
|
||||
$done = 1;
|
||||
$needed = count($criteria);
|
||||
foreach ($showInfo as $info) {
|
||||
foreach($criteria as $key => $value) {
|
||||
if (empty($value) && !empty($info[$key])) {
|
||||
$criteria[$key] = $info[$key];
|
||||
$done++;
|
||||
}
|
||||
}
|
||||
if ($done == $needed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$episodeArray = '';
|
||||
@@ -164,7 +148,7 @@ if (isset($_GET["id"]))
|
||||
$page->smarty->assign('reAudio',$reAudio);
|
||||
$page->smarty->assign('reSubs',$reSubs);
|
||||
$page->smarty->assign('nfo',$nfo);
|
||||
$page->smarty->assign('show',$criteria);
|
||||
$page->smarty->assign('show',$showInfo);
|
||||
$page->smarty->assign('movie',$mov);
|
||||
$page->smarty->assign('xxx', $xxx);
|
||||
$page->smarty->assign('episode',$episodeArray);
|
||||
|
||||
@@ -51,14 +51,22 @@
|
||||
class="label label-success">Add to My Shows</a>
|
||||
<a class="label label-default" href="{$serverroot}series/{$release.videos_id}"
|
||||
title="View all releases for this series">View all episodes</a>
|
||||
{if $release.source = 1}
|
||||
{if $release.tvdb > 0}<a class="label label-default" target="_blank"
|
||||
href="{$site->dereferrer_link}http://thetvdb.com/?tab=series&id={$release.tvdb}&lid=7"
|
||||
title="View at TheTVDB">TheTVDB</a>{/if}
|
||||
{elseif $release.source = 3}
|
||||
{if show.source == 1}
|
||||
<a class="label label-default" target="_blank"
|
||||
href="{$site->dereferrer_link}http://www.tvrage.com/shows/id-{$release.videos_id}"
|
||||
href="{$site->dereferrer_link}http://thetvdb.com/?tab=series&id={$s.tvdb}">
|
||||
title="View at TheTVDB">TheTVDB</a>
|
||||
{elseif $show.source == 2}
|
||||
<a class="label label-default" target="_blank"
|
||||
href="{$site->dereferrer_link}http://www.trakt.tv/shows/{$s.trakt}">
|
||||
title="View at TraktTv">Trakt</a>
|
||||
{elseif $show.source == 3}
|
||||
<a class="label label-default" target="_blank"
|
||||
href="{$site->dereferrer_link}http://www.tvrage.com/shows/id-{$s.tvrage}"
|
||||
title="View at TV Rage">TV Rage</a>
|
||||
{elseif $show.source == 4}
|
||||
<a class="label label-default" target="_blank"
|
||||
href="{$site->dereferrer_link}http://tvmaze.com/shows/{$s.tvmaze}"
|
||||
title="View at TVMaze">TVMaze</a>
|
||||
{/if}
|
||||
{/if}
|
||||
{if $con && $con.url != ""}<a href="{$site->dereferrer_link}{$con.url}/"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
<div class="header">
|
||||
<h2>TV Series > <strong>List</strong></h2>
|
||||
<h2> Series > <strong>List</strong></h2>
|
||||
<div class="breadcrumb-wrapper">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{$smarty.const.WWW_TOP}{$site->home_link}">Home</a></li> / TV Series List
|
||||
@@ -58,7 +58,15 @@
|
||||
<td class="mid">
|
||||
<a title="View series" href="{$smarty.const.WWW_TOP}/series/{$s.id}">Series</a><br />
|
||||
{if $s.id > 0}
|
||||
<a title="View at TVRage" target="_blank" href="{$site->dereferrer_link}http://www.tvrage.com/shows/id-{$s.id}">TVRage</a>
|
||||
{if $s.source == 1}
|
||||
<a title="View at TVDB" target="_blank" href="{$site->dereferrer_link}http://thetvdb.com/?tab=series&id={$s.tvdb}">TVDB</a>
|
||||
{else if $s.source == 2}
|
||||
<a title="View at Trakt" target="_blank" href="{$site->dereferrer_link}http://www.trakt.tv/shows/{$s.trakt}">Trakt</a>
|
||||
{else if $s.source == 3}
|
||||
<a title="View at TVRage" target="_blank" href="{$site->dereferrer_link}http://www.tvrage.com/shows/id-{$s.tvrage}">TVRage</a>
|
||||
{else if $s.source == 4}
|
||||
<a title="View at TVMaze" target="_blank" href="{$site->dereferrer_link}http://tvmaze.com/shows/{$s.tvmaze}">TVMaze</a>
|
||||
{/if}
|
||||
<a title="RSS Feed for {$s.title|escape:"htmlall"}" href="{$smarty.const.WWW_TOP}/rss?show={$s.id}&dl=1&i={$userdata.id}&r={$userdata.rsstoken}"><i class="fa fa-rss"></i></a>
|
||||
{/if}
|
||||
</td>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 459 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Reference in New Issue
Block a user