<s> """<STR_LIT>""" <EOL> from __future__ import division <EOL> from collections import defaultdict <EOL> from datetime import timedelta <EOL> import json <EOL> import logging <EOL> import os <EOL> import re <EOL> from babelfish import Error as BabelfishError , Language <EOL> import click <EOL> from dogpile . cache . backends . file import AbstractFileLock <EOL> from dogpile . core import ReadWriteMutex <EOL> from six . moves import configparser <EOL> from subliminal import ( Episode , Movie , ProviderPool , Video , __version__ , check_video , provider_manager , region , <EOL> save_subtitles , scan_video , scan_videos ) <EOL> from subliminal . subtitle import compute_score <EOL> logger = logging . getLogger ( __name__ ) <EOL> class MutexLock ( AbstractFileLock ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , filename ) : <EOL> self . mutex = ReadWriteMutex ( ) <EOL> def acquire_read_lock ( self , wait ) : <EOL> ret = self . mutex . acquire_read_lock ( wait ) <EOL> return wait or ret <EOL> def acquire_write_lock ( self , wait ) : <EOL> ret = self . mutex . acquire_write_lock ( wait ) <EOL> return wait or ret <EOL> def release_read_lock ( self ) : <EOL> return self . mutex . release_read_lock ( ) <EOL> def release_write_lock ( self ) : <EOL> return self . mutex . release_write_lock ( ) <EOL> class Config ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , path ) : <EOL> self . path = path <EOL> self . config = configparser . SafeConfigParser ( ) <EOL> self . config . add_section ( '<STR_LIT>' ) <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , json . dumps ( [ '<STR_LIT>' ] ) ) <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , json . dumps ( sorted ( [ p . name for p in provider_manager ] ) ) ) <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( <NUM_LIT:0> ) ) <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( <NUM_LIT:1> ) ) <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( int ( timedelta ( weeks = <NUM_LIT:2> ) . total_seconds ( ) ) ) ) <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( <NUM_LIT:1> ) ) <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( <NUM_LIT:0> ) ) <EOL> def read ( self ) : <EOL> """<STR_LIT>""" <EOL> self . config . read ( self . path ) <EOL> def write ( self ) : <EOL> """<STR_LIT>""" <EOL> with open ( self . path , '<STR_LIT:w>' ) as f : <EOL> self . config . write ( f ) <EOL> @ property <EOL> def languages ( self ) : <EOL> return { Language . fromietf ( l ) for l in json . loads ( self . config . get ( '<STR_LIT>' , '<STR_LIT>' ) ) } <EOL> @ languages . setter <EOL> def languages ( self , value ) : <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , json . dumps ( sorted ( [ str ( l ) for l in value ] ) ) ) <EOL> @ property <EOL> def providers ( self ) : <EOL> return json . loads ( self . config . get ( '<STR_LIT>' , '<STR_LIT>' ) ) <EOL> @ providers . setter <EOL> def providers ( self , value ) : <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , json . dumps ( sorted ( [ p . lower ( ) for p in value ] ) ) ) <EOL> @ property <EOL> def single ( self ) : <EOL> return self . config . getboolean ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> @ single . setter <EOL> def single ( self , value ) : <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( int ( value ) ) ) <EOL> @ property <EOL> def embedded_subtitles ( self ) : <EOL> return self . config . getboolean ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> @ embedded_subtitles . setter <EOL> def embedded_subtitles ( self , value ) : <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( int ( value ) ) ) <EOL> @ property <EOL> def age ( self ) : <EOL> return timedelta ( seconds = self . config . getint ( '<STR_LIT>' , '<STR_LIT>' ) ) <EOL> @ age . setter <EOL> def age ( self , value ) : <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( int ( value . total_seconds ( ) ) ) ) <EOL> @ property <EOL> def hearing_impaired ( self ) : <EOL> return self . config . getboolean ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> @ hearing_impaired . setter <EOL> def hearing_impaired ( self , value ) : <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( int ( value ) ) ) <EOL> @ property <EOL> def min_score ( self ) : <EOL> return self . config . getfloat ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> @ min_score . setter <EOL> def min_score ( self , value ) : <EOL> self . config . set ( '<STR_LIT>' , '<STR_LIT>' , str ( value ) ) <EOL> @ property <EOL> def provider_configs ( self ) : <EOL> rv = { } <EOL> for provider in provider_manager : <EOL> if self . config . has_section ( provider . name ) : <EOL> rv [ provider . name ] = { k : v for k , v in self . config . items ( provider . name ) } <EOL> return rv <EOL> @ provider_configs . setter <EOL> def provider_configs ( self , value ) : <EOL> for provider , config in value . items ( ) : <EOL> if not self . config . has_section ( provider ) : <EOL> self . config . add_section ( provider ) <EOL> for k , v in config . items ( ) : <EOL> self . config . set ( provider , k , v ) <EOL> class LanguageParamType ( click . ParamType ) : <EOL> """<STR_LIT>""" <EOL> name = '<STR_LIT>' <EOL> def convert ( self , value , param , ctx ) : <EOL> try : <EOL> return Language . fromietf ( value ) <EOL> except BabelfishError : <EOL> self . fail ( '<STR_LIT>' % value ) <EOL> LANGUAGE = LanguageParamType ( ) <EOL> class AgeParamType ( click . ParamType ) : <EOL> """<STR_LIT>""" <EOL> name = '<STR_LIT>' <EOL> def convert ( self , value , param , ctx ) : <EOL> match = re . match ( r'<STR_LIT>' , value ) <EOL> if not match : <EOL> self . fail ( '<STR_LIT>' % value ) <EOL> return timedelta ( ** { k : int ( v ) for k , v in match . groupdict ( <NUM_LIT:0> ) . items ( ) } ) <EOL> AGE = AgeParamType ( ) <EOL> PROVIDER = click . Choice ( sorted ( provider_manager . names ( ) ) ) <EOL> app_dir = click . get_app_dir ( '<STR_LIT>' ) <EOL> cache_file = '<STR_LIT>' <EOL> config_file = '<STR_LIT>' <EOL> @ click . group ( context_settings = { '<STR_LIT>' : <NUM_LIT:100> } , epilog = '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , type = click . STRING , nargs = <NUM_LIT:2> , metavar = '<STR_LIT>' , help = '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , type = click . STRING , nargs = <NUM_LIT:2> , metavar = '<STR_LIT>' , <EOL> help = '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , type = click . STRING , nargs = <NUM_LIT:2> , metavar = '<STR_LIT>' , help = '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , type = click . Path ( writable = True , resolve_path = True , file_okay = False ) , default = app_dir , <EOL> show_default = True , expose_value = True , help = '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , is_flag = True , help = '<STR_LIT>' ) <EOL> @ click . version_option ( __version__ ) <EOL> @ click . pass_context <EOL> def subliminal ( ctx , addic7ed , opensubtitles , subscenter , cache_dir , debug ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> os . makedirs ( cache_dir ) <EOL> except OSError : <EOL> if not os . path . isdir ( cache_dir ) : <EOL> raise <EOL> region . configure ( '<STR_LIT>' , expiration_time = timedelta ( days = <NUM_LIT:30> ) , <EOL> arguments = { '<STR_LIT:filename>' : os . path . join ( cache_dir , cache_file ) , '<STR_LIT>' : MutexLock } ) <EOL> if debug : <EOL> handler = logging . StreamHandler ( ) <EOL> handler . setFormatter ( logging . Formatter ( logging . BASIC_FORMAT ) ) <EOL> logging . getLogger ( '<STR_LIT>' ) . addHandler ( handler ) <EOL> logging . getLogger ( '<STR_LIT>' ) . setLevel ( logging . DEBUG ) <EOL> ctx . obj = { '<STR_LIT>' : { } } <EOL> if addic7ed : <EOL> ctx . obj [ '<STR_LIT>' ] [ '<STR_LIT>' ] = { '<STR_LIT:username>' : addic7ed [ <NUM_LIT:0> ] , '<STR_LIT:password>' : addic7ed [ <NUM_LIT:1> ] } <EOL> if opensubtitles : <EOL> ctx . obj [ '<STR_LIT>' ] [ '<STR_LIT>' ] = { '<STR_LIT:username>' : opensubtitles [ <NUM_LIT:0> ] , '<STR_LIT:password>' : opensubtitles [ <NUM_LIT:1> ] } <EOL> if subscenter : <EOL> ctx . obj [ '<STR_LIT>' ] [ '<STR_LIT>' ] = { '<STR_LIT:username>' : subscenter [ <NUM_LIT:0> ] , '<STR_LIT:password>' : subscenter [ <NUM_LIT:1> ] } <EOL> @ subliminal . command ( ) <EOL> @ click . option ( '<STR_LIT>' , is_flag = True , help = '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> @ click . pass_context <EOL> def cache ( ctx , clear_subliminal ) : <EOL> """<STR_LIT>""" <EOL> if clear_subliminal : <EOL> os . remove ( os . path . join ( ctx . parent . params [ '<STR_LIT>' ] , cache_file ) ) <EOL> click . echo ( '<STR_LIT>' ) <EOL> else : <EOL> click . echo ( '<STR_LIT>' ) <EOL> @ subliminal . command ( ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , type = LANGUAGE , required = True , multiple = True , help = '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , type = PROVIDER , multiple = True , help = '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , type = AGE , help = '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , type = click . STRING , metavar = '<STR_LIT>' , help = '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , type = click . STRING , metavar = '<STR_LIT>' , help = '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , is_flag = True , default = False , help = '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , is_flag = True , default = False , help = '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , is_flag = True , default = False , help = '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , type = click . IntRange ( <NUM_LIT:0> , <NUM_LIT:100> ) , default = <NUM_LIT:0> , help = '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> @ click . option ( '<STR_LIT>' , '<STR_LIT>' , count = True , help = '<STR_LIT>' ) <EOL> @ click . argument ( '<STR_LIT:path>' , type = click . Path ( ) , required = True , nargs = - <NUM_LIT:1> ) <EOL> @ click . pass_obj <EOL> def download ( obj , provider , language , age , directory , encoding , single , force , hearing_impaired , min_score , verbose , <EOL> path ) : <EOL> """<STR_LIT>""" <EOL> language = set ( language ) <EOL> videos = [ ] <EOL> ignored_videos = [ ] <EOL> errored_paths = [ ] <EOL> with click . progressbar ( path , label = '<STR_LIT>' , item_show_func = lambda p : p or '<STR_LIT>' ) as bar : <EOL> for p in bar : <EOL> logger . debug ( '<STR_LIT>' , p ) <EOL> if not os . path . exists ( p ) : <EOL> try : <EOL> video = Video . fromname ( p ) <EOL> except : <EOL> logger . exception ( '<STR_LIT>' , p ) <EOL> errored_paths . append ( p ) <EOL> continue <EOL> videos . append ( video ) <EOL> continue <EOL> if os . path . isdir ( p ) : <EOL> try : <EOL> scanned_videos = scan_videos ( p , subtitles = not force , embedded_subtitles = not force , <EOL> subtitles_dir = directory ) <EOL> except : <EOL> logger . exception ( '<STR_LIT>' , p ) <EOL> errored_paths . append ( p ) <EOL> continue <EOL> for video in scanned_videos : <EOL> if check_video ( video , languages = language , age = age , undefined = single ) : <EOL> videos . append ( video ) <EOL> else : <EOL> ignored_videos . append ( video ) <EOL> continue <EOL> try : <EOL> video = scan_video ( p , subtitles = not force , embedded_subtitles = not force , subtitles_dir = directory ) <EOL> except : <EOL> logger . exception ( '<STR_LIT>' , p ) <EOL> errored_paths . append ( p ) <EOL> continue <EOL> if check_video ( video , languages = language , age = age , undefined = single ) : <EOL> videos . append ( video ) <EOL> else : <EOL> ignored_videos . append ( video ) <EOL> if verbose > <NUM_LIT:0> : <EOL> for p in errored_paths : <EOL> click . secho ( '<STR_LIT>' % p , fg = '<STR_LIT>' ) <EOL> if verbose > <NUM_LIT:1> : <EOL> for video in ignored_videos : <EOL> click . secho ( '<STR_LIT>' % ( <EOL> os . path . split ( video . name ) [ <NUM_LIT:1> ] , <EOL> '<STR_LIT:U+002CU+0020>' . join ( str ( s ) for s in video . subtitle_languages ) or '<STR_LIT:none>' , <EOL> video . age . days , <EOL> '<STR_LIT:s>' if video . age . days > <NUM_LIT:1> else '<STR_LIT>' <EOL> ) , fg = '<STR_LIT>' ) <EOL> click . echo ( '<STR_LIT>' % ( <EOL> click . style ( str ( len ( videos ) ) , bold = True , fg = '<STR_LIT>' if videos else None ) , <EOL> '<STR_LIT:s>' if len ( videos ) > <NUM_LIT:1> else '<STR_LIT>' , <EOL> click . style ( str ( len ( ignored_videos ) ) , bold = True , fg = '<STR_LIT>' if ignored_videos else None ) , <EOL> '<STR_LIT:s>' if len ( ignored_videos ) > <NUM_LIT:1> else '<STR_LIT>' , <EOL> click . style ( str ( len ( errored_paths ) ) , bold = True , fg = '<STR_LIT>' if errored_paths else None ) , <EOL> '<STR_LIT:s>' if len ( errored_paths ) > <NUM_LIT:1> else '<STR_LIT>' , <EOL> ) ) <EOL> if not videos : <EOL> return <EOL> downloaded_subtitles = defaultdict ( list ) <EOL> with ProviderPool ( providers = provider , provider_configs = obj [ '<STR_LIT>' ] ) as pool : <EOL> with click . progressbar ( videos , label = '<STR_LIT>' , <EOL> item_show_func = lambda v : os . path . split ( v . name ) [ <NUM_LIT:1> ] if v is not None else '<STR_LIT>' ) as bar : <EOL> for v in bar : <EOL> subtitles = pool . download_best_subtitles ( pool . list_subtitles ( v , language - v . subtitle_languages ) , <EOL> v , language , min_score = v . scores [ '<STR_LIT>' ] * min_score / <NUM_LIT:100> , <EOL> hearing_impaired = hearing_impaired , only_one = single ) <EOL> downloaded_subtitles [ v ] = subtitles <EOL> total_subtitles = <NUM_LIT:0> <EOL> for v , subtitles in downloaded_subtitles . items ( ) : <EOL> saved_subtitles = save_subtitles ( v , subtitles , single = single , directory = directory , encoding = encoding ) <EOL> total_subtitles += len ( saved_subtitles ) <EOL> if verbose > <NUM_LIT:0> : <EOL> click . echo ( '<STR_LIT>' % ( click . style ( str ( len ( saved_subtitles ) ) , bold = True ) , <EOL> '<STR_LIT:s>' if len ( saved_subtitles ) > <NUM_LIT:1> else '<STR_LIT>' , <EOL> os . path . split ( v . name ) [ <NUM_LIT:1> ] ) ) <EOL> if verbose > <NUM_LIT:1> : <EOL> for s in saved_subtitles : <EOL> matches = s . get_matches ( v , hearing_impaired = hearing_impaired ) <EOL> score = compute_score ( matches , v ) <EOL> score_color = None <EOL> if isinstance ( v , Movie ) : <EOL> if score < v . scores [ '<STR_LIT:title>' ] : <EOL> score_color = '<STR_LIT>' <EOL> elif score < v . scores [ '<STR_LIT:title>' ] + v . scores [ '<STR_LIT>' ] + v . scores [ '<STR_LIT>' ] : <EOL> score_color = '<STR_LIT>' <EOL> else : <EOL> score_color = '<STR_LIT>' <EOL> elif isinstance ( v , Episode ) : <EOL> if score < v . scores [ '<STR_LIT>' ] + v . scores [ '<STR_LIT>' ] + v . scores [ '<STR_LIT>' ] : <EOL> score_color = '<STR_LIT>' <EOL> elif score < ( v . scores [ '<STR_LIT>' ] + v . scores [ '<STR_LIT>' ] + v . scores [ '<STR_LIT>' ] + <EOL> v . scores [ '<STR_LIT>' ] ) : <EOL> score_color = '<STR_LIT>' <EOL> else : <EOL> score_color = '<STR_LIT>' <EOL> scaled_score = score <EOL> if s . hearing_impaired == hearing_impaired : <EOL> scaled_score -= v . scores [ '<STR_LIT>' ] <EOL> scaled_score *= <NUM_LIT:100> / v . scores [ '<STR_LIT>' ] <EOL> click . echo ( '<STR_LIT>' . format ( <EOL> score = click . style ( '<STR_LIT>' . format ( scaled_score ) , fg = score_color , bold = score >= v . scores [ '<STR_LIT>' ] ) , <EOL> language = s . language . name if s . language . country is None else '<STR_LIT>' % ( s . language . name , <EOL> s . language . country . name ) , <EOL> provider_name = s . provider_name , <EOL> matches = '<STR_LIT:U+002CU+0020>' . join ( sorted ( matches , key = v . scores . get , reverse = True ) ) <EOL> ) ) <EOL> if verbose == <NUM_LIT:0> : <EOL> click . echo ( '<STR_LIT>' % ( click . style ( str ( total_subtitles ) , bold = True ) , <EOL> '<STR_LIT:s>' if total_subtitles > <NUM_LIT:1> else '<STR_LIT>' ) ) </s>
