echooutput = ($echooutput && nZEDb_ECHOCLI); $this->db = new DB(); $this->s = new Sites(); $this->site = $this->s->get(); $this->groups = new Groups($this->db); $this->releaseCleaning = new ReleaseCleaning(); $this->consoleTools = new ConsoleTools(); $this->stage5limit = (isset($this->site->maxnzbsprocessed)) ? (int)$this->site->maxnzbsprocessed : 1000; $this->completion = (isset($this->site->releasecompletion)) ? (int)$this->site->releasecompletion : 0; $this->crosspostt = (isset($this->site->crossposttime)) ? (int)$this->site->crossposttime : 2; $this->updategrabs = ($this->site->grabstatus == '0') ? false : true; $this->requestids = $this->tmux->lookup_reqids; $this->delaytimet = (isset($this->site->delaytime)) ? (int)$this->site->delaytime : 2; $this->c = new ColorCLI(); } /** * @return array */ public function get() { return $this->db->query( ' SELECT releases.*, g.name AS group_name, c.title AS category_name FROM releases INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN groups g ON g.ID = releases.groupID WHERE nzbstatus = 1' ); } /** * @param $start * @param $num * * @return array */ public function getRange($start, $num) { return $this->db->query( sprintf( " SELECT releases.*, CONCAT(cp.title, ' > ', c.title) AS category_name FROM releases INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN category cp ON cp.ID = c.parentID WHERE nzbstatus = 1 ORDER BY postdate DESC %s", ($start === false ? '' : 'LIMIT ' . $num . ' OFFSET ' . $start) ) ); } /** * Used for paginator. * * @param $cat * @param $maxage * @param array $excludedcats * @param string $grp * * @return mixed */ public function getBrowseCount($cat, $maxage = -1, $excludedcats = array(), $grp = '') { $catsrch = $this->categorySQL($cat); $exccatlist = $grpjoin = $grpsql = ''; $maxagesql = ( $maxage > 0 ? " AND postdate > NOW() - INTERVAL " . (DB_TYPE === 'mysql' ? $maxage . ' DAY ' : "'" . $maxage . " DAYS' ") : '' ); if ($grp != '') { $grpjoin = 'INNER JOIN groups ON groups.ID = releases.groupID'; $grpsql = sprintf(' AND groups.name = %s ', $this->db->escapeString($grp)); } if (count($excludedcats) > 0) { $exccatlist = ' AND categoryID NOT IN (' . implode(',', $excludedcats) . ')'; } $res = $this->db->queryOneRow( sprintf( ' SELECT COUNT(releases.ID) AS num FROM releases %s WHERE nzbstatus = 1 AND releases.passwordstatus <= %d %s %s %s %s', $grpjoin, $this->showPasswords(), $catsrch, $maxagesql, $exccatlist, $grpsql ) ); return ($res === false ? 0 : $res['num']); } /** * Used for browse results. * * @param $cat * @param $start * @param $num * @param $orderby * @param $maxage * @param array $excludedcats * @param string $grp * * @return array */ public function getBrowseRange($cat, $start, $num, $orderby, $maxage = -1, $excludedcats = array(), $grp = '') { $limit = ($start === false ? '' : ' LIMIT ' . $num . ' OFFSET ' . $start); $catsrch = $this->categorySQL($cat); $grpsql = $exccatlist = ''; $maxagesql = ( $maxage > 0 ? " AND postdate > NOW() - INTERVAL " . (DB_TYPE === 'mysql' ? $maxage . ' DAY ' : "'" . $maxage . " DAYS' ") : '' ); if ($grp != '') { $grpsql = sprintf(' AND groups.name = %s ', $this->db->escapeString($grp)); } if (count($excludedcats) > 0) { $exccatlist = ' AND releases.categoryID NOT IN (' . implode(',', $excludedcats) . ')'; } $order = $this->getBrowseOrder($orderby); return $this->db->query( sprintf( " SELECT releases.*, CONCAT(cp.title, ' > ', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, groups.name AS group_name, rn.ID AS nfoid, re.releaseID AS reid FROM releases INNER JOIN groups ON groups.ID = releases.groupID LEFT OUTER JOIN releasevideo re ON re.releaseID = releases.ID LEFT OUTER JOIN releasenfo rn ON rn.releaseID = releases.ID AND rn.nfo IS NOT NULL INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN category cp ON cp.ID = c.parentID WHERE nzbstatus = 1 AND releases.passwordstatus <= %d %s %s %s %s ORDER BY %s %s %s", $this->showPasswords(), $catsrch, $maxagesql, $exccatlist, $grpsql, $order[0], $order[1], $limit ), true ); } /** * Return site setting for hiding/showing passworded releases. * * @return int */ public function showPasswords() { $res = $this->db->queryOneRow("SELECT value FROM site WHERE setting = 'showpasswordedrelease'"); return ($res === false ? 0 : $res['value']); } /** * Use to order releases on site. * * @param string $orderby * * @return array */ public function getBrowseOrder($orderby) { $order = ($orderby == '') ? 'posted_desc' : $orderby; $orderArr = explode('_', $order); switch ($orderArr[0]) { case 'cat': $orderfield = 'categoryID'; break; case 'name': $orderfield = 'searchname'; break; case 'size': $orderfield = 'size'; break; case 'files': $orderfield = 'totalpart'; break; case 'stats': $orderfield = 'grabs'; break; case 'posted': default: $orderfield = 'postdate'; break; } $ordersort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc'; return array($orderfield, $ordersort); } /** * Return ordering types usable on site. * * @return array */ public function getBrowseOrdering() { return array( 'name_asc', 'name_desc', 'cat_asc', 'cat_desc', 'posted_asc', 'posted_desc', 'size_asc', 'size_desc', 'files_asc', 'files_desc', 'stats_asc', 'stats_desc' ); } /** * Get list of releases avaible for export. * * @param string $postfrom (optional) Date in this format : 01/01/2014 * @param string $postto (optional) Date in this format : 01/01/2014 * @param string $group (optional) Group ID. * * @return array */ public function getForExport($postfrom = '', $postto = '', $group = '') { if ($postfrom != '') { $dateparts = explode('/', $postfrom); if (count($dateparts) == 3) { $postfrom = sprintf( ' AND postdate > %s ', $this->db->escapeString($dateparts[2] . '-' . $dateparts[1] . '-' . $dateparts[0] . ' 00:00:00') ); } else { $postfrom = ''; } } if ($postto != '') { $dateparts = explode('/', $postto); if (count($dateparts) == 3) { $postto = sprintf( ' AND postdate < %s ', $this->db->escapeString($dateparts[2] . '-' . $dateparts[1] . '-' . $dateparts[0] . ' 23:59:59') ); } else { $postto = ''; } } if ($group != '' && $group != '-1') { $group = sprintf(' AND groupID = %d ', $group); } else { $group = ''; } return $this->db->query( sprintf( " SELECT searchname, guid, groups.name AS gname, CONCAT(cp.title,'_',category.title) AS catName FROM releases INNER JOIN category ON releases.categoryID = category.ID INNER JOIN groups ON releases.groupID = groups.ID INNER JOIN category cp ON cp.ID = category.parentID WHERE nzbstatus = 1 %s %s %s", $postfrom, $postto, $group ) ); } /** * Get date in this format : 01/01/2014 of the oldest release. * * @return mixed */ public function getEarliestUsenetPostDate() { $row = $this->db->queryOneRow( sprintf( " SELECT %s AS postdate FROM releases", (DB_TYPE === 'mysql' ? "DATE_FORMAT(min(postdate), '%d/%m/%Y')" : "to_char(min(postdate), 'dd/mm/yyyy')" ) ) ); return ($row === false ? '01/01/2014' : $row['postdate']); } /** * Get date in this format : 01/01/2014 of the newest release. * * @return mixed */ public function getLatestUsenetPostDate() { $row = $this->db->queryOneRow( sprintf( " SELECT %s AS postdate FROM releases", (DB_TYPE === 'mysql' ? "DATE_FORMAT(max(postdate), '%d/%m/%Y')" : "to_char(max(postdate), 'dd/mm/yyyy')" ) ) ); return ($row === false ? '01/01/2014' : $row['postdate']); } /** * Gets all groups for drop down selection on NZB-Export web page. * * @param bool $blnIncludeAll * * @return array */ public function getReleasedGroupsForSelect($blnIncludeAll = true) { $groups = $this->db->query('SELECT DISTINCT groups.ID, groups.name FROM releases INNER JOIN groups on groups.ID = releases.groupID'); $temp_array = array(); if ($blnIncludeAll) { $temp_array[-1] = '--All Groups--'; } foreach ($groups as $group) { $temp_array[$group['ID']] = $group['name']; } return $temp_array; } /** * Get releases for RSS. * * @param $cat * @param $num * @param int $uid * @param int $rageID * @param int $anidbID * @param int $airdate * * @return array */ public function getRss($cat, $num, $uid = 0, $rageID, $anidbID, $airdate = -1) { if (DB_TYPE === 'mysql') { $limit = ' LIMIT 0,' . ($num > 100 ? 100 : $num); } else { $limit = ' LIMIT ' . ($num > 100 ? 100 : $num) . ' OFFSET 0'; } $catsrch = $cartsrch = ''; if (count($cat) > 0) { if ($cat[0] == -2) { $cartsrch = sprintf(' INNER JOIN usercart ON usercart.userID = %d AND usercart.releaseID = releases.ID ', $uid); } else if ($cat[0] != -1) { $catsrch = ' AND ('; foreach ($cat as $category) { if ($category != -1) { $categ = new Category(); if ($categ->isParent($category)) { $children = $categ->getChildren($category); $chlist = '-99'; foreach ($children as $child) { $chlist .= ', ' . $child['ID']; } if ($chlist != '-99') { $catsrch .= ' releases.categoryID IN (' . $chlist . ') OR '; } } else { $catsrch .= sprintf(' releases.categoryID = %d OR ', $category); } } } $catsrch .= '1=2 )'; } } $rage = ($rageID > -1) ? sprintf(' AND releases.rageID = %d ', $rageID) : ''; $anidb = ($anidbID > -1) ? sprintf(' AND releases.anidbID = %d ', $anidbID) : ''; if (DB_TYPE === 'mysql') { $airdate = ($airdate > -1) ? sprintf(' AND releases.tvairdate >= DATE_SUB(CURDATE(), INTERVAL %d DAY) ', $airdate) : ''; } else { $airdate = ($airdate > -1) ? sprintf(" AND releases.tvairdate >= (CURDATE() - INTERVAL '%d DAYS') ", $airdate) : ''; } return $this->db->query( sprintf( " SELECT releases.*, m.cover, m.imdbID, m.rating, m.plot, m.year, m.genre, m.director, m.actors, g.name AS group_name, CONCAT(cp.title, ' > ', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, COALESCE(cp.ID,0) AS parentcategoryID, mu.title AS mu_title, mu.url AS mu_url, mu.artist AS mu_artist, mu.publisher AS mu_publisher, mu.releasedate AS mu_releasedate, mu.review AS mu_review, mu.tracks AS mu_tracks, mu.cover AS mu_cover, mug.title AS mu_genre, co.title AS co_title, co.url AS co_url, co.publisher AS co_publisher, co.releasedate AS co_releasedate, co.review AS co_review, co.cover AS co_cover, cog.title AS co_genre FROM releases INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN category cp ON cp.ID = c.parentID INNER JOIN groups g ON g.ID = releases.groupID LEFT OUTER JOIN movieinfo m ON m.imdbID = releases.imdbID AND m.title != '' LEFT OUTER JOIN musicinfo mu ON mu.ID = releases.musicinfoID LEFT OUTER JOIN genres mug ON mug.ID = mu.genreID LEFT OUTER JOIN consoleinfo co ON co.ID = releases.consolenfoID LEFT OUTER JOIN genres cog ON cog.ID = co.genreID %s WHERE releases.passwordstatus <= %d %s %s %s %s ORDER BY postdate DESC %s", $cartsrch, $this->showPasswords(), $catsrch, $rage, $anidb, $airdate, $limit ) ); } /** * Get TV shows for RSS. * * @param $num * @param int $uid * @param array $excludedcats * @param $airdate * * @return array */ public function getShowsRss($num, $uid = 0, $excludedcats = array(), $airdate = -1) { $exccatlist = ''; if (count($excludedcats) > 0) { $exccatlist = ' AND releases.categoryID NOT IN (' . implode(',', $excludedcats) . ')'; } $usql = $this->uSQL($this->db->query(sprintf('SELECT rageID, categoryID FROM userseries WHERE userID = %d', $uid), true), 'rageID'); if (DB_TYPE === 'mysql') { $airdate = ($airdate > -1) ? sprintf(' AND releases.tvairdate >= DATE_SUB(CURDATE(), INTERVAL %d DAY) ', $airdate) : ''; } else { $airdate = ($airdate > -1) ? sprintf(" AND releases.tvairdate >= (CURDATE() - INTERVAL '%d DAYS') ", $airdate) : ''; } $limit = ' LIMIT ' . ($num > 100 ? 100 : $num) . ' OFFSET 0'; return $this->db->query( sprintf( " SELECT releases.*, tvr.rageID, tvr.releasetitle, g.name AS group_name, CONCAT(cp.title, '-', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, COALESCE(cp.ID,0) AS parentcategoryID FROM releases INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN category cp ON cp.ID = c.parentID INNER JOIN groups g ON g.ID = releases.groupID LEFT OUTER JOIN tvrage tvr ON tvr.rageID = releases.rageID WHERE %s %s %s AND releases.passwordstatus <= %d ORDER BY postdate DESC %s", $usql, $exccatlist, $airdate, $this->showPasswords(), $limit ) ); } /** * Get movies for RSS. * * @param $num * @param int $uid * @param array $excludedcats * * @return array */ public function getMyMoviesRss($num, $uid = 0, $excludedcats = array()) { $exccatlist = ''; if (count($excludedcats) > 0) { $exccatlist = ' AND releases.categoryID NOT IN (' . implode(',', $excludedcats) . ')'; } $usql = $this->uSQL($this->db->query(sprintf('SELECT imdbID, categoryID FROM usermovies WHERE userID = %d', $uid), true), 'imdbID'); $limit = ' LIMIT ' . ($num > 100 ? 100 : $num) . ' OFFSET 0'; return $this->db->query( sprintf( " SELECT releases.*, mi.title AS releasetitle, g.name AS group_name, CONCAT(cp.title, '-', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, COALESCE(cp.ID,0) AS parentcategoryID FROM releases INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN category cp ON cp.ID = c.parentID INNER JOIN groups g ON g.ID = releases.groupID LEFT OUTER JOIN movieinfo mi ON mi.imdbID = releases.imdbID WHERE %s %s AND releases.passwordstatus <= %d ORDER BY postdate DESC %s", $usql, $exccatlist, $this->showPasswords(), $limit ) ); } /** * Get TV for my shows page. * * @param $usershows * @param $start * @param $num * @param $orderby * @param $maxage * @param array $excludedcats * * @return array */ public function getShowsRange($usershows, $start, $num, $orderby, $maxage = -1, $excludedcats = array()) { if ($start === false) { $limit = ''; } else { $limit = ' LIMIT ' . $num . ' OFFSET ' . $start; } $exccatlist = $maxagesql = ''; if (count($excludedcats) > 0) { $exccatlist = ' AND releases.categoryID NOT IN (' . implode(',', $excludedcats) . ')'; } $usql = $this->uSQL($usershows, 'rageID'); if ($maxage > 0) { if (DB_TYPE === 'mysql') { $maxagesql = sprintf(' AND releases.postdate > NOW() - INTERVAL %d DAY ', $maxage); } else { $maxagesql = sprintf(" AND releases.postdate > NOW() - INTERVAL '%d DAYS' ", $maxage); } } $order = $this->getBrowseOrder($orderby); return $this->db->query( sprintf( " SELECT releases.*, CONCAT(cp.title, '-', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, groups.name AS group_name, rn.ID AS nfoid, re.releaseID AS reid FROM releases LEFT OUTER JOIN releasevideo re ON re.releaseID = releases.ID INNER JOIN groups ON groups.ID = releases.groupID LEFT OUTER JOIN releasenfo rn ON rn.releaseID = releases.ID AND rn.nfo IS NOT NULL INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN category cp ON cp.ID = c.parentID WHERE %s %s AND releases.passwordstatus <= %d %s ORDER BY %s %s %s", $usql, $exccatlist, $this->showPasswords(), $maxagesql, $order[0], $order[1], $limit ) ); } /** * Get count for my shows page pagination. * * @param $usershows * @param $maxage * @param array $excludedcats * * @return int */ public function getShowsCount($usershows, $maxage = -1, $excludedcats = array()) { $exccatlist = $maxagesql = ''; if (count($excludedcats) > 0) { $exccatlist = ' AND releases.categoryID NOT IN (' . implode(',', $excludedcats) . ')'; } $usql = $this->uSQL($usershows, 'rageID'); if ($maxage > 0) { if (DB_TYPE === 'mysql') { $maxagesql = sprintf(' AND releases.postdate > NOW() - INTERVAL %d DAY ', $maxage); } else { $maxagesql = sprintf(" AND releases.postdate > NOW() - INTERVAL '%d DAYS' ", $maxage); } } $res = $this->db->queryOneRow( sprintf( ' SELECT COUNT(releases.ID) AS num FROM releases WHERE %s %s AND releases.passwordstatus <= %d %s', $usql, $exccatlist, $this->showPasswords(), $maxagesql ), true ); return ($res === false ? 0 : $res['num']); } /** * Get count for admin release list page. * * @return int */ public function getCount() { $res = $this->db->queryOneRow('SELECT COUNT(ID) AS num FROM releases'); return ($res === false ? 0 : $res['num']); } /** * Delete a release or multiple releases. * * @param int|string $id * @param bool $isGuid */ public function delete($id, $isGuid = false) { if (!is_array($id)) { $id = array($id); } foreach ($id as $identifier) { if ($isGuid) { $rel = $this->getByGuid($identifier); } else { $rel = $this->getById($identifier); } $this->fastDelete($rel['ID'], $rel['guid']); } } /** * Deletes a single release, and all the corresponding files. * * @param int $id release id * @param string $guid release guid */ public function fastDelete($id, $guid) { $nzb = new Enzebe(); // Delete NZB from disk. $nzbpath = $nzb->getNZBPath($guid); if (is_file($nzbpath)) { @unlink($nzbpath); } // Delete images. $ri = new ReleaseImage(); $ri->delete($guid); // Delete from DB. if (DB_TYPE === 'mysql') { $this->db->exec( sprintf( 'DELETE releases, releasenfo, releasecomment, usercart, releasefiles, releaseaudio, releasesubs, releasevideo, releaseextrafull FROM releases LEFT OUTER JOIN releasenfo ON releasenfo.releaseID = releases.ID LEFT OUTER JOIN releasecomment ON releasecomment.releaseID = releases.ID LEFT OUTER JOIN usercart ON usercart.releaseID = releases.ID LEFT OUTER JOIN releasefiles ON releasefiles.releaseID = releases.ID LEFT OUTER JOIN releaseaudio ON releaseaudio.releaseID = releases.ID LEFT OUTER JOIN releasesubs ON releasesubs.releaseID = releases.ID LEFT OUTER JOIN releasevideo ON releasevideo.releaseID = releases.ID LEFT OUTER JOIN releaseextrafull ON releaseextrafull.releaseID = releases.ID WHERE releases.ID = %d', $id ) ); } else { $this->db->exec('DELETE FROM releasenfo WHERE releaseID = ' . $id); $this->db->exec('DELETE FROM releasecomment WHERE releaseID = ' . $id); $this->db->exec('DELETE FROM usercart WHERE releaseID = ' . $id); $this->db->exec('DELETE FROM releasefiles WHERE releaseID = ' . $id); $this->db->exec('DELETE FROM releaseaudio WHERE releaseID = ' . $id); $this->db->exec('DELETE FROM releasesubs WHERE releaseID = ' . $id); $this->db->exec('DELETE FROM releasevideo WHERE releaseID = ' . $id); $this->db->exec('DELETE FROM releaseextrafull WHERE releaseID = ' . $id); $this->db->exec('DELETE FROM releases WHERE ID = ' . $id); } } /** * Used for release edit page on site. * * @param $id * @param $name * @param $searchname * @param $fromname * @param $category * @param $parts * @param $grabs * @param $size * @param $posteddate * @param $addeddate * @param $rageID * @param $seriesfull * @param $season * @param $episode * @param $imdbID * @param $anidbID */ public function update( $id, $name, $searchname, $fromname, $category, $parts, $grabs, $size, $posteddate, $addeddate, $rageID, $seriesfull, $season, $episode, $imdbID, $anidbID ) { $this->db->exec( sprintf( 'UPDATE releases SET name = %s, searchname = %s, fromname = %s, categoryID = %d, totalpart = %d, grabs = %d, size = %s, postdate = %s, adddate = %s, rageID = %d, seriesfull = %s, season = %s, episode = %s, imdbID = %d, anidbID = %d WHERE ID = %d', $this->db->escapeString($name), $this->db->escapeString($searchname), $this->db->escapeString($fromname), $category, $parts, $grabs, $this->db->escapeString($size), $this->db->escapeString($posteddate), $this->db->escapeString($addeddate), $rageID, $this->db->escapeString($seriesfull), $this->db->escapeString($season), $this->db->escapeString($episode), $imdbID, $anidbID, $id ) ); } /** * Used for updating releases on site. * * @param $guids * @param $category * @param $grabs * @param $rageID * @param $season * @param $imdbID * * @return array|bool|int */ public function updatemulti($guids, $category, $grabs, $rageID, $season, $imdbID) { if (!is_array($guids) || sizeof($guids) < 1) { return false; } $update = array( 'categoryID' => (($category == '-1') ? '' : $category), 'grabs' => $grabs, 'rageID' => $rageID, 'season' => $season, 'imdbID' => $imdbID ); $updateSql = array(); foreach ($update as $updk => $updv) { if ($updv != '') { $updateSql[] = sprintf($updk . '=%s', $this->db->escapeString($updv)); } } if (count($updateSql) < 1) { return -1; } $updateGuids = array(); foreach ($guids as $guid) { $updateGuids[] = $this->db->escapeString($guid); } return $this->db->query( sprintf( ' UPDATE releases SET %s WHERE guid IN (%s)', implode(', ', $updateSql), implode(', ', $updateGuids) ) ); } /** * Creates part of a query for some functions. * * @param $userquery * @param $type * * @return string */ public function uSQL($userquery, $type) { $usql = '(1=2 '; foreach ($userquery as $u) { $usql .= sprintf('OR (releases.%s = %d', $type, $u[$type]); if ($u['categoryID'] != '') { $catsArr = explode('|', $u['categoryID']); if (count($catsArr) > 1) { $usql .= sprintf(' AND releases.categoryID IN (%s)', implode(',', $catsArr)); } else { $usql .= sprintf(' AND releases.categoryID = %d', $catsArr[0]); } } $usql .= ') '; } $usql .= ') '; return $usql; } /** * Creates part of a query for searches based on the type of search. * * @param $search * @param $type * * @return string */ public function searchSQL($search, $type) { // If the query starts with a ^ or ! it indicates the search is looking for items which start with the term // still do the fulltext match, but mandate that all items returned must start with the provided word. $words = explode(' ', $search); //only used to get a count of words $searchwords = $searchsql = ''; $intwordcount = 0; if (count($words) > 0) { if ($type === 'name' || $type === 'searchname') { //at least 1 term needs to be mandatory if (!preg_match('/[+|!|^]/', $search)) { $search = '+' . $search; $words = explode(' ', $search); } foreach ($words as $word) { $word = trim(rtrim(trim($word), '-')); $word = str_replace('!', '+', $word); $word = str_replace('^', '+', $word); $word = str_replace("'", "\\'", $word); if ($word !== '' && $word !== '-' && strlen($word) >= 2) { $searchwords .= sprintf('%s ', $word); } } $searchwords = trim($searchwords); $searchsql .= sprintf(" AND MATCH(rs.name, rs.searchname) AGAINST('%s' IN BOOLEAN MODE)", $searchwords ); } if ($searchwords === '') { $words = explode(' ', $search); $like = 'ILIKE'; if (DB_TYPE === 'mysql') { $like = 'LIKE'; } foreach ($words as $word) { if ($word != '') { $word = trim(rtrim(trim($word), '-')); if ($intwordcount == 0 && (strpos($word, '^') === 0)) { $searchsql .= sprintf( ' AND releases.%s %s %s', $type, $like, $this->db->escapeString( substr($word, 1) . '%' ) ); } else if (substr($word, 0, 2) == '--') { $searchsql .= sprintf( ' AND releases.%s NOT %s %s', $type, $like, $this->db->escapeString( '%' . substr($word, 2) . '%' ) ); } else { $searchsql .= sprintf( ' AND releases.%s %s %s', $type, $like, $this->db->escapeString( '%' . $word . '%' ) ); } $intwordcount++; } } } return $searchsql; } } // Creates part of a query for searches requiring the categoryID's. public function categorySQL($cat) { $catsrch = ''; if (count($cat) > 0 && $cat[0] != -1) { $categ = new Category(); $catsrch = ' AND ('; foreach ($cat as $category) { if ($category != -1) { if ($categ->isParent($category)) { $children = $categ->getChildren($category); $chlist = '-99'; foreach ($children as $child) { $chlist .= ', ' . $child['ID']; } if ($chlist != '-99') { $catsrch .= ' releases.categoryID IN (' . $chlist . ') OR '; } } else { $catsrch .= sprintf(' releases.categoryID = %d OR ', $category); } } } $catsrch .= '1=2 )'; } return $catsrch; } // Function for searching on the site (by subject, searchname or advanced). public function search($searchname, $usenetname, $postername, $groupname, $cat = array(-1), $sizefrom, $sizeto, $hasnfo, $hascomments, $daysnew, $daysold, $offset = 0, $limit = 1000, $orderby = '', $maxage = -1, $excludedcats = array(), $type = 'basic') { if ($type !== 'advanced') { $catsrch = $this->categorySQL($cat); } else { $catsrch = ''; if ($cat != '-1') { $catsrch = sprintf(' AND (releases.categoryID = %d) ', $cat); } } $daysnewsql = $daysoldsql = $maxagesql = $groupIDsql = $parentcatsql = ''; $searchnamesql = ($searchname != '-1' ? $this->searchSQL($searchname, 'searchname') : ''); $usenetnamesql = ($usenetname != '-1' ? $this->searchSQL($usenetname, 'name') : ''); $posternamesql = ($postername != '-1' ? $this->searchSQL($postername, 'fromname') : ''); $hasnfosql = ($hasnfo != '0' ? ' AND releases.nfostatus = 1 ' : ''); $hascommentssql = ($hascomments != '0' ? ' AND releases.comments > 0 ' : ''); $exccatlist = (count($excludedcats) > 0 ? ' AND releases.categoryID NOT IN (' . implode(',', $excludedcats) . ')' : ''); if ($daysnew != '-1') { if (DB_TYPE === 'mysql') { $daysnewsql = sprintf(' AND releases.postdate < (NOW() - INTERVAL %d DAY) ', $daysnew); } else { $daysnewsql = sprintf(" AND releases.postdate < NOW() - INTERVAL '%d DAYS' ", $daysnew); } } if ($daysold != '-1') { if (DB_TYPE === 'mysql') { $daysoldsql = sprintf(' AND releases.postdate > (NOW() - INTERVAL %d DAY) ', $daysold); } else { $daysoldsql = sprintf(" AND releases.postdate > NOW() - INTERVAL '%d DAYS' ", $daysold); } } if ($maxage > 0) { if (DB_TYPE === 'mysql') { $maxagesql = sprintf(' AND releases.postdate > (NOW() - INTERVAL %d DAY) ', $maxage); } else { $maxagesql = sprintf(" AND releases.postdate > NOW() - INTERVAL '%d DAYS' ", $maxage); } } if ($groupname != '-1') { $groupID = $this->functions->getIDByName($groupname); $groupIDsql = sprintf(' AND releases.groupID = %d ', $groupID); } $sizefromsql = ''; switch ($sizefrom) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '10': case '11': $sizefromsql = ' AND releases.size > ' . (string)(104857600 * (int)$sizefrom) . ' '; break; default: break; } $sizetosql = ''; switch ($sizeto) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '10': case '11': $sizetosql = ' AND releases.size < ' . (string)(104857600 * (int)$sizeto) . ' '; break; default: break; } if ($orderby == '') { $order[0] = 'postdate '; $order[1] = 'desc '; } else { $order = $this->getBrowseOrder($orderby); } $sql = sprintf( "SELECT * FROM (SELECT releases.*, CONCAT(cp.title, ' > ', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, groups.name AS group_name, rn.ID AS nfoid, re.releaseID AS reid, cp.ID AS categoryparentID FROM releases INNER JOIN releasesearch rs on rs.releaseID = releases.ID LEFT OUTER JOIN releasevideo re ON re.releaseID = releases.ID LEFT OUTER JOIN releasenfo rn ON rn.releaseID = releases.ID INNER JOIN groups ON groups.ID = releases.groupID INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN category cp ON cp.ID = c.parentID WHERE releases.passwordstatus <= %d %s %s %s %s %s %s %s %s %s %s %s %s %s) r ORDER BY r.%s %s LIMIT %d OFFSET %d", $this->showPasswords(), $searchnamesql, $usenetnamesql, $maxagesql, $posternamesql, $groupIDsql, $sizefromsql, $sizetosql, $hasnfosql, $hascommentssql, $catsrch, $daysnewsql, $daysoldsql, $exccatlist, $order[0], $order[1], $limit, $offset ); $wherepos = strpos($sql, 'WHERE'); $countres = $this->db->queryOneRow( 'SELECT COUNT(releases.ID) AS num FROM releases INNER JOIN releasesearch rs on rs.releaseID = releases.ID ' . substr($sql, $wherepos, strrpos($sql, ')') - $wherepos) ); $res = $this->db->query($sql); if (count($res) > 0) { $res[0]['_totalrows'] = $countres['num']; } return $res; } public function searchbyrageID($rageID, $series = '', $episode = '', $offset = 0, $limit = 100, $name = '', $cat = array(-1), $maxage = -1) { $rageIDsql = $maxagesql = ''; if ($rageID != '-1') { $rageIDsql = sprintf(' AND rageID = %d ', $rageID); } if ($series != '') { // Exclude four digit series, which will be the year 2010 etc. if (is_numeric($series) && strlen($series) != 4) { $series = sprintf('S%02d', $series); } $series = sprintf(' AND UPPER(releases.season) = UPPER(%s)', $this->db->escapeString($series)); } if ($episode != '') { if (is_numeric($episode)) { $episode = sprintf('E%02d', $episode); } $like = 'ILIKE'; if (DB_TYPE === 'mysql') { $like = 'LIKE'; } $episode = sprintf(' AND releases.episode %s %s', $like, $this->db->escapeString('%' . $episode . '%')); } $searchsql = ''; if ($name !== '') { $searchsql = $this->searchSQL($name, 'searchname'); } $catsrch = $this->categorySQL($cat); if ($maxage > 0) { if (DB_TYPE === 'mysql') { $maxagesql = sprintf(' AND releases.postdate > NOW() - INTERVAL %d DAY ', $maxage); } else { $maxagesql = sprintf(" AND releases.postdate > NOW() - INTERVAL '%d DAYS' ", $maxage); } } $sql = sprintf("SELECT releases.*, concat(cp.title, ' > ', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, groups.name AS group_name, rn.ID AS nfoid, re.releaseID AS reid FROM releases INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN groups ON groups.ID = releases.groupID INNER JOIN releasesearch rs on rs.releaseID = releases.ID LEFT OUTER JOIN releasevideo re ON re.releaseID = releases.ID LEFT OUTER JOIN releasenfo rn ON rn.releaseID = releases.ID AND rn.nfo IS NOT NULL INNER JOIN category cp ON cp.ID = c.parentID WHERE releases.passwordstatus <= %d %s %s %s %s %s %s ORDER BY postdate DESC LIMIT %d OFFSET %d", $this->showPasswords(), $rageIDsql, $series, $episode, $searchsql, $catsrch, $maxagesql, $limit, $offset); $orderpos = strpos($sql, 'ORDER BY'); $wherepos = strpos($sql, 'WHERE'); $sqlcount = 'SELECT COUNT(releases.ID) AS num FROM releases INNER JOIN releasesearch rs on rs.releaseID = releases.ID ' . substr($sql, $wherepos, $orderpos - $wherepos); $countres = $this->db->queryOneRow($sqlcount); $res = $this->db->query($sql); if (count($res) > 0) { $res[0]['_totalrows'] = $countres['num']; } return $res; } public function searchbyanidbID($anidbID, $epno = '', $offset = 0, $limit = 100, $name = '', $cat = array(-1), $maxage = -1) { $anidbID = ($anidbID > -1) ? sprintf(' AND anidbID = %d ', $anidbID) : ''; $like = 'ILIKE'; if (DB_TYPE === 'mysql') { $like = 'LIKE'; } is_numeric($epno) ? $epno = sprintf( " AND releases.episode %s '%s' ", $like, $this->db->escapeString( '%' . $epno . '%' ) ) : ''; $searchsql = ''; if ($name !== '') { $searchsql = $this->searchSQL($name, 'searchname'); } $catsrch = $this->categorySQL($cat); $maxagesql = ''; if ($maxage > 0) { if (DB_TYPE === 'mysql') { $maxagesql = sprintf(' AND releases.postdate > NOW() - INTERVAL %d DAY ', $maxage); } else { $maxagesql = sprintf(" AND releases.postdate > NOW() - INTERVAL '%d DAYS' ", $maxage); } } $sql = sprintf("SELECT releases.*, CONCAT(cp.title, ' > ', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, groups.name AS group_name, rn.ID AS nfoid FROM releases INNER JOIN releasesearch rs on rs.releaseID = releases.ID INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN groups ON groups.ID = releases.groupID LEFT OUTER JOIN releasenfo rn ON rn.releaseID = releases.ID and rn.nfo IS NOT NULL INNER JOIN category cp ON cp.ID = c.parentID WHERE releases.passwordstatus <= %d %s %s %s %s %s ORDER BY postdate DESC LIMIT %d OFFSET %d", $this->showPasswords(), $anidbID, $epno, $searchsql, $catsrch, $maxage, $limit, $offset); $orderpos = strpos($sql, 'ORDER BY'); $wherepos = strpos($sql, 'WHERE'); $sqlcount = 'SELECT COUNT(releases.ID) AS num FROM releases INNER JOIN releasesearch rs on rs.releaseID = releases.ID ' . substr($sql, $wherepos, $orderpos - $wherepos); $countres = $this->db->queryOneRow($sqlcount); $res = $this->db->query($sql); if (count($res) > 0) { $res[0]['_totalrows'] = $countres['num']; } return $res; } public function searchbyimdbID($imdbID, $offset = 0, $limit = 100, $name = '', $cat = array(-1), $maxage = -1) { if ($imdbID != '-1' && is_numeric($imdbID)) { // Pad ID with zeros just in case. $imdbID = str_pad($imdbID, 7, '0', STR_PAD_LEFT); $imdbID = sprintf(' AND imdbID = %d ', $imdbID); } else { $imdbID = ''; } $searchsql = ''; if ($name !== '') { $searchsql = $this->searchSQL($name, 'searchname'); } $catsrch = $this->categorySQL($cat); if ($maxage > 0) { if (DB_TYPE === 'mysql') { $maxage = sprintf(' AND releases.postdate > NOW() - INTERVAL %d DAY ', $maxage); } else { $maxage = sprintf(" AND releases.postdate > NOW() - INTERVAL '%d DAYS ", $maxage); } } else { $maxage = ''; } $sql = sprintf("SELECT releases.*, concat(cp.title, ' > ', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, groups.name AS group_name, rn.ID AS nfoid FROM releases INNER JOIN groups ON groups.ID = releases.groupID INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN releasesearch rs on rs.releaseID = releases.ID LEFT OUTER JOIN releasenfo rn ON rn.releaseID = releases.ID AND rn.nfo IS NOT NULL INNER JOIN category cp ON cp.ID = c.parentID WHERE releases.passwordstatus <= %d %s %s %s %s ORDER BY postdate DESC LIMIT %d OFFSET %d", $this->showPasswords(), $searchsql, $imdbID, $catsrch, $maxage, $limit, $offset); $orderpos = strpos($sql, 'ORDER BY'); $wherepos = strpos($sql, 'WHERE'); $sqlcount = 'SELECT COUNT(releases.ID) AS num FROM releases INNER JOIN releasesearch rs on rs.releaseID = releases.ID ' . substr($sql, $wherepos, $orderpos - $wherepos); $countres = $this->db->queryOneRow($sqlcount); $res = $this->db->query($sql); if (count($res) > 0) { $res[0]['_totalrows'] = $countres['num']; } return $res; } public function searchSimilar($currentid, $name, $limit = 6, $excludedcats = array()) { // Get the category for the parent of this release. $currRow = $this->getById($currentid); $cat = new Category(); $catrow = $cat->getById($currRow['categoryID']); $parentCat = $catrow['parentID']; $name = $this->getSimilarName($name); $results = $this->search( $name, -1, -1, -1, array($parentCat), -1, -1, 0, 0, -1, -1, 0, $limit, '', -1, $excludedcats ); if (!$results) { return $results; } $ret = array(); foreach ($results as $res) { if ($res['ID'] != $currentid && $res['categoryparentID'] == $parentCat) { $ret[] = $res; } } return $ret; } public function getSimilarName($name) { $words = str_word_count(str_replace(array('.', '_'), ' ', $name), 2); $firstwords = array_slice($words, 0, 3); return implode(' ', $firstwords); } public function getByGuid($guid) { if (is_array($guid)) { $tmpguids = array(); foreach ($guid as $g) { $tmpguids[] = $this->db->escapeString($g); } $gsql = sprintf('guid IN (%s)', implode(',', $tmpguids)); } else { $gsql = sprintf('guid = %s', $this->db->escapeString($guid)); } $sql = sprintf("SELECT releases.*, CONCAT(cp.title, ' > ', c.title) AS category_name, CONCAT(cp.ID, ',', c.ID) AS category_ids, groups.name AS group_name FROM releases INNER JOIN groups ON groups.ID = releases.groupID INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN category cp ON cp.ID = c.parentID WHERE %s ", $gsql); return (is_array($guid)) ? $this->db->query($sql) : $this->db->queryOneRow($sql); } // Writes a zip file of an array of release guids directly to the stream. public function getZipped($guids) { $nzb = new Enzebe(); $zipfile = new ZipFile(); foreach ($guids as $guid) { $nzbpath = $nzb->getNZBPath($guid); if (is_file($nzbpath)) { ob_start(); @readgzfile($nzbpath); $nzbfile = ob_get_contents(); ob_end_clean(); $filename = $guid; $r = $this->getByGuid($guid); if ($r) { $filename = $r['searchname']; } $zipfile->addFile($nzbfile, $filename . '.nzb'); } } return $zipfile->file(); } public function getbyrageID($rageID, $series = '', $episode = '') { if ($series != '') { // Exclude four digit series, which will be the year 2010 etc. if (is_numeric($series) && strlen($series) != 4) { $series = sprintf('S%02d', $series); } $series = sprintf(' AND UPPER(releases.season) = UPPER(%s)', $this->db->escapeString($series)); } if ($episode != '') { if (is_numeric($episode)) { $episode = sprintf('E%02d', $episode); } $episode = sprintf(' AND UPPER(releases.episode) = UPPER(%s)', $this->db->escapeString($episode)); } return $this->db->queryOneRow(sprintf("SELECT releases.*, CONCAT(cp.title, ' > ', c.title) AS category_name, groups.name AS group_name FROM releases INNER JOIN groups ON groups.ID = releases.groupID INNER JOIN category c ON c.ID = releases.categoryID INNER JOIN category cp ON cp.ID = c.parentID WHERE releases.passwordstatus <= %d AND rageID = %d %s %s", $this->showPasswords(), $rageID, $series, $episode)); } public function removerageIDFromReleases($rageID) { $res = $this->db->queryOneRow(sprintf('SELECT COUNT(ID) AS num FROM releases WHERE rageID = %d', $rageID)); $this->db->exec(sprintf('UPDATE releases SET rageID = -1, seriesfull = NULL, season = NULL, episode = NULL WHERE rageID = %d', $rageID)); return $res['num']; } public function removeanidbIDFromReleases($anidbID) { $res = $this->db->queryOneRow(sprintf('SELECT COUNT(ID) AS num FROM releases WHERE anidbID = %d', $anidbID)); $this->db->exec(sprintf('UPDATE releases SET anidbID = -1, episode = NULL, tvtitle = NULL, tvairdate = NULL WHERE anidbID = %d', $anidbID)); return $res['num']; } public function getById($id) { return $this->db->queryOneRow(sprintf('SELECT releases.*, groups.name AS group_name FROM releases INNER JOIN groups ON groups.ID = releases.groupID WHERE releases.ID = %d ', $id)); } public function getReleaseNfo($id, $incnfo = true) { if (DB_TYPE === 'mysql') { $uc = 'UNCOMPRESS(nfo)'; } else { $uc = 'nfo'; } $selnfo = ($incnfo) ? ", {$uc} AS nfo" : ''; return $this->db->queryOneRow( sprintf( 'SELECT ID, releaseID' . $selnfo . ' FROM releasenfo WHERE releaseID = %d AND nfo IS NOT NULL', $id ) ); } public function updateGrab($guid) { if ($this->updategrabs) { $this->db->exec(sprintf('UPDATE releases SET grabs = grabs + 1 WHERE guid = %s', $this->db->escapeString($guid))); } } // Sends releases back to other->misc. public function resetCategorize($where = '') { $this->db->exec('UPDATE releases SET categoryID = 7010, iscategorized = 0 ' . $where); } // Categorizes releases. // $type = name or searchname // Returns the quantity of categorized releases. public function categorizeRelease($type, $where = '', $echooutput = false) { $cat = new Category(); $relcount = 0; $resrel = $this->db->queryDirect('SELECT ID, ' . $type . ', groupID FROM releases ' . $where); $total = 0; if ($resrel !== false) { $total = $resrel->rowCount(); } if ($total > 0) { foreach ($resrel as $rowrel) { $catId = $cat->determineCategory($rowrel[$type], $rowrel['groupID']); $this->db->exec(sprintf('UPDATE releases SET categoryID = %d, iscategorized = 1 WHERE ID = %d', $catId, $rowrel['ID'])); $relcount++; if ($this->echooutput) { $this->consoleTools->overWritePrimary( 'Categorizing: ' . $this->consoleTools->percentString($relcount, $total) ); } } } if ($this->echooutput !== false && $relcount > 0) { echo "\n"; } return $relcount; } public function processReleasesStage1($groupID) { require_once(WWW_DIR . "/lib/binaries.php"); $db = new DB; $currTime_ori = $db->queryOneRow("SELECT NOW() as now"); $cat = new Category(); $nzb = new Enzebe(); $s = new Sites(); $releaseRegex = new ReleaseRegex(); $page = new Page(); $groups = new Groups; $retcount = 0; echo $s->getLicense(); echo "\n\nStarting release update process (" . date("Y-m-d H:i:s") . ")\n"; if (!file_exists($page->site->nzbpath)) { echo "Bad or missing nzb directory - " . $page->site->nzbpath; return -1; } $this->checkRegexesUptoDate($page->site->latestregexurl, $page->site->latestregexrevision, $page->site->newznabID); // // Get all regexes for all groups which are to be applied to new binaries // in order of how they should be applied // $releaseRegex->get(); echo "Stage 1 : Applying regex to binaries\n"; $activeGroups = $groups->getActive(false); foreach ($activeGroups as $groupArr) { //check if regexes have already been applied during update binaries if ($groupArr['regexmatchonly'] == 1) continue; $groupRegexes = $releaseRegex->getForGroup($groupArr['name']); echo "Stage 1 : Applying " . sizeof($groupRegexes) . " regexes to group " . $groupArr['name'] . "\n"; // Get out all binaries of STAGE0 for current group $newUnmatchedBinaries = array(); $ressql = sprintf("SELECT binaries.ID, binaries.name, binaries.date, binaries.totalParts, binaries.procstat, binaries.fromname from binaries where groupID = %d and procstat IN (%d,%d) and regexID IS NULL order by binaries.date asc", $groupArr['ID'], Releases::PROCSTAT_NEW, Releases::PROCSTAT_TITLENOTMATCHED); $resbin = $db->queryDirect($ressql); $matchedbins = 0; while ($rowbin = $db->getAssocArray($resbin)) { $regexMatches = array(); foreach ($groupRegexes as $groupRegex) { $regexCheck = $releaseRegex->performMatch($groupRegex, $rowbin['name']); if ($regexCheck !== false) { $regexMatches = $regexCheck; break; } } if (!empty($regexMatches)) { $matchedbins++; $relparts = explode("/", $regexMatches['parts']); $db->exec(sprintf("update binaries set relname = replace(%s, '_', ' '), relpart = %d, reltotalpart = %d, procstat=%d, categoryID=%s, regexID=%d, reqID=%s where ID = %d", $db->escapeString($regexMatches['name']), $relparts[0], $relparts[1], Releases::PROCSTAT_TITLEMATCHED, $regexMatches['regcatid'], $regexMatches['regexID'], $db->escapeString($regexMatches['reqID']), $rowbin["ID"] ) ); } else { if ($rowbin['procstat'] == Releases::PROCSTAT_NEW) $newUnmatchedBinaries[] = $rowbin['ID']; } } //mark as not matched if (!empty($newUnmatchedBinaries)) $db->exec(sprintf("update binaries set procstat=%d where ID IN (%s)", Releases::PROCSTAT_TITLENOTMATCHED, implode(',', $newUnmatchedBinaries))); } } public function processReleasesStage2($groupID) { // // Move all binaries from releases which have the correct number of files on to the next stage. // echo "Stage 2 : Marking binaries where all parts are available"; $result = $db->queryDirect(sprintf("SELECT relname, date, SUM(reltotalpart) AS reltotalpart, groupID, reqID, fromname, SUM(num) AS num, coalesce(g.minfilestoformrelease, s.minfilestoformrelease) as minfilestoformrelease FROM ( SELECT relname, reltotalpart, groupID, reqID, fromname, max(date) as date, COUNT(ID) AS num FROM binaries WHERE procstat = %s GROUP BY relname, reltotalpart, groupID, reqID, fromname ORDER BY NULL ) x left outer join groups g on g.ID = x.groupID inner join ( select value as minfilestoformrelease from site where setting = 'minfilestoformrelease' ) s GROUP BY relname, groupID, reqID, fromname, minfilestoformrelease ORDER BY NULL", Releases::PROCSTAT_TITLEMATCHED)); while ($row = $db->getAssocArray($result)) { $retcount++; // // Less than the site permitted number of files in a release. Dont discard it, as it may // be part of a set being uploaded. // if ($row["num"] < $row["minfilestoformrelease"]) { //echo "Number of files in release ".$row["relname"]." less than site/group setting (".$row['num']."/".$row["minfilestoformrelease"].")\n"; $db->exec(sprintf("update binaries set procattempts = procattempts + 1 where relname = %s and procstat = %d and groupID = %d and fromname = %s", $db->escapeString($row["relname"]), Releases::PROCSTAT_TITLEMATCHED, $row["groupID"], $db->escapeString($row["fromname"]))); } // // There are the same or more files in our release than the number of files specified // in the message subject so go ahead and make a release // elseif ($row["num"] >= $row["reltotalpart"]) { $incomplete = false; if ($row['reltotalpart'] == 0 && strtotime($currTime_ori['now']) - strtotime($row['date']) < 14400) { $incomplete = true; } else { // Check that the binary is complete $binlist = $db->query(sprintf("SELECT binaries.ID, totalParts, date, COUNT(DISTINCT parts.messageID) AS num FROM binaries, parts WHERE binaries.ID=parts.binaryID AND binaries.relname = %s AND binaries.procstat = %d AND binaries.groupID = %d AND binaries.fromname = %s GROUP BY binaries.ID ORDER BY NULL", $db->escapeString($row["relname"]), Releases::PROCSTAT_TITLEMATCHED, $row["groupID"], $db->escapeString($row["fromname"]))); foreach ($binlist as $rowbin) { if ($rowbin['num'] < $rowbin['totalParts']) { // Allow to binary to release if posted to usenet longer than four hours ago and we still don't have all the parts if (!(strtotime($currTime_ori['now']) - strtotime($rowbin['date']) > 14400)) { $incomplete = true; break; } } } } if (!$incomplete) { // // Right number of files, but see if the binary is a allfilled/reqid post, in which case it needs its name looked up // if ($row['reqID'] != '' && $page->site->reqidurl != "") { // // Try and get the name using the group // $binGroup = $db->queryOneRow(sprintf("SELECT name FROM groups WHERE ID = %d", $row["groupID"])); $newtitle = $this->getReleaseNameForReqId($page->site->reqidurl, $page->site->newznabID, $binGroup["name"], $row["reqID"]); // // if the feed/group wasnt supported by the scraper, then just use the release name as the title. // if ($newtitle == "no feed") { $newtitle = $row["relname"]; } // // Valid release with right number of files and title now, so move it on // if ($newtitle != "") { $db->exec(sprintf("update binaries set relname = %s, procstat=%d where relname = %s and procstat = %d and groupID = %d and fromname=%s", $db->escapeString($newtitle), Releases::PROCSTAT_READYTORELEASE, $db->escapeString($row["relname"]), Releases::PROCSTAT_TITLEMATCHED, $row["groupID"], $db->escapeString($row["fromname"]) ) ); } else { // // Item not found, if the binary was added to the index yages ago, then give up. // $maxaddeddate = $db->queryOneRow(sprintf("SELECT NOW() as now, MAX(dateadded) as dateadded FROM binaries WHERE relname = %s and procstat = %d and groupID = %d and fromname=%s", $db->escapeString($row["relname"]), Releases::PROCSTAT_TITLEMATCHED, $row["groupID"], $db->escapeString($row["fromname"]) ) ); // // If added to the index over 48 hours ago, give up trying to determine the title // if (strtotime($maxaddeddate['now']) - strtotime($maxaddeddate['dateadded']) > (60 * 60 * 48)) { $db->exec(sprintf("update binaries set procstat=%d where relname = %s and procstat = %d and groupID = %d and fromname=%s", Releases::PROCSTAT_NOREQIDNAMELOOKUPFOUND, $db->escapeString($row["relname"]), Releases::PROCSTAT_TITLEMATCHED, $row["groupID"], $db->escapeString($row["fromname"]) ) ); } } } else { $db->exec(sprintf("update binaries set procstat=%d where relname = %s and procstat = %d and groupID = %d and fromname=%s", Releases::PROCSTAT_READYTORELEASE, $db->escapeString($row["relname"]), Releases::PROCSTAT_TITLEMATCHED, $row["groupID"], $db->escapeString($row["fromname"]) ) ); } } } // // Theres less than the expected number of files, so update the attempts and move on. // else { // pointless updating of attempts, as was creating a lot of database writes for people regex groups with posts without part numbering. //$db->exec(sprintf("update binaries set procattempts = procattempts + 1 where relname = %s and procstat = %d and groupID = %d and fromname=%s", $db->escapeString($row["relname"]), Releases::PROCSTAT_TITLEMATCHED, $row["groupID"], $db->escapeString($row["fromname"]) )); } if ($retcount % 100 == 0) echo "."; } $retcount = 0; } public function processReleasesStage3($groupID) { $minsizecounts = $maxsizecounts = $minfilecounts = 0; // Set table names if ($this->tablepergroup === 1) { if ($groupID == '') { exit($this->c->error("\nYou are using 'tablepergroup', you must use releases_threaded.py")); } $group['cname'] = 'collections_' . $groupID; $group['bname'] = 'binaries_' . $groupID; $group['pname'] = 'parts_' . $groupID; } else { $group['cname'] = 'collections'; $group['bname'] = 'binaries'; $group['pname'] = 'parts'; } if ($this->echooutput) { $this->c->doEcho($this->c->header("Stage 3 -> Creating releases from complete binaries.")); } $stage3 = TIME(); if ($groupID == '') { $groupIDs = $this->groups->getActiveIDs(); foreach ($groupIDs as $groupID) { $res = $this->db->query( 'SELECT ID FROM ' . $group['cname'] . ' WHERE filecheck = 3 AND filesize > 0 AND groupID = ' . $groupID['ID'] ); if (count($res) > 0) { $minsizecount = 0; if (DB_TYPE === 'mysql') { $mscq = $this->db->exec( "UPDATE " . $group['cname'] . " c LEFT JOIN (SELECT g.ID, COALESCE(g.minsizetoformrelease, s.minsizetoformrelease) AS minsizetoformrelease FROM groups g INNER JOIN ( SELECT value AS minsizetoformrelease FROM settings WHERE setting = 'minsizetoformrelease' ) s ) g ON g.ID = c.groupID SET c.filecheck = 5 WHERE g.minsizetoformrelease != 0 AND c.filecheck = 3 AND c.filesize < g.minsizetoformrelease AND c.filesize > 0 AND groupID = " . $groupID['ID'] ); if ($mscq !== false) { $minsizecount = $mscq->rowCount(); } } else { $s = $this->db->queryOneRow( "SELECT GREATEST(s.value::integer, g.minsizetoformrelease::integer) as size FROM settings s, groups g WHERE s.setting = 'minsizetoformrelease' AND g.ID = " . $groupID['ID'] ); if ($s['size'] > 0) { $mscq = $this->db->exec( sprintf( 'UPDATE ' . $group['cname'] . ' SET filecheck = 5 WHERE filecheck = 3 AND filesize < %d AND filesize > 0 AND groupID = ' . $groupID['ID'], $s['size'] ) ); if ($mscq !== false) { $minsizecount = $mscq->rowCount(); } } } if ($minsizecount < 1) { $minsizecount = 0; } $minsizecounts = $minsizecount + $minsizecounts; $maxfilesizeres = $this->db->queryOneRow("SELECT value FROM settings WHERE setting = 'maxsizetoformrelease'"); if ($maxfilesizeres['value'] != 0) { $mascq = $this->db->exec( sprintf( 'UPDATE ' . $group['cname'] . ' SET filecheck = 5 WHERE filecheck = 3 AND groupID = %d AND filesize > %d ', $groupID['ID'], $maxfilesizeres['value'] ) ); $maxsizecount = 0; if ($mascq !== false) { $maxsizecount = $mascq->rowCount(); } if ($maxsizecount < 1) { $maxsizecount = 0; } $maxsizecounts = $maxsizecount + $maxsizecounts; } $minfilecount = 0; if (DB_TYPE === 'mysql') { $mifcq = $this->db->exec( "UPDATE " . $group['cname'] . " c LEFT JOIN (SELECT g.ID, COALESCE(g.minfilestoformrelease, s.minfilestoformrelease) AS minfilestoformrelease FROM groups g INNER JOIN ( SELECT value AS minfilestoformrelease FROM settings WHERE setting = 'minfilestoformrelease' ) s ) g ON g.ID = c.groupID SET c.filecheck = 5 WHERE g.minfilestoformrelease != 0 AND c.filecheck = 3 AND c.totalfiles < g.minfilestoformrelease AND groupID = " . $groupID['ID'] ); if ($mifcq !== false) { $minfilecount = $mifcq->rowCount(); } } else { $f = $this->db->queryOneRow( "SELECT GREATEST(s.value::integer, g.minfilestoformrelease::integer) as files FROM settings s, groups g WHERE s.setting = 'minfilestoformrelease' AND g.ID = " . $groupID['ID'] ); if ($f['files'] > 0) { $mifcq = $this->db->exec( sprintf( 'UPDATE ' . $group['cname'] . ' SET filecheck = 5 WHERE filecheck = 3 AND filesize < %d AND filesize > 0 AND groupID = ' . $groupID['ID'], $s['size'] ) ); if ($mifcq !== false) { $minfilecount = $mifcq->rowCount(); } } } if ($minfilecount < 1) { $minfilecount = 0; } $minfilecounts = $minfilecount + $minfilecounts; } } } else { $res = $this->db->queryDirect( 'SELECT ID FROM ' . $group['cname'] . ' WHERE filecheck = 3 AND filesize > 0 AND groupID = ' . $groupID ); if ($res !== false && $res->rowCount() > 0) { $minsizecount = 0; if (DB_TYPE === 'mysql') { $mscq = $this->db->exec( "UPDATE " . $group['cname'] . " c LEFT JOIN (SELECT g.ID, coalesce(g.minsizetoformrelease, s.minsizetoformrelease) AS minsizetoformrelease FROM groups g INNER JOIN ( SELECT value AS minsizetoformrelease FROM settings WHERE setting = 'minsizetoformrelease' ) s ) g ON g.ID = c.groupID SET c.filecheck = 5 WHERE g.minsizetoformrelease != 0 AND c.filecheck = 3 AND c.filesize < g.minsizetoformrelease AND c.filesize > 0 AND groupID = " . $groupID ); if ($mscq !== false) { $minsizecount = $mscq->rowCount(); } } else { $s = $this->db->queryOneRow( "SELECT GREATEST(s.value::integer, g.minsizetoformrelease::integer) as size FROM settings s, groups g WHERE s.setting = 'minsizetoformrelease' AND g.ID = " . $groupID ); if ($s['size'] > 0) { $mscq = $this->db->exec( sprintf( 'UPDATE ' . $group['cname'] . ' SET filecheck = 5 WHERE filecheck = 3 AND filesize < %d AND filesize > 0 AND groupID = ' . $groupID, $s['size'] ) ); if ($mscq !== false) { $minsizecount = $mscq->rowCount(); } } } if ($minsizecount < 0) { $minsizecount = 0; } $minsizecounts = $minsizecount + $minsizecounts; $maxfilesizeres = $this->db->queryOneRow("SELECT value FROM settings WHERE setting = 'maxsizetoformrelease'"); if ($maxfilesizeres['value'] != 0) { $mascq = $this->db->exec( sprintf( 'UPDATE ' . $group['cname'] . ' SET filecheck = 5 WHERE filecheck = 3 AND filesize > %d ', $maxfilesizeres['value'] ) ); if ($mascq !== false) { $maxsizecount = $mascq->rowCount(); } if ($maxsizecount < 0) { $maxsizecount = 0; } $maxsizecounts = $maxsizecount + $maxsizecounts; } $minfilecount = 0; if (DB_TYPE === 'mysql') { $mifcq = $this->db->exec( "UPDATE " . $group['cname'] . " c LEFT JOIN (SELECT g.ID, coalesce(g.minfilestoformrelease, s.minfilestoformrelease) AS minfilestoformrelease FROM groups g INNER JOIN ( SELECT value AS minfilestoformrelease FROM settings WHERE setting = 'minfilestoformrelease' ) s ) g ON g.ID = c.groupID SET c.filecheck = 5 WHERE g.minfilestoformrelease != 0 AND c.filecheck = 3 AND c.totalfiles < g.minfilestoformrelease AND groupID = " . $groupID ); if ($mifcq !== false) { $minfilecount = $mifcq->rowCount(); } } else { $f = $this->db->queryOneRow( "SELECT GREATEST(s.value::integer, g.minfilestoformrelease::integer) as files FROM settings s, groups g WHERE s.setting = 'minfilestoformrelease' AND g.ID = " . $groupID ); if ($f['files'] > 0) { $mifcq = $this->db->exec( sprintf( 'UPDATE ' . $group['cname'] . ' SET filecheck = 5 WHERE filecheck = 3 AND filesize < %d AND filesize > 0 AND groupID = ' . $groupID, $s['size'] ) ); if ($mifcq !== false) { $minfilecount = $mifcq->rowCount(); } } } if ($minfilecount < 0) { $minfilecount = 0; } $minfilecounts = $minfilecount + $minfilecounts; } } $delcount = $minsizecounts + $maxsizecounts + $minfilecounts; if ($this->echooutput && $delcount > 0) { $this->c->doEcho( $this->c->primary( 'Deleted ' . number_format($delcount) . " collections smaller/larger than group/site settings." ) ); } if ($this->echooutput) { $this->c->doEcho($this->c->primary($this->consoleTools->convertTime(TIME() - $stage3)), true); } } public function processReleasesStage4($groupID) { $categorize = new Category(); $retcount = $duplicate = 0; $where = (!empty($groupID)) ? ' groupID = ' . $groupID . ' AND ' : ' '; // Set table names if ($this->tablepergroup === 1) { if ($groupID == '') { exit($this->c->error("\nYou are using 'tablepergroup', you must use releases_threaded.py")); } $group['cname'] = 'collections_' . $groupID; $group['bname'] = 'binaries_' . $groupID; $group['pname'] = 'parts_' . $groupID; } else { $group['cname'] = 'collections'; $group['bname'] = 'binaries'; $group['pname'] = 'parts'; } if ($this->echooutput) { $this->c->doEcho($this->c->header("Stage 4 -> Create releases.")); } $stage4 = TIME(); $rescol = $this->db->queryDirect( 'SELECT ' . $group['cname'] . '.*, groups.name AS gname FROM ' . $group['cname'] . ' INNER JOIN groups ON ' . $group['cname'] . '.groupID = groups.ID WHERE' . $where . 'filecheck = 3 AND filesize > 0 LIMIT ' . $this->stage5limit ); if ($rescol !== false && $this->echooutput) { echo $this->c->primary($rescol->rowCount() . " Collections ready to be converted to releases."); } if ($rescol !== false && $rescol->rowCount() > 0) { $predb = new PreDb($this->echooutput); foreach ($rescol as $rowcol) { $propername = true; $relid = false; $cleanRelName = str_replace(array('#', '@', '$', '%', '^', '§', '¨', '©', 'Ö'), '', $rowcol['subject']); $cleanerName = $this->releaseCleaning->releaseCleaner($rowcol['subject'], $rowcol['fromname'], $rowcol['filesize'], $rowcol['gname']); /* $ncarr = $this->collectionsCleaning->collectionsCleaner($subject, $rowcol['gname']); $cleanerName = $ncarr['subject']; $category = $ncarr['cat']; $relstat = $ncar['rstatus']; */ $fromname = trim($rowcol['fromname'], "'"); if (!is_array($cleanerName)) { $cleanName = $cleanerName; } else { $cleanName = $cleanerName['cleansubject']; $propername = $cleanerName['properlynamed']; } $relguid = sha1(uniqid('', true) . mt_rand()); $category = $categorize->determineCategory($cleanName, $rowcol['groupID']); $cleanRelName = utf8_encode($cleanRelName); $cleanName = utf8_encode($cleanName); $fromname = utf8_encode($fromname); // Look for duplicates, duplicates match on releases.name, releases.fromname and releases.size // A 1% variance in size is considered the same size when the subject and poster are the same $minsize = $rowcol['filesize'] * .99; $maxsize = $rowcol['filesize'] * 1.01; $dupecheck = $this->db->queryOneRow(sprintf('SELECT ID, guid FROM releases WHERE name = %s AND fromname = %s AND size BETWEEN %s AND %s', $this->db->escapeString($cleanRelName), $this->db->escapeString($fromname), $this->db->escapeString($minsize), $this->db->escapeString($maxsize))); if (!$dupecheck) { if ($propername == true) { $relid = $this->db->queryInsert( sprintf( 'INSERT INTO releases (name, searchname, totalpart, groupID, adddate, guid, rageID, postdate, fromname, size, passwordstatus, haspreview, categoryID, nfostatus, isrenamed, iscategorized) VALUES (%s, %s, %d, %d, NOW(), %s, -1, %s, %s, %s, %d, -1, %d, -1, 1, 1)', $this->db->escapeString($cleanRelName), $this->db->escapeString($cleanName), $rowcol['totalfiles'], $rowcol['groupID'], $this->db->escapeString($relguid), $this->db->escapeString($rowcol['date']), $this->db->escapeString($fromname), $this->db->escapeString($rowcol['filesize']), ($this->site->checkpasswordedrar == '1' ? -1 : 0), $category ) ); } else { $relid = $this->db->queryInsert( sprintf( 'INSERT INTO releases (name, searchname, totalpart, groupID, adddate, guid, rageID, postdate, fromname, size, passwordstatus, haspreview, categoryID, nfostatus, iscategorized) VALUES (%s, %s, %d, %d, NOW(), %s, -1, %s, %s, %s, %d, -1, %d, -1, 1)', $this->db->escapeString($cleanRelName), $this->db->escapeString($cleanName), $rowcol['totalfiles'], $rowcol['groupID'], $this->db->escapeString($relguid), $this->db->escapeString($rowcol['date']), $this->db->escapeString($fromname), $this->db->escapeString($rowcol['filesize']), ($this->site->checkpasswordedrar == '1' ? -1 : 0), $category ) ); } } if ($relid) { // try to match to predb here $predb->matchPre($cleanRelName, $relid); // Update collections table to say we inserted the release. $this->db->exec( sprintf( 'UPDATE ' . $group['cname'] . ' SET filecheck = 4, releaseID = %d WHERE ID = %d', $relid, $rowcol['ID'] ) ); $retcount++; if ($this->echooutput) { echo $this->c->primary('Added release ' . $cleanName); } } else if (isset($relid) && $relid == false) { $this->db->exec( sprintf( 'UPDATE ' . $group['cname'] . ' SET filecheck = 5 WHERE collectionhash = %s', $this->db->escapeString($rowcol['collectionhash']) ) ); $duplicate++; } } } if ($this->echooutput) { $this->c->doEcho( $this->c->primary( number_format($retcount) . ' Releases added and ' . number_format($duplicate) . ' marked for deletion in ' . $this->consoleTools->convertTime(TIME() - $stage4) ), true ); } return $retcount; } /* * Adding this in to delete releases before NZB's are created. */ public function processReleasesStage4dot5($groupID) { $minsizecount = $maxsizecount = $minfilecount = $catminsizecount = 0; if ($this->echooutput) { echo $this->c->header("Stage 4.5 -> Delete releases smaller/larger than minimum size/file count from group/site setting."); } $stage4dot5 = TIME(); // Delete smaller than min sizes $catresrel = $this->db->queryDirect('SELECT c.ID AS id, CASE WHEN c.minsize = 0 THEN cp.minsize ELSE c.minsize END AS minsize FROM category c INNER JOIN category cp ON cp.ID = c.parentID WHERE c.parentID IS NOT NULL'); foreach ($catresrel as $catrowrel) { if ($catrowrel['minsize'] > 0) { //printf("SELECT r.id, r.guid FROM releases r WHERE r.categoryID = %d AND r.size < %d\n", $catrowrel['ID'], $catrowrel['minsize']); $resrel = $this->db->queryDirect(sprintf('SELECT r.id, r.guid FROM releases r WHERE r.categoryID = %d AND r.size < %d', $catrowrel['ID'], $catrowrel['minsize'])); foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $catminsizecount++; } } } // Delete larger than max sizes if ($groupID == '') { $groupIDs = $this->groups->getActiveIDs(); foreach ($groupIDs as $groupID) { if (DB_TYPE === 'mysql') { $resrel = $this->db->queryDirect(sprintf("SELECT r.id, r.guid FROM releases r LEFT JOIN (SELECT g.ID, coalesce(g.minsizetoformrelease, s.minsizetoformrelease) AS minsizetoformrelease FROM groups g INNER JOIN ( SELECT value as minsizetoformrelease FROM settings WHERE setting = 'minsizetoformrelease' ) s WHERE g.ID = %s ) g ON g.ID = r.groupID WHERE g.minsizetoformrelease != 0 AND r.size < minsizetoformrelease AND r.groupID = %s", $groupID['ID'], $groupID['ID'])); } else { $resrel = array(); $s = $this->db->queryOneRow( "SELECT GREATEST(s.value::integer, g.minsizetoformrelease::integer) as size FROM settings s, groups g WHERE s.setting = 'minsizetoformrelease' AND g.ID = " . $groupID['ID'] ); if ($s['size'] > 0) { $resrel = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE size < %d AND groupID = %d', $s['size'], $groupID['ID'])); } } if ($resrel !== false && $resrel->rowCount() > 0) { foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $minsizecount++; } } $maxfilesizeres = $this->db->queryOneRow("SELECT value FROM settings WHERE setting = 'maxsizetoformrelease'"); if ($maxfilesizeres['value'] != 0) { $resrel = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE groupID = %d AND size > %d', $groupID['ID'], $maxfilesizeres['value'])); if ($resrel !== false && $resrel->rowCount() > 0) { foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $maxsizecount++; } } } if (DB_TYPE === 'mysql') { $resrel = $this->db->queryDirect(sprintf("SELECT r.id, r.guid FROM releases r LEFT JOIN (SELECT g.ID, coalesce(g.minfilestoformrelease, s.minfilestoformrelease) as minfilestoformrelease FROM groups g INNER JOIN ( SELECT value as minfilestoformrelease FROM settings WHERE setting = 'minfilestoformrelease' ) s WHERE g.ID = %d ) g ON g.ID = r.groupID WHERE g.minfilestoformrelease != 0 AND r.totalpart < minfilestoformrelease AND r.groupID = %d", $groupID['ID'], $groupID['ID'])); } else { $resrel = array(); $f = $this->db->queryOneRow( "SELECT GREATEST(s.value::integer, g.minfilestoformrelease::integer) as files FROM settings s, groups g WHERE s.setting = 'minfilestoformrelease' AND g.ID = " . $groupID['ID'] ); if ($f['files'] > 0) { $resrel = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE totalpart < %d AND groupID = %d', $f['files'], $groupID['ID'])); } } if ($resrel !== false && $resrel->rowCount() > 0) { foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $minfilecount++; } } } } else { if (DB_TYPE === 'mysql') { $resrel = $this->db->queryDirect(sprintf("SELECT r.id, r.guid FROM releases r LEFT JOIN (SELECT g.ID, coalesce(g.minsizetoformrelease, s.minsizetoformrelease) AS minsizetoformrelease FROM groups g INNER JOIN ( SELECT value AS minsizetoformrelease FROM settings WHERE setting = 'minsizetoformrelease' ) s WHERE g.ID = %d ) g ON g.ID = r.groupID WHERE g.minsizetoformrelease != 0 AND r.size < minsizetoformrelease AND r.groupID = %d", $groupID, $groupID)); } else { $resrel = array(); $s = $this->db->queryOneRow( "SELECT GREATEST(s.value::integer, g.minsizetoformrelease::integer) as size FROM settings s, groups g WHERE s.setting = 'minsizetoformrelease' AND g.ID = " . $groupID ); if ($s['size'] > 0) { $resrel = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE size < %d AND groupID = %d', $s['size'], $groupID)); } } if ($resrel !== false && $resrel->rowCount() > 0) { foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $minsizecount++; } } $maxfilesizeres = $this->db->queryOneRow("SELECT value FROM settings WHERE setting = 'maxsizetoformrelease'"); if ($maxfilesizeres['value'] != 0) { $resrel = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE groupID = %d AND size > %s', $groupID, $this->db->escapeString($maxfilesizeres['value']))); if ($resrel !== false && $resrel->rowCount() > 0) { foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $maxsizecount++; } } } if (DB_TYPE === 'mysql') { $resrel = $this->db->queryDirect(sprintf("SELECT r.id, r.guid FROM releases r LEFT JOIN (SELECT g.ID, coalesce(g.minfilestoformrelease, s.minfilestoformrelease) AS minfilestoformrelease FROM groups g INNER JOIN ( SELECT value AS minfilestoformrelease FROM settings WHERE setting = 'minfilestoformrelease' ) s WHERE g.ID = %d ) g ON g.ID = r.groupID WHERE g.minfilestoformrelease != 0 AND r.totalpart < minfilestoformrelease AND r.groupID = %d", $groupID, $groupID)); } else { $resrel = array(); $f = $this->db->queryOneRow( "SELECT GREATEST(s.value::integer, g.minfilestoformrelease::integer) as files FROM settings s, groups g WHERE s.setting = 'minfilestoformrelease' AND g.ID = " . $groupID ); if ($f['files'] > 0) { $resrel = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE totalpart < %d AND groupID = %d', $f['files'], $groupID)); } } if ($resrel !== false && $resrel->rowCount() > 0) { foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $minfilecount++; } } } $delcount = $minsizecount + $maxsizecount + $minfilecount + $catminsizecount; if ($this->echooutput && $delcount > 0) { $this->c->doEcho( $this->c->primary( 'Deleted ' . number_format($delcount) . " releases smaller/larger than group/site settings." ) ); } if ($this->echooutput) { $this->c->doEcho($this->c->primary($this->consoleTools->convertTime(TIME() - $stage4dot5)), true); } } public function processReleasesStage5($groupID) { $nzbcount = $reccount = 0; $where = (!empty($groupID)) ? ' r.groupID = ' . $groupID . ' AND ' : ' '; // Set table names if ($this->tablepergroup === 1) { if ($groupID == '') { exit($this->c->error("\nYou are using 'tablepergroup', you must use releases_threaded.py")); } $group['cname'] = 'collections_' . $groupID; $group['bname'] = 'binaries_' . $groupID; $group['pname'] = 'parts_' . $groupID; } else { $group['cname'] = 'collections'; $group['bname'] = 'binaries'; $group['pname'] = 'parts'; } // Create NZB. if ($this->echooutput) { $this->c->doEcho($this->c->header("Stage 5 -> Create the NZB, mark collections as ready for deletion.")); } $stage5 = TIME(); $resrel = $this->db->queryDirect( "SELECT CONCAT(COALESCE(cp.title,'') , CASE WHEN cp.title IS NULL THEN '' ELSE ' > ' END , c.title) AS title, r.name, r.id, r.guid FROM releases r INNER JOIN category c ON r.categoryID = c.ID INNER JOIN category cp ON cp.ID = c.parentID WHERE" . $where . "nzbstatus = 0" ); $total = 0; if ($resrel !== false) { $total = $resrel->rowCount(); } if ($total > 0) { $nzb = new Enzebe(); // Init vars for writing the NZB's. $nzb->initiateForWrite($this->db, htmlspecialchars(date('F j, Y, g:i a O'), ENT_QUOTES, 'utf-8'), $groupID); foreach ($resrel as $rowrel) { $nzb_create = $nzb->writeNZBforreleaseID($rowrel['ID'], $rowrel['guid'], $rowrel['name'], $rowrel['title']); if ($nzb_create !== false) { $this->db->exec( sprintf( 'UPDATE %s SET filecheck = 5 WHERE releaseID = %s', $group['cname'], $rowrel['ID'] ) ); $nzbcount++; if ($this->echooutput) { echo $this->consoleTools->overWritePrimary( 'Creating NZBs: ' . $this->consoleTools->percentString($nzbcount, $total) ); } } } // Reset vars for next use. $nzb->cleanForWrite(); } $timing = $this->c->primary($this->consoleTools->convertTime(TIME() - $stage5)); if ($this->echooutput) { $this->c->doEcho( $this->c->primary( number_format($nzbcount) . ' NZBs created in ' . $timing ) ); } return $nzbcount; } /** * Process RequestID's. * * @param int $groupID */ public function processReleasesStage5b($groupID) { if ($this->site->lookup_reqids == 1 || $this->site->lookup_reqids == 2) { $category = new Category(); $iFoundCnt = 0; $stage8 = TIME(); if ($this->echooutput) { $this->c->doEcho($this->c->header("Stage 5b -> Request ID lookup. ")); } // Look for records that potentially have requestID titles and have not been renamed by any other means $resRel = $this->db->queryDirect( sprintf(" SELECT r.id, r.name, r.searchname, g.name AS groupname FROM releases r LEFT JOIN groups g ON r.groupID = g.ID WHERE r.groupID = %d AND nzbstatus = 1 AND isrenamed = 0 AND (isrequestid = 1 AND reqidstatus in (%d, %d) OR (reqidstatus = %d AND adddate > NOW() - INTERVAL %d HOUR)) LIMIT 100", $groupID, self::REQID_UPROC, self::REQID_BAD, self::REQID_NONE, (isset($this->site->request_hours) ? (int)$this->site->request_hours : 1) ) ); if ($resRel !== false && $resRel->rowCount() > 0) { $newTitle = false; $web = (!empty($this->site->request_url) && (nzedb\utility\getUrl($this->site->request_url) === false ? false : true)); foreach ($resRel as $rowRel) { $newTitle = $local = false; // Try to get request id. if (preg_match('/\[\s*(\d+)\s*\]/', $rowRel['name'], $requestID)) { $requestID = (int)$requestID[1]; } else { $requestID = 0; } if ($requestID === 0) { $this->db->exec( sprintf(' UPDATE releases SET reqidstatus = %d WHERE ID = %d', self::REQID_ZERO, $rowRel['ID'] ) ); } else { // Do a local lookup first. $run = $this->db->queryOneRow( sprintf(" SELECT title FROM predb WHERE requestid = %d AND groupID = %d", $requestID, $groupID ) ); if ($run !== false) { $newTitle = $run['title']; $local = true; $iFoundCnt++; // Do a web lookup. } else if ($web !== false) { $xml = @simplexml_load_file( str_ireplace( '[REQUEST_ID]', $requestID, str_ireplace( '[GROUP_NM]', urlencode($rowRel['groupname']), $this->site->request_url ) ) ); if ($xml !== false && isset($xml->request[0]['name']) && !empty($xml->request[0]['name']) && strtolower($xml->request[0]['name']) !== strtolower($rowRel['searchname']) ) { $newTitle = $xml->request[0]['name']; $iFoundCnt++; } } } if ($newTitle !== false) { $determinedCat = $category->determineCategory($newTitle, $groupID); $this->db->exec( sprintf(' UPDATE releases SET reqidstatus = %d, isrenamed = 1, proc_files = 1, searchname = %s, categoryID = %d WHERE ID = %d', self::REQID_FOUND, $this->db->escapeString($newTitle), $determinedCat, $rowRel['ID'] ) ); if ($this->echooutput) { echo $this->c->primary( "\n\nNew name: $newTitle" . "\nOld name: " . $rowRel['searchname'] . "\nNew cat: " . $category->getNameByID($determinedCat) . "\nGroup: " . $rowRel['groupname'] . "\nMethod: " . ($local === true ? 'requestID local' : 'requestID web') . "\nreleaseID: " . $rowRel['ID'] ); } } else { $this->db->exec( sprintf( 'UPDATE releases SET reqidstatus = %d WHERE ID = %d', self::REQID_NONE, $rowRel['ID'] ) ); } } if ($this->echooutput && $newTitle !== false) { echo "\n"; } } if ($this->echooutput) { $this->c->doEcho( $this->c->primary( number_format($iFoundCnt) . ' Releases updated in ' . $this->consoleTools->convertTime(TIME() - $stage8) ), true ); } } } public function processReleasesStage6($categorize, $postproc, $groupID, $nntp) { $where = (!empty($groupID)) ? 'WHERE iscategorized = 0 AND groupID = ' . $groupID : 'WHERE iscategorized = 0'; // Categorize releases. if ($this->echooutput) { echo $this->c->header("Stage 6 -> Categorize and post process releases."); } $stage6 = TIME(); if ($categorize == 1) { $this->categorizeRelease('name', $where); } if ($postproc == 1) { $postprocess = new PostProcess($this->echooutput); $postprocess->processAll($nntp); } else { if ($this->echooutput) { $this->c->doEcho( $this->c->info( "\nPost-processing is not running inside the releases.php file.\n" . "If you are using tmux or screen they might have their own files running Post-processing." ) ); } } if ($this->echooutput) { $this->c->doEcho($this->c->primary($this->consoleTools->convertTime(TIME() - $stage6)), true); } } public function processReleasesStage7a($groupID) { $reccount = $delq = 0; $where = ' '; $where1 = ''; // Set table names if ($this->tablepergroup === 1) { if ($groupID == '') { exit($this->c->error("\nYou are using 'tablepergroup', you must use releases_threaded.py")); } $group['cname'] = 'collections_' . $groupID; $group['bname'] = 'binaries_' . $groupID; $group['pname'] = 'parts_' . $groupID; } else { $group['cname'] = 'collections'; $group['bname'] = 'binaries'; $group['pname'] = 'parts'; $where = (!empty($groupID)) ? ' ' . $group['cname'] . '.groupID = ' . $groupID . ' AND ' : ' '; $where1 = (!empty($groupID)) ? ' AND ' . $group['cname'] . '.groupID = ' . $groupID : ''; } // Delete old releases and finished collections. if ($this->echooutput) { echo $this->c->header("Stage 7a -> Delete finished collections."); } $stage7 = TIME(); // Completed releases and old collections that were missed somehow. if (DB_TYPE === 'mysql') { $delq = $this->db->exec( sprintf( 'DELETE ' . $group['cname'] . ', ' . $group['bname'] . ', ' . $group['pname'] . ' FROM ' . $group['cname'] . ', ' . $group['bname'] . ', ' . $group['pname'] . ' WHERE' . $where . $group['cname'] . '.filecheck = 5 AND ' . $group['cname'] . '.id = ' . $group['bname'] . '.collectionid AND ' . $group['bname'] . '.id = ' . $group['pname'] . '.binaryid' ) ); if ($delq !== false) { $reccount += $delq->rowCount(); } } else { $idr = $this->db->queryDirect('SELECT ID FROM ' . $group['cname'] . ' WHERE filecheck = 5 ' . $where); if ($idr !== false && $idr->rowCount() > 0) { foreach ($idr as $id) { $delqa = $this->db->exec( sprintf( 'DELETE FROM ' . $group['pname'] . ' WHERE EXISTS (SELECT ID FROM ' . $group['bname'] . ' WHERE ' . $group['bname'] . '.id = ' . $group['pname'] . '.binaryid AND ' . $group['bname'] . '.collectionid = %d)', $id['ID'] ) ); if ($delqa !== false) { $reccount += $delqa->rowCount(); } $delqb = $this->db->exec( sprintf( 'DELETE FROM ' . $group['bname'] . ' WHERE collectionid = %d', $id['ID'] ) ); if ($delqb !== false) { $reccount += $delqb->rowCount(); } } $delqc = $this->db->exec('DELETE FROM ' . $group['cname'] . ' WHERE filecheck = 5 ' . $where); if ($delqc !== false) { $reccount += $delqc->rowCount(); } } } // Old collections that were missed somehow. if (DB_TYPE === 'mysql') { $delq = $this->db->exec( sprintf( 'DELETE ' . $group['cname'] . ', ' . $group['bname'] . ', ' . $group['pname'] . ' FROM ' . $group['cname'] . ', ' . $group['bname'] . ', ' . $group['pname'] . ' WHERE ' . $group['cname'] . '.dateadded < (NOW() - INTERVAL %d HOUR) AND ' . $group['cname'] . '.id = ' . $group['bname'] . '.collectionid AND ' . $group['bname'] . '.id = ' . $group['pname'] . '.binaryid' . $where1, $this->site->partretentionhours ) ); if ($delq !== false) { $reccount += $delq->rowCount(); } } else { $idr = $this->db->queryDirect( sprintf( "SELECT ID FROM " . $group['cname'] . " WHERE dateadded < (NOW() - INTERVAL '%d HOURS')" . $where1, $this->site->partretentionhours ) ); if ($idr !== false && $idr->rowCount() > 0) { foreach ($idr as $id) { $delqa = $this->db->exec( sprintf( 'DELETE FROM ' . $group['pname'] . ' WHERE EXISTS (SELECT ID FROM ' . $group['bname'] . ' WHERE ' . $group['bname'] . '.id = ' . $group['pname'] . '.binaryid AND ' . $group['bname'] . '.collectionid = %d)', $id['ID'] ) ); if ($delqa !== false) { $reccount += $delqa->rowCount(); } $delqb = $this->db->exec( sprintf( 'DELETE FROM ' . $group['bname'] . ' WHERE collectionid = %d', $id['ID'] ) ); if ($delqb !== false) { $reccount += $delqb->rowCount(); } } } $delqc = $this->db->exec( sprintf( "DELETE FROM " . $group['cname'] . " WHERE dateadded < (NOW() - INTERVAL '%d HOURS')" . $where1, $this->site->partretentionhours ) ); if ($delqc !== false) { $reccount += $delqc->rowCount(); } } // Binaries/parts that somehow have no collection. if (DB_TYPE === 'mysql') { $delqd = $this->db->exec( 'DELETE ' . $group['bname'] . ', ' . $group['pname'] . ' FROM ' . $group['bname'] . ', ' . $group['pname'] . ' WHERE ' . $group['bname'] . '.collectionid = 0 AND ' . $group['bname'] . '.id = ' . $group['pname'] . '.binaryid' ); if ($delqd !== false) { $reccount += $delqd->rowCount(); } } else { $delqe = $this->db->exec( 'DELETE FROM ' . $group['pname'] . ' WHERE EXISTS (SELECT ID FROM ' . $group['bname'] . ' WHERE ' . $group['bname'] . '.id = ' . $group['pname'] . '.binaryid AND ' . $group['bname'] . '.collectionid = 0)' ); if ($delqe !== false) { $reccount += $delqe->rowCount(); } $delqf = $this->db->exec('DELETE FROM ' . $group['bname'] . ' WHERE collectionid = 0'); if ($delqf !== false) { $reccount += $delqf->rowCount(); } } // Parts that somehow have no binaries. if (mt_rand(1, 100) % 3 == 0) { $delqg = $this->db->exec( 'DELETE FROM ' . $group['pname'] . ' WHERE binaryid NOT IN (SELECT b.id FROM ' . $group['bname'] . ' b)' ); if ($delqg !== false) { $reccount += $delqg->rowCount(); } } // Binaries that somehow have no collection. $delqh = $this->db->exec( 'DELETE FROM ' . $group['bname'] . ' WHERE collectionid NOT IN (SELECT c.ID FROM ' . $group['cname'] . ' c)' ); if ($delqh !== false) { $reccount += $delqh->rowCount(); } // Collections that somehow have no binaries. $delqi = $this->db->exec( 'DELETE FROM ' . $group['cname'] . ' WHERE ' . $group['cname'] . '.id NOT IN (SELECT ' . $group['bname'] . '.collectionid FROM ' . $group['bname'] . ') ' . $where1 ); if ($delqi !== false) { $reccount += $delqi->rowCount(); } if ($this->echooutput) { $this->c->doEcho( $this->c->primary( 'Removed ' . number_format($reccount) . ' parts/binaries/collection rows in ' . $this->consoleTools->convertTime(TIME() - $stage7) ) ); } } // Queries that are not per group public function processReleasesStage7b() { $category = new Category(); $genres = new Genres(); $remcount = $reccount = $passcount = $dupecount = $relsizecount = $completioncount = $disabledcount = $disabledgenrecount = $miscothercount = $total = 0; // Delete old releases and finished collections. if ($this->echooutput) { $this->c->doEcho($this->c->header("Stage 7b -> Delete old releases and passworded releases.")); } $stage7 = TIME(); // Releases past retention. if ($this->site->releaseretentiondays != 0) { if (DB_TYPE === 'mysql') { $result = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE postdate < (NOW() - INTERVAL %d DAY)', $this->site->releaseretentiondays)); } else { $result = $this->db->queryDirect(sprintf("SELECT ID, guid FROM releases WHERE postdate < (NOW() - INTERVAL '%d DAYS')", $this->site->releaseretentiondays)); } if ($result !== false && $result->rowCount() > 0) { foreach ($result as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $remcount++; } } } // Passworded releases. if ($this->site->deletepasswordedrelease == 1) { $result = $this->db->queryDirect( 'SELECT ID, guid FROM releases WHERE passwordstatus = ' . Releases::PASSWD_RAR ); if ($result !== false && $result->rowCount() > 0) { foreach ($result as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $passcount++; } } } // Possibly passworded releases. if ($this->site->deletepossiblerelease == 1) { $result = $this->db->queryDirect( 'SELECT ID, guid FROM releases WHERE passwordstatus = ' . Releases::PASSWD_POTENTIAL ); if ($result !== false && $result->rowCount() > 0) { foreach ($result as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $passcount++; } } } // Crossposted releases. do { if ($this->crosspostt != 0) { if (DB_TYPE === 'mysql') { $resrel = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE adddate > (NOW() - INTERVAL %d HOUR) GROUP BY name HAVING COUNT(name) > 1', $this->crosspostt)); } else { $resrel = $this->db->queryDirect(sprintf("SELECT ID, guid FROM releases WHERE adddate > (NOW() - INTERVAL '%d HOURS') GROUP BY name, id HAVING COUNT(name) > 1", $this->crosspostt)); } $total = 0; if ($resrel !== false) { $total = $resrel->rowCount(); } if ($total > 0) { foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $dupecount++; } } } } while ($total > 0); // Releases below completion %. if ($this->completion > 100) { $this->completion = 100; echo $this->c->error("\nYou have an invalid setting for completion."); } if ($this->completion > 0) { $resrel = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE completion < %d AND completion > 0', $this->completion)); if ($resrel !== false && $resrel->rowCount() > 0) { foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $completioncount++; } } } // Disabled categories. $catlist = $category->getDisabledIDs(); if (count($catlist) > 0) { foreach ($catlist as $cat) { $res = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE categoryID = %d', $cat['ID'])); if ($res !== false && $res->rowCount() > 0) { foreach ($res as $rel) { $disabledcount++; $this->fastDelete($rel['ID'], $rel['guid']); } } } } // Disabled music genres. $genrelist = $genres->getDisabledIDs(); if (count($genrelist) > 0) { foreach ($genrelist as $genre) { $rels = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases INNER JOIN (SELECT ID AS mid FROM musicinfo WHERE musicinfo.genreID = %d) mi ON releases.musicinfoID = mid', $genre['ID'])); if ($rels !== false && $rels->rowCount() > 0) { foreach ($rels as $rel) { $disabledgenrecount++; $this->fastDelete($rel['ID'], $rel['guid']); } } } } // Misc other. if ($this->site->miscotherretentionhours > 0) { if (DB_TYPE === 'mysql') { $resrel = $this->db->queryDirect(sprintf('SELECT ID, guid FROM releases WHERE categoryID = %d AND adddate <= NOW() - INTERVAL %d HOUR', CATEGORY::CAT_MISC, $this->site->miscotherretentionhours)); } else { $resrel = $this->db->queryDirect(sprintf("SELECT ID, guid FROM releases WHERE categoryID = %d AND adddate <= NOW() - INTERVAL '%d HOURS'", CATEGORY::CAT_MISC, $this->site->miscotherretentionhours)); } if ($resrel !== false && $resrel->rowCount() > 0) { foreach ($resrel as $rowrel) { $this->fastDelete($rowrel['ID'], $rowrel['guid']); $miscothercount++; } } } if (DB_TYPE === 'mysql') { $this->db->exec(sprintf('DELETE FROM nzbs WHERE dateadded < (NOW() - INTERVAL %d HOUR)', $this->site->partretentionhours)); } else { $this->db->exec(sprintf("DELETE FROM nzbs WHERE dateadded < (NOW() - INTERVAL '%d HOURS')", $this->site->partretentionhours)); } if ($this->echooutput && $this->completion > 0) { $this->c->doEcho( $this->c->primary( 'Removed releases: ' . number_format($remcount) . ' past retention, ' . number_format($passcount) . ' passworded, ' . number_format($dupecount) . ' crossposted, ' . number_format($disabledcount) . ' from disabled categories, ' . number_format($disabledgenrecount) . ' from disabled music genres, ' . number_format($miscothercount) . ' from misc->other, ' . number_format($completioncount) . ' under ' . $this->completion . '% completion.' ) ); } else if ($this->echooutput && $this->completion == 0) { $this->c->doEcho( $this->c->primary( 'Removed releases: ' . number_format($remcount) . ' past retention, ' . number_format($passcount) . ' passworded, ' . number_format($dupecount) . ' crossposted, ' . number_format($disabledcount) . ' from disabled categories, ' . number_format($disabledgenrecount) . ' from disabled music genres, ' . number_format($miscothercount) . ' from misc->other' ) ); } if ($this->echooutput) { if ($reccount > 0) { $this->c->doEcho( $this->c->primary( "Removed " . number_format($reccount) . ' parts/binaries/collection rows.' ) ); } $this->c->doEcho($this->c->primary($this->consoleTools->convertTime(TIME() - $stage7)), true); } } public function processReleasesStage4567_loop($categorize, $postproc, $groupID, $nntp) { $DIR = nZEDb_MISC; $PYTHON = shell_exec('which python3 2>/dev/null'); $PYTHON = (empty($PYTHON) ? 'python -OOu' : 'python3 -OOu'); $tot_retcount = $tot_nzbcount = $loops = 0; do { $retcount = $this->processReleasesStage4($groupID); $tot_retcount = $tot_retcount + $retcount; $nzbcount = $this->processReleasesStage5($groupID); if ($this->requestids == '1') { $this->processReleasesStage5b($groupID); } else if ($this->requestids == '2') { $stage8 = TIME(); if ($this->echooutput) { $this->c->doEcho($this->c->header("Stage 5b -> Request ID Threaded lookup.")); } passthru("$PYTHON ${DIR}update/python/requestid_threaded.py"); if ($this->echooutput) { $this->c->doEcho( $this->c->primary( "\nReleases updated in " . $this->consoleTools->convertTime(TIME() - $stage8) ) ); } } $tot_nzbcount = $tot_nzbcount + $nzbcount; $this->processReleasesStage6($categorize, $postproc, $groupID, $nntp); $this->processReleasesStage7a($groupID); $loops++; // This loops as long as there were releases created or 3 loops, otherwise, you could loop indefinately } while (($nzbcount > 0 || $retcount > 0) && $loops < 3); return $tot_retcount; } public function processReleases($categorize, $postproc, $groupName, $nntp, $echooutput) { $this->echooutput = $echooutput; if ($this->hashcheck == 0) { exit($this->c->error("You must run update_binaries.php to update your collectionhash.\n")); } $groupID = ''; if (!empty($groupName)) { $groupInfo = $this->groups->getByName($groupName); $groupID = $groupInfo['ID']; } $this->processReleases = microtime(true); if ($this->echooutput) { $this->c->doEcho($this->c->header("Starting release update process (" . date('Y-m-d H:i:s') . ")"), true); } if (!file_exists($this->site->nzbpath)) { if ($this->echooutput) { $this->c->doEcho($this->c->error('Bad or missing nzb directory - ' . $this->site->nzbpath), true); } return; } $this->processReleasesStage1($groupID); $this->processReleasesStage2($groupID); $this->processReleasesStage3($groupID); $releasesAdded = $this->processReleasesStage4567_loop($categorize, $postproc, $groupID, $nntp); $this->processReleasesStage4dot5($groupID); $this->processReleasesStage7b(); $where = (!empty($groupID)) ? ' WHERE groupID = ' . $groupID : ''; //Print amount of added releases and time it took. if ($this->echooutput && $this->tablepergroup == 0) { $countID = $this->db->queryOneRow('SELECT COUNT(ID) FROM collections ' . $where); $this->c->doEcho( $this->c->primary( 'Completed adding ' . number_format($releasesAdded) . ' releases in ' . $this->consoleTools->convertTime(number_format(microtime(true) - $this->processReleases, 2)) . '. ' . number_format(array_shift($countID)) . ' collections waiting to be created (still incomplete or in queue for creation)' ), true ); } return $releasesAdded; } // This resets collections, useful when the namecleaning class's collectioncleaner function changes. public function resetCollections() { $res = $this->db->queryDirect('SELECT b.id as bid, b.name as bname, c.* FROM binaries b LEFT JOIN collections c ON b.collectionid = c.ID'); if ($res !== false && $res->rowCount() > 0) { $timestart = TIME(); if ($this->echooutput) { echo "Going to remake all the collections. This can be a long process, be patient. DO NOT STOP THIS SCRIPT!\n"; } // Reset the collectionhash. $this->db->exec('UPDATE collections SET collectionhash = 0'); $delcount = 0; $cIDS = array(); foreach ($res as $row) { $groupName = $this->groups->getByNameByID($row['groupID']); $newSHA1 = sha1( $this->collectionsCleaning->collectionsCleaner( $row['bname'], $groupName . $row['fromname'] . $row['groupID'] . $row['totalfiles'] ) ); $cres = $this->db->queryOneRow(sprintf('SELECT ID FROM collections WHERE collectionhash = %s', $this->db->escapeString($newSHA1))); if (!$cres) { $cIDS[] = $row['ID']; $csql = sprintf('INSERT INTO collections (subject, fromname, date, xref, groupID, totalfiles, collectionhash, filecheck, dateadded) VALUES (%s, %s, %s, %s, %d, %s, %s, 0, NOW())', $this->db->escapeString($row['bname']), $this->db->escapeString($row['fromname']), $this->db->escapeString($row['date']), $this->db->escapeString($row['xref']), $row['groupID'], $this->db->escapeString($row['totalfiles']), $this->db->escapeString($newSHA1)); $collectionID = $this->db->queryInsert($csql); if ($this->echooutput) { $this->consoleTools->overWrite( 'Recreated: ' . count($cIDS) . ' collections. Time:' . $this->consoleTools->convertTimer(TIME() - $timestart) ); } } else { $collectionID = $cres['ID']; } //Update the binaries with the new info. $this->db->exec(sprintf('UPDATE binaries SET collectionid = %d WHERE ID = %d', $collectionID, $row['bid'])); } //Remove the old collections. $delstart = TIME(); if ($this->echooutput) { echo "\n"; } $totalcIDS = count($cIDS); foreach ($cIDS as $cID) { $this->db->exec(sprintf('DELETE FROM collections WHERE ID = %d', $cID)); $delcount++; if ($this->echooutput) { $this->consoleTools->overWrite( 'Deleting old collections:' . $this->consoleTools->percentString($delcount, $totalcIDS) . ' Time:' . $this->consoleTools->convertTimer(TIME() - $delstart) ); } } // Delete previous failed attempts. $this->db->exec('DELETE FROM collections WHERE collectionhash = "0"'); if ($this->hashcheck == 0) { $this->db->exec("UPDATE settings SET value = 1 WHERE setting = 'hashcheck'"); } if ($this->echooutput) { echo "\nRemade " . count($cIDS) . ' collections in ' . $this->consoleTools->convertTime(TIME() - $timestart) . "\n"; } } else { $this->db->exec("UPDATE settings SET value = 1 WHERE setting = 'hashcheck'"); } } public function getTopDownloads() { return $this->db->query('SELECT ID, searchname, guid, adddate, SUM(grabs) AS grabs FROM releases WHERE grabs > 0 GROUP BY id, searchname, adddate HAVING SUM(grabs) > 0 ORDER BY grabs DESC LIMIT 10'); } public function getTopComments() { return $this->db->query('SELECT ID, guid, searchname, adddate, SUM(comments) AS comments FROM releases WHERE comments > 0 GROUP BY id, searchname, adddate HAVING SUM(comments) > 0 ORDER BY comments DESC LIMIT 10'); } public function getRecentlyAdded() { if (DB_TYPE === 'mysql') { return $this->db->query("SELECT CONCAT(cp.title, ' > ', category.title) AS title, COUNT(*) AS count FROM category INNER JOIN category cp on cp.ID = category.parentID INNER JOIN releases ON releases.categoryID = category.id WHERE releases.adddate > NOW() - INTERVAL 1 WEEK GROUP BY concat(cp.title, ' > ', category.title) ORDER BY COUNT(*) DESC"); } else { return $this->db->query("SELECT CONCAT(cp.title, ' > ', category.title) AS title, COUNT(*) AS count FROM category INNER JOIN category cp on cp.ID = category.parentID INNER JOIN releases ON releases.categoryID = category.id WHERE releases.adddate > NOW() - INTERVAL '1 WEEK' GROUP BY concat(cp.title, ' > ', category.title) ORDER BY COUNT(*) DESC"); } } /** * Get all newest movies with coves for poster wall. * * @return array */ public function getNewestMovies() { return $this->db->query( "SELECT DISTINCT (a.imdbID), guid, name, b.title, searchname, size, completion, postdate, categoryID, comments, grabs, c.cover FROM releases a, category b, movieinfo c WHERE a.categoryID BETWEEN 2000 AND 2999 AND b.title = 'Movies' AND a.imdbID = c.imdbID AND a.imdbID !='NULL' AND a.imdbID != 0 AND c.cover = 1 GROUP BY a.imdbID ORDER BY a.postdate DESC LIMIT 24" ); } /** * Get all newest games with covers for poster wall. * * @return array */ public function getNewestConsole() { return $this->db->query( "SELECT DISTINCT (a.consolenfoID), guid, name, b.title, searchname, size, completion, postdate, categoryID, comments, grabs, c.cover FROM releases a, category b, consoleinfo c WHERE c.cover > 0 AND a.categoryID BETWEEN 1000 AND 1999 AND b.title = 'Console' AND a.consolenfoID = c.ID AND a.consolenfoID != -2 AND a.consolenfoID != 0 GROUP BY a.consolenfoID ORDER BY a.postdate DESC LIMIT 35" ); } /** * Get all newest music with covers for poster wall. * * @return array */ public function getNewestMP3s() { return $this->db->query( "SELECT DISTINCT (a.musicinfoID), guid, name, b.title, searchname, size, completion, postdate, categoryID, comments, grabs, c.cover FROM releases a, category b, musicinfo c WHERE c.cover > 0 AND a.categoryID BETWEEN 3000 AND 3999 AND a.categoryID != 3030 AND b.title = 'Audio' AND a.musicinfoID = c.ID AND a.musicinfoID != -2 GROUP BY a.musicinfoID ORDER BY a.postdate DESC LIMIT 24" ); } /** * Get all newest books with covers for poster wall. * * @return array */ public function getNewestBooks() { return $this->db->query( "SELECT DISTINCT (a.bookinfoid), guid, name, b.title, searchname, size, completion, postdate, categoryID, comments, grabs, url, c.cover, c.title as booktitle, c.author FROM releases a, category b, bookinfo c WHERE c.cover > 0 AND (a.categoryID BETWEEN 8000 AND 8999 OR a.categoryID = 3030) AND (b.title = 'Books' OR b.title = 'Audiobook') AND a.bookinfoid = c.ID AND a.bookinfoid != -2 GROUP BY a.bookinfoid ORDER BY a.postdate DESC LIMIT 24" ); } }