0){ $lines = array_merge($lines, file($matches[1])); } continue; } $d = explode("=", $line); $key = trim(array_shift($d)); $value = trim(implode("=", $d)); switch ($value){ case "true": case "on": case "yes": $value = true; break; case "false": case "off": case "no": $value = false; break; } if(preg_match("/^([^\\[\\]]+)\\[([^\\]=]*)\\]$/", $key, $matches) > 0){ if(!isset(self::$config[$matches[1]])){ self::$config[$matches[1]] = []; } if($matches[2] !== ""){ self::$config[$matches[1]][$matches[2]] = $value; }else{ self::$config[$matches[1]][] = $value; } }else{ self::$config[$key] = $value; } } } public static function getConfigKey($key, $default = null){ return isset(self::$config[$key]) ? self::$config[$key] : $default; } public function __construct(AniDB $anidb){ $this->anidb = $anidb; $this->extractor = new SceneExtractor($anidb); $user = Database::getConfigKey("database.psql.user"); $pass = Database::getConfigKey("database.psql.password"); $host = Database::getConfigKey("database.psql.host"); $dbname = Database::getConfigKey("database.psql.dbname", "animarr"); $this->db = pg_connect("host=$host user=$user password=$pass dbname=$dbname"); //$this->isTracked = @json_decode(file_get_contents($this->path . "/track/all.json"), true); //if(!is_array($this->isTracked)){ // $this->isTracked = []; //} } public function getAniDB(){ return $this->anidb; } public function getTracked(){ $entries = []; $q = pg_query($this->db, "SELECT * FROM tracked;"); while(($row = pg_fetch_assoc($q, null)) !== false){ $entries[$row["aid"]] = $row; } return $entries; } public function getAlternateTitles($aid = null){ $entries = []; if($aid === null){ $q = pg_query($this->db, "SELECT * FROM alternate_titles;"); }else{ $q = pg_query_params($this->db, 'SELECT * FROM alternate_titles WHERE aid = $1;', [(int) $aid]); } while(($row = pg_fetch_assoc($q, null)) !== false){ $entries[] = $row; } return $entries; } public function addAlternateTitle($aid, $langCode, $title, $entryType = 2){ pg_query_params($this->db, 'INSERT INTO alternate_titles (aid, language, title, type) VALUES ($1, $2, $3, $4);', [$aid, $langCode, $title, $entryType]); $this->anidb->addEntryName($aid, $langCode, $title, $entryType); } public function matchRelease(Release $release, $force = false){ $match = $this->anidb->matchRelease($release); if($match !== null){ return ["aid" => $match["aid"], "new" => $this->addReleaseToDatabase($match["aid"], $release, $force)]; } return null; } public function isReleaseInDatabase(Release $release){ if(isset($this->cacheExists[$release->getId()])){ return $this->cacheExists[$release->getId()]; } return $this->cacheExists[$release->getId()] = pg_fetch_assoc(pg_query_params($this->db, 'SELECT COUNT(release_id) as count FROM releases WHERE release_id = $1;', [$release->getId()]))["count"] > 0; } private function addReleaseToDatabase($aid, Release $release, $force = false){ if($release->getParent() !== null){ return false; } if($release->getId() === null or $release->getId() === ""){ return false; } $isInDb = $this->isReleaseInDatabase($release); if($isInDb){ if(!$force){ return false; } pg_query_params($this->db, 'DELETE FROM episodes_releases WHERE release_id = $1;', [$release->getId()]); pg_query_params($this->db, 'INSERT INTO releases (release_id, aid, release_type, release_data, release_date) VALUES ($1, $2, $3, $4, $5) ON CONFLICT ON CONSTRAINT releases_pkey DO UPDATE SET aid = $2, release_type = $3, release_data = $4, release_date = $5;', [$release->getId(), $aid, $release->getType(), $release->encode(), $release->getUploadDate()]); }else{ pg_query_params($this->db, 'INSERT INTO releases (release_id, aid, release_type, release_data, release_date) VALUES ($1, $2, $3, $4, $5) ON CONFLICT ON CONSTRAINT releases_pkey DO UPDATE SET aid = $2, release_type = $3, release_data = $4, release_date = $5;', [$release->getId(), $aid, $release->getType(), $release->encode(), $release->getUploadDate()]); } unset($this->cacheExists[$release->getId()]); if($release instanceof MultiRelease){ foreach ($release->getContents($this->extractor) as $r){ $m = $this->anidb->matchRelease($r); if($r->getType() === Release::TYPE_SINGLE and $r->getNumber() >= 0 and $m !== null/* and $m["aid"] === $aid*/){ pg_query_params($this->db, 'INSERT INTO episodes_releases (aid, episode, release_id, release_type, release_data) VALUES ($1, $2, $3, $4, $5) ON CONFLICT ON CONSTRAINT episodes_releases_pkey DO UPDATE SET aid = $1, episode = $2, release_id = $3, release_type = $4, release_data = $5;', [$m["aid"], $r->getNumber(), $r->getId(), $r->getType(), $r->encode()]); } } }elseif($release->getType() === Release::TYPE_SINGLE and $release->getNumber() >= 0){ pg_query_params($this->db, 'INSERT INTO episodes_releases (aid, episode, release_id, release_type, release_data) VALUES ($1, $2, $3, $4, $5);', [$aid, $release->getNumber(), $release->getId(), $release->getType(), $release->encode()]); } return !$isInDb; } /** * @param $aid * @return Release[][] */ public function getAnimeEpisodes($aid){ $q = pg_query_params($this->db, 'SELECT * FROM episodes_releases WHERE aid = $1 AND release_type = $2;', [$aid, Release::TYPE_SINGLE]); $episodes = []; while(($row = pg_fetch_assoc($q, null)) !== false){ if(!isset($episodes[$row["episode"]])){ $episodes[$row["episode"]] = []; } $episodes[$row["episode"]][$row["release_id"]] = Release::undecode($row["release_data"]); } return $episodes; } /** * @param $aid * @return Release[] */ public function getRecentReleases($limit = 100, $aid = null, $type = null){ if($aid !== null){ if($type !== null){ $q = pg_query_params($this->db, 'SELECT * FROM releases WHERE aid = $1 AND release_type = $2 ORDER BY release_date DESC NULLS LAST LIMIT $3;', [$aid, $type, $limit]); }else{ $q = pg_query_params($this->db, 'SELECT * FROM releases WHERE aid = $1 ORDER BY release_date DESC NULLS LAST LIMIT $2;', [$aid, $limit]); } }else{ $q = pg_query_params($this->db, 'SELECT * FROM releases ORDER BY release_date DESC NULLS LAST LIMIT $1;', [$limit]); } $releases = []; while(($row = pg_fetch_assoc($q, null)) !== false){ $releases[$row["release_id"]] = Release::undecode($row["release_data"]); } return $releases; } /** * @param $aid * @return Release[] */ public function getAnimeBaseReleases($aid){ $q = pg_query_params($this->db, 'SELECT * FROM releases WHERE aid = $1;', [$aid]); $releases = []; while(($row = pg_fetch_assoc($q, null)) !== false){ $releases[$row["release_id"]] = Release::undecode($row["release_data"]); } return $releases; } /** * @param $aid * @return Release[] */ public function getAnimeReleases($aid){ $q = pg_query_params($this->db, 'SELECT * FROM episodes_releases WHERE aid = $1;', [$aid]); $releases = []; while(($row = pg_fetch_assoc($q, null)) !== false){ $releases[$row["release_id"]] = Release::undecode($row["release_data"]); } return $releases; } public function isTracking($aid){ return pg_fetch_assoc(pg_query_params($this->db, 'SELECT COUNT(aid) as count FROM tracked WHERE aid = $1;', [$aid]), null)["count"] > 0; } public function getTrackInfo($aid){ return pg_fetch_assoc(pg_query_params($this->db, 'SELECT * FROM tracked WHERE aid = $1;', [$aid]), null); } /** * @param $aid * @param $episode * @return MultiRelease|Release|null */ public function getTrackEpisode($aid, $episode){ $row = pg_fetch_assoc(pg_query_params($this->db, 'SELECT * FROM tracked_releases WHERE aid = $1 AND episode = $2 AND release_type = $3;', [$aid, $episode, Release::TYPE_SINGLE]), null); return $row !== false ? Release::undecode($row["release_data"]) : null; } /** * @param $aid * @return Release[] */ public function getTrackEpisodes($aid){ $q = pg_query_params($this->db, 'SELECT * FROM tracked_releases WHERE aid = $1 AND release_type = $2 ORDER BY episode ASC;', [$aid, Release::TYPE_SINGLE]); $episodes = []; while(($row = pg_fetch_assoc($q, null)) !== false){ if(isset($episodes[$row["episode"]])){ Downloader::log("Duplicate episode ".$row["episode"]." for tracked anidb-$aid! Some results might be truncated.", "WARNING"); $episodes[$row["episode"]] = []; } $episodes[$row["episode"]] = Release::undecode($row["release_data"]); } return $episodes; } /** * @param $releaseId * @return Release */ public function getRelease($releaseId){ $row = pg_fetch_assoc(pg_query_params($this->db, 'SELECT * FROM releases WHERE release_id = $1;', [$releaseId]), null); if(!is_array($row)){ return null; } return Release::undecode($row["release_data"]); } /** * @param $releaseId * @param $episode * @return Release */ public function getReleaseEpisode($releaseId, $episode){ $row = pg_fetch_assoc(pg_query_params($this->db, 'SELECT * FROM episodes_releases WHERE release_id = $1 AND episode = $2;', [$releaseId, $episode]), null); if(!is_array($row)){ return null; } return Release::undecode($row["release_data"]); } public function clearTrackedEpisodes($aid){ pg_query_params($this->db, 'DELETE FROM tracked_releases WHERE aid = $1;', [$aid]); } public function clearEpisodes($aid){ pg_query_params($this->db, 'DELETE FROM episodes_releases WHERE aid = $1;', [$aid]); pg_query_params($this->db, 'DELETE FROM releases WHERE aid = $1;', [$aid]); } public function saveTrackEpisode($aid, $episode, Release $release = null){ if($release === null){ pg_query_params($this->db, 'DELETE FROM tracked_releases WHERE aid = $1 AND episode = $2;', [$aid, $episode]); }else{ if($this->getTrackEpisode($aid, $episode) !== null){ //Update pg_query_params($this->db, 'UPDATE tracked_releases SET aid = $1, episode = $2, release_id = $3, release_type = $4, release_data = $5 WHERE aid = $1 AND episode = $2;', [$aid, $episode, $release->getId(), $release->getType(), $release->encode()]); }else{ pg_query_params($this->db, 'INSERT INTO tracked_releases (aid, episode, release_id, release_type, release_data) VALUES ($1, $2, $3, $4, $5);', [$aid, $episode, $release->getId(), $release->getType(), $release->encode()]); } } $this->updateTrackEpisodes($aid); } public function updateTrackEpisodes($aid, $number = null){ if($number === null){ pg_query_params($this->db, "UPDATE tracked SET episode_count = (SELECT COUNT(episode) FROM tracked_releases WHERE aid = $1) WHERE aid = $1;", [$aid]); }else{ pg_query_params($this->db, "UPDATE tracked SET episode_count = $2 WHERE aid = $1;", [$aid, $number]); } return $this->getTrackInfo($aid)["episode_count"]; } public static function cleanNameForFolder($name){ return str_replace(["../", "/..", "/", "\x00"], ["", "", "⁄", ""], $name); } public function addTrack($aid, $download_folder = ""){ if($download_folder === ""){ $download_folder = Database::getConfigKey("download.folder", './Download') . "/[Animarr] " . $this->cleanNameForFolder($this->getAniDB()->getAnime($aid)["title"]) . " [anidb-$aid]/"; } if(!$this->isTracking($aid)){ pg_query_params($this->db, "INSERT INTO tracked (aid, episode_count, prefer_groups, download_folder) VALUES ($1, -1, '', $2);", [$aid, $download_folder]); } } public function stopTrack($aid){ if($this->isTracking($aid)){ pg_query_params($this->db, "DELETE FROM tracked_releases WHERE aid = $1;", [$aid]); pg_query_params($this->db, "DELETE FROM tracked WHERE aid = $1;", [$aid]); $this->cacheExists = []; } } public function getTrackGroups($aid){ if($this->isTracking($aid)){ return explode(",", base64_decode($this->getTrackInfo($aid)["prefer_groups"])); } return []; } public function getTrackFolder($aid, $default = ""){ if($this->isTracking($aid)){ $folder = $this->getTrackInfo($aid)["download_folder"]; if($folder != ""){ return $folder; } } return $default; } public function setTrackFolder($aid, $folder){ pg_query_params($this->db, "UPDATE tracked SET download_folder = $1 WHERE aid = $2;", [$folder, $aid]); } public function getTrackFlag($aid, $flag){ if($this->isTracking($aid)){ return ($this->getTrackInfo($aid)["flags"] & $flag) != 0; } return false; } public function setTrackFlag($aid, $flag, $value){ if($this->isTracking($aid)){ $flags = ($this->getTrackInfo($aid)["flags"] & ~($value)); if($value){ $flags |= $flag; } pg_query_params($this->db, "UPDATE tracked SET flags = $1 WHERE aid = $2;", [$flags, $aid]); } return false; } public function saveTrackGroups($aid, array $groups){ if($this->isTracking($aid)){ pg_query_params($this->db, "UPDATE tracked SET prefer_groups = $1 WHERE aid = $2;", [base64_encode(implode(",", $groups)), $aid]); } } public function matchTitle($title){ return $this->anidb->matchTitle($title); } }