@ -16,124 +16,147 @@
# You should have received a copy of the GNU Lesser General Public License
# You should have received a copy of the GNU Lesser General Public License
# along with subliminal. If not, see <http://www.gnu.org/licenses/>.
# along with subliminal. If not, see <http://www.gnu.org/licenses/>.
from . import ServiceBase
from . import ServiceBase
from . . exceptions import DownloadFailedError , ServiceError
from . . exceptions import ServiceError
from . . language import language_set
from . . language import language_set
from . . subtitles import get_subtitle_path , ResultSubtitle
from . . subtitles import get_subtitle_path , ResultSubtitle
from . . videos import Episode , Movie
from . . videos import Episode , Movie
from . . utils import to_unicode , get_keywords
from . . utils import to_unicode
from bs4 import BeautifulSoup
import bisect
import bisect
import json
import logging
import logging
from urllib import urlencode
logger = logging . getLogger ( __name__ )
logger = logging . getLogger ( __name__ )
class Subscenter ( ServiceBase ) :
class Subscenter ( ServiceBase ) :
server = ' http://www.subscenter.info/he / '
server = ' http://www.cinemast.org/he/cinemast/api / '
api_based = Fals e
api_based = Tru e
languages = language_set ( [ ' he ' ] )
languages = language_set ( [ ' he ' ] )
videos = [ Episode , Movie ]
videos = [ Episode , Movie ]
require_video = False
require_video = False
def _search_url_title ( self , title , kind ) :
default_username = ' subliminal@gmail.com '
""" Search the URL title for the given `title`.
default_password = ' subliminal '
: param str title : title to search for .
: param str kind : kind of the title , ` ` movie ` ` or ` ` series ` ` .
: return : the URL version of the title .
: rtype : str or None
"""
# make the search
logger . info ( ' Searching title name for %r ' , title )
r = self . session . get ( self . server + ' subtitle/search/ ' , params = { ' q ' : title } , allow_redirects = False , timeout = 10 )
r . raise_for_status ( )
# if redirected, get the url title from the Location header
def __init__ ( self , config = None ) :
if r . is_redirect :
super ( Subscenter , self ) . __init__ ( config )
parts = r . headers [ ' Location ' ] . split ( ' / ' )
self . token = None
self . user_id = None
# check kind
def init ( self ) :
if parts [ - 3 ] == kind :
super ( Subscenter , self ) . init ( )
return parts [ - 2 ]
logger . debug ( ' Logging in ' )
url = self . server_url + ' login/ '
return None
# actual login
data = { ' username ' : self . default_username , ' password ' : self . default_password }
r = self . session . post ( url , data = urlencode ( data ) , allow_redirects = False , timeout = 10 )
# otherwise, get the first valid suggestion
if r . status_code != 200 :
soup = BeautifulSoup ( r . content , [ ' lxml ' , ' html.parser ' ] )
raise ServiceError ( ' Login failed ' )
suggestions = soup . select ( ' #processes div.generalWindowTop a ' )
logger . debug ( ' Found %d suggestions ' , len ( suggestions ) )
try :
for suggestion in suggestions :
result = r . json ( )
parts = suggestion . attrs [ ' href ' ] . split ( ' / ' )
if ' token ' not in result :
raise ServiceError ( ' Login failed ' )
# check kind
logger . info ( ' Logged in ' )
if parts [ - 3 ] == kind :
self . user_id = r . json ( ) . get ( ' user ' )
return parts [ - 2 ]
self . token = r . json ( ) . get ( ' token ' )
except ValueError :
raise ServiceError ( ' Login failed ' )
def terminate ( self ) :
super ( Subscenter , self ) . terminate ( )
if self . token or self . user_id :
logger . info ( ' Logged out ' )
self . token = None
self . user_id = None
def list_checked ( self , video , languages ) :
def list_checked ( self , video , languages ) :
series = None
series = None
season = None
season = None
episode = None
episode = None
title = video . title
title = video . title
year = video . year
if isinstance ( video , Episode ) :
if isinstance ( video , Episode ) :
series = video . series
series = video . series
season = video . season
season = video . season
episode = video . episode
episode = video . episode
return self . query ( video . path or video . release , languages , get_keywords ( video . guess ) , series , season ,
return self . query ( video . path or video . release , languages , series , season , episode , title , year )
episode , title )
def query ( self , filepath , languages = None , keywords = None , series = None , season = None , episode = None , title = None ) :
def query ( self , filepath , languages = None , series = None , season = None , episode = None , title = None , year = None ) :
logger . debug ( u ' Getting subtitles for {0} season {1} episode {2} with languages {3} ' . format (
logger . debug ( u ' Getting subtitles for {0} season {1} episode {2} with languages {3} ' . format (
series , season , episode , languages ) )
series , season , episode , languages ) )
# Set the correct parameters depending on the kind.
if series and season and episode :
query = {
url_series = self . _search_url_title ( series , ' series ' )
' user ' : self . user_id ,
url = self . server + ' cst/data/series/sb/ {} / {} / {} / ' . format ( url_series , season , episode )
' token ' : self . token
}
# episode
if season and episode :
query [ ' q ' ] = series
query [ ' type ' ] = ' series '
query [ ' season ' ] = season
query [ ' episode ' ] = episode
elif title :
elif title :
url_title = self . _search_url_title ( title , ' movie ' )
query [ ' q ' ] = title
url = self . server + ' cst/data/movie/sb/ {} / ' . format ( url_title )
query [ ' type ' ] = ' movies '
if year :
query [ ' year_start ' ] = year - 1
query [ ' year_end ' ] = year
else :
else :
raise ServiceError ( ' One or more parameters are missing ' )
raise ServiceError ( ' One or more parameters are missing ' )
logger . debug ( ' Searching subtitles for title {0} , season {1} , episode {2} ' . format ( title , season , episode ) )
response = self . session . get ( url )
# get the list of subtitles
if response . status_code != 200 :
logger . debug ( ' Getting the list of subtitles ' )
raise ServiceError ( ' Request failed with status code {0} ' . format ( response . status_code ) )
url = self . server_url + ' search/ '
# Loop over results.
r = self . session . post ( url , data = urlencode ( query ) )
subtitles = dict ( )
r . raise_for_status ( )
response_json = json . loads ( response . content )
for language_code , language_data in response_json . items ( ) :
try :
language_object = self . get_language ( language_code )
results = r . json ( )
if language_object in self . languages and language_object in languages :
except ValueError :
for quality_data in language_data . values ( ) :
return { }
for quality , subtitles_data in quality_data . items ( ) :
for subtitle_item in subtitles_data . values ( ) :
# loop over results
# Read the item.
subtitles = { }
subtitle_id = subtitle_item [ ' id ' ]
for group_data in results . get ( ' data ' , [ ] ) :
subtitle_key = subtitle_item [ ' key ' ]
for language_code , subtitles_data in group_data . get ( ' subtitles ' , { } ) . items ( ) :
subtitle_version = subtitle_item [ ' h_version ' ]
language_object = self . get_language ( language_code )
release = subtitle_item [ ' subtitle_version ' ]
subtitle_path = get_subtitle_path ( filepath , language_object , self . config . multi )
for subtitle_item in subtitles_data :
download_link = self . server_url + ' subtitle/download/ {0} / {1} /?v= {2} &key= {3} ' . format (
# read the item
language_code , subtitle_id , subtitle_version , subtitle_key )
subtitle_id = subtitle_item [ ' id ' ]
# Add the release and increment downloaded count if we already have the subtitle.
subtitle_key = subtitle_item [ ' key ' ]
if subtitle_id in subtitles :
release = subtitle_item [ ' version ' ]
logger . debug ( ' Found additional release {0} for subtitle {1} ' . format (
release , subtitle_id ) )
subtitle_path = get_subtitle_path ( filepath , language_object , self . config . multi )
bisect . insort_left ( subtitles [ subtitle_id ] . release , release ) # Deterministic order.
download_link = self . server_url + ' subtitle/download/ {0} /?v= {1} &key= {2} &sub_id= {3} ' . format (
continue
language_code , release , subtitle_key , subtitle_id )
# Otherwise create it.
# Add the release and increment downloaded count if we already have the subtitle.
subtitle = ResultSubtitle ( subtitle_path , language_object , self . __class__ . __name__ . lower ( ) ,
if subtitle_id in subtitles :
download_link , release = to_unicode ( release ) )
logger . debug ( ' Found additional release {0} for subtitle {1} ' . format (
logger . debug ( ' Found subtitle %r ' , subtitle )
release , subtitle_id ) )
subtitles [ subtitle_id ] = subtitle
bisect . insort_left ( subtitles [ subtitle_id ] . release , release ) # Deterministic order.
continue
# Otherwise create it.
subtitle = ResultSubtitle ( subtitle_path , language_object , self . __class__ . __name__ . lower ( ) ,
download_link , release = to_unicode ( release ) )
logger . debug ( ' Found subtitle %r ' , subtitle )
subtitles [ subtitle_id ] = subtitle
return subtitles . values ( )
return subtitles . values ( )
def download ( self , subtitle ) :
def download ( self , subtitle ) :
try :
data = {
self . download_zip_file ( subtitle . link , subtitle . path )
' user ' : self . user_id ,
except DownloadFailedError :
' token ' : self . token
# If no zip file was retrieved, daily downloads limit has exceeded.
}
raise ServiceError ( ' Daily limit exceeded ' )
self . download_zip_file ( subtitle . link , subtitle . path , data = urlencode ( data ) )
return subtitle
return subtitle