Location: PHPKode > projects > Nzbirc > nzbirc-1.4/modules/tvnzb.php
<?php

/**************************************************
 * NZBirc v1
 * Copyright (c) 2006 Harry Bragg
 * tiberious.org
 * Module: nzb
 **************************************************
 *
 * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */

class Net_SmartIRC_module_tvnzb extends Net_SmartIRC_module_base
{

	// default module variable
	var $name = 'tvnzb';
	var $version = 'v0.1';
	var $description = 'interfaces with tvnzb.com';
	
	/**
	 * TVNZB Module - Please note the commands are regex's www.regular-expressions.info for a very good reference.
	 *
	 * STARTCONFIG
	 * @var array publicCommand  - Lists the commands that trigger this module, and return publicly
	 * @var array privateCommand - Lists the commands that trigger this module privatly (notice you)
	 * @var array download
	 * @var     string nzbPath   - path to store all the nzb files
	 * @var     bool nickPreface - Add a (nickname) at the beginning of each nzb file for ident later
	 * @var int searchResults    - How many results you want to return from a search result
	 * @var int reportCache      - The number of days to keep information about a particular ID	 
	 * ENDCONFIG
	 */
	var $_config = array(
		'publicCommand' => array( '^tvnzb', '^!tvnzb' ),
		'privateCommand' => array( '^@tvnzb' ),
		'download' => array(
			'nzbPath' => '/path/to/nzb/',
			'nickPreface' => true ),
		'searchResults' => 4,
		'reportCache' => 1.1,		
	);
	
	/**
	 * newzbin.com definition listing
	 */
	var $_def = array(
		'url' => array(
			'base' => 'http://www.tvnzb.com/nzb',
			'search' => 'http://www.tvnzb.com/nzb/%s/%s',
			'download' => 'http://www.tvnzb.com/direct/nzb/%d'
		),
		'regex' => array(
			'showid' => "/<option value='(\d+)'>(.*%s.*)<\/option>/i",
			'search' => array(
				'result' => "/<\/td>\s+<td><font title='([^']+)'>.+?<\/font><\/td>\s+<td><a href='\/direct\/nzb\/(\d+)' class='.+?'>(.+?)<\/a><\/td>/i",
				'queryExpansion' => '/^(.*?)\{([^\}]+)\}(.*)$/i',
				'numberSearch' => '/(?:(\d+)-(\d+)|([^-,]+))/',
				'flags' => '/(.+)\sf(?:lags?)?:([a-z0-9,.\s]+)/i',
				'showEp' => '/^\^"?(.+?) (?:-\s)?s?(\d+)(?:x|e)(\d+)"?/i',
				'showSeries' => '/^(.+) s?(\d+)$/',
				'showOnly' => '/^\^?"?(.+)( -)?"?$/i',
				'date' => '/(\w+)\. (\w+)\. (\d+)(\S+) (\d+) at (\d+):(\d+):(\d+) (A|P)M (\w+)/i'
				),
			'add' => array(
				'next' => '/^next$/i',
				'force' => '/^force"/i',
				'split' => '/(\+|\!|\^)(\d{7,9})/i',
				'url' => '/(http:\/\/)?[a-z0-9_\-.\/]+\/([a-z0-9_\-.\/]+)/i' )
		),
		'date' => array(
			'history' => array(
				'time' => 'h:ia'
			)
		),
		'replace' => array(
			'fileToTitle' => array(
				'from' => array( '_' ),
				'to' => array( ' ' )
			),
			'titleToFile' => array(
				'from' => array(' ', '..', '.', '?', ':', '#', '<', '>', '/', '\\', '|', '*', '\'', '"', '&amp;' ),
				'to' => array( '_' )
			)
		)
	);
	
	/**
	 * Template system
	 */	 
	var $_template = array(
		'search' => '({id}) {show} - {series}x{episode} - {title} | {extraInfo} | {filename}',
		'extraInfo' => '{res} {format} ',
		'addSucc' => 'Queued: [{addQueued}]',
		'addQueued' => '{id}:{title}',
		'addError' => 'Error: [{addQueued}]',
		'history' => '[{date}] {nzbHistory}',
		'nzbHistory' => '({time}) {id}: {title}',
		'error' => '**Error:** {errormsg}',
		'commandList' => 'List of commands available for TVNZB | type {trigger} help command, for more information on each command',
		'help' => '{command} - {description}',
		'helpList' => array(
			'Commands available for TVNZB: {helpCommands}',
			'Type: {trigger} {subTrigger} command, for more information on each command'
			)
		);
	
