utils.py 11.7 KB
Newer Older
1
# -*- coding: utf-8 -*-
prx's avatar
prx committed
2

Tankypon's avatar
Tankypon committed
3
import hashlib
prx's avatar
prx committed
4
import os
prx's avatar
prx committed
5
import string
prx's avatar
prx committed
6
import random
7
import socket
8
import sys
9
import logging
prx's avatar
prx committed
10
import tempfile
prx's avatar
prx committed
11 12 13
import urllib.request
import urllib.parse
import configparser as cp
Tankypon's avatar
Tankypon committed
14

prx's avatar
prx committed
15 16 17 18
try:
    from i18nlib import _
except :
    from .i18nlib import _
prx's avatar
prx committed
19

20 21 22
####################
# Global variables #
####################
prx's avatar
prx committed
23

24
# Global directories
25
confdir = os.path.expanduser(os.path.join('~', '.dontpanic'))
26
currentdir = os.path.dirname(os.curdir)
27 28 29 30 31 32 33 34
tmpprefix='dontpanic'
tempdir = ''
for d in os.listdir(os.path.join('/',tempfile.template)):
    if d.startswith(tmpprefix):
        tempdir = os.path.join('/',tempfile.template,d)
        break
if tempdir == '':
    tempdir = tempfile.mkdtemp(prefix="dontpanic")
35 36 37 38 39 40

# Translation directories
localedir = os.path.join(currentdir, 'locale')
podir = os.path.join(currentdir, 'po')

# Util files
41
config_file = os.path.join(confdir, 'config.cfg')
prx's avatar
prx committed
42
lock_file = os.path.join(confdir, 'lock')
prx's avatar
prx committed
43
logfile = os.path.join(tempdir, "dontpanic.log")
44
watchlist_file = os.path.join(confdir, 'watchlist.pkl')
prx's avatar
prx committed
45

46
# Util global variables
47
progname = "dontpanic"
prx's avatar
prx committed
48
progurl = "http://3hg.toile-libre.org/dontpanic"
prx's avatar
prx committed
49
progversion = 1.9
50

51 52 53
defaultconf = {'startperc': 7,
               'uplimit': 20,
               'downlimit': -1,
54
               'searchengine': 'alphareign',
55 56 57 58
               'proxy_type': 'none',
               'proxy_hostname': '',
               'proxy_username': '',
               'proxy_password': ''
59
               }
60

prx's avatar
prx committed
61 62 63 64 65 66
WELCOMEMSG = [_("What do we watch tonight?"),
              _("Don't forget your towel"),
              _("Do you have pizza?"),
              _("Type and watch"),
              _("Turn off the lights"),
              _("Get some beer before searching")
Tankypon's avatar
Tankypon committed
67 68
              ]

69 70
logger = logging.getLogger(__name__)

prx's avatar
prx committed
71 72 73

def makedir(d):
    if not os.path.isdir(d):
prx's avatar
prx committed
74
        os.makedirs(d)
prx's avatar
prx committed
75

Tankypon's avatar
Tankypon committed
76

prx's avatar
prx committed
77 78 79
def prepdirs():
    makedir(confdir)
    makedir(tempdir)
prx's avatar
prx committed
80

Tankypon's avatar
Tankypon committed
81

prx's avatar
prx committed
82 83
def prepconfig():
    prepdirs()
prx's avatar
prx committed
84

prx's avatar
prx committed
85 86 87 88 89 90 91
def htmlget(url, params=None):
    opener = urllib.request.build_opener()
    opener.addheaders = [('User-agent', 'Mozilla/5.0')]
    if params != None: 
        p = urllib.parse.urlencode(params)
        if url.endswith('?'):
            url = '{}{}'.format(url,p)
92
            response = opener.open(url, timeout=10)
prx's avatar
prx committed
93 94
        else:
            p = p.encode('ascii')
95
            response = opener.open(url, p, timeout=10)
prx's avatar
prx committed
96 97 98 99 100 101 102
    else:
        response = opener.open(url)
    data = response.read()      
    text = data.decode('utf-8')
    response.close()
    return(text)

