<?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 );
}
}
?>