	var $_help = array(
		'help' => array(
			'command' => '{trigger} help [command]',
			'description' => 'Display the available commands, if a __command__ is specified, then extra information is provided',
			'longDescription' => 'Display the available commands, if a __command__ is specified, then extra information is provided'
			),
		'commands' => array(
			'command' => '{trigger} commands',
			'description' => 'List the available commands with their descriptions',
			'longDescription' => 'List the available commands with their descriptions'
			),
		'forceadd' => 'add',
		'nextadd' => 'add',
		'enqueue' => 'add',
		'forceenqueue' => 'add',
		'nextenqueue' => 'add',
		'add' => array(
			'command' => '{trigger} [force/next]add query [f:flags]',
			'description' => 'Download nzb files based on the __query__. The query can be a tvnzb ID, or a tv show query',
			'longDescription' => array(
				'Download nzb files based on the __query__. The query can be a tvnzb ID, or a tv show query',
				'a tvnzb ID will only work if the title has been previously found from a search',
				'The search query can include **variables**, for example: {01,02,09-20}, will add 01, 02, 09, 10, ... 20',
				'This also works with words {cat,mouse,dog} will add cat, mouse and dog seperatly. Multiple **variables** can be defined in a single query',
				'Flags, define the quality of files to be downloaded (mainly for tv, but works for films too), more information can be found with {trigger} help search',
				'REQ: HellaNZB, If force or next are placed before the add part, the nzb\'s downloaded will be placed in the approprate places in the queue',
				)
			),	
		'search' => array(
			'command' => '{trigger} search query [f:flags]',
			'description' => 'Searches newzbin based on the query, if __flags__ are specified, the results are based on their flags',
			'longDescription' => array(
				'Searches newzbin based on the query, if __flags__ are specified, the results are based on their flags',
				'Current flags are: 1080p, 720p, hr, h.264, xvid, divx, svcd, hd .ts, wmv, normal. **hr** means halfres (1080p/2 = 540p)',
				'The order of the flags, specifies their priority, placing them earlier makes them more important, for example:',
				'f:720p,hr,xvid - means if 720p can be found it will download that, otherwise hr, then xvid',
				'These flags are based on the filenames of the reports',
				'see: http://www.tiberious.org/wiki/index.php/Nzbirc/v1/flags for more information'
				)
			),
		'history' => array(
			'command' => '{trigger} history date/duration',
			'description' => 'Return the nzb\'s downloaded on the specified __date__, or __duration__',
			'longDescription' => array(
				'Return the nzb\'s downloaded on the specified __date__, or __duration__',
				'__date__ can be in almost any date format: today, next wednesday, 10/11/06, 15th Jan 06, etc',
				'__duration__ is in the format: Xw Yd',
				'date periods can be specified using **-** or **to**, these will list items between 2 absolute dates/durations, i.e.: {trigger} history -4d to yesterday',
				'the joining word **for** can also be used for relative periods, i.e.: {trigger} history 15 dec 06 for 3d',
				'see: http://www.tiberious.org/wiki/index.php/Nzbirc/v1/times for more information'
				)
			)
		);

	/**
	 * Store temporary errors
	 */
	var $_error;	
	
	function _registerCommands()
	{
	 	global $irc;
	 	
		$this->_setHandler( '^search', $this, 'doSearch' );
		
		$this->_setHandler( '^(add|enqueue)', $this, 'add' );
		if ( $irc->isLoadedModule( 'hella' ) )
		{
			$this->_setHandler( '^(force|next)(add|enqueue)', $this, 'add' );
		}
		
		$this->_setHandler( '^history', $this, 'history' );

		//help
		$this->_setHandler( '^help', $this, 'botHelp' );
		$this->_setHandler( '^commands', $this, 'botCommands' );
		
		$irc->_modules['store']->addVariable( '_tvnzbShowCache' );
		$irc->_modules['store']->addVariable( '_tvnzbCache' );
		$irc->_modules['store']->addVariable( '_tvnzbHistory' );
		$irc->_modules['store']->addVariable( '_tvnzbWait', true );
		$irc->_modules['store']->addVariable( '_tvnzbQueued', true );
		$irc->_modules['store']->addVariable( '_tvnzbQError', true );
		
		$irc->_tvnzbTimerID = $irc->registerTimeHandler( 30000, $this, 'checkNzb' );
	}
	
	function _customClose()
	{
		global $irc;
		
		$irc->unregisterTimeid( $irc->_tvnzbTimerID );
	}
	
	/*****************************************************
	 * Bot functions
	 *****************************************************/	
	