prx's avatar
prx committed
103 104 105 106 107 108
def islastversion():
    """
    check if running version is the last one
    """
    v = 0
    try:
prx's avatar
prx committed
109
        response = htmlget("{}/version".format(progurl))
prx's avatar
prx committed
110 111 112 113 114 115 116 117 118
        v = float(response.text)
    except Exception as e:
        logging.info("Can't check dontpanic version")
        logging.info(e)

    if progversion >= v:
        return True
    else:
        return False
Tankypon's avatar
Tankypon committed
119

prx's avatar
prx committed
120
def convb(nbbyte):
121 122 123 124 125 126 127 128
    """
    Convert a number of bytes to a good unit

    Args:
        nbbyte (int): Number to convert

    Return:
        Return a string
prx's avatar
prx committed
129 130 131
    """
    l = len(str(nbbyte))
    if l < 4:
Tankypon's avatar
Tankypon committed
132
        return "{0:.2f} B".format(nbbyte)
prx's avatar
prx committed
133
    elif l < 7:
Tankypon's avatar
Tankypon committed
134
        return "{0:.2f} kB".format(nbbyte / 1000)
prx's avatar
prx committed
135
    elif l < 10:
Tankypon's avatar
Tankypon committed
136
        return "{0:.2f} MB".format(nbbyte / 1000000)
prx's avatar
prx committed
137
    else:
Tankypon's avatar
Tankypon committed
138
        return "{0:.2f} GB".format(nbbyte / 1000000000)
prx's avatar
prx committed
139 140 141 142


def get_cache_size():
    size = 0
Tankypon's avatar
Tankypon committed
143

prx's avatar
prx committed
144 145 146 147
    for dirpath, dirnames, filenames in os.walk(tempdir):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            size += os.path.getsize(fp)
Tankypon's avatar
Tankypon committed
148

Tankypon's avatar
Tankypon committed
149 150
    return convb(size)

prx's avatar
prx committed
151 152 153

def cleancache():
    import shutil
Tankypon's avatar
Tankypon committed
154

prx's avatar
prx committed
155
    for f in os.listdir(tempdir):
Tankypon's avatar
Tankypon committed
156
        path = os.path.join(tempdir, f)
prx's avatar
prx committed
157 158 159 160 161
        if os.path.isdir(path):
            shutil.rmtree(path)
        elif os.path.isfile(path):
            os.remove(path)

Tankypon's avatar
Tankypon committed
162

prx's avatar
prx committed
163
def simplifyname(name):
164 165 166 167 168 169 170 171 172
    """
    Remove weird characters from a research

    Args:
        name (str): String to format

    Return:
        Return a string without weird characters
    """
Tankypon's avatar
Tankypon committed
173 174 175 176
    valid_chars = "-_. {}{}".format(string.ascii_letters, string.digits)
    name = name.replace('_', ' ')
    name = name.replace('.', ' ')
    name = ''.join(c for c in name if c in valid_chars)
Tankypon's avatar
Tankypon committed
177

Tankypon's avatar
Tankypon committed
178
    return name
Tankypon's avatar
Tankypon committed
179

prx's avatar
prx committed
180 181

def save_config(confdic):
182 183 184 185 186 187
    """
    Save the configuration to a file

    Args:
        confdic (dict): is a dictionnary containing various options
    """
Tankypon's avatar
Tankypon committed
188
    config = cp.RawConfigParser()
189 190 191 192 193
    config.add_section('Configuration')
    for key in defaultconf.keys():
        config.set('Configuration', key, confdic[key])
    with open(config_file, 'w') as cf:
        config.write(cf)
prx's avatar
prx committed
194

Tankypon's avatar
Tankypon committed
195

prx's avatar
prx committed
196
def load_config():
197 198
    confdic = {}
    tosave = False
prx's avatar
prx committed
199
    try:
Tankypon's avatar
Tankypon committed
200
        config = cp.RawConfigParser()
201 202
        config.read(config_file)
        for key in defaultconf.keys():
Tankypon's avatar
Tankypon committed
203
            try:
