2014-03-10 01:18:05 -04:00
# Author: Nyaran <nyayukko@gmail.com>, based on Antoine Bertin <diaoulael@gmail.com> work
# URL: http://code.google.com/p/sickbeard/
#
# This file is part of Sick Beard.
#
# Sick Beard 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 3 of the License, or
# (at your option) any later version.
#
# Sick Beard 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 Sick Beard. If not, see <http://www.gnu.org/licenses/>.
2014-05-17 14:14:48 -04:00
import time
2014-03-10 01:18:05 -04:00
import datetime
import sickbeard
from sickbeard . common import *
2014-05-14 21:41:08 -04:00
from sickbeard import notifiers
2014-03-10 01:18:05 -04:00
from sickbeard import logger
from sickbeard import helpers
from sickbeard import encodingKludge as ek
from sickbeard import db
2014-05-14 21:41:08 -04:00
from sickbeard import history
2014-03-10 01:18:05 -04:00
from lib import subliminal
2014-05-14 21:41:08 -04:00
SINGLE = ' und '
2014-05-14 17:52:05 -04:00
def sortedServiceList ( ) :
2014-05-14 21:41:08 -04:00
servicesMapping = dict ( [ ( x . lower ( ) , x ) for x in subliminal . core . SERVICES ] )
2014-03-10 01:18:05 -04:00
newList = [ ]
# add all services in the priority list, in order
curIndex = 0
for curService in sickbeard . SUBTITLES_SERVICES_LIST :
2014-05-14 21:41:08 -04:00
if curService in servicesMapping :
curServiceDict = { ' id ' : curService , ' image ' : curService + ' .png ' , ' name ' : servicesMapping [ curService ] , ' enabled ' : sickbeard . SUBTITLES_SERVICES_ENABLED [ curIndex ] == 1 , ' api_based ' : __import__ ( ' lib.subliminal.services. ' + curService , globals = globals ( ) , locals = locals ( ) , fromlist = [ ' Service ' ] , level = - 1 ) . Service . api_based , ' url ' : __import__ ( ' lib.subliminal.services. ' + curService , globals = globals ( ) , locals = locals ( ) , fromlist = [ ' Service ' ] , level = - 1 ) . Service . site_url }
2014-03-10 01:18:05 -04:00
newList . append ( curServiceDict )
curIndex + = 1
# add any services that are missing from that list
2014-05-14 21:41:08 -04:00
for curService in servicesMapping . keys ( ) :
2014-03-10 01:18:05 -04:00
if curService not in [ x [ ' id ' ] for x in newList ] :
2014-05-14 21:41:08 -04:00
curServiceDict = { ' id ' : curService , ' image ' : curService + ' .png ' , ' name ' : servicesMapping [ curService ] , ' enabled ' : False , ' api_based ' : __import__ ( ' lib.subliminal.services. ' + curService , globals = globals ( ) , locals = locals ( ) , fromlist = [ ' Service ' ] , level = - 1 ) . Service . api_based , ' url ' : __import__ ( ' lib.subliminal.services. ' + curService , globals = globals ( ) , locals = locals ( ) , fromlist = [ ' Service ' ] , level = - 1 ) . Service . site_url }
2014-03-10 01:18:05 -04:00
newList . append ( curServiceDict )
return newList
2014-04-24 01:18:16 -04:00
2014-03-10 01:18:05 -04:00
def getEnabledServiceList ( ) :
return [ x [ ' name ' ] for x in sortedServiceList ( ) if x [ ' enabled ' ] ]
2014-04-24 01:18:16 -04:00
2014-05-14 21:41:08 -04:00
def isValidLanguage ( language ) :
return subliminal . language . language_list ( language )
2014-03-10 01:18:05 -04:00
def getLanguageName ( selectLang ) :
2014-05-14 21:41:08 -04:00
return subliminal . language . Language ( selectLang ) . name
2014-03-10 01:18:05 -04:00
2014-04-24 01:18:16 -04:00
def wantedLanguages ( sqlLike = False ) :
2014-03-10 01:18:05 -04:00
wantedLanguages = sorted ( sickbeard . SUBTITLES_LANGUAGES )
if sqlLike :
return ' % ' + ' , ' . join ( wantedLanguages ) + ' % '
return wantedLanguages
def subtitlesLanguages ( video_path ) :
""" Return a list detected subtitles for the given video file """
2014-05-14 21:41:08 -04:00
video = subliminal . videos . Video . from_path ( video_path )
subtitles = video . scan ( )
languages = set ( )
for subtitle in subtitles :
if subtitle . language :
languages . add ( subtitle . language . alpha2 )
else :
languages . add ( SINGLE )
return list ( languages )
2014-03-10 01:18:05 -04:00
# Return a list with languages that have alpha2 code
def subtitleLanguageFilter ( ) :
2014-05-14 21:41:08 -04:00
return [ language for language in subliminal . language . LANGUAGES if language [ 2 ] != " " ]
2014-03-10 01:18:05 -04:00
class SubtitlesFinder ( ) :
"""
The SubtitlesFinder will be executed every hour but will not necessarly search
and download subtitles . Only if the defined rule is true
"""
2014-05-19 13:40:25 -04:00
def run ( self , force = False ) :
2014-03-10 01:18:05 -04:00
# TODO: Put that in the __init__ before starting the thread?
if not sickbeard . USE_SUBTITLES :
logger . log ( u ' Subtitles support disabled ' , logger . DEBUG )
return
if len ( sickbeard . subtitles . getEnabledServiceList ( ) ) < 1 :
2014-04-24 01:18:16 -04:00
logger . log ( u ' Not enough services selected. At least 1 service is required to search subtitles in the background ' , logger . ERROR )
2014-03-10 01:18:05 -04:00
return
logger . log ( u ' Checking for subtitles ' , logger . MESSAGE )
# get episodes on which we want subtitles
# criteria is:
# - show subtitles = 1
# - episode subtitles != config wanted languages or SINGLE (depends on config multi)
# - search count < 2 and diff(airdate, now) > 1 week : now -> 1d
# - search count < 7 and diff(airdate, now) <= 1 week : now -> 4h -> 8h -> 16h -> 1d -> 1d -> 1d
2014-04-24 01:18:16 -04:00
2014-03-10 01:18:05 -04:00
myDB = db . DBConnection ( )
today = datetime . date . today ( ) . toordinal ( )
# you have 5 minutes to understand that one. Good luck
2014-04-24 01:18:16 -04:00
sqlResults = myDB . select ( ' SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.subtitles, e.subtitles_searchcount AS searchcount, e.subtitles_lastsearch AS lastsearch, e.location, (? - e.airdate) AS airdate_daydiff FROM tv_episodes AS e INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id) WHERE s.subtitles = 1 AND e.subtitles NOT LIKE (?) AND ((e.subtitles_searchcount <= 2 AND (? - e.airdate) > 7) OR (e.subtitles_searchcount <= 7 AND (? - e.airdate) <= 7)) AND (e.status IN ( ' + ' , ' . join ( [ str ( x ) for x in Quality . DOWNLOADED ] ) + ' ) OR (e.status IN ( ' + ' , ' . join ( [ str ( x ) for x in Quality . SNATCHED + Quality . SNATCHED_PROPER ] ) + ' ) AND e.location != " " )) ' , [ today , wantedLanguages ( True ) , today , today ] )
2014-03-10 01:18:05 -04:00
if len ( sqlResults ) == 0 :
logger . log ( ' No subtitles to download ' , logger . MESSAGE )
return
2014-04-24 01:18:16 -04:00
2014-03-10 01:18:05 -04:00
rules = self . _getRules ( )
2014-03-25 01:57:24 -04:00
now = datetime . datetime . now ( )
2014-03-10 01:18:05 -04:00
for epToSub in sqlResults :
2014-05-17 14:14:48 -04:00
2014-03-10 01:18:05 -04:00
if not ek . ek ( os . path . isfile , epToSub [ ' location ' ] ) :
2014-04-24 01:18:16 -04:00
logger . log ( ' Episode file does not exist, cannot download subtitles for episode %d x %d of show %s ' % ( epToSub [ ' season ' ] , epToSub [ ' episode ' ] , epToSub [ ' show_name ' ] ) , logger . DEBUG )
2014-03-10 01:18:05 -04:00
continue
2014-04-24 01:18:16 -04:00
2014-03-10 01:18:05 -04:00
# Old shows rule
2014-04-27 18:16:43 -04:00
throwaway = datetime . datetime . strptime ( ' 20110101 ' , ' % Y % m %d ' )
2014-04-24 01:18:16 -04:00
if ( ( epToSub [ ' airdate_daydiff ' ] > 7 and epToSub [ ' searchcount ' ] < 2 and now - datetime . datetime . strptime ( epToSub [ ' lastsearch ' ] , ' % Y- % m- %d % H: % M: % S ' ) > datetime . timedelta ( hours = rules [ ' old ' ] [ epToSub [ ' searchcount ' ] ] ) ) or
2014-03-10 01:18:05 -04:00
# Recent shows rule
2014-04-24 01:18:16 -04:00
( epToSub [ ' airdate_daydiff ' ] < = 7 and epToSub [ ' searchcount ' ] < 7 and now - datetime . datetime . strptime ( epToSub [ ' lastsearch ' ] , ' % Y- % m- %d % H: % M: % S ' ) > datetime . timedelta ( hours = rules [ ' new ' ] [ epToSub [ ' searchcount ' ] ] ) ) ) :
logger . log ( ' Downloading subtitles for episode %d x %d of show %s ' % ( epToSub [ ' season ' ] , epToSub [ ' episode ' ] , epToSub [ ' show_name ' ] ) , logger . DEBUG )
2014-03-10 01:18:05 -04:00
showObj = helpers . findCertainShow ( sickbeard . showList , int ( epToSub [ ' showid ' ] ) )
if not showObj :
logger . log ( u ' Show not found ' , logger . DEBUG )
return
2014-04-24 01:18:16 -04:00
2014-03-10 01:18:05 -04:00
epObj = showObj . getEpisode ( int ( epToSub [ " season " ] ) , int ( epToSub [ " episode " ] ) )
if isinstance ( epObj , str ) :
logger . log ( u ' Episode not found ' , logger . DEBUG )
return
2014-04-24 01:18:16 -04:00
2014-03-10 01:18:05 -04:00
previous_subtitles = epObj . subtitles
2014-04-24 01:18:16 -04:00
2014-03-10 01:18:05 -04:00
try :
subtitles = epObj . downloadSubtitles ( )
except :
logger . log ( u ' Unable to find subtitles ' , logger . DEBUG )
return
def _getRules ( self ) :
"""
Define the hours to wait between 2 subtitles search depending on :
- the episode : new or old
- the number of searches done so far ( searchcount ) , represented by the index of the list
"""
return { ' old ' : [ 0 , 24 ] , ' new ' : [ 0 , 4 , 8 , 4 , 16 , 24 , 24 ] }