	function doSearch( &$irc, &$data, $notice )
	{
		// check to see if flags are specified
		if ( preg_match( $this->_def['regex']['search']['flags'], $data->subMessage, $match ) )
		{
			$flags = explode(',', $match[2]);
			$query = $match[1];
		}
		else 
		{
			$query = $data->subMessage;
			$flags = array();
		}
		
		$results = $this->search( $query, $this->_config['searchResults'], $flags );
		
		if ( count( $results ) == 0 )
		{
			$irc->_modules['func']->reply( $irc, $data, 'No results found for: '.$data->subMessage, $notice );
		}
		
		foreach( $results as $res )
		{
			// check res for result
			if ( isset( $res['id'] ) )
			{			
				// filter result into string and output
				$vars = array(
					'id' => $res['id'],
					'date' => $irc->_modules['func']->snicedate( $res['date'] ),
					'filename' => $res['title'] );
				
				if ( isset( $res['flags']['res'] ) )
				{
					$vars['extraInfo'][] = array(
						'res' => $res['flags']['res'],
						'format' => $res['flags']['format']
					);				
				}
				else
				{
					$vars['extraInfo'][] = array(
						'res' => $res['flags']['resolution'],
						'format' => $res['flags']['video format']
					);			
				}
			
				if ( ( $showInfo = $irc->_modules['ed']->doQuery( $irc, $res['title'] ) ) !== false )
				{
					$vars['show'] = $showInfo['name'];
					$vars['series'] = $showInfo['series'];
					$vars['episode'] = $showInfo['sepnum'];
					$vars['title'] = $showInfo['title'];
				}
				else
				{
					$this->_template['search'] = '({id}) {filename} | {extraInfo}';
				}
							
				$this->parseTemplate( $msg, 'search', $vars );
			}
			
			unset( $vars );
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
		}
		
	}
	
	
	function add( &$irc, &$data, $notice )
	{
	 	$data->notice = $notice;
	 	$hellaMod = false;
		if ( count( $data->trig ) > 2 )
		{
			// hella moving stuffs
			if ( preg_match( $this->_def['regex']['add']['next'], $data->trig[1] ) )
			{
				$hellaMod = 'next';				
			}
			else if ( preg_match( $this->_def['regex']['add']['force'], $data->trig[1] ) )
			{
				$hellaMod = 'force';
			}
		}
		
		$data->hellaMod = $hellaMod;
		
		$subMessageex = explode( ' ', $data->subMessage );

		if ( ( !is_numeric( $subMessageex[0] ) ) || ( strlen($subMessageex[0]) < 3 ) )
		{		
			// check to see if flags are specified
			if ( preg_match( $this->_def['regex']['search']['flags'], $data->subMessage, $match ) )
			{
				$flags = explode(',', $match[2]);
				$query = $match[1];
			} 
			else 
			{
				$query = $data->subMessage;
				$flags = array();
			}
				
			$results = $this->search( $query, 1, $flags );

			
			if ( count( $results ) == 0 )
			{
				$irc->_modules['func']->reply( $irc, $data, 'No results found for: '.$data->subMessage, $notice );
			}
		}
		else
		{
			foreach( $subMessageex as $id )
			{
				if ( isset( $irc->_tvnzbCache[$id] ) )
				{
					$results[] = $irc->_tvnzbCache[$id];
				}
			}
		}			
	
		if ( ( $irc->config->useWorker == true ) &&
		     ( $irc->isWorker == false ) )
		{
			foreach( $results as $res )
			{
				if ( isset( $res['id'] ) )
				{
					$irc->_tvnzbWait[$res['id']] = $res;
					$irc->_tvnzbWait[$res['id']]['data'] = $irc->_modules['func']->getTData( $data );
				}
			}
			$irc->_modules['store']->manualUpdate( '_tvnzbWait', true );
			return;
		}
		
		foreach( $results as $res )
		{
			if ( isset( $res['id'] ) )
		 	{
			 	if ( ( $title = $this->_addID( $res['id'], $res['title'], $data, $hellaMod ) ) !== false )
			 	{
			 	 	$succ[] = array(
					  'id' => $res['id'],
					  'title' => $title );
			 	}
			 	else
			 	{
					$errors[] = array(
					  'id' => $res['id'],
					  'title' => $this->_error );
				}
			}
		}
		
		if ( is_array( $succ ) )
		{
			$vars['addQueued'] = $succ;
			$this->parseTemplate( $msg, 'addSucc', $vars );
		}
		if ( is_array( $errors ) )
		{
			$vars['addQueued'] = $errors;
			$this->parseTemplate( $msg, 'addError', $vars );
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
		}
		
	}
	
