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

/**************************************************
 * NZBirc v1
 * Copyright (c) 2006 Harry Bragg
 * tiberious.org
 * Module: autoquery
 **************************************************
 *
 * 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_autoquery extends Net_SmartIRC_module_base
{

    // default module variable
    var $name = 'autoquery';
    var $version = 'v0.3';
    var $description = 'automatic query downloading';
    
    /**
     * AutoQuery Module
     *
     * 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 int checkTime         - When to start checking for a new episode (in hours from 00:00 on the day of airing)
     * @var string defaultFlags   - List of default flags
     * @var array startTime
     * @var     array dayCheck    - List of times to check for episodes daily (mintues of the hour) [splits the search evenly between the times]
     * @var array list
     * @var     int compactLimit  - Number of results in a list, to use the compact view method (many results on one line)
     * ENDCONFIG
     */
    var $_config = array(
        'publicCommand' => array( '^autoquery', '^!autoquery' ),
        'privateCommand' => array( '^@autoquery' ),
        'checkTime' => 5,
        'defaultFlags' => 'any',
        'startTime' => array(
            'dayCheck' => array( 04, 14, 24, 34, 44, 54 ),
            ),
        'list' => array(
            'compactLimit' => 6
            )
        );
        
    var $_def = array(
        'regex' => array(
            'flags' => '/(.+)\sf(?:lags?)?:([a-z0-9,.\s\&\(\)\~\|\-\+\/]+)/i',
            'getOptionSplit' => '/^(.+) (\S+)$/i',
            'getTimeSecs' => '/(\d{2}):(\d{2})(a|p)m/i'
            ),
        'date' => array(
            'history' => array(
                'time' => 'h:ia'
                )
            )            
        );
    
    var $_template = array(
        'queryExist' => 'The query **{query}** allready exists, please delete and re-add to change flags',
        'queryNotExist' => 'No query found with name matching: {query}',
        'queryAdded' => 'Added **{query}** to the autodownloader',
        'queryDeleted' => 'Deleted **{query}** from the autodownloader',
        'toManyMatch' => 'Unable to find a single match for {query}, possible queries: {listQueries}',
        'listShort' => '{listItemShort}',
        'listItem' => '**{query}**: f:{flags}{flagQueueBridge}{lastCheck}',
        'listItemShort' => '**{query}**',
        'flagQueueBridge' => '{flagQueue}', //change me to ' ({flagQueue})' when using it [see botList]
        //'flagQueue' => '{flag}{nzbid}{queued}{downloaded}',
        'flagQueue' => '{flag}{nzbid}',
        'error' => '**Error:** {errormsg}',
        'help' => '{command} - {description}',
        'helpList' => array(
            'Commands available for autoquery: {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'
            ),
        'add' => array(
            'command' => '{trigger} add query [f:flags]',
            'description' => 'Add the __query__ to the auto download list, when the query get posted on newzbin, it is automatically downloaded, __flags__ specifies the quality of the query you wish to download',
            'longDescription' => array(
                'Add the __query__ to the auto download list, when a report gets posted on newzbin matching the query, it is automatically downloaded',
                '__flags__, define the quality of files to be downloaded, a list of flags can be found: http://www.tiberious.org/wiki/index.php/Nzbirc/v1/flags',
                'The order of the flags define their importance (with the first being the most important), and the auto downloader will always attempt to dowload the best quality version',
                )
            ),
        'del' => array(
            'command' => '{trigger} del query',
            'description' => 'Delete a __query__ from the auto downloader list',
            'longDescription' => 'Delete a __query__ from the auto downloader list'
            ),
        'list' => array(
            'command' => '{trigger} list [query]',
            'description' => 'List information about a __query__, or all queries',
            'longDescription' => 'List information about a __query__, is no __query__ is specified, information about all the queries are shown',
            ),
        'update' => array(
            'command' => '{trigger} update query',
            'description' => 'Perform a manual update on a particular __query__, this will check for new reports on newzbin.com',
            'longDescription' => 'Perform a manual update on a particular __query__, this will check for new reports on newzbin.com'
            ),
        );
            
    function _registerCommands()
    {
         global $irc;
         
        $this->_setHandler( '^add', $this, 'botAdd' );
        $this->_setHandler( '^del', $this, 'botDel' );
        $this->_setHandler( '^list', $this, 'botList' );
        $this->_setHandler( '^update', $this, 'botUpdate' );
        
        //help
        $this->_setHandler( '^help', $this, 'botHelp' );
        $this->_setHandler( '^commands', $this, 'botCommands' );
        
        $irc->_modules['store']->addVariable( '_autoqueryInfo' );
        
        $this->_checkQueryFlags();
        
        if ( ( ( $irc->config->useWorker == true ) &&
               ( $irc->isWorker == true ) ) ||
             ( $irc->config->useWorker == false ) )
        {
            $this->_setupTimers();
        }
    }
    
    function _customClose()
    {
        global $irc;
        
        if ( is_array( $irc->_autoqueryTimers ) )
        {
            foreach( $irc->_autoqueryTimers as $id )
            {
                $irc->unregisterTimeid( $id );
            }
        }
        
        if ( is_array( $irc->_autoquerySTimers ) )
        {
            foreach( $irc->_autoquerySTimers as $t )
            {
                if ( is_array( $t ) )
                {
                    foreach( $t as $s )
                    {
                        $irc->unregisterTimeid( $s );
                    }
                }
            }
        }
    }
    
    
    /*****************************************************
     * Bot functions
     *****************************************************/    
    
    function botAdd( &$irc, &$data, $notice )
    {
        // split up the query string
        if ( preg_match( $this->_def['regex']['flags'], $data->subMessage, $flagSplit ) )
        {
            $flags = $flagSplit[2];
            $query = $flagSplit[1];
        }
        else
        {
            $flags = $this->_config['defaultFlags'];
            $query = $data->subMessage;
        }
    
        // check if the query allready exists
        if ( ( $qID = $this->_findQuery( $query ) ) != false )
        {
            $vars = array(
                'query' => $query
                );
            $this->parseTemplate( $msg, 'queryExists', $vars );   
        }
        else
        {
            $id = $this->addQuery( $query, $flags, $data ); 
            
            $vars = array(
                'query' => $query
                );
                
            $this->parseTemplate( $msg, 'queryAdded', $vars );
        }
        
        if ( isset( $msg ) )
        {
            $irc->_modules['func']->reply( $irc, $data, $msg, $notice );            
        }
    }
    
    function botDel( &$irc, &$data, $notice )
    {
        $qIDs = $this->_getQuery( $data->subMessage );
        
        if ( count( $qIDs ) == 1 )
        {
            $query = $irc->_autoqueryInfo[$qIDs[0]]['query'];
            // delete show
            unset( $irc->_autoqueryInfo[$qIDs[0]] );
            $irc->_modules['store']->manualUpdate( '_autoqueryInfo', true );
            
            $this->parseTemplate( $msg, 'queryDeleted', array( 'query' => $query ) );
        }
        else if ( count( $qIDs ) > 1 )
        {
            $vars = array(
                'query' => $data->subMessage
                );
            foreach( $qIDs as $id )
            {
                $vars['listQueries'][] = $irc->_autoqueryInfo[$id]['query'];
            }
            $this->parseTemplate( $msg, 'toManyMatch', $vars );
        }
        else
        {
            $this->parseTemplate( $msg, 'queryNotExist', array( 'query' => $data->subMessage ) );            
        }
        if ( isset( $msg ) )
        {
            $irc->_modules['func']->reply( $irc, $data, $msg, $notice );
        }
    }

    function botList( &$irc, &$data, $notice )
    {       
        global $irc;
        
        $list = $this->listQueries( $data->subMessage );

        if ( count( $list ) == 0 )
        {
            if ( strlen( $query ) > 0 )
            {
                $vars['search'] = ' for: '.$query;
            }
            $this->parseTemplate( $msg, 'listEmpty', $vars );
        }
        else if ( count( $list ) > $this->_config['list']['compactLimit'] )
        {
            foreach( $list as $id )
            {
                $tmp = $irc->_autoqueryInfo[$id];
                
                $vars['listItemShort'][] = $tmp;
            }
            $this->parseTemplate( $msg, 'listShort', $vars );
        }
        else
        {
            foreach( $list as $id )
            {
                $tmp = $irc->_autoqueryInfo[$id];
                
                $vars['query'] = $tmp['query'];

                $vars['lastCheck'] = ( $tmp['lastCheck'] > 0 )? ', chk:'.$irc->_modules['func']->nicedur( $tmp['lastCheck'] ):'';                        
                               
                foreach( $tmp['flags'] as $flag )
                {
                    $vars['flags'][] = $flag['name'];
                                                
                    if ( isset( $flag['nzbid'] ) )
                    {
                        $tFlag = array(
                            'flag' => $flag['name'],
                            'nzbid' => ':'.$flag['nzbid']
                            );
                        if ( isset( $flag['queued'] ) )
                        {
                            $tFlag['queued'] = ':q'.$irc->_modules['func']->snicedate( $flag['queued'] );
                        }
                        if ( isset( $flag['downloaded'] ) )
                        {
                            $tFlag['downloaded'] = ':d'.$irc->_modules['func']->duration( $flag['downloaded'], $fOpts['queued'] );
                        }
                        $vars['flagQueue'][] = $tFlag;
                        $vars['flagQueueBridge'] = ' | {flagQueue}';
                    }
                }                
                $this->parseTemplate( $msg, 'listItem', $vars );
                unset( $vars );
            }
        }
        
        if ( isset( $msg ) )
        {
            $irc->_modules['func']->reply( $irc, $data, $msg, $notice );
        }
            
    }
    
    function botUpdate( &$irc, &$data, $notice )
    {
        if ( strlen( $data->subMessage ) > 0 )
        {
            $qIDs = $this->_getQuery( $data->subMessage );
            
            if ( count( $qIDs ) == 1 )
            {
                $this->_updateQuery( $qIDs[0] );
            }
            else if ( count( $qIDs  ) > 1 )
            {
                $vars = array(
                    'query' => $data->subMessage
                );
                
                foreach( $qIDs  as $id )
                {
                    $vars['listQuery'][] = $irc->_autoqueryInfo[$id]['query'];
                }
                $this->parseTemplate( $msg, 'toManyMatch', $vars );
            }
            else
            {
                $this->parseTemplate( $msg, 'queryNotExist', array( 'query' => $query ) );            
            }
        }
        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 );
        }
    }    
    
    /*****************************************************
     * General functions
     *****************************************************/
    
    function addQuery( $query, $flags, $data )
    {
        global $irc;
        
        $irc->modDebug( 'autoquery', 'Added query: '.$query, __FILE__, __LINE__ );
        
        $options = array(
            'query' => $query,
            'data' => $irc->_modules['func']->getTData( $data ),
            'checkTime' => $this->_config['checkTime'],
            );
        
        if ( strlen( $flags ) == 0 )
        {
            $flags = $this->_config['defaultFlags'];
        }

        $fExplode = explode( ',', $flags );
        
        foreach( $fExplode as $value )
        {
            $options['flags'][] = array( 
            	'name' => $value,
            	'done' => false
            );
        }
        
        $irc->_modules['store']->manualUpdate( '_autoqueryInfo' );
        $irc->_autoqueryInfo[] = $options;
        $irc->_modules['store']->manualUpdate( '_autoqueryInfo', true );
        
        $id = $this->_findQuery( $query );      
        
        return $id;
    }
                  
    
    function _getQuery( $name )
    {
        global $irc;
        
        $out = array();
        $regex = '/.*'.str_replace( ' ', '.*', $name ).'.*/i';
        
        $irc->_modules['store']->manualUpdate( '_autoqueryInfo' );
        
        if ( is_array( $irc->_autoqueryInfo ) )
        {
            foreach( $irc->_autoqueryInfo as $id => $query )
            {
                if ( strlen( $name ) > 0 )
                {
                    if ( strtolower( $query['query'] ) == strtolower( $query ) )
                    {
                        $out = array( $id );
                        return $out;
                    }
                }
                $irc->modDebug( 'autoquery', 'query: '.$query['query'], __FILE__, __LINE__ );
                if ( preg_match( $regex, $query['query'] ) )
                {
                    $irc->modDebug( 'autoquery', 'regexMatch '.$id, __FILE__, __LINE__ );
                    $out[] = $id;
                }
            }
        }
        return $out;
    }
    
    function listQueries( $query = '' )
    {
        return $this->_getQuery( $query );
    }
    
    function _updateQuery( $qID )
    {
        global $irc;

        $irc->_modules['store']->manualUpdate( '_autoqueryInfo' );
        
        if ( isset( $irc->_autoqueryInfo[$qID] ) )
        {
            // get a list of flags that have not been downloaded
            $listFlags = array();
            foreach( $irc->_autoqueryInfo[$qID]['flags'] as $flag )
            {
                if ( !$flag['done'] )
                {
                    $listFlags[] = $flag['name'];
                }
            }

            if ( count( $listFlags ) > 0 )
            {
                $irc->_autoqueryInfo[$qID]['lastCheck'] = time();
                
                $irc->modDebug( 'autoquery', sprintf( 'Checking: %s | flags: %s', $irc->_autoqueryInfo[$qID]['query'], implode( ',', $listFlags ) ), __FILE__, __LINE__, SMARTIRC_DEBUG_MODULES );                
                
                $result = array();
                
                $result = $irc->_modules['nzb']->search( $irc->_autoqueryInfo[$qID]['query'], 1, $listFlags );
                
                // sod it, lets take the first entry
                if ( count( $result ) > 0 )
                {
                    $theResult = $result[0];
                    
					// use the score to get which flag was successful
					$flagID = count( $listFlags ) - $theResult['score'];
										
					$rFlag = $listFlags[$flagID];
					$fid = $this->_getFlagIndex( $irc->_autoqueryInfo[$qID], $rFlag );
					
                	// unset the lower flags
                	$qFlags = $irc->_autoqueryInfo[$qID]['flags'];
					for ( $i = $fid; $i < count( $qFlags ); $i++ )
					{
						unset( $irc->_autoqueryInfo[$qID]['flags'][$i] );
					}					
					
					$irc->_autoqueryInfo[$qID]['flags'][$fid] = array(
						'name' => $rFlag,
						'done' => true,
						'nzbid' => $theResult['report:id'],
						'queued' => time()
					);
					
					$irc->_autoqueryInfo[$qID]['beenQueued'] = true;
					$irc->_modules['store']->manualUpdate( '_autoqueryInfo', true );
					
					$irc->modDebug( 'autoquery', sprintf( 'queued %d:%s, %s', $theResult['report:id'], $theResult['report:title'], $rFlag ), __FILE__, __LINE__ );
					//$irc->_modules['func']->reply( $irc, $irc->_autotvInfo[$sID]['data'], sprintf( 'Fake Download: %d:%s, %s', $theResult['id'], $theResult['title'], $rFlag ) );

					// add to download queue
					// $irc->_modules['nzb']->addID( $theResult['id'], $irc->_autotvInfo[$sID]['data'], $irc->_autotvInfo[$sID]['priority'] );
					$irc->_modules['store']->setVariable( '_nzbWait', array(
							'id' => $theResult['report:id'],
							'data' => $irc->_autoqueryInfo[$qID]['data'] ),
						$theResult['report:id']
					);
					$irc->_modules['store']->setVariable( '_nzbCache', $theResult, $theResult['report:id'] );
				}
            }
        }
        $irc->_modules['store']->manualUpdate( '_autoqueryInfo', true );
    }
    
	/**
	 * Get the index of a particular flag for a query
	 *
	 * @param array $query - The query to search for the flag in
	 * @param string $flagName - The name of the flag 
	 * @return int - The index of the flag
	 * @access private
	 */
	function _getFlagIndex( $query, $flagName )
	{
		foreach( $query['flags'] as $k => $val )
		{
			if ( $val['name'] == $flagName )
			{
				return $k;
			}
		}
		return -1;
	}
    
    /**
    * @desc Find a query in the list, and return the index
    * 
    * @var string $query    - the query to search for
    * @return mixed         - the index if it exists, otherwise false
    * @access private
    */
    function _findQuery( $query )
    {
        global $irc;
        
        if ( is_array( $irc->_autoqueryList ) )
        {
            foreach( $irc->_autoqueryList as $index => $val )
            {
                if ($val['query'] == $query)
                {
                    return $index;
                }   
            }
        }
        
        return false;
    }
    

	/**
	 * Check the queries for old flag type and fix
	 *
	 */
	function _checkQueryFlags()
	{
		global $irc;
		
		if ( is_array( $irc->_autoqueryInfo ) )
		{
			foreach( $irc->_autoqueryInfo as $qID => $query )
			{
				if ( ( count( $query['flags'] ) > 0 ) && ( !isset( $query['flags'][0]['name'] ) ) )
				{
					$irc->modDebug( 'autoquery', sprintf( 'Fixing query %s to new flag system', $query['query'] ), __FILE__, __LINE__ );
	
					$flags = $query['flags'];
					
					$irc->_autoqueryInfo[$qID]['flags'] = array();
					
					foreach( $flags as $name => $flag )
					{
						$flag['name'] = $name;
						$irc->_autoqueryInfo[$qID]['flags'][] = $flag;
					}
				}
				elseif ( isset( $query['flags'][0]['name'] ) )
				{
					$irc->modDebug( 'autoquery', 'Found new flag system, nothing to fix', __FILE__, __LINE__ );
					return;
				}
			}
		}
		$irc->_modules['store']->manualUpdate('_autoqueryInfo', true);
	}
    
    /*****************************************************
     * Timers
     *****************************************************/    
    
    function _setupTimers()
    {
        global $irc;

        // daily check
        foreach( $this->_config['startTime']['dayCheck'] as $i => $cTime )
        {
            // 3am, why not
            $nTime = strtotime( date('Y/m/d').' '.$this->_config['checkTime'].':'.$cTime );
            $nTime = $nTime - time();
            if ( $nTime < 5 )
                $nTime += 86400;            
            $irc->_autoquerySTimers['day'][$i] = $irc->registerTimeHandler( $nTime * 1000, $this, '_firstDUS', array( 'id' => $i ) );
            $irc->modDebug( 'autoquery', 'Registered inital day check timer: '.$cTime.', in '.$irc->_modules['func']->duration($nTime), __FILE__, __LINE__ );            
        }
    }
            
    
    function _firstDUS( &$irc, $vars )
    {
        $id = $vars['id'];
        
        $irc->unregisterTimeid( $irc->_autoquerySTimers['day'][$id] );
        unset( $irc->_autoquerySTimers['day'][$id] );
        
        $irc->_autoqueryTimers[] = $irc->registerTimeHandler( 86400000, $this, '_dailyUpdateShows', $vars );
        $irc->modDebug( 'autoquery', 'Registered regular day check timer: '.date('i').', in '.$irc->_modules['func']->duration(86400), __FILE__, __LINE__ );        
        $this->_dailyUpdateShows( $irc, $vars );
    }
    
    
    function _dailyUpdateShows( &$irc, $vars )
    {
        list( $tStart, $tStop ) = $this->_timerSplit( 'dayCheck', $vars['id'] );
        
        $irc->_modules['store']->manualUpdate( '_autoqueryInfo' );

        if ( is_array( $irc->_autoqueryInfo ) )
        {        
            $keys = array_keys( $irc->_autoqueryInfo );        
            for( $i=$tStart; $i < $tStop; $i++ )
            {
                $cShows .= $irc->_autoqueryInfo[$keys[$i]]['query'].', ';
                $this->_updateQuery( $keys[$i] );
            }
            $irc->modDebug( 'autoquery', 'Checked queries: '.$cShows.'for new reports', __FILE__, __LINE__ );
        }
    }
    
    /**
     * Get the current entry in the startTime split
     * 
     * @param string $name - Variable name in startTime config array
     * @param int $id - The timer identifier
     * @return array $tStart, $tStop - The starting and stopping positions of the autoqueryInfo array
     */
    function _timerSplit( $name, $id )
    {
        global $irc;
            
        $nSplit = count( $this->_config['startTime'][$name] );

        $tTotal = count( $irc->_autoqueryInfo );
        $tStart = floor( ( $tTotal / $nSplit ) * $id );
        $tStop = ceil( ( $tTotal / $nSplit ) * ($id + 1) );
        
        return array( $tStart, $tStop );
    }
    
}

?>
Return current item: Nzbirc