204 205 206 207 208
                confdic[key] = config.get('Configuration', key)
            except Exception as e:
                logger.info(e)
                confdic[key] = defaultconf[key]
                tosave = True
209
    except IOError:
Tankypon's avatar
Tankypon committed
210
        # restore default config
211
        logger.info('fail at opening config. Restore defaults')
prx's avatar
prx committed
212
        save_config(defaultconf)
Tankypon's avatar
Tankypon committed
213
        return defaultconf
Tankypon's avatar
Tankypon committed
214

215 216 217 218
    if tosave:
        save_config(confdic)

    return confdic
Tankypon's avatar
Tankypon committed
219

prx's avatar
prx committed
220

Tankypon's avatar
Tankypon committed
221 222 223 224 225 226 227 228 229
def get_hash(name):
    readsize = 64 * 1024
    with open(name, 'rb') as f:
        data = f.read(readsize)
        f.seek(-readsize, os.SEEK_END)
        data += f.read(readsize)
    return hashlib.md5(data).hexdigest()


Tankypon's avatar
Tankypon committed
230
def randomtext(n):
Tankypon's avatar
Tankypon committed
231 232
    # stackoverflow.com/questions/2257441
    #   /random-string-generation-with-upper-case-letters-and-digits-in-python/23728630#23728630
233
    txt = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(n))
Tankypon's avatar
Tankypon committed
234

Tankypon's avatar
Tankypon committed
235 236
    return txt

prx's avatar
prx committed
237

238
def is_running():
prx's avatar
prx committed
239
    """return  True if dontpanic is ready to browse"""
240 241 242 243 244 245 246 247 248
    running = False
    if os.path.isfile(lock_file):
        try:
            with open(lock_file, 'r') as l:
                port = l.read().strip()
        # Warning: Better handle the exception, but FileNotFoundError doesn't exist in Python 2.7
        # The handler exception in common to both the version of Python is IOError
        except IOError:  # If the file doesn't exist (for example: first run of Don't Panic)
            port = 0
249

250
        try:
prx's avatar
prx committed
251
            retval = htmlget("http://localhost:{}".format(port))
252

253 254 255
            # If we are here, Don't Panic is already running
            running = True
            logger.warning("{} is already running".format(progname))
Tankypon's avatar
Tankypon committed
256

prx's avatar
prx committed
257
        except Exception as e:
Tankypon's avatar
Tankypon committed
258
            # If we are here, Don't Panic is not running
prx's avatar
prx committed
259
            logger.warning(e)
Tankypon's avatar
Tankypon committed
260

261
    return running
262

prx's avatar
prx committed
263

264 265 266 267
def lock():
    """Allow just one instance"""
    if not is_running():
        # If we are here, Don't Panic is not running
268 269 270 271
        port = get_free_port()
        logger.warning("{} is not running, open a new instance on the port {}".format(progname, port))
        with open(lock_file, "w") as p:
            p.write(str(port))
272 273
        return port
    else:
274
        return False
prx's avatar
prx committed
275 276


277 278
def get_free_port():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Tankypon's avatar
Tankypon committed
279
    s.bind(("", 0))
280 281
    port = s.getsockname()[1]
    s.close()
Tankypon's avatar
Tankypon committed
282

Tankypon's avatar
Tankypon committed
283
    return port
284

285

prx's avatar
prx committed
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
def which(program):
    #https://stackoverflow.com/questions/377017/test-if-executable-exists-in-python/377028#377028
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None



306 307
def setup_logging(verbose):
    if verbose == 1:
308
        level = logging.INFO
309
    elif verbose > 1:
310
        level = logging.DEBUG
311
    else:
312
        level = logging.WARNING
313

314
    # to uncomment! 
prx's avatar
prx committed
315
    logging.basicConfig(filename=logfile,
316 317
                        format='%(asctime)s %(module)s:%(funcName)s:%(message)s',
                        datefmt='%H:%M:%S',
318
                        level=level)
319 320
    logging.info("Logging level set to {}".format(logging.getLevelName(logging.root.getEffectiveLevel())))

321

