diff --git a/bin/backfill_all_quick.php b/bin/backfill_all_quick.php index bad18fb59..d445a6872 100644 --- a/bin/backfill_all_quick.php +++ b/bin/backfill_all_quick.php @@ -3,7 +3,7 @@ require_once(dirname(__FILE__).'/config.php'); require_once(WWW_DIR.'/lib/nntp.php'); require_once(dirname(__FILE__).'/../lib/ColorCLI.php'); -require_once(dirname(__FILE__).'/../lib/functions.php'); +require_once(dirname(__FILE__) . '/../lib/Functions.php'); $c = new ColorCLI(); if (!isset($argv[1])) { diff --git a/bin/backfill_interval.php b/bin/backfill_interval.php index 4131e6cc0..87c03e083 100644 --- a/bin/backfill_interval.php +++ b/bin/backfill_interval.php @@ -4,7 +4,7 @@ require_once(dirname(__FILE__).'/config.php'); require_once(WWW_DIR.'/lib/nntp.php'); require_once(WWW_DIR.'/lib/Tmux.php'); require_once(dirname(__FILE__).'/../lib/ColorCLI.php'); -require_once(dirname(__FILE__).'/../lib/functions.php'); +require_once(dirname(__FILE__) . '/../lib/Functions.php'); $c = new ColorCLI(); if (!isset($argv[1])) { diff --git a/bin/fixreleasenames.php b/bin/fixreleasenames.php index 377d34fbe..bea1215a4 100644 --- a/bin/fixreleasenames.php +++ b/bin/fixreleasenames.php @@ -5,8 +5,8 @@ require_once(WWW_DIR."/lib/framework/db.php"); require_once(WWW_DIR."/lib/groups.php"); require_once(WWW_DIR.'/lib/nntp.php'); require_once("../lib/ColorCLI.php"); -require_once("../lib/namefixer.php"); -require_once("../lib/functions.php"); +require_once("../lib/NameFixer.php"); +require_once("../lib/Functions.php"); require_once("../lib/Info.php"); require_once("../lib/Pprocess.php"); diff --git a/bin/groupfixrelnames.php b/bin/groupfixrelnames.php new file mode 100644 index 000000000..3c8b7269f --- /dev/null +++ b/bin/groupfixrelnames.php @@ -0,0 +1,208 @@ +error("This script is not intended to be run manually, it is called from groupfixrelnames_threaded.py.")); +} else if (isset($argv[1])) { + $pdo = new DB(); + $namefixer = new NameFixer(true); + $functions = new Functions(); + $pieces = explode(' ', $argv[1]); + $guidChar = $pieces[1]; + $maxperrun = $pieces[2]; + $thread = $pieces[3]; + + switch (true) { + case $pieces[0] === 'nfo' && isset($guidChar) && isset($maxperrun) && is_numeric($maxperrun): + $releases = $pdo->queryDirect( + sprintf(' + SELECT r.ID AS releaseID, r.guid, r.groupID, r.categoryID, r.name, r.searchname, + uncompress(nfo) AS textstring + FROM releases r USE INDEX (ix_releases_guid) + INNER JOIN releasenfo rn ON r.ID = rn.releaseID + WHERE r.guid %s + AND r.nzbstatus = 1 + AND r.proc_nfo = 0 + AND r.nfostatus = 1 + AND r.prehashID = 0 + ORDER BY r.postdate DESC + LIMIT %s', + $functions->likeString($guidChar, false, true), + $maxperrun + ) + ); + if ($releases !== false) { + foreach ($releases as $release) { + if (preg_match('/^=newz\[NZB\]=\w+/', $release['textstring'])) { + $namefixer->done = $namefixer->matched = false; + $pdo->queryDirect(sprintf('UPDATE releases SET proc_nfo = 1 WHERE ID = %d', $release['releaseID'])); + $namefixer->checked++; + echo '.'; + } else { + $namefixer->done = $namefixer->matched = false; + if ($namefixer->checkName($release, true, 'NFO, ', 1, 1) !== true) { + echo '.'; + } + $namefixer->checked++; + } + } + } + break; + case $pieces[0] === 'filename' && isset($guidChar) && isset($maxperrun) && is_numeric($maxperrun): + $releases = $pdo->queryDirect( + sprintf(' + SELECT rf.name AS textstring, rf.releaseID AS fileid, + r.ID AS releaseID, r.name, r.searchname, r.categoryID, r.groupID + FROM releases r USE INDEX (ix_releases_guid) + INNER JOIN releasefiles rf ON r.ID = rf.releaseID + WHERE r.guid %s + AND r.nzbstatus = 1 AND r.proc_files = 0 + AND r.prehashID = 0 + ORDER BY r.postdate ASC + LIMIT %s', + $functions->likeString($guidChar, false, true), + $maxperrun + ) + ); + if ($releases !== false) { + foreach ($releases as $release) { + $namefixer->done = $namefixer->matched = false; + if ($namefixer->checkName($release, true, 'Filenames, ', 1, 1) !== true) { + echo '.'; + } + $namefixer->checked++; + } + } + break; + case $pieces[0] === 'md5' && isset($guidChar) && isset($maxperrun) && is_numeric($maxperrun): + $releases = $pdo->queryDirect( + sprintf(' + SELECT DISTINCT r.ID AS releaseID, r.name, r.searchname, r.categoryID, r.groupID, r.dehashstatus, + rf.name AS filename + FROM releases r USE INDEX (ix_releases_guid) + LEFT OUTER JOIN releasefiles rf ON r.ID = rf.releaseID AND rf.ishashed = 1 + WHERE r.guid %s + AND nzbstatus = 1 AND r.ishashed = 1 + AND r.dehashstatus BETWEEN -6 AND 0 + AND r.prehashID = 0 + ORDER BY r.dehashstatus DESC, r.postdate ASC + LIMIT %s', + $functions->likeString($guidChar, false, true), + $maxperrun + ) + ); + if ($releases !== false) { + foreach ($releases as $release) { + if (preg_match('/[a-fA-F0-9]{32,40}/i', $release['name'], $matches)) { + $namefixer->matchPredbHash($matches[0], $release, 1, 1, true, 1); + } else if (preg_match('/[a-fA-F0-9]{32,40}/i', $release['filename'], $matches)) { + $namefixer->matchPredbHash($matches[0], $release, 1, 1, true, 1); + } else { + $pdo->exec(sprintf("UPDATE releases SET dehashstatus = %d - 1 WHERE ID = %d", $release['dehashstatus'], $release['releaseID'])); + echo '.'; + } + } + } + break; + case $pieces[0] === 'par2' && isset($guidChar) && isset($maxperrun) && is_numeric($maxperrun): + $releases = $pdo->queryDirect( + sprintf(' + SELECT r.ID AS releaseID, r.guid, r.groupID + FROM releases r USE INDEX (ix_releases_guid) + WHERE r.guid %s + AND r.nzbstatus = 1 + AND r.proc_par2 = 0 + AND r.prehashID = 0 + ORDER BY r.postdate ASC + LIMIT %s', + $functions->likeString($guidChar, false, true), + $maxperrun + ) + ); + if ($releases !== false) { + $nntp = new NNTP(['Settings' => $pdo, 'ColorCLI' => $c]); + $Nfo = new Info(); + $nzbcontents = new NZBContents( + array( + 'Echo' => true, 'NNTP' => $nntp, 'Nfo' => $Nfo, 'Settings' => $pdo, + 'PostProcess' => new PProcess(['Settings' => $pdo, 'Nfo' => $Nfo, 'NameFixer' => $namefixer]) + ) + ); + foreach ($releases as $release) { + $res = $nzbcontents->checkPAR2($release['guid'], $release['releaseID'], $release['groupID'], 1, 1); + if ($res === false) { + echo '.'; + } + } + } + break; + case $pieces[0] === 'miscsorter' && isset($guidChar) && isset($maxperrun) && is_numeric($maxperrun): + $releases = $pdo->queryDirect( + sprintf(' + SELECT r.ID AS releaseID + FROM releases r USE INDEX (ix_releases_guid) + WHERE r.guid %s + AND r.nzbstatus = 1 AND r.nfostatus = 1 + AND r.proc_sorter = 0 AND r.isrenamed = 0 + AND r.prehashID = 0 + ORDER BY r.postdate DESC + LIMIT %s', + $pdo->likeString($guidChar, false, true), + $maxperrun + ) + ); + if ($releases !== false) { + $nntp = new NNTP(['Settings' => $pdo, 'ColorCLI' => $c]); + $sorter = new MiscSorter(true); + foreach ($releases as $release) { + $res = $sorter->nfosorter(null, $release['releaseID'], $nntp); + if ($res != true) { + $pdo->exec(sprintf('UPDATE releases SET proc_sorter = 1 WHERE ID = %d', $release['releaseID'])); + echo '.'; + } + } + } + break; + case $pieces[0] === 'predbft' && isset($maxperrun) && is_numeric($maxperrun) && isset($thread) && is_numeric($thread): + $pres = $pdo->queryDirect( + sprintf(' + SELECT p.ID AS prehashID, p.title, p.source, p.searched + FROM prehash p + WHERE LENGTH(title) >= 15 AND title NOT REGEXP "[\"\<\> ]" + AND searched = 0 + AND DATEDIFF(NOW(), predate) > 1 + ORDER BY predate ASC + LIMIT %s + OFFSET %s', + $maxperrun, + $thread * $maxperrun + ) + ); + if ($pres !== false) { + foreach ($pres as $pre) { + $namefixer->done = $namefixer->matched = false; + $ftmatched = $searched = 0; + $ftmatched = $namefixer->matchPredbFT($pre, 1, 1, true, 1); + if ($ftmatched > 0) { + $searched = 1; + } elseif ($ftmatched < 0) { + $searched = -6; + echo "*"; + } else { + $searched = $pre['searched'] - 1; + echo "."; + } + $pdo->exec(sprintf("UPDATE prehash SET searched = %d WHERE ID = %d", $searched, $pre['prehashID'])); + $namefixer->checked++; + } + } + } +} \ No newline at end of file diff --git a/bin/monitor.php b/bin/monitor.php index 6a1c45582..41ff15d53 100644 --- a/bin/monitor.php +++ b/bin/monitor.php @@ -5,10 +5,10 @@ require_once(WWW_DIR . '/lib/site.php'); require_once(WWW_DIR . '/lib/Tmux.php'); require_once(dirname(__FILE__) . "/../lib/ColorCLI.php"); require_once(dirname(__FILE__) . "/../lib/showsleep.php"); -require_once(dirname(__FILE__) . "/../lib/functions.php"); +require_once(dirname(__FILE__) . "/../lib/Functions.php"); -$version = "0.4r2011"; +$version = "0.4r2015"; $db = new DB(); $functions = new Functions(); @@ -55,7 +55,7 @@ $proc = "SELECT ( SELECT COUNT(*) FROM releases r INNER JOIN category c ON c.ID = r.categoryID WHERE r.nzbstatus = 1 AND ((r.passwordstatus BETWEEN -6 AND -1 AND r.haspreview = -1 AND c.disablepreview = 0) OR (r.categoryID = 4050 AND r.gamesinfo_id IS NULL))) AS work, ( SELECT COUNT(*) FROM releases USE INDEX(ix_releases_status)) AS releases, ( SELECT COUNT(*) FROM releases USE INDEX(ix_releases_status) WHERE releasenfoID = 0 AND nfostatus BETWEEN -6 AND -1) AS nforemains, -( SELECT COUNT(*) FROM releases USE INDEX(ix_releases_status) WHERE nfostatus = 1 AND releasenfoID = 1) AS nfo, +( SELECT COUNT(*) FROM releases USE INDEX(ix_releases_status) WHERE nfostatus = 1 OR releasenfoID > 0) AS nfo, ( SELECT table_rows AS cnt FROM information_schema.TABLES WHERE table_name = 'parts' AND TABLE_SCHEMA = '" . DB_NAME . "' ) AS parts, ( SELECT COUNT(ID) FROM binaries WHERE procstat = 0 ) AS binaries, ( SELECT table_rows AS cnt FROM information_schema.TABLES WHERE table_name = 'binaries' AND TABLE_SCHEMA = '" . DB_NAME . "' ) AS binaries_total, @@ -529,6 +529,7 @@ while ($i > 0) { //kill mediainfo and ffmpeg if exceeds 60 sec shell_exec("killall -o 60s -9 mediainfo 2>&1 1> /dev/null"); shell_exec("killall -o 60s -9 ffmpeg 2>&1 1> /dev/null"); + shell_exec("killall -o 60s -9 avconv 2>&1 1> /dev/null"); $getdate = gmDate("Ymd"); @@ -1742,11 +1743,12 @@ while ($i > 0) { $log = writelog($panes3[0]); shell_exec("tmux respawnp -t${tmux_session}:3.0 ' \ cd $_lib && $_php fixReleaseNames.php 1 true other yes show 2>&1 $log; \ - cd $_py && $_python ${DIR}/../python/fixreleasenames_threaded.py nfo 2>&1 $log; \ - $_python ${DIR}/../python/fixreleasenames_threaded.py filename 2>&1 $log; \ - $_python ${DIR}/../python/fixreleasenames_threaded.py par2 2>&1 $log; \ - $_python ${DIR}/../python/fixreleasenames_threaded.py predbft 2>&1 $log; \ - $_php ${DIR}/../lib/fixReleaseNames.php 4 true other yes show $log; $_sleep $fix_timer' 2>&1 1> /dev/null" + cd $_py && $_python ${DIR}/../python/groupfixrelnames_threaded.py nfo 2>&1 $log; \ + $_python ${DIR}/../python/groupfixrelnames_threaded.py md5 2>&1 $log; \ + $_python ${DIR}/../python/groupfixrelnames_threaded.py filename 2>&1 $log; \ + $_python ${DIR}/../python/groupfixrelnames_threaded.py par2 2>&1 $log; \ + $_python ${DIR}/../python/groupfixrelnames_threaded.py miscsorter 2>&1 $log; \ + $_python ${DIR}/../python/groupfixrelnames_threaded.py predbft 2>&1 $log; $_sleep $fix_timer' 2>&1 1> /dev/null" ); $time27 = TIME(); } elseif (($maxload >= get_load()) && ($fix_names == 1)) { diff --git a/bin/nzb-import-new.php b/bin/nzb-import-new.php index b03872f43..0c9552366 100644 --- a/bin/nzb-import-new.php +++ b/bin/nzb-import-new.php @@ -7,8 +7,8 @@ require_once(WWW_DIR . '/lib/category.php'); require_once(WWW_DIR . '/lib/Categorize.php'); require_once(WWW_DIR . '/lib/groups.php'); require_once(dirname(__FILE__) . '/../lib/ColorCLI.php'); -require_once(dirname(__FILE__) . '/../lib/namecleaner.php'); -require_once(dirname(__FILE__) . '/../lib/consoletools.php'); +require_once(dirname(__FILE__) . '/../lib/ReleaseCleaner.php'); +require_once(dirname(__FILE__) . '/../lib/ConsoleTools.php'); require_once(dirname(__FILE__) . '/../lib/Enzebe.php'); $c = new ColorCLI(); diff --git a/bin/requestID.php b/bin/requestID.php index fb4991a76..7b89a20e6 100644 --- a/bin/requestID.php +++ b/bin/requestID.php @@ -5,7 +5,7 @@ require_once(WWW_DIR . "/lib/framework/db.php"); require_once(WWW_DIR . "/lib/groups.php"); require_once(WWW_DIR . "/lib/category.php"); require_once(WWW_DIR . "/lib/Tmux.php"); -require_once(dirname(__FILE__) . '/../lib/functions.php'); +require_once(dirname(__FILE__) . '/../lib/Functions.php'); require_once(dirname(__FILE__) . '/../lib/ColorCLI.php'); $c = new ColorCLI(); diff --git a/bin/safe_pull.php b/bin/safe_pull.php index d1bd5c6fc..d5e1e0107 100644 --- a/bin/safe_pull.php +++ b/bin/safe_pull.php @@ -3,8 +3,8 @@ require_once(dirname(__FILE__).'/config.php'); require_once(WWW_DIR.'/lib/nntp.php'); require_once(dirname(__FILE__).'/../lib/ColorCLI.php'); -require_once(dirname(__FILE__).'/../lib/consoletools.php'); -require_once(dirname(__FILE__).'/../lib/functions.php'); +require_once(dirname(__FILE__) . '/../lib/ConsoleTools.php'); +require_once(dirname(__FILE__) . '/../lib/Functions.php'); $c = new ColorCLI(); diff --git a/bin/update_groups.php b/bin/update_groups.php index 520a45bc1..992f36532 100644 --- a/bin/update_groups.php +++ b/bin/update_groups.php @@ -3,7 +3,7 @@ require_once(dirname(__FILE__).'/config.php'); require_once(WWW_DIR.'/lib/nntp.php'); require_once(dirname(__FILE__).'/../lib/ColorCLI.php'); -require_once(dirname(__FILE__).'/../lib/consoletools.php'); +require_once(dirname(__FILE__) . '/../lib/ConsoleTools.php'); $start = TIME(); diff --git a/lib/DB/db.sql b/lib/DB/db.sql index a42b685b7..f8e400bad 100644 --- a/lib/DB/db.sql +++ b/lib/DB/db.sql @@ -565,8 +565,8 @@ INSERT INTO category (ID, title, parentID) VALUES (2010, 'Foreign', 2000); INSERT INTO category (ID, title, parentID) VALUES (2020, 'Other', 2000); INSERT INTO category (ID, title, parentID) VALUES (2030, 'SD', 2000); INSERT INTO category (ID, title, parentID) VALUES (2040, 'HD', 2000); -INSERT INTO category (ID, title, parentID) VALUES (2050, 'BluRay', 2000); -INSERT INTO category (ID, title, parentID) VALUES (2060, '3D', 2000); +INSERT INTO category (ID, title, parentID) VALUES (2050, '3D', 2000); +INSERT INTO category (ID, title, parentID) VALUES (2060, 'BluRay', 2000); INSERT INTO category (ID, title, parentID) VALUES (2070, 'DVD', 2000); INSERT INTO category (ID, title, parentID) VALUES (3010, 'MP3', 3000); diff --git a/lib/DB/patches/0050_category.sql b/lib/DB/patches/0050_category.sql index ccf36d5c5..cf9083e77 100644 --- a/lib/DB/patches/0050_category.sql +++ b/lib/DB/patches/0050_category.sql @@ -43,8 +43,8 @@ INSERT INTO category (ID, title, parentID) VALUES (2010, 'Foreign', 2000); INSERT INTO category (ID, title, parentID) VALUES (2020, 'Other', 2000); INSERT INTO category (ID, title, parentID) VALUES (2030, 'SD', 2000); INSERT INTO category (ID, title, parentID) VALUES (2040, 'HD', 2000); -INSERT INTO category (ID, title, parentID) VALUES (2050, 'BluRay', 2000); -INSERT INTO category (ID, title, parentID) VALUES (2060, '3D', 2000); +INSERT INTO category (ID, title, parentID) VALUES (2050, '3D', 2000); +INSERT INTO category (ID, title, parentID) VALUES (2060, 'BluRay', 2000); INSERT INTO category (ID, title, parentID) VALUES (2070, 'DVD', 2000); INSERT INTO category (ID, title, parentID) VALUES (3010, 'MP3', 3000); diff --git a/lib/DB/patches/0057~releases.sql b/lib/DB/patches/0057~releases.sql new file mode 100644 index 000000000..32db0690f --- /dev/null +++ b/lib/DB/patches/0057~releases.sql @@ -0,0 +1,2 @@ +ALTER TABLE releases ADD COLUMN proc_sorter TINYINT(1) NOT NULL DEFAULT '0'; +UPDATE `tmux` SET `value` = '57' WHERE `setting` = 'sqlpatch'; \ No newline at end of file diff --git a/lib/Film.php b/lib/Film.php index 71341117e..cc58025a7 100644 --- a/lib/Film.php +++ b/lib/Film.php @@ -10,7 +10,7 @@ require_once(WWW_DIR."/lib/rottentomato.php"); require_once(WWW_DIR."/lib/Tmux.php"); require_once("ColorCLI.php"); require_once("TraktTv.php"); -require_once("functions.php"); +require_once("Functions.php"); /** * Class Film diff --git a/lib/IRCScraper.php b/lib/IRCScraper.php index 1f7493094..aca7332f3 100644 --- a/lib/IRCScraper.php +++ b/lib/IRCScraper.php @@ -3,7 +3,7 @@ require_once(dirname(__FILE__) . "/../bin/config.php"); require_once(WWW_DIR . "/lib/framework/db.php"); require_once("prehash.php"); require_once("IRCClient.php"); -require_once("functions.php"); +require_once("Functions.php"); /** diff --git a/lib/Info.php b/lib/Info.php index f65c77483..e66b45914 100644 --- a/lib/Info.php +++ b/lib/Info.php @@ -9,7 +9,7 @@ require_once("ColorCLI.php"); require_once("Pprocess.php"); require_once("Film.php"); require_once("TvAnger.php"); -require_once("functions.php"); +require_once("Functions.php"); require_once("getid3/getid3/getid3.php"); /** diff --git a/lib/MiscSorter.php b/lib/MiscSorter.php new file mode 100644 index 000000000..89d2ca210 --- /dev/null +++ b/lib/MiscSorter.php @@ -0,0 +1,859 @@ +qualities = array('(:?..)?tv', '480[ip]?', '640[ip]?', '720[ip]?', '1080[ip]?', 'ac3', 'audio_ts', 'avi', 'bd[\- ]?rip', 'bd25', 'bd50', + 'bdmv', 'blu ?ray', 'br[\- ]?disk', 'br[\- ]?rip', 'cam', 'cam[\- ]?rip', 'dc', 'directors.?cut', 'divx\d?', 'dts', 'dvd', 'dvd[\- ]?r', + 'dvd[\- ]?rip', 'dvd[\- ]?scr', 'extended', 'hd', 'hd[\- ]?tv', 'h264', 'hd[\- ]?cam', 'hd[\- ]?ts', 'iso', 'm2ts', 'mkv', 'mpeg(:?\-\d)?', + 'mpg', 'ntsc', 'pal', 'proper', 'ppv', 'ppv[\- ]?rip', 'r\d{1}', 'repack', 'repacked', 'scr', 'screener', 'tc', 'telecine', 'telesync', 'ts', + 'tv[\- ]?rip', 'unrated', 'vhs( ?rip)', 'video_ts', 'video ts', 'x264', 'xvid', 'web[\- ]?rip'); + + $this->echooutput = $echooutput; + $this->qty = 100; + + $this->pdo = new DB(); + $s = new Sites(); + $this->site = $s->get(); + $this->category = new Categorize($this->echooutput); + $this->movie = new Film($this->echooutput); + $this->nfolib = new Info($this->echooutput); + $this->nc = new ReleaseCleaning(); + $this->groups = new Groups($this->pdo); + $this->c = new ColorCLI(); + + //$res = $this->pdo->exec("SET NAMES 'utf8'"); + //$res = $this->pdo->exec("SET CHARACTER SET 'utf8'"); + + mb_internal_encoding("UTF-8"); + mb_regex_encoding("UTF-8"); + mb_http_output("UTF-8"); + mb_language("uni"); + } + + function getHash($name) + { + return false; + } + + function doecho($str = '', $type = '') + { + if ($this->echooutput && $str != '') { + if ($type == 'debug') + echo "$str\n"; + else if ($type != 'debug') + echo "$str\n"; + } + } + + function nfopos($nfo, $str) + { + $nfo = preg_replace('/[ \t\_\.\?]/Ui', " ", $nfo); + $nfo = preg_replace('/ +/', " ", $nfo); + $nfo = preg_replace('/^\s+?/Umi', "", $nfo); + + $str = preg_replace('/[ \t\_\.\?]/Ui', " ", $str); + $str = preg_replace('/ +/', " ", $str); + $str = preg_replace('/^\s+?/Umi', "", $str); + + $pos = stripos($nfo, $str); + if ($pos !== false) + return $pos / strlen($nfo); + else + return false; + } + + function getIDs($cat) + { + if ($cat > 0) + $cats = $this->category->getChildren(substr($cat, 0, 1) . "000"); + else + $cats = $this->category->get(true, array()); + $thecategory = array(); + foreach ($cats as $c) + $thecategory[] = $c['ID']; + + $thecategory = implode(", ", $thecategory); + $res = $this->pdo->query(sprintf("SELECT ID FROM releases WHERE nfostatus = 1 AND passwordstatus >= 0 AND releases.categoryID IN (%s) LIMIT %d", $thecategory, $this->qty)); + + if (count($res) == 0) + return false; + + $this->idarr = $res[0]['ID']; + unset($res[0]); + foreach ($res as $r) + $this->idarr = $this->idarr . ", " . $r['ID']; + + if ($this->idarr == '') + return false; + + return $this->idarr; + } + + function doarray($matches) + { + $r = array(); + $i = 0; + + $matches = array_count_values($matches); + $matches = array_change_key_case($matches, CASE_LOWER); + + foreach ($matches as $m => $v) { + $x = -1; + + if (strlen($m) < 50) { + $str = preg_replace("/\s/iU", "", $m); + + $m = strtolower($str); + + $x = 0; + if ($m == 'imdb') { + $x = -11; + } else if ($m == 'anidb.net') { + $x = -10; + } else if ($m == 'upc') { + $x = -9; + } else if ($m == 'amazon.') { + $x = -8; + } else if ($m == 'asin' || $m == 'isbn') { + $x = -7; + } else if ($m == 'tvrage') { + $x = -6; + } else if ($m == 'audiobook') { + $x = -5; + } else if ($m == 'os') { + $x = -4; + } else if ($m == 'mac' || $m == 'macintosh' || $m == 'dmg' || $m == 'macos' || $m == 'macosx' || $m == 'osx') { + $x = -3; + } else if ($m == 'itunes.apple.com/') { + $x = -2; + } else if ($m == 'documentaries' || $m == 'documentary' || $m == 'doku') { + $x = -1; + } else if (preg_match('/sport|deportes|nhl|nfl|\bnba/i', $m)) { + $x = 1000; + } else if (preg_match('/avi|xvid|divx|mkv/i', $m)) { + $x = 1001; + } else if (preg_match('/\.(?:rar|001)/i', $m)) { + $x = 1002; + } else if (preg_match('/pdf/i', $m)) { + $x = 1003; + } + } + + if ($x != -1) { + if ($x == 0) + $r[$i++] = $m; + else if (isset($r[$x])) + $r[$x + mt_rand(0, 100) / 100] = $m; + else + $r[$x] = $m; + } + } + ksort($r); + $r = array_values($r); + return $r; + } + + function cleanname($name) + { + if (is_array($name)) + return $name; + + do { + $original = $name; + $name = preg_replace("/[\{\[\(]\d+[ \.\-\/]+\d+[\]\}\)]/iU", " ", $name); + $name = preg_replace("/[\x01-\x1f\!\?\[\{\}\]\/\:\|]+/iU", " ", $name); + $name = preg_replace("/ +/iU", " ", $name); + $name = preg_replace("/^[\s\.]+|[\s\.]{2,}$/iU", "", $name); + $name = preg_replace("/ \- \- /iU", " - ", $name); + $name = preg_replace("/^[\s\-\_\.]/iU", "", $name); + $name = trim($name); + } while ($original != $name); + + return $name; + } + + function dodbupdate($id, $cat, $name = '', $typeid = 0, $type = '', $debug = '') + { + $n = "\n"; + $groups = $this->groups; + + $release = $this->pdo->query("SELECT r.searchname as searchname, categoryID as cat, g.name as name FROM releases r INNER JOIN groups g ON r.groupID = g.ID WHERE r.ID = {$id}"); + $oldcatname = $this->category->getNameByID($release[0]['cat']); + $newcatname = $this->category->getNameByID($cat); + + $query = "UPDATE releases SET categoryID = {$cat}, proc_sorter = 1"; + if ($name != '') { + $query .= ", isrenamed = 1, iscategorized = 1, searchname = " . $this->pdo->escapeString($name); + $name = preg_replace(array('/^[-=_\.:\s]+/', '/[-=_\.:\s]+$/'), '', $name); + echo $n . $n . $this->c->headerOver("New name: ") . $this->c->primary($name) . + $this->c->headerOver("Old name: ") . $this->c->primaryOver($release[0]["searchname"]); + } + + switch ($type) { + case 'imdb': + if ($typeid != 0) + $query .= ", imdbID = {$typeid}"; + break; + case 'book': + if ($typeid != 0) + $query .= ", bookinfoID = {$typeid}"; + break; + case 'music': + if ($typeid != 0) + $query .= ", musicinfoID = {$typeid}"; + break; + case 'anime': + if ($typeid != 0) + $query .= ", anidbID = {$typeid}"; + break; + case 'tv': + if ($typeid != 0) + $query .= ", rageID = {$typeid}"; + break; + default: + break; + } + echo $n . $this->c->headerOver("New cat: ") . $this->c->primary($newcatname) . + $this->c->headerOver("Old cat: ") . $this->c->primary($oldcatname) . + $this->c->headerOver("Group: ") . $this->c->primary($release[0]['name']) . + $this->c->headerOver("Method: ") . $this->c->primary('sorter ' . $type) . + $this->c->headerOver("ReleaseID: ") . $this->c->primary($id); + + $query .= " WHERE ID = {$id}"; + //$this->doecho($query); + if (!$debug) { + if ($this->pdo->exec($query) !== false) + return true; + } else + return true; + return false; + } + + function doOS($nfo, $id, $cat) + { + $ok = false; + + $nfo = preg_replace("/[^\x09-\x80]|\?/", "", $nfo); + $nfo = preg_replace("/[\x01-\x09\x0e-\x20]/", " ", $nfo); + + //$pattern = '/(?nfopos($nfo, $set[1]); + else + $pos = false; + + $pattern = '/(?:[\s\_\.\:\xb0-\x{3000}]{2,}|^)([a-z0-9].+v(?:er(?:sion)?)?[\.\s]*?\d+\.\d(?:\.\d+)?.+)(?:[\s\_\.\:\xb0-\x{3000}]{2,}|$)/Uui'; + $set1 = preg_split($pattern, $nfo, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + if (isset($set1[1])) + $pos1 = $this->nfopos($nfo, $set1[1]); + else + $pos1 = false; + if ((isset($set1[1]) && $pos1 !== false && (real) $pos > (real) $pos1) || $pos === false) { + $set = $set1; + $pos = $pos1; + } + + $pattern = '/(?:[\*\?\-\=\|\;\:\.\[\}\]\( \xb0-\x{ff}\?]+)([a-z0-9\&].+\s*\(c\).+)(?:\s\s\s|$|\.\.\.)/Uui'; + $set1 = preg_split($pattern, $nfo, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + if (isset($set1[1])) + $pos1 = $this->nfopos($nfo, $set1[1]); + else + $pos1 = false; + if ((isset($set1[1]) && $pos1 !== false && (real) $pos > (real) $pos1) || $pos === false) { + $set = $set1; + $pos = $pos1; + } + + if (!isset($set[1]) || strlen($set[1]) < 3) { + $pattern = '/(?:(?:presents?|p +r +e +s +e +n +t +s)(?:[^a-z0-9]+?))([a-z0-9 \.\-\_\']+?)/Ui'; + $set = preg_split($pattern, $nfo, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + if (isset($set[1]) && preg_match('/(another)? *(fine)? *relase/i', $set[1])) + $set = null; + } + + if (isset($set[1]) && preg_match('/^(.+)(\(c\)|\xA9)/i', $this->cleanname($set[1]), $tmp)) + $set[1] = $tmp[1]; + + if (isset($set[1]) && strlen($set[1]) < 128) + $ok = $this->dodbupdate($id, $cat, $this->cleanname($set[1])); + return $ok; + } + + function moviename($nfo, $imdb, $name) + { + $qual = array(); + foreach ($this->qualities as $quality) { + if (preg_match("/(?nc->fixerCleaner($name); + foreach ($qual as $key => $quality) { + if (@preg_match("/$quality/i", $name)) { + unset($qual[$key]); + } + } + + $n = ''; + if (count($qual) > 0) { + foreach ($qual as $quality) { + $n = $n . " " . $quality; + } + } + + $name1 = $name; + + if ($imdb > 0) { + $movie = $this->movie->getMovieInfo($imdb); + foreach (explode(" ", $movie['title'] . " " . $movie['year']) as $word) { + //echo "word ".$word."\n";; + $tmp = preg_split("/$word/i", $name1); + $name2 = ''; + + foreach ($tmp as $t) { + $name2 = $name2 . " " . $t; + } + $name1 = $name2; + } + } + $name1 = trim($name1); + $name1 = preg_replace('/[ \-\_]{2,}/', ' ', $name1); + $name1 = preg_replace('/ {2,}/', ' ', $name1); + $name1 = preg_replace('/ /', ' ', $name1); + if ($imdb > 0) + $name = $movie['title'] . " (" . $movie['year'] . ") " . $name1 . " " . $n . "_"; + else + $name = $name1 . " " . $n . "_"; + return trim($name); + } + + function doAmazon($name, $id, $nfo = "", $q, $region = 'com', $case = false, $nfo = '', $row = '') + { + $amazon = new AmazonProductAPI($this->site->amazonpubkey, $this->site->amazonprivkey, $this->site->amazonassociatetag); + $ok = false; + + try { + switch ($case) { + case 'upc': + $amaz = $amazon->getItemByUpc(trim($q), $region); + break; + case 'asin': + $amaz = $amazon->getItemByAsin(trim($q), $region); + break; + case 'isbn': + $amaz = $amazon->searchProducts(trim($q), '', "ISBN"); + break; + } + } catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), "\n"; + unset($s); + unset($amaz); + unset($amazon); + return $ok; + } + if (!isset($amaz->Items->Item)) + return $ok; + + $type = $amaz->Items->Item->ItemAttributes->ProductGroup; + switch ($type) { + case 'Book': + case 'eBooks': + $audiobook = false; + $v = (string) $amaz->Items->Item->ItemAttributes->Format; + if (stripos($v, "audiobook") !== false) + $audiobook = true; + + $new = (string) $amaz->Items->Item->ItemAttributes->Author; + $new = $new . " - " . (string) $amaz->Items->Item->ItemAttributes->Title; + $name = $this->nc->fixerCleaner($new); + + $query = "SELECT ID FROM bookinfo WHERE asin = '" . (string) $amaz->Items->Item->ASIN . "'"; + $rel = $this->pdo->query($query); + if (count($rel) == 0) { + $book = new Books($this->echooutput); + $bookId = $book->updateBookInfo('', $amaz); + unset($book); + } else { + $bookId = $rel[0]['ID']; + } + + $query = "SELECT * FROM releases INNER JOIN releaseaudio ON releases.ID = releaseaudio.releaseID WHERE releases.ID = {$id}"; + $rel = $this->pdo->query($query); + if (count($rel) > 0 || $audiobook) + $ok = $this->dodbupdate($id, Category::CAT_MUSIC_AUDIOBOOK, $name, $bookId, 'book'); + else + $ok = $this->dodbupdate($id, Category::CAT_BOOK_EBOOK, $name, $bookId, 'book'); + unset($rel); + break; + + case 'Digital Music Track': + case 'Digital Music Album': + case 'Music': + $new = (string) $amaz->Items->Item->ItemAttributes->Artist; + if ($new != '') + $new .= " - "; + $new = $new . (string) $amaz->Items->Item->ItemAttributes->Title; + $name = $this->nc->fixerCleaner($new); + + $query = "SELECT * FROM musicinfo WHERE asin = '" . (string) $amaz->Items->Item->ASIN . "'"; + $rel = $this->pdo->query($query); + if (count($rel) == 0) { + $music = new Music(); + //$musicId = $music->updateMusicInfo('', '', $amaz) + unset($music); + } else + $musicId = $rel[0]['ID']; + + //$ok = $this->dodbupdate($id, 3010, $name, $musicId, 'music'); + break; + + case 'Movies': + case 'DVD': + $new = (string) $amaz->Items->Item->ItemAttributes->Title; + $new = $new . " (" . substr((string) $amaz->Items->Item->ItemAttributes->ReleaseDate, 0, 4) . ")"; + $new = $this->moviename($nfo, 0, $new); + $name = $this->nc->fixerCleaner($new); + $ok = $this->dodbupdate($id, Category::CAT_MOVIE_OTHER, $name); + + break; + + default: + echo "* * * * * * uncatched amazon category $type " . $name; + break; + } + + unset($s); + unset($amaz); + unset($amazon); + return $ok; + } + + public function nzblist($guid = '') + { + if (empty($guid)) { + return false; + } + + $nzb1 = new NZB(); + $nzbpath = $nzb1->NZBPath($guid); + $nzb = array(); + + if ($nzbpath !== false) { + $xmlObj = @simplexml_load_file('compress.zlib://' . $nzbpath); + if ($xmlObj && strtolower($xmlObj->getName()) == 'nzb') { + foreach ($xmlObj->file as $file) { + $nzbfile = array(); + $nzbfile['subject'] = (string) $file->attributes()->subject; + $nzbfile = array_merge($nzbfile, (array) $file->groups); + $nzbfile = array_merge($nzbfile, (array) $file->segments); + $nzb[] = $nzbfile; + $nzbfile = null; + } + } else { + $nzb = false; + } + unset($xmlObj); + return $nzb; + } else { + return false; + } + } + + function domusicfiles($row) + { + $m3u = $alt = $mp3name = ''; + $mp3 = false; + $files = $extras = 0; + + $nzbfiles = $this->nzblist($row['guid']); + + if ($nzbfiles) { + $name = $row['name']; + $name = preg_replace("/\//", ' ', $name); + $name = preg_quote($name); + foreach ($nzbfiles as $nzbsubject) { + $sub = $nzbsubject['subject'] . "\n"; + + if (preg_match('/^[a-f0-9]+$/i', $name)) + $sub = preg_replace("/$name/i", '', $sub); + + if (preg_match('/\.(vol\d{1,3}?\+\d{1,3}?|par2|nfo\b|sfv|par\b|p\d{1,3}?|sv\b)/iU', $sub)) { + $extras++; + $alt = preg_replace('/(\.vol\d{1,3}?\+\d{1,3}?|\.par2|\.[a-z][a-z0-9]{2})+?".+?/iU', '', $sub); + } + + if (preg_match('/\.mp3|\.flac/', $sub, $matches)) { + $mp3name = preg_replace('/(\.mp3".+?)/iU', '.mp3', $sub); + $mp3name = preg_replace('/(\.flac".+?)/iU', '.flac', $sub); + $mp3name = preg_replace('/(?iU)^[^\"]+\"(0\d+?-?(00)??)??/iU', '', $mp3name); + + $mp3 = true; + $files++; + } + + if (preg_match('/\.m3u|\"00+[ \-\_\.]+?|\.nfo\b|\.sfv/iU', $sub, $matches)) { + if (preg_match('/\.url|playlist/iU', $sub)) { + continue; + } + $sub = preg_replace('/(\.vol\d{1,3}?\+\d{1,3}?|\.par2|\.[a-z][a-z0-9]{2})+?".+?/iU', '', $sub); + $m3u = preg_replace('/(?iU)^[^\"]+\"(0\d+?-?(00)??)??/iU', '', $sub); + } + } + } + $name = ''; + if (count($nzbfiles) > 0) { + + if (($m3u != '' || (($files + $extras) / count($nzbfiles) > 0.7)) && $mp3) { + $name = $m3u; + + if ($files == 1) + $name = $mp3name; + + if (empty($name)) { + $name = $alt; + } + $name = $row["searchname"]; + } + } + $name = $this->cleanname($name); + $name = preg_replace("/\.[a-z][a-z0-9]{2,3}($|\" yenc)/i", "", $name); + $name = preg_replace("/^[a-f0-9]{10,}$/i", "", $name); + + unset($file, $nzbfiles, $nzbinfo, $nzb); + return $name; + } + + function matchnfo($case, $nfo, $row) + { + $ok = false; + + switch (strtolower($case)) { + case 't r a c k': + case 'track': + case 'trax': + case 'lame': + case 'album': + case 'music': + case '44.1kHz': + case 'm3u': + case 'flac': + if (preg_match('/(a\s?r\s?t\s?i\s?s\s?t|l\s?a\s?b\s?e\s?l|mp3|e\s?n\s?c\s?o\s?d\s?e\s?r|rip|stereo|mono|single charts)/i', $nfo)) { + if (!preg_match('/(\bavi\b|x\.?264|divx|mvk|xvid|install(?!ation)|Setup\.exe|unzip|unrar)/i', $nfo)) { + $artist = preg_split('/(?:a\s?r\s?t\s?i\s?s\s?ts?\b[^ \.\:]*) *?(?!(?:[^\s\.\:\}\]\*\xb0-\x{3000}\?] ?){2,}?\b)(?:[\*\?\-\=\|\;\:\.\[\}\]\(\s\xb0-\x{3000}\?]+?)[\s\.\>\:\(\)\xb0-\x{3000}\?]((?!\:) ?[a-z0-9\&].+)(?:\s\s\s|$|\.\.\.)/Uuim', $nfo, 0, PREG_SPLIT_DELIM_CAPTURE); + $title = preg_split('/(?:t+\s?i+\s?t+\s?l+\s?e+\b|a\s?l\s?b\s?u\s?m\b) *?(?!(?:[^\s\.\:\}\]\*\xb0-\x{3000}\?] ?){2,}?\b)(?:[\*\?\-\=\|\;\:\.\[\}\]\(\s\xb0-\x{3000}\?]+?)[\s\.\>\:\(\)\xb0-\x{3000}\?]((?!\:) ?[a-z0-9\&].+)(?:\s\s\s|$|\.\.\.)/Uuim', $nfo, 0, PREG_SPLIT_DELIM_CAPTURE); + + if (!isset($title[1]) || !isset($artist[1])) { + if (preg_match('/presents[\W\. \xb0-\x{3000}]+? ([^\-]+?) \- ([a-z0-9]?(?!\:).+(?:\s\s\s))/iuUm', $nfo, $matches)) { + $artist[1] = $matches[1]; + $title[1] = $matches[2]; + } + if (!isset($matches[2]) && preg_match('/[\h\_\.\:\xb0-\x{3000}]{2,}?([a-z].+) \- (.+?)(?:[\?\s\_\.\:\xb0-\x{3000}]{2,}|$)/Uiu', $nfo, $matches)) { + + $pos = $this->nfopos($nfo, $matches[1] . " - " . $matches[2]); + if ($pos !== false && $pos < 0.45 && !preg_match('/\:\d\d$/', $matches[2]) && strlen($matches[1]) < 48 && strlen($matches[2]) < 64) { + if (!preg_match('/title/i', $matches[1]) && !preg_match('/title/i', $matches[2])) { + $artist[1] = $matches[1]; + $title[1] = $matches[2]; + } + } + } + } + if (isset($artist[1]) && $artist[1] == " ") + $artist[1] = $artist[3]; + + if (isset($title[1]) && isset($artist[1])) + $ok = $this->dodbupdate($row['ID'], Category::CAT_MUSIC_MP3, $this->cleanname($artist[1]) . " - " . $this->cleanname($title[1])); + } + } + break; + case 'dmg': + case 'mac': + case 'macintosh': + case 'macos': + case 'macosx': + case 'osx': + $ok = $this->doOS($nfo, $row['ID'], Category::CAT_PC_MAC); + break; + + case 'windows': + case 'win': + case 'winall': + case 'winxp': + case 'plugin': + case 'crack': + case 'linux': + case 'install': + case 'application': + $ok = $this->doOS($nfo, $row['ID'], Category::CAT_PC_0DAY); + break; + + case 'android': + $ok = $this->doOS($nfo, $row['ID'], Category::CAT_PC_MOBILEANDROID); + break; + + case 'ios': + case 'iphone': + case 'ipad': + case 'ipod': + $ok = $this->doOS($nfo, $row['ID'], Category::CAT_PC_MOBILEIOS); + break; + + case 'game': + $set = preg_split('/\>(.*)\dodbupdate($row['ID'], Category::CAT_PC_GAMES, $this->cleanname($set[1])); + else + $ok = $this->doOS($nfo, $row['ID'], Category::CAT_PC_GAMES); + break; + + case 'imdb': + $imdb = $this->movie->doMovieUpdate($nfo, "sorter", $row['ID']); + if ($imdb !== false) { + $movie = $this->movie->getMovieInfo($imdb); + $name = $this->moviename($nfo, $imdb, $row['searchname']); + + if ($movie !== false) { + if (preg_match('/sport/iU', $movie['genre'])) + $cat = Category::CAT_TV_SPORT; + else if (preg_match('/docu/iU', $movie['genre'])) + $cat = Category::CAT_TV_DOCU; + else if (preg_match('/talk\-show/iU', $movie['genre'])) + $cat = Category::CAT_TV_OTHER; + else if (preg_match('/tv/iU', $movie['genre']) || preg_match('/episode/iU', $movie['genre']) || preg_match('/reality/iU', $movie['genre'])) + $cat = Category::CAT_TV_OTHER; + else { + $cat = $this->category->determineCategory($name, $row['groupID']); + if ($cat == Category::CAT_MISC_OTHER) + $cat = Category::CAT_MOVIE_OTHER; + } + } else + $cat = $this->category->determineCategory($name, $row['groupID']); + + if ($cat < Category::CAT_PARENT_GAME || $cat > Category::CAT_PARENT_BOOK + 1000) + $cat = Category::CAT_MOVIE_OTHER; + + $ok = $this->dodbupdate($row['ID'], $cat, $name, $imdb, 'imdb'); + } + break; + case 'audiobook': + case 'audible': + case 'recordedbooks': + case 'spokenbook': + case 'readby': + case 'narratedby': + case 'narrator': + case 'speech': + $author = preg_split('/(?:a\s?u\s?t\s?h\s?o\s?r\b)+? *?(?!(?:[^\s\.\:\}\]\*\xb0-\x{3000}\?] ?){2,}?\b)(?:[\*\?\-\=\|\;\:\.\[\}\]\(\s\xb0-\x{3000}\?]+?)[\s\.\>\:\(\)]((?!\:) ?[a-z0-9\&].+)(?:\s\s\s|$|\.\.\.)/Uuim', $nfo, 0, PREG_SPLIT_DELIM_CAPTURE); + $title = preg_split('/(?:t\s?i\s?t\s?l\s?e\b|b\s?o\s?o\s?k\b)+? *?(?!(?:[^\s\.\:\}\]\*\xb0-\x{3000}\?] ?){2,}?\b)(?:[\*\?\-\=\|\;\:\.\[\}\]\(\s\xb0-\x{3000}\?]+?)[\s\.\>\:\(\)]((?!\:) ?[a-z0-9\&].+)(?:\s\s\s|$|\.\.\.)/Uuim', $nfo, 0, PREG_SPLIT_DELIM_CAPTURE); + if (isset($author[1]) && isset($title[1])) + $ok = $this->dodbupdate($row['ID'], Category::CAT_MUSIC_AUDIOBOOK, $this->cleanname($author[1] . " - " . $title[1])); + else if (preg_match('/[\h\_\.\:\xb0-\x{3000}]{2,}?([a-z].+) \- (.+)(?:[\s\_\.\:\xb0-\x{3000}]{2,}|$)/iu', $nfo, $matches)) { + $pos = $this->nfopos($nfo, $matches[1] . " - " . $matches[2]); + if ($pos !== false && $pos < 0.4 && !preg_match('/\:\d\d$/', $matches[2]) && strlen($matches[1]) < 48 && strlen($matches[2]) < 48) + if (!preg_match('/title/i', $matches[1]) && !preg_match('/title/i', $matches[2])) + $ok = $this->dodbupdate($row['ID'], Category::CAT_MUSIC_AUDIOBOOK, $this->cleanname($matches[1] . " - " . $matches[2])); + } + + break; + + case 'comicbook': + case 'comix': + $ok = $this->dodbupdate($row['ID'], Category::CAT_BOOK_COMICS, ''); + break; + + case 'avi': + case 'dvd': + case 'h264': + case 'mkv': + case 'movie': + case 'x264': + case 'xvid': + break; + + case 'tvrage': + break; + + case 'hdtv': + case 'tvseries': + break; + + case "asin": + case "isbn": + case "amazon.": + case "upc": + $ok = false; + if ($case == 'asin' || $case == 'isbn') { + preg_match('/(?:isbn|asin)[ \:\.=]*? *?([a-zA-Z0-9\-\.]{8,20}?)/iU', $nfo, $set); + if (isset($set[1])) { + $set[1] = preg_replace('/[\-\.]/', '', $set[1]); + //echo "asin ".$set[1]."\n"; + if (strlen($set[1]) > 13) + break; + if (isset($set[1])) { + $set[2] = $set[1]; + $set[1] = "com"; + } + } + } else if ($case == 'amazon.') { + preg_match('/amazon\.([a-z]*?\.?[a-z]{2,3}?)\/.*\/dp\/([a-zA-Z0-9]{8,10}?)/iU', $nfo, $set); + $case = 'asin'; + } else if ($case == 'upc') { + preg_match('/UPC\:?? *?([a-zA-Z0-9]*?)/iU', $nfo, $set); + if (isset($set[1])) { + $set[2] = $set[1]; + $set[1] = "All"; + } + } else { + echo "* * * * * error in amazon"; + break; + } + + if (count($set) > 1) { + //var_dump($set); + $ok = $this->doAmazon($row['name'], $row['ID'], $nfo, $set[2], $set[1], $case, $nfo, $row); + } + break; + } + return $ok; + } + + function nfosorter($category = Category::CAT_PARENT_MISC, $id = 0, $nntp) + { + if (!isset($nntp)) + exit($this->c->error("Not connected to usenet(miscsorter->nfosorter).\n")); + + $this->idarr = $this->getIDs($category); + if ($id != 0) + $this->idarr = $id; + + + $uc = "UNCOMPRESS(releasenfo.nfo)"; + $res = $this->pdo->query(sprintf("SELECT {$uc} AS nfo, releases.ID, releases.guid, releases.fromname, releases.name, releases.searchname, groups.name AS gname, releases.groupID FROM releasenfo INNER JOIN releases ON releasenfo.releaseID = releases.ID INNER JOIN groups ON releases.groupID = groups.id WHERE releases.ID IN (%s)", $this->idarr)); + if (strlen($this->idarr) > 0 && count($res) > 0) { + foreach ($res as $row) { + $hash = $this->getHash($row['name']); + if ($hash !== false) + $row['searchname'] = $hash; + + $nfo = utf8_decode($row['nfo']); + + if (strlen($nfo) > 100) { + $pattern = '/.+(\.rar|\.001) [0-9a-f]{6,10}?|(imdb)\.[a-z0-9\.\_\-\/]+?(?:tt|\?)\d+?\/?|(tvrage)\.com\/|(\bASIN)|(isbn)|(UPC\b)|(comic book)|(comix)|(tv series)|(\bos\b)|(documentaries)|(documentary)|(doku)|(macintosh)|(dmg)|(mac[ _\.\-]??os[ _\.\-]??x??)|(\bos\b\s??x??)|(\bosx\b)'; + $pattern .= '|(\bios\b)|(iphone)|(ipad)|(ipod)|(pdtv)|(hdtv)|(video streams)|(movie)|(audiobook)|(audible)|(recorded books)|(spoken book)|(speech)|(read by)\:?|(narrator)\:?|(narrated by)'; + $pattern .= '|(dvd)|(ntsc)|(m4v)|(mov\b)|(avi\b)|(xvid)|(divx)|(mkv)|(amazon\.)[a-z]{2,3}.*\/dp\/|(anidb.net).*aid=|(\blame\b)|(\btrack)|(trax)|(t r a c k)|(music)|(44.1kHz)|video (game)|type:(game)|(game) Type|(game)[ \.]+|(platform)|(console)|\b(win(?:dows|all|xp)\b)|(\bwin\b)'; + $pattern .= '|(m3u)|(flac\b)|(?doarray($matches); + + foreach ($matches as $m) { + if (isset($m)) + $case = preg_replace('/ /', '', $m); + else + $case = ''; + + if (($m == 'os' || $m == 'platform' || $m == 'console') && preg_match('/(?:\bos\b(?: type)??|platform|console)[ \.\:\}]+(\w+?).??(\w*?)/iU', $nfo, $set)) { + + if (isset($set[1])) { + $case = strtolower($set[1]); + } + if (strlen($set[2]) && (stripos($set[2], 'mac') !== false || stripos($set[2], 'osx') !== false)) + $case = strtolower($set[2]); + } + + $pos = $this->nfopos($nfo, $m); + + if ($pos !== false && $pos > 0.55 && $case != 'imdb') { + $this->pdo->exec(sprintf('UPDATE releases SET proc_sorter = 1 WHERE ID = %d', $res[0]['ID'])); + return false; + } + + if ($ret = $this->matchnfo($case, $nfo, $row)) + return $ret; + $this->pdo->exec(sprintf('UPDATE releases SET proc_sorter = 1 WHERE ID = %d', $res[0]['ID'])); + return false; + } + } + } + } + } + + function musicnzb($category = Category::CAT_PARENT_MISC, $id = 0) + { + if ($id != 0) + $query = "SELECT releases.*, g.name AS gname FROM releases INNER JOIN groups g ON releases.groupID = g.ID WHERE releases.ID = ($id)"; // AND NOT (`imdbID` > 1 OR `rageID` > 1 OR `musicinfoID` is not null OR `consoleinfoID` is not null OR `bookinfoID` is not null )"; + else { + if ($this->category->isParent($category)) { + $thecategory = array(); + foreach ($this->category->getChildren($category) as $c) + $thecategory[] = $c['ID']; + $category = implode(", ", $thecategory); + } + $query = "SELECT releases.*, g.name AS gname FROM releases INNER JOIN groups g ON releases.groupID = g.ID WHERE categoryID IN (" . $category . ") AND nfostatus >= 0 AND passwordstatus >= 0 AND NOT (imdbID IS NOT NULL OR rageID > 0 OR consoleinfoID IS NOT NULL OR bookinfoID IS NOT NULL)"; + } + + $res = $this->pdo->query($query); + if (count($res) > 0) { + echo "Doing NZB music files match.\n"; + foreach ($res as $row) { + $hash = $this->getHash($row['name']); + if ($hash !== false) + $row['searchname'] = $hash; + + $frommail = $row['fromname']; + + //trigger_error("doing part 2".$row['ID']); + $query = "SELECT releasevideo.releaseID FROM releasevideo WHERE releasevideo.releaseID = " . $row['ID']; + $rel = $this->pdo->queryOneRow($query); + + if ($rel !== false) + continue; + + $uc = "UNCOMPRESS(releasenfo.nfo)"; + $query = "SELECT releasenfo.releaseID, {$uc} AS nfo FROM releasenfo WHERE releasenfo.releaseID = " . $row['ID']; + $rel = $this->pdo->queryOneRow($query); + + $nfo = ''; + if ($rel !== false) + if ($rel['releaseID'] == $row['ID']) + $nfo = $rel['nfo']; + + $name = $this->domusicfiles($row); + if ($name != ' ' && $name != '') { + $ok = $this->dodbupdate($row['ID'], Category::CAT_MUSIC_MP3, $name); + return $ok; + } + } + } + } + +} \ No newline at end of file diff --git a/lib/NZBGet.php b/lib/NZBGet.php index 3c8675c5a..10febccf4 100644 --- a/lib/NZBGet.php +++ b/lib/NZBGet.php @@ -3,7 +3,7 @@ require_once(dirname(__FILE__) . "/../bin/config.php"); require_once(WWW_DIR . "/lib/framework/db.php"); require_once(WWW_DIR . "/lib/releases.php"); require_once("Enzebe.php"); -require_once("functions.php"); +require_once("Functions.php"); /** * Class NZBGet * diff --git a/lib/Pprocess.php b/lib/Pprocess.php index 8e98b44e6..c505bb6da 100644 --- a/lib/Pprocess.php +++ b/lib/Pprocess.php @@ -17,10 +17,10 @@ require_once(WWW_DIR . "/lib/genres.php"); require_once(WWW_DIR . "/lib/anidb.php"); require_once(WWW_DIR . "/lib/book.php"); require_once(WWW_DIR . "/lib/Games.php"); -require_once("consoletools.php"); +require_once("ConsoleTools.php"); require_once("ColorCLI.php"); -require_once("nzbcontents.php"); -require_once("namefixer.php"); +require_once("NZBContents.php"); +require_once("NameFixer.php"); require_once("Info.php"); require_once("prehash.php"); require_once("Sharing.php"); @@ -28,7 +28,7 @@ require_once("TraktTv.php"); require_once("Film.php"); require_once("TvAnger.php"); require_once("Konsole.php"); -require_once("functions.php"); +require_once("Functions.php"); require_once("ProcessAdditional.php"); /** diff --git a/lib/ProcessAdditional.php b/lib/ProcessAdditional.php index 719f758cd..f74b41c7a 100644 --- a/lib/ProcessAdditional.php +++ b/lib/ProcessAdditional.php @@ -18,10 +18,10 @@ require_once(WWW_DIR . "/lib/genres.php"); require_once(WWW_DIR . "/lib/anidb.php"); require_once(WWW_DIR . "/lib/book.php"); require_once(WWW_DIR . "/lib/nzb.php"); -require_once("consoletools.php"); +require_once("ConsoleTools.php"); require_once("ColorCLI.php"); -require_once("nzbcontents.php"); -require_once("namefixer.php"); +require_once("NZBContents.php"); +require_once("NameFixer.php"); require_once("Info.php"); require_once("prehash.php"); require_once("Sharing.php"); @@ -29,7 +29,7 @@ require_once("TraktTv.php"); require_once("Film.php"); require_once("TvAnger.php"); require_once("Konsole.php"); -require_once("functions.php"); +require_once("Functions.php"); require_once("Enzebe.php"); Class ProcessAdditional diff --git a/lib/namecleaner.php b/lib/ReleaseCleaner.php similarity index 99% rename from lib/namecleaner.php rename to lib/ReleaseCleaner.php index 4d6684b47..9efbb13d4 100644 --- a/lib/namecleaner.php +++ b/lib/ReleaseCleaner.php @@ -3,7 +3,7 @@ require_once(dirname(__FILE__)."/../bin/config.php"); require_once(WWW_DIR . "lib/framework/db.php"); require_once(WWW_DIR."lib/groups.php"); require_once("prehash.php"); -require_once("functions.php"); +require_once("Functions.php"); diff --git a/lib/ReleaseFiles.php b/lib/ReleaseFiles.php index 4e73c9b23..e3a8e5a12 100644 --- a/lib/ReleaseFiles.php +++ b/lib/ReleaseFiles.php @@ -1,7 +1,7 @@ siteSettings['fetching'] = ($this->siteSettings['fetching'] == 1 ? true : false); $this->siteSettings['enabled'] = ($this->siteSettings['enabled'] == 1 ? true : false); $this->siteSettings['start_position'] = ($this->siteSettings['start_position'] == 1 ? true : false); - //add functions.php + //add Functions.php $this->functions = new Functions(); } diff --git a/lib/TraktTv.php b/lib/TraktTv.php index 9687b2616..de425ac77 100644 --- a/lib/TraktTv.php +++ b/lib/TraktTv.php @@ -1,7 +1,7 @@ cli = Utility::isCLI(); + $this->log = new ColorCLI(); + + if (!(self::$instance instanceof PDO)) { + $dbconnstring = sprintf( + "%s:host=%s;dbname=%s%s", + DB_TYPE, + DB_HOST, + DB_NAME, + (defined('DB_PORT') ? ";port=" . DB_PORT : "") + ); + $errmode = defined('DB_ERRORMODE') ? DB_ERRORMODE : PDO::ERRMODE_SILENT; + + try { + self::$instance = new PDO( + $dbconnstring, DB_USER, DB_PASSWORD, array( + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_ERRMODE => $errmode, + PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" + ) + ); + + if (defined('DB_PCONNECT') && DB_PCONNECT) { + self::$instance->setAttribute(PDO::ATTR_PERSISTENT, true); + } + } catch (PDOException $e) { + die("fatal error: could not connect to database! Check your config. " . $e); + } + } + + $this->ct = new ConsoleTools(); + if (!empty(DB_TYPE)) { + $this->dbSystem = strtolower(DB_TYPE); + } + } + + /** + * Init PDO instance. + */ + private function initialiseDatabase() + { + + + $dsn = $this->dbSystem . ':host=' . DB_HOST; + if (!empty(DB_PORT)) { + $dsn .= ';port=' . DB_PORT; + } + $dsn .= ';charset=utf8'; + + $options = [ + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::ATTR_TIMEOUT => 180, + \PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8", + \PDO::MYSQL_ATTR_LOCAL_INFILE => true + ]; + + $this->dsn = $dsn; + // removed try/catch to let the instantiating code handle the problem (Install for + // instance can output a message that connecting failed. + self::$instance = new \PDO($dsn, DB_USER, DB_PASSWORD, $options); + + if (DB_NAME != '') { + self::$instance->query("USE {DB_NAME}"); + } + + // In case PDO is not set to produce exceptions (PHP's default behaviour). + if (self::$instance === false) { + $this->echoError( + "Unable to create connection to the Database!", + 'initialiseDatabase', + 1, + true + ); + } + + // For backwards compatibility, no need for a patch. + self::$instance->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER); + self::$instance->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC); + } + + /** + * Get the plain PDO connection + * + * @return PDO + */ + public function getPDO() + { + return self::$instance; + } + + /** + * Call functions from PDO + * + * @param $function + * @param $args + * + * @return mixed + */ + public function __call($function, $args) + { + if (method_exists(self::$instance, $function)) { + return call_user_func_array(array(self::$instance, $function), $args); + } + trigger_error("Unknown PDO Method Called: $function()\n", E_USER_ERROR); + } + + /** + * Escape a string using PDO + * + * @param string $str + * + * @return string + */ + public function escapeString($str) + { + if (is_null($str)) { + return 'NULL'; + } + + return self::$instance->quote($str); + } + + /** + * Formats a 'like' string. ex.(LIKE '%chocolate%') + * + * @param string $str The string. + * @param bool $left Add a % to the left. + * @param bool $right Add a % to the right. + * + * @return string + */ + public function likeString($str, $left = true, $right = true) + { + return ( + 'LIKE ' . + $this->escapeString( + ($left ? '%' : '') . + $str . + ($right ? '%' : '') + ) + ); + } + /** + * Reconnect to MySQL when the connection has been lost. + * + * @see ping(), _checkGoneAway() for checking the connection. + * + * @return bool + */ + protected function _reconnect() + { + // Check if we are really connected to MySQL. + if ($this->ping() === false) { + // If we are not reconnected, return false. + return false; + } + return true; + } + + /** + * Verify that we've lost a connection to MySQL. + * + * @param string $errorMessage + * + * @return bool + */ + protected function _checkGoneAway($errorMessage) + { + if (stripos($errorMessage, 'MySQL server has gone away') !== false) { + return true; + } + return false; + } + + /** + * Execute a query and return the result or last inserted id + * + * @param string $query + * @param bool $returnlastid + * + * @return bool|int + */ + public function queryInsert($query, $returnlastid = true) + { + if ($query == "") + return false; + + if (DB_TYPE == "mysql") { + //$result = $this->exec(utf8_encode($query)); + $result = self::$instance->exec($query); + + return ($returnlastid) ? self::$instance->lastInsertId() : $result; + } elseif (DB_TYPE == "postgres") { + $p = self::$instance->prepare($query . ' RETURNING id'); + $p->execute(); + + return $p->fetchColumn(); + } + } + + /** + * Perform a query and return the first result + * + * @param string $query + * @param bool $useCache + * @param string|int $cacheTTL + * + * @return bool|array + */ + public function queryOneRow($query, $useCache = false, $cacheTTL = '') + { + if ($query == "") + return false; + + $rows = $this->query($query, $useCache, $cacheTTL); + + return ($rows ? $rows[0] : false); + } + + /** + * Perform a single query + * + * @param string $query + * @param bool $useCache + * @param string|int $cacheTTL + * + * @return bool|array + */ + public function query($query, $useCache = false, $cacheTTL = '') + { + if ($query == "") + return false; + + if ($useCache) { + $cache = new Cache(); + if ($cache->enabled && $cache->exists($query)) { + $ret = $cache->fetch($query); + if ($ret !== false) + return $ret; + } + } + + $result = self::$instance->query($query)->fetchAll(); + + if ($result === false || $result === true) + return array(); + + if ($useCache) + if ($cache->enabled) + $cache->store($query, $result, $cacheTTL); + + return $result; + } + + /** + * Query without returning an empty array like our function query(). http://php.net/manual/en/pdo.query.php + * + * @param string $query The query to run. + * @param bool $ignore Ignore errors, do not log them? + * + * @return bool|\PDOStatement + */ + public function queryDirect($query, $ignore = false) + { + if (empty($query)) { + return false; + } + + $query = Utility::collapseWhiteSpace($query); + + + try { + $result = self::$instance->query($query); + } catch (\PDOException $e) { + + // Check if we lost connection to MySQL. + if ($this->_checkGoneAway($e->getMessage()) !== false) { + + // Reconnect to MySQL. + if ($this->_reconnect() === true) { + + // If we reconnected, retry the query. + $result = $this->queryDirect($query); + + } else { + // If we are not reconnected, return false. + $result = false; + } + + } else { + if ($ignore === false) { + $this->echoError($e->getMessage(), 'queryDirect', 4, false); + } + $result = false; + } + } + return $result; + } + + /** + * Used for deleting, updating (and inserting without needing the last insert id). + * + * @param string $query + * @param bool $silent Echo or log errors? + * + * @return bool|\PDOStatement + */ + public function queryExec($query, $silent = false) + { + if (empty($query)) { + return false; + } + + $query = Utility::collapseWhiteSpace($query); + + + $i = 2; + $error = ''; + while($i < 11) { + $result = $this->queryExecHelper($query); + if (is_array($result) && isset($result['deadlock'])) { + $error = $result['message']; + if ($result['deadlock'] === true) { + $this->ct->showsleep($i * ($i/2)); + $i++; + } else { + break; + } + } elseif ($result === false) { + $error = 'Unspecified error.'; + break; + } else { + return $result; + } + } + if ($silent === false) { + $this->echoError($error, 'queryExec', 4); + } + return false; + } + + /** + * Helper method for queryInsert and queryExec, checks for deadlocks. + * + * @param string $query + * @param bool $insert + * + * @return array|\PDOStatement + */ + protected function queryExecHelper($query, $insert = false) + { + try { + if ($insert === false ) { + $run = self::$instance->prepare($query); + $run->execute(); + return $run; + } else { + $ins = self::$instance->prepare($query); + $ins->execute(); + return self::$instance->lastInsertId(); + } + + } catch (\PDOException $e) { + // Deadlock or lock wait timeout, try 10 times. + if ( + $e->errorInfo[1] == 1213 || + $e->errorInfo[0] == 40001 || + $e->errorInfo[1] == 1205 || + $e->getMessage() == 'SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction' + ) { + return ['deadlock' => true, 'message' => $e->getMessage()]; + } + + // Check if we lost connection to MySQL. + else if ($this->_checkGoneAway($e->getMessage()) !== false) { + + // Reconnect to MySQL. + if ($this->_reconnect() === true) { + + // If we reconnected, retry the query. + return $this->queryExecHelper($query, $insert); + + } + } + + return ['deadlock' => false, 'message' => $e->getMessage()]; + } + } + + /** + * Get the total number of rows in the result set + * + * @param PDOStatement $result + * + * @return int + */ + public function getNumRows(PDOStatement $result) + { + return $result->rowCount(); + } + + /** + * Fetch a assoc row from a result set + * + * @param PDOStatement $result + * + * @return array + */ + public function getAssocArray(PDOStatement $result) + { + return $result->fetch(); + } + + /** + * Main method for creating results as an array. + * + * @param string $query SQL to execute. + * + * @return array|boolean Array of results on success or false on failure. + */ + public function queryArray($query) + { + $result = false; + if (!empty($query)) { + $result = $this->queryDirect($query); + + if (!empty($result)) { + $result = $result->fetchAll(); + } + } + + return $result; + } + + /** + * Optimize the database + * + * @param bool $force + * + * @return array + */ + public function optimise($force = false) + { + $ret = array(); + if ($force) + $alltables = $this->query("show table status"); + else + $alltables = $this->query("show table status where Data_free != 0"); + + foreach ($alltables as $tablename) { + $ret[] = $tablename['Name']; + if (strtolower($tablename['Engine']) == "myisam") + $this->queryDirect("REPAIR TABLE `" . $tablename['Name'] . "` USE_FRM"); + + $this->queryDirect("OPTIMIZE TABLE `" . $tablename['Name'] . "`"); + $this->queryDirect("ANALYZE TABLE `" . $tablename['Name'] . "`"); + } + + $nulltables = $this->query("select table_name from information_schema.TABLES where table_schema = '" . DB_NAME . "' and engine is null"); + foreach ($nulltables as $tablename) { + $ret[] = $tablename['table_name']; + $this->queryDirect("REPAIR TABLE `" . $tablename['table_name'] . "` USE_FRM"); + } + + return $ret; + } + + /** + * Checks whether the connection to the server is working. Optionally restart a new connection. + * NOTE: Restart does not happen if PDO is not using exceptions (PHP's default configuration). + * In this case check the return value === false. + * + * @param boolean $restart Whether an attempt should be made to reinitialise the Db object on failure. + * + * @return boolean + */ + public function ping($restart = false) + { + try { + return (bool) self::$instance->query('SELECT 1+1'); + } catch (\PDOException $e) { + if ($restart == true) { + $this->initialiseDatabase(); + } + return false; + } + } + + /** + * Echo error, optionally exit. + * + * @param string $error The error message. + * @param bool $exit Exit or not? + * + * @internal param string $method The method where the error occured. + * @internal param int $severity The severity of the error. + */ + protected function echoError($error, $exit = false) + { + echo( + ($this->cli ? $this->log->error($error) . PHP_EOL : '