	function history( &$irc, &$data, $notice )
	{ 
		list( $date, $date2 ) = $irc->_modules['func']->dateDurationParse( $data->subMessage );
			
		$date = $irc->_modules['func']->dateToDay( $date );
		if ( $date2 >= 0 )
			$date2 = $irc->_modules['func']->dateToDay( $date2 );
		
		$nzbs = $this->_getHistory( $date, $date2 );
		
		if ( count( $nzbs ) > 0 ) 
		{
			foreach( $nzbs as $id => $item )
			{
			 	$vars = array(
					'date' => $irc->_modules['func']->snicedate( $id )
				);
			 	
				foreach( $item as $nzb )
				{
				 	$tmp = array(
				 		'time' => date( $this->_def['date']['history']['time'], $nzb['queued'] ),
				 		'id' => $nzb['id'],
				 		'title' => $nzb['title']
				 	);
					$vars['nzbHistory'][] = $tmp;
				}
				
				$this->parseTemplate( $msg, 'history', $vars );
				
			}
		}
		else
		{
			$msg[] = 'No results found for the times specified';
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
		}
		
	}

	function botHelp( &$irc, &$data, $notice )
	{
		if ( strlen( $data->subMessage ) > 0 )
		{
			if ( isset( $this->_help[$data->subMessage] ) )
			{
				$this->parseHelp( $msg, $data->subMessage, array( 'trigger' => $data->trigger ) );
			}
			else
			{
				//$this->parseTemplate( $msg, 'error', array( 'errormsg' => sprintf( 'Unknown command: %s', $data->subMessage ) ) );
			}
		}
		else
		{
			foreach ( $this->_help as $id => $helpItem )
			{
				$vars['helpCommands'][] = $id;
			}
			$vars['trigger'] = $data->trigger;
			$vars['subTrigger'] = $data->trig[0];
			$this->parseTemplate( $msg, 'helpList', $vars );
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, true );
		}
		
	}
	
	function botCommands( &$irc, &$data, $notice )
	{
		$vars['trigger'] = $data->trigger;
		
		$this->parseTemplate( $msg, 'commandList', $vars );
		
		foreach( $this->_help as $id => $helpItem )
		{
			if ( is_array( $helpItem ) )
			{
				$helpItem['trigger'] = $data->trigger;
				$this->parseTemplate( $msg, 'help', $helpItem );			
			}
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, true );
		}
	}	
	
	/*****************************************************
	 * Main functions
	 *****************************************************/	

	/**
	 * Add a newzbinID, with a specified modifier
	 *
	 * @param int $id          - Newzbin.com ID
	 * @param string $nick     - Nickname of the person who added the nzb
	 * @param string $modifier - modifiy the item in the queue afterwards (Default: false)
	 * @return bool/string     - string containing nzb report title, or false if failed
	 * @access private
	 */
	function _addID( $res, &$data, $modifier = false )
	{
	 	global $irc;
	 	
	 	$irc->modDebug( 'tvnzb', 'adding tvnzbID: '. $res['id'] .': '.$res['title'].' to download queue', __FILE__, __LINE__, SMARTIRC_DEBUG_MODULES );
	 	
		$filetitle = trim( str_replace( array( ' ','..','.','?',':','#','<','>','/','\\','|','*','\'','"','&' ), '_', html_entity_decode( $res['title'] ) ), '_' );
 				
		$filename = $this->_config['download']['nzbPath'] . sprintf( 'msgid_%d_%s%s.nzb', $res['id'], (( $this->_config['download']['nickPreface'] )? '('.$data->nick.')_':'' ), $filetitle );
 				
		if ( ( $err = $this->_downloadID( $res['id'], $filename ) ) === true )
		{					
			// add the item to history
			$irc->_tvnzbHistory[$res['id']] = $res;
			$irc->_tvnzbHistory[$res['id']]['queued'] = time();
			$irc->_tvnzbHistory[$res['id']]['data'] = $irc->_modules['func']->getTData( $data );
			$irc->_tvnzbHistory[$res['id']]['tvnzb'] = true;
			
			if ( ( $modifier ) && ( $irc->isLoadedModule( 'hella' ) ) )
			{
				if ( isset( $ta[$modifier] ) )
				{
					$ta = array( 'last' => -2, 'next' => -1, 'force' => 0 );					 
					$irc->_modules['hella']->moveItem( $res['id'], $ta[$modifier], $irc->_modules['func']->getTData( $data ) );
				}
			}
									
			// remove any old episodes in the history
			$this->_checkHistory();
			
			return $res['title'];
		}
		else
		{
			$this->_error = $err;
			return false;
		}
	}

	/*****************************************************
	 * History
	 *
	 * The history is only stored for 2 weeks 
	 * (or the number of days you speicified in the config)
	 *****************************************************/

	/**
	 * Get the history from a day, or region of days
	 *
	 * @var int $date	- First date
	 * @var int $date2  - Second date | Default: false
	 * @return array    - Information related to 
	 * @access private
	 */
	function _getHistory( $date, $date2 = false )
	{
	 	global $irc;
	 
	 	if ( ( !$date2 ) || ( $date2 < 0 ) )
	 	{
	 	 	// date2 = 1 day after date
			$date2 = $date + 3600 * 24;
		}
		else
		{
			// make date2 + 1 day
			$date2 = $date2 + (3600 * 24) - 1;
		}
		
		if ( is_array( $irc->_tvnzbHistory ) )
		{
			foreach( $irc->_tvnzbHistory as $id => $item )
			{
				if ( ( $item['queued'] >= $date ) &&
				     ( $item['queued'] <= $date2 ) )
				{
					$out[$id] = $item;
					$downloaded[$id] = $item['queued'];
				}
			}
			
			if ( count( $out ) > 0 )
			{
				// all nicely ordered
				array_multisort( $downloaded, SORT_ASC, $out );
				
				foreach( $out as $item )
				{
					$ret[$irc->_modules['func']->dateToDay( $item['queued'] )][] = $item;
				}
			}
		}
		
		return $ret;
	}

	/**
	 * Check the nzb history, for old reports
	 *
	 * @return void
	 */
	function _checkHistory()
	{
	 	global $irc;
	 
        foreach( $irc->_tvnzbHistory as $id => $history )
        {
			if ( $history['queued'] < ( time() - ( $this->_config['download']['history'] * 3600 * 24 ) ) )
			{
				unset( $irc->_tvnzbHistory[$id] );
			}
		}
		
		$irc->_modules['store']->manualUpdate( '_tvnzbHistory' );		
	}
	

	/*****************************************************
	 * Search
	 *****************************************************/
	 
	/**
	 * Search for some nzb posts
	 *
	 * @param string $query - Query to search for
	 * @param int $results  - Number of results to return, 0 = all
	 * @param array $flags  = List of flags to conform to, default: empty, i.e. first result
	 * @returns array       - All the results in an array
	 * @access public
	 */
	function search( $query, $results, $flags = array() )
	{	
		global $irc;
	
		$res = array();
	
		// check to see if the query contains a variable
		if ( preg_match( $this->_def['regex']['search']['queryExpansion'], $query, $varMatch ) )
		{
			// screw tvnzb, we shall search like fook
			
			// get all the numbers in the first variable
			$nums = $this->_getSearchNumbers( $varMatch[2] );			
			foreach( $nums as $num ) 
			{				
				$tmp = $this->search( sprintf( '%s%s%s', $varMatch[1], $num, $varMatch[3] ), 1, $flags );
				$irc->_modules['func']->array_append( $res, $tmp );
			}
			
			return $res;
		}

		// parse query, to get show, series, and title
		$info = $this->_getInfo( $query );
			
		// do the search
		$page = $this->_getTvUrl( $info['show'], $info['series'], $info['episode'] );
		
		// split the result up
		preg_match_all( $this->_def['regex']['search']['result'], $page, $matches );
			
		$res = $this->_flagFilter( $matches, $results, $flags );
		$this->_checkCache();

		return $res;
		
	}
	
	/**
	 * Filter result by flags
	 *
	 * @param array $results - Search results
	 * @param int $numRes    - Number of results to return
	 * @param array $flags   - Flags
	 * @param bool $sort 	 - Sort the list based on flags
	 * @return array		 - Only the relevant results are kept
	 * @access private
	 */
	function _flagFilter( $results, $numRes, $flags, $sort = true )
	{
		global $irc;
		
		$res = array();
		$score = array();
		$age = array();
		
		for ( $r = 0; $r < count($results[0]); $r++ )
		{
			/**
			 * 1 => date
			 * 2 => id
			 * 3 => title
			 */

			// format date
			if ( preg_match( $this->_def['regex']['search']['date'], $results[1][$r], $match ) )
			{
				
				$date = sprintf( '%d %s %d %d:%d:%d %sM %s', $match[3], $match[2], $match[5], $match[6], $match[7], $match[8], $match[9], $match[10] );
				$date = strtotime( $date );
			}
			else
			{
				$date = time();
			}

			$result = array(
				'date' => $date,
				'id' => $results[2][$r],
				'title' => $results[3][$r] );
				
			$result['flags'] = $this->_setFlags( $result['title'] );
						      			
			if ( count( $flags ) > 0 ) {
			
				$tot = 0;
											
				for( $i=0; $i < count($flags); $i++ ) {
					if ( $result['flags'][$flags[$i]] == true ) {
						$tot += count($flags) - $i;
					}
				}
				
				if ( $tot > 0 ) {
					$result['score'] = $tot;
					$res[] = $result;
				}
			} else {
				if ( $r < $numRes )
				{
					$result['score'] = 0;
					$res[] = $result;
				}
			}
			$result['searched'] = time();
			$irc->_tvnzbCache[$result['id']] = $result;
		}
			
		if ( ( $sort ) && ( count( $flags ) > 0 ) ) {
		 
		 	foreach( $res as $key => $row )
		 	{
				$score[$key] = $row['score'];
				$age[$key] = intval( $row['age'] );
			}
		 
			array_multisort( $age, SORT_ASC, $score, SORT_DESC, $res );

			$res = array_slice( $res, 0, $numRes );
		}
		
		return $res;
		
	}
	
	function _setFlags( $title )
	{
		global $irc;

		$map = array(
			'Format' => 'video format',
			'Res' => 'resolution',
			'Source' => 'video source',
			'Audio' => 'audio Format' );
		
		foreach( $irc->_modules['ed']->_def['attributes'] as $attr => $aArr )
		{
			foreach( $aArr as $id => $regex ) {
				if ( substr( $regex, 0, 1 ) == '!' )
				{
					if ( !preg_match( substr( $regex, 1 ) , $title ) ) {
						$result[strtolower($id)] = true;
						if ( ( ( isset( $result[$map[$attr]] ) ) && ( !in_array( $id, $result[$map[$attr]] ) ) ) ||
						     ( !isset( $result[$map[$attr]] ) ) )
						{
							$result[$map[$attr]][] = $id;
						}
					}				
				}
				else
				{
					if ( preg_match( $regex, $title ) ) {
						$result[strtolower($id)] = true;
						if ( ( ( isset( $result[$map[$attr]] ) ) && ( !in_array( $id, $result[$map[$attr]] ) ) ) ||
						     ( !isset( $result[$map[$attr]] ) ) )
						{
							$result[$map[$attr]][] = $id;
						}
					}
				}
			}
		}
		
		return $result;
	}
	
	/**
	 * Gets the numbers inside a {01-05,06} variale
	 *
	 * @param string $variable - List of numbers
	 * @returns array 		   - Of all the numbers
	 * @access private
	 */
	function _getSearchNumbers( $variable ) {
		
		$res = array();
		
		if ( preg_match_all( $this->_def['regex']['search']['numberSearch'], $variable, $matches ) )
		{
			for( $i = 0; $i < count( $matches[0] ); $i++ ) 
			{
				if ( !empty( $matches[3][$i] ) ) {
					$res[] = $matches[3][$i];
				}
				else 
				{
					$len = strlen( $matches[1][$i] );
					for ( $j = $matches[1][$i]; $j <= $matches[2][$i]; $j++ ) {
						$res[] = sprintf( '%0'.$len.'d', $j);
					}
				}
			}
		}
		
		return $res;
		
	}

	function _checkCache()
	{
	 	global $irc;
	 
	 	if ( is_array( $irc->_tvnzbCache ) )
		{
			foreach( $irc->_tvnzbCache as $id => $nzb )
			{
				if ( $nzb['searched'] < ( time() - ( $this->_config['reportCache'] * 3600 * 24 ) ) )
				{
					unset( $irc->_tvnzbCache[$id] );
				}
			}
		}
				
		$irc->_modules['store']->manualUpdate( '_tvnzbCache' );
	}

	/*****************************************************
	 * Worker Thread Stuffs
	 *****************************************************/
	
	function checkNzb( &$irc )
	{
		// check wait variable
		if ( ( $irc->isWorker == true ) || 
		     ( ( $irc->config->useWorker == false ) &&
			   ( $irc->isWorker == false ) ) )			 
		{
			if ( ( isset( $irc->_tvnzbWait ) ) && ( count( $irc->_tvnzbWait ) > 0 ) )
			{
				$irc->_modules['store']->delayWrite( &$irc );
				list( $succ, $errors ) = $this->addIds( $irc->_tvnzbWait );
				foreach( $succ as $s1 )
				{
					$irc->_tvnzbQueued[] = $s1;
					foreach( $s1 as $sInfo )
					{
						unset( $irc->_tvnzbWait[$sInfo['id']] );
					}
				}
				foreach( $errors as $e1 )
				{
					$irc->_tvnzbQError[] = $e1;
					foreach( $e1 as $eInfo )
					{
						unset( $irc->_tvnzbWait[$eInfo['id']] );
					}
				}
				
				// update variables
				$irc->_modules['store']->manualUpdate( array( '_tvnzbWait', '_tvnzbQueued', '_tvnzbQError' ) );
			}
		}
		
		if ( ( $irc->config->useWorker == true ) &&
		     ( $irc->isWorker == false ) )
		{
			if ( ( isset( $irc->_tvnzbQueued ) ) && ( count( $irc->_tvnzbQueued ) > 0 ) )
			{
				$irc->_modules['store']->delayWrite( &$irc );		
				foreach( $irc->_tvnzbQueued as $succ )
				{					
					if ( is_array( $succ ) )
					{
						$vars['addQueued'] = $succ;
						$this->parseTemplate( $msg, 'addSucc', $vars );
					}
					if ( isset( $msg ) )
					{
						$irc->_modules['func']->reply( $irc, $succ[0]['data'], $msg, $succ[0]['data']->notice );
						unset( $msg );
					}
					unset( $vars );
				}
				$irc->_tvnzbQueued = array();
				$irc->_modules['store']->manualUpdate( '_tvnzbQueued' );
			}
			if ( ( isset( $irc->_tvnzbQError ) ) && ( count( $irc->_tvnzbQError ) > 0 ) )
			{
				$irc->_modules['store']->delayWrite( &$irc );
				foreach( $irc->_tvnzbQError as $errors )
				{				
					if ( is_array( $errors ) )
					{
						$vars['addQueued'] = $errors;
						$this->parseTemplate( $msg, 'addError', $vars );
					}
					
					if ( isset( $msg ) )
					{
						$irc->_modules['func']->reply( $irc, $errors[0]['data'], $msg, $errors[0]['data']->notice );
						unset( $msg );
					}
					unset( $vars );
				}
				$irc->_tvnzbQError = array();
				$irc->_modules['store']->manualUpdate( '_tvnzbQError' );
			}
		}
	}
	
	/**
	 * Add a bunch of ids to download
	 *
	 * @var array ids - Array of ids/urls to add
	 * @return array - Successful and Failed enties
	 */
	function addIds( $ids )
	{
		global $irc;
		
		$dArray = array();
		$succ = array();
		$errors = array();
		
		foreach( $ids as $tmp => $res )
		{
			if ( !isset( $res['id'] ) )
			{
				unset( $irc->_tvnzbWait[$tmp] );
				continue;
			}
			if ( isset( $res['id'] ) )
		 	{
			 	if ( ( $title = $this->_addID( $res, $res['data'], $res['data']->hellaMod ) ) !== false )
			 	{
			 	 	$succ[$this->_findDMatch( $dArray, $res['data'] )][] = array(
					  'id' => $res['id'],
					  'data' => $res['data'],
					  'title' => $title );
			 	}
			 	else
			 	{
					$errors[$this->_findDMatch( $dArray, $res['data'] )][] = array(
					  'id' => $res['id'],
					  'data' => $res['data'],						  
					  'title' => $this->_error );
				}
			}
		}
		return array( $succ, $errors );
	}
	
	function _findDMatch( &$dArray, $data )
	{
		if ( ( is_array( $dArray ) ) && ( is_array( $data ) ) )
		{
			foreach( $dArray as $id => $dInfo )
			{
				if ( ( $dInfo['type'] == $data['type'] ) &&
				     ( ( ( ( $dInfo['type'] == SMARTIRC_TYPE_QUERY ) ||
					       ( $dInfo['type'] == SMARTIRC_TYPE_NOTICE ) ) &&
				         ( $dInfo['nick'] == $data['nick'] ) ) ||
					   ( $dInfo['type'] == SMARTIRC_TYPE_CHANNEL ) ) &&
				     ( $dInfo['channel'] == $data['channel'] ) &&
					 ( $dInfo['notice'] == $data['notice'] ) )
				{
					return $id;
				}
				$tD = $id+1;
			}
			$dArray[$tD]['data'] = $data;
			return $tD;
		}
	}
	
	/*****************************************************
	 * TVNZB.com website function
	 *****************************************************/		

	function _getInfo( $query )
	{
		if ( preg_match( $this->_def['regex']['search']['showEp'], $query, $matches ) )
		{
			$out = array(
				'show' => $matches[1],
				'series' => $matches[2],
				'episode' => $matches[3] );
		}
		else if ( preg_match( $this->_def['regex']['search']['showSeries'], $query, $matches ) )
		{
			$out = array(
				'show' => $matches[1],
				'series' => $matches[2],
				'episode' => false );
		}
		else if ( preg_match( $this->_def['regex']['search']['showOnly'], $query, $matches ) )
		{
			$out = array(
				'show' => $matches[1],
				'series' => false,
				'episode' => false );
		}
		return $out;
	}

	function _getTvUrl( $show, $series = false, $episode = false )
	{
		$sStr = 's'.(($series !== false)? 'v':'').(($episode !== false)? 'e':'');
		
		$eNum = $this->_getShowID( $show );
		
		$eNum .= (($series !== false)? '/'.$series:'').(($episode !== false)? '/'.$episode:'');
		
		return $this->_getUrl( sprintf( $this->_def['url']['search'], $sStr, $eNum ) );
		
	}

	function _getShowID( $show )
	{
		global $irc;
		
		if ( isset( $irc->_tvnzbShowCache[$show] ) )
		{
			return $irc->_tvnzbShowCache[$show];
		}
		
		$sPage = $this->_getUrl( $this->_def['url']['base'] );
		
		if ( preg_match( sprintf( $this->_def['regex']['showid'], str_replace( ' ', '.*', $show ) ), $sPage, $match ) )
		{
			$irc->_tvnzbShowCache[$show] = $match[1];
			$irc->_modules['store']->manualUpdate( '_tvnzbShowCache' );
			return $match[1];
		}
		else
		{
			return false;
		}
	}

	/**
	 * Get a url from newzbin.com
	 *
	 * @param string $url - URL to get
	 * @return string     - Page retrived
	 * @access private
	 */
	function _getUrl( $url )
	{
		global $irc;
		
		$req = new HTTP_Request( );
		$req->setMethod(HTTP_REQUEST_METHOD_GET);
		
		if ( isset( $irc->config->proxy ) )
		{
			if ( strlen($irc->config->proxy['host']) > 0 )
			{
				if ( strlen($irc->config->proxy['username']) > 0)
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port'],
						$irc->config->proxy['username'],
						$irc->config->proxy['password']);
				}
				else
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port']);
				}
			}
		}
				
		$req->setURL( $url, array( 'timeout' => '30', 'readTimeout' => 30, 'allowRedirects' => true ) );

		$request = $req->sendRequest();
		$irc->modDebug( 'tvnzb', 'request sent for: '.$url, __FILE__, __LINE__ );		
		if (PEAR::isError($request)) {
			$irc->modDebug( 'tvnzb', 'failed to get '.$url.', error: '.$request->getMessage(), __FILE__, __LINE__ );
			unset( $req, $request );
			return false;
		} else {
			$body = $req->getResponseBody();
			unset( $req, $request );			
			return $body;
		}				
	}
	
	/**
	 * Download a nzb from a url
	 *
	 * @param string $id - URL
	 * @param string $file - filename to save
	 */
	function _downloadID( $id, $file )
	{
		global $irc;	

		$fp = @fopen( $file, 'w' );
		if (!$fp) return 'unable to open file: '.$file;

		$url = sprintf( $this->_def['url']['download'], $id );

		$req = new HTTP_Request( );
		$req->setMethod(HTTP_REQUEST_METHOD_GET);	

		if ( isset( $irc->config->proxy ) )
		{
			if ( strlen($irc->config->proxy['host']) > 0 )
			{
				if ( strlen($irc->config->proxy['username']) > 0)
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port'],
						$irc->config->proxy['username'],
						$irc->config->proxy['password']);
				}
				else
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port']);
				}
			}
		}
		
		$req->setURL( $url, 
			array( 'timeout' => '60', 'readTimeout' => 120, 'allowRedirects' => true ) );

		ini_set( 'memory_limit', '50M' );
		$request = $req->sendRequest();
		$irc->modDebug( 'tvnzb', 'request sent for: '.$url, __FILE__, __LINE__ );		
		if (PEAR::isError($request))
		{
			$irc->modDebug( 'tvnzb', 'failed to get '.$url.', error: '.$request->getMessage(), __FILE__, __LINE__, SMARTIRC_DEBUG_MODULES );
			fclose( $fp );
			$msg = $request->getMessage();
			unset( $req, $request );			
			ini_set( 'memory_limit', '8M' );
			return chr(2).'Error:'.chr(2).' '.$msg;
		}
		else
		{
			$body = $req->getResponseBody();
			unset( $req, $request );			
			fwrite( $fp, $body );
			fclose( $fp );
			
			ini_set( 'memory_limit', '8M' );
			return true;
			
		}	        
	}

}

?>
Return current item: Nzbirc