322
# Dictionnary containing every string to translate in templates
Tankypon's avatar
Tankypon committed
323 324
tpl_msg = {'tpl_about': _("About"),
           'tpl_back_to_main': _('Back to main page'),
325 326 327 328 329 330 331 332 333
           'tpl_movie_or_serie': _('Movie or serie title'),
           'tpl_best_dvd': _("Best DVD's"),
           'tpl_popular_series': _('Popular series'),
           'tpl_configuration': _("Configuration"),
           'tpl_incache': _("in cache"),
           'tpl_remove_all_t': _("Remove all finished torrents"),
           'tpl_show_play_link': _("Show play link at"),
           'tpl_upload_limit': _("Set upload limit in kB (-1 is no limit):"),
           'tpl_download_limit': _("Set download limit in kB (-1 is no limit):"),
Tankypon's avatar
Tankypon committed
334
           'tpl_apply_changes': _("Apply General & Proxy changes"),
335 336 337
           'tpl_config_restart': _("Don't Panic must be restarted for some options to apply"),
           'tpl_footer_bg': _("Background image"),
           'tpl_footer_your': _("Your page"),
338 339
           'tpl_storage': _("Storage"),
           'tpl_general': _("General"),
340 341 342
           'tpl_admin': _("Administration"),
           'tpl_stopdp': _("Stop Don't Panic"),
           'tpl_yourpage': _("This is your page"),
343 344
           'tpl_unsubscribe': _("Unsubscribe"),
           'tpl_logout': _("Log out"),
345 346 347 348 349 350 351 352 353 354
           'tpl_watchlist': _("Watchlist"),
           'tpl_movies': _("Movies"),
           'tpl_series': _("Series"),
           'tpl_schres': _("Search Results"),
           'tpl_see_also': _("See also"),
           'tpl_director': _("Director: "),
           'tpl_writer': _("Writers: "),
           'tpl_actors': _("Actors: "),
           'tpl_extrawords': _("Subtitle (or any extra words):"),
           'tpl_searchon': _("Search on:"),
prx's avatar
prx committed
355
           'tpl_watchnow': _("Watch now"),
prx's avatar
prx committed
356
           'tpl_provided': _("Provided by"),
Tankypon's avatar
Tankypon committed
357
           'tpl_all': _("all"),
358
           'tpl_search': _("Search"),
prx's avatar
prx committed
359
           'tpl_clean': _("clean"),
prx's avatar
prx committed
360
           'tpl_google_translate': _("Translate with google"),
361
           'tpl_watch_nothing': _("At the moment you have seen nothing. "
prx's avatar
prx committed
362
                                  "Put yourself comfortable and try to watch something!"),
363
           'tpl_favourite_search_engine': _("Default search engine"),
prx's avatar
prx committed
364 365 366 367
           'tpl_proxy_type': _("Proxy type"),
           'tpl_proxy_hostname': _("Proxy hostname"),
           'tpl_proxy_username': _("Proxy username"),
           'tpl_proxy_password': _("Proxy password"),
Tankypon's avatar
Tankypon committed
368 369 370 371 372 373 374 375 376 377
           'tpl_proxy_type_exp': _("none : no proxy - socks4 : username is required - socks5 : username and password "
                                   "are ignored - socks5_pw : username and password are send to the proxy if "
                                   "necessary - http : http proxy, username and password are ignored - http_pw : "
                                   "http proxy with username/password authentication - i2p_proxy : i2p SAM proxy"),
           'tpl_proxy_explanations': _("These options let you configure a proxy to hide your ip. By default, all "
                                       "data is encrypted with dontpanic, so this solution is faster than a VPN. Note "
                                       "if you already have a VPN configured, the following is useless. See <a "
                                       "href='http://www.libtorrent.org/reference-Settings.html#proxy-settings'>here"
                                       "</a> for more information. You can find <a href='http://proxylist.hidemyass.com"
                                       "/'>a list of free proxy here</a> or <a href='http://www.samair.ru/proxy/'>here"
prx's avatar
prx committed
378
                                       "</a>."),
prx's avatar
prx committed
379
           'tpl_not_last_version': _("> Upgrade dontpanic")
380
           }
381

prx's avatar
prx committed
382
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4