2014-04-26 13:35:37 +00:00
# Author: Mr_Orange
# URL: https://github.com/mr-orange/Sick-Beard
#
2014-05-23 12:37:22 +00:00
# This file is part of SickRage.
2014-04-26 13:35:37 +00:00
#
2014-05-23 12:37:22 +00:00
# SickRage is free software: you can redistribute it and/or modify
2014-04-26 13:35:37 +00:00
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
2014-05-23 12:37:22 +00:00
# SickRage is distributed in the hope that it will be useful,
2014-04-26 13:35:37 +00:00
# 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
2014-05-23 12:37:22 +00:00
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
2014-04-26 13:35:37 +00:00
import re
import datetime
2014-04-27 10:31:54 +00:00
import urlparse
2014-05-07 07:50:49 +00:00
import time
2014-04-26 13:35:37 +00:00
import sickbeard
import generic
2014-04-27 10:31:54 +00:00
2014-05-17 11:40:26 +00:00
from sickbeard . common import Quality , cpu_presets
2014-04-26 13:35:37 +00:00
from sickbeard import logger
from sickbeard import tvcache
from sickbeard import db
from sickbeard import classes
from sickbeard import helpers
from sickbeard import show_name_helpers
from sickbeard . common import Overview
from sickbeard . exceptions import ex
from sickbeard import clients
from lib import requests
2014-04-27 10:31:54 +00:00
from lib . requests import exceptions
2014-04-27 14:48:19 +00:00
from sickbeard . helpers import sanitizeSceneName
2014-04-26 13:35:37 +00:00
class SpeedCDProvider ( generic . TorrentProvider ) :
urls = { ' base_url ' : ' http://speed.cd/ ' ,
' login ' : ' http://speed.cd/takelogin.php ' ,
' detail ' : ' http://speed.cd/t/ %s ' ,
' search ' : ' http://speed.cd/V3/API/API.php ' ,
' download ' : ' http://speed.cd/download.php?torrent= %s ' ,
}
def __init__ ( self ) :
generic . TorrentProvider . __init__ ( self , " Speedcd " )
self . supportsBacklog = True
2014-05-17 05:23:11 +00:00
self . enabled = False
self . username = None
self . password = None
self . ratio = None
self . freeleech = False
2014-05-20 16:06:11 +00:00
self . minseed = None
self . minleech = None
2014-05-17 05:23:11 +00:00
2014-04-26 13:35:37 +00:00
self . cache = SpeedCDCache ( self )
self . url = self . urls [ ' base_url ' ]
self . categories = { ' Season ' : { ' c14 ' : 1 } , ' Episode ' : { ' c2 ' : 1 , ' c49 ' : 1 } , ' RSS ' : { ' c14 ' : 1 , ' c2 ' : 1 , ' c49 ' : 1 } }
def isEnabled ( self ) :
2014-05-17 05:23:11 +00:00
return self . enabled
2014-04-26 13:35:37 +00:00
def imageName ( self ) :
return ' speedcd.png '
2014-05-26 06:29:22 +00:00
def getQuality ( self , item , anime = False ) :
2014-04-26 13:35:37 +00:00
2014-05-26 06:29:22 +00:00
quality = Quality . sceneQuality ( item [ 0 ] , anime )
2014-04-26 13:35:37 +00:00
return quality
def _doLogin ( self ) :
2014-05-17 05:23:11 +00:00
login_params = { ' username ' : self . username ,
' password ' : self . password
2014-04-26 13:35:37 +00:00
}
try :
2014-04-27 10:31:54 +00:00
response = self . session . post ( self . urls [ ' login ' ] , data = login_params , timeout = 30 , verify = False )
2014-04-26 13:35:37 +00:00
except ( requests . exceptions . ConnectionError , requests . exceptions . HTTPError ) , e :
logger . log ( u ' Unable to connect to ' + self . name + ' provider: ' + ex ( e ) , logger . ERROR )
return False
if re . search ( ' Incorrect username or Password. Please try again. ' , response . text ) \
or response . status_code == 401 :
logger . log ( u ' Invalid username or password for ' + self . name + ' Check your settings ' , logger . ERROR )
return False
return True
2014-04-30 13:49:50 +00:00
def _get_season_search_strings ( self , ep_obj ) :
2014-04-26 13:35:37 +00:00
#If Every episode in Season is a wanted Episode then search for Season first
2014-05-07 07:50:49 +00:00
search_string = { ' Season ' : [ ] }
2014-05-14 08:01:36 +00:00
for show_name in set ( show_name_helpers . allPossibleShowNames ( self . show ) ) :
if ep_obj . show . air_by_date or ep_obj . show . sports :
2014-05-23 05:02:49 +00:00
ep_string = show_name + str ( ep_obj . airdate ) . split ( ' - ' ) [ 0 ]
2014-05-14 08:01:36 +00:00
else :
2014-05-04 03:16:26 +00:00
ep_string = show_name + ' S %02d ' % int ( ep_obj . scene_season ) #1) showName SXX
2014-04-26 13:35:37 +00:00
2014-05-14 08:01:36 +00:00
search_string [ ' Season ' ] . append ( ep_string )
2014-04-26 13:35:37 +00:00
return [ search_string ]
2014-04-30 13:49:50 +00:00
def _get_episode_search_strings ( self , ep_obj , add_string = ' ' ) :
2014-04-26 13:35:37 +00:00
search_string = { ' Episode ' : [ ] }
2014-04-30 13:49:50 +00:00
if not ep_obj :
2014-04-26 13:35:37 +00:00
return [ ]
2014-04-29 13:14:19 +00:00
if self . show . air_by_date :
for show_name in set ( show_name_helpers . allPossibleShowNames ( self . show ) ) :
2014-04-27 14:48:19 +00:00
ep_string = sanitizeSceneName ( show_name ) + ' ' + \
2014-05-11 14:17:11 +00:00
str ( ep_obj . airdate ) . replace ( ' - ' , ' | ' )
2014-04-28 09:15:29 +00:00
search_string [ ' Episode ' ] . append ( ep_string )
2014-04-29 13:14:19 +00:00
elif self . show . sports :
for show_name in set ( show_name_helpers . allPossibleShowNames ( self . show ) ) :
2014-04-28 09:15:29 +00:00
ep_string = sanitizeSceneName ( show_name ) + ' ' + \
2014-04-30 13:49:50 +00:00
str ( ep_obj . airdate ) . replace ( ' - ' , ' | ' ) + ' | ' + \
ep_obj . airdate . strftime ( ' % b ' )
2014-04-26 13:35:37 +00:00
search_string [ ' Episode ' ] . append ( ep_string )
else :
2014-04-29 13:14:19 +00:00
for show_name in set ( show_name_helpers . allPossibleShowNames ( self . show ) ) :
2014-04-26 13:35:37 +00:00
ep_string = show_name_helpers . sanitizeSceneName ( show_name ) + ' ' + \
2014-04-30 13:49:50 +00:00
sickbeard . config . naming_ep_type [ 2 ] % { ' seasonnumber ' : ep_obj . scene_season , ' episodenumber ' : ep_obj . scene_episode }
2014-04-26 13:35:37 +00:00
search_string [ ' Episode ' ] . append ( re . sub ( ' \ s+ ' , ' ' , ep_string ) )
return [ search_string ]
2014-05-07 07:50:49 +00:00
def _doSearch ( self , search_params , epcount = 0 , age = 0 ) :
2014-04-26 13:35:37 +00:00
results = [ ]
items = { ' Season ' : [ ] , ' Episode ' : [ ] , ' RSS ' : [ ] }
if not self . _doLogin ( ) :
return [ ]
for mode in search_params . keys ( ) :
for search_string in search_params [ mode ] :
logger . log ( u " Search string: " + search_string , logger . DEBUG )
search_string = ' + ' . join ( search_string . split ( ) )
post_data = dict ( { ' /browse.php? ' : None , ' cata ' : ' yes ' , ' jxt ' : 4 , ' jxw ' : ' b ' , ' search ' : search_string } , * * self . categories [ mode ] )
data = self . session . post ( self . urls [ ' search ' ] , data = post_data ) . json ( )
try :
torrents = data . get ( ' Fs ' , [ ] ) [ 0 ] . get ( ' Cn ' , { } ) . get ( ' torrents ' , [ ] )
except :
continue
for torrent in torrents :
2014-05-17 05:23:11 +00:00
if self . freeleech and not torrent [ ' free ' ] :
2014-04-26 13:35:37 +00:00
continue
title = re . sub ( ' <[^>]*> ' , ' ' , torrent [ ' name ' ] )
url = self . urls [ ' download ' ] % ( torrent [ ' id ' ] )
seeders = int ( torrent [ ' seed ' ] )
leechers = int ( torrent [ ' leech ' ] )
2014-05-20 16:06:11 +00:00
if mode != ' RSS ' and ( seeders == 0 or seeders < self . minseed or leechers < self . minleech ) :
2014-04-26 13:35:37 +00:00
continue
if not title or not url :
continue
item = title , url , seeders , leechers
items [ mode ] . append ( item )
#For each search mode sort all the items by seeders
items [ mode ] . sort ( key = lambda tup : tup [ 2 ] , reverse = True )
results + = items [ mode ]
return results
def _get_title_and_url ( self , item ) :
title , url , seeders , leechers = item
if url :
url = str ( url ) . replace ( ' & ' , ' & ' )
return ( title , url )
2014-04-30 13:49:50 +00:00
def getURL ( self , url , post_data = None , headers = None , json = False ) :
2014-04-26 13:35:37 +00:00
if not self . session :
self . _doLogin ( )
try :
2014-04-27 10:31:54 +00:00
# Remove double-slashes from url
parsed = list ( urlparse . urlparse ( url ) )
parsed [ 2 ] = re . sub ( " / { 2,} " , " / " , parsed [ 2 ] ) # replace two or more / with one
url = urlparse . urlunparse ( parsed )
if sickbeard . PROXY_SETTING :
proxies = {
" http " : sickbeard . PROXY_SETTING ,
" https " : sickbeard . PROXY_SETTING ,
}
r = self . session . get ( url , proxies = proxies , verify = False )
else :
r = self . session . get ( url , verify = False )
2014-04-26 13:35:37 +00:00
except ( requests . exceptions . ConnectionError , requests . exceptions . HTTPError ) , e :
logger . log ( u " Error loading " + self . name + " URL: " + ex ( e ) , logger . ERROR )
return None
2014-04-27 10:31:54 +00:00
if r . status_code != 200 :
logger . log ( self . name + u " page requested with url " + url + " returned status code is " + str ( r . status_code ) + ' : ' + clients . http_error_code [ r . status_code ] , logger . WARNING )
2014-04-26 13:35:37 +00:00
return None
2014-04-27 10:31:54 +00:00
return r . content
2014-04-26 13:35:37 +00:00
def findPropers ( self , search_date = datetime . datetime . today ( ) ) :
results = [ ]
sqlResults = db . DBConnection ( ) . select ( ' SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e ' +
2014-05-02 09:59:13 +00:00
' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id) ' +
2014-04-26 13:35:37 +00:00
' WHERE e.airdate >= ' + str ( search_date . toordinal ( ) ) +
' AND (e.status IN ( ' + ' , ' . join ( [ str ( x ) for x in Quality . DOWNLOADED ] ) + ' ) ' +
' OR (e.status IN ( ' + ' , ' . join ( [ str ( x ) for x in Quality . SNATCHED ] ) + ' ))) '
)
if not sqlResults :
return [ ]
2014-04-29 13:14:19 +00:00
for sqlshow in sqlResults :
2014-04-29 15:16:17 +00:00
self . show = curshow = helpers . findCertainShow ( sickbeard . showList , int ( sqlshow [ " showid " ] ) )
2014-05-19 17:40:25 +00:00
if not self . show : continue
2014-04-29 13:14:19 +00:00
curEp = curshow . getEpisode ( int ( sqlshow [ " season " ] ) , int ( sqlshow [ " episode " ] ) )
2014-04-28 09:15:29 +00:00
2014-04-30 13:49:50 +00:00
searchString = self . _get_episode_search_strings ( curEp , add_string = ' PROPER|REPACK ' )
2014-04-26 13:35:37 +00:00
2014-04-30 13:49:50 +00:00
for item in self . _doSearch ( searchString [ 0 ] ) :
2014-04-26 13:35:37 +00:00
title , url = self . _get_title_and_url ( item )
results . append ( classes . Proper ( title , url , datetime . datetime . today ( ) ) )
return results
2014-05-08 22:28:28 +00:00
def seedRatio ( self ) :
2014-05-17 05:23:11 +00:00
return self . ratio
2014-04-26 13:35:37 +00:00
class SpeedCDCache ( tvcache . TVCache ) :
def __init__ ( self , provider ) :
tvcache . TVCache . __init__ ( self , provider )
# only poll Speedcd every 20 minutes max
self . minTime = 20
def updateCache ( self ) :
2014-05-18 15:33:31 +00:00
# delete anything older then 7 days
logger . log ( u " Clearing " + self . provider . name + " cache " )
self . _clearCache ( )
2014-04-26 13:35:37 +00:00
if not self . shouldUpdate ( ) :
return
search_params = { ' RSS ' : [ ' ' ] }
rss_results = self . provider . _doSearch ( search_params )
if rss_results :
self . setLastUpdate ( )
else :
return [ ]
ql = [ ]
for result in rss_results :
2014-05-08 14:03:50 +00:00
2014-04-26 13:35:37 +00:00
item = ( result [ 0 ] , result [ 1 ] )
ci = self . _parseItem ( item )
if ci is not None :
ql . append ( ci )
myDB = self . _getDB ( )
myDB . mass_action ( ql )
def _parseItem ( self , item ) :
( title , url ) = item
if not title or not url :
return None
2014-05-11 12:49:07 +00:00
logger . log ( u " Attempting to cache item:[ " + title + " ] " , logger . DEBUG )
2014-04-26 13:35:37 +00:00
return self . _addCacheEntry ( title , url )
provider = SpeedCDProvider ( )