utils.py 11.2 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
import requests

13

Tankypon's avatar
Tankypon committed
14 15 16 17 18
if sys.version_info >= (3, 0):
    import configparser as cp
else:
    import ConfigParser as cp

19
from i18n import _
prx's avatar
prx committed
20

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

25
# Global directories
26
confdir = os.path.expanduser(os.path.join('~', '.dontpanic'))
27
currentdir = os.path.dirname(os.curdir)
28 29 30 31 32 33 34 35
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")
36 37 38 39 40 41

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

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

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

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

prx's avatar
prx committed
62 63 64 65 66 67
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
68 69
              ]

70 71
logger = logging.getLogger(__name__)

prx's avatar
prx committed
72 73 74

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

Tankypon's avatar
Tankypon committed
77

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

Tankypon's avatar
Tankypon committed
82

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

prx's avatar
prx committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
def islastversion():
    """
    check if running version is the last one
    """
    v = 0
    try:
        response = requests.get("{}/version".format(progurl))
        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
102

prx's avatar
prx committed
103
def convb(nbbyte):
104 105 106 107 108 109 110 111
    """
    Convert a number of bytes to a good unit

    Args:
        nbbyte (int): Number to convert

    Return:
        Return a string
prx's avatar
prx committed
112 113 114
    """
    l = len(str(nbbyte))
    if l < 4:
Tankypon's avatar
Tankypon committed
115
        return "{0:.2f} B".format(nbbyte)
prx's avatar
prx committed
116
    elif l < 7:
Tankypon's avatar
Tankypon committed
117
        return "{0:.2f} kB".format(nbbyte / 1000)
prx's avatar
prx committed
118
    elif l < 10:
Tankypon's avatar
Tankypon committed
119
        return "{0:.2f} MB".format(nbbyte / 1000000)
prx's avatar
prx committed
120
    else:
Tankypon's avatar
Tankypon committed
121
        return "{0:.2f} GB".format(nbbyte / 1000000000)
prx's avatar
prx committed
122 123 124 125


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

prx's avatar
prx committed
127 128 129 130
    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
131

Tankypon's avatar
Tankypon committed
132 133
    return convb(size)

prx's avatar
prx committed
134 135 136

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

prx's avatar
prx committed
138
    for f in os.listdir(tempdir):
Tankypon's avatar
Tankypon committed
139
        path = os.path.join(tempdir, f)
prx's avatar
prx committed
140 141 142 143 144
        if os.path.isdir(path):
            shutil.rmtree(path)
        elif os.path.isfile(path):
            os.remove(path)

Tankypon's avatar
Tankypon committed
145

prx's avatar
prx committed
146
def simplifyname(name):
147 148 149 150 151 152 153 154 155
    """
    Remove weird characters from a research

    Args:
        name (str): String to format

    Return:
        Return a string without weird characters
    """
Tankypon's avatar
Tankypon committed
156 157 158 159
    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
160

Tankypon's avatar
Tankypon committed
161
    return name
Tankypon's avatar
Tankypon committed
162

prx's avatar
prx committed
163 164

def save_config(confdic):
165 166 167 168 169 170
    """
    Save the configuration to a file

    Args:
        confdic (dict): is a dictionnary containing various options
    """
Tankypon's avatar
Tankypon committed
171
    config = cp.RawConfigParser()
172 173 174 175 176
    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
177

Tankypon's avatar
Tankypon committed
178

prx's avatar
prx committed
179
def load_config():
180 181
    confdic = {}
    tosave = False
prx's avatar
prx committed
182
    try:
Tankypon's avatar
Tankypon committed
183
        config = cp.RawConfigParser()
184 185
        config.read(config_file)
        for key in defaultconf.keys():
Tankypon's avatar
Tankypon committed
186
            try:
187 188 189 190 191
                confdic[key] = config.get('Configuration', key)
            except Exception as e:
                logger.info(e)
                confdic[key] = defaultconf[key]
                tosave = True
192
    except IOError:
Tankypon's avatar
Tankypon committed
193
        # restore default config
194
        logger.info('fail at opening config. Restore defaults')
prx's avatar
prx committed
195
        save_config(defaultconf)
Tankypon's avatar
Tankypon committed
196
        return defaultconf
Tankypon's avatar
Tankypon committed
197

198 199 200 201
    if tosave:
        save_config(confdic)

    return confdic
Tankypon's avatar
Tankypon committed
202

prx's avatar
prx committed
203

Tankypon's avatar
Tankypon committed
204 205 206 207 208 209 210 211 212
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
213
def randomtext(n):
Tankypon's avatar
Tankypon committed
214 215
    # stackoverflow.com/questions/2257441
    #   /random-string-generation-with-upper-case-letters-and-digits-in-python/23728630#23728630
216
    txt = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(n))
Tankypon's avatar
Tankypon committed
217

Tankypon's avatar
Tankypon committed
218 219
    return txt

prx's avatar
prx committed
220

221
def is_running():
prx's avatar
prx committed
222
    """return  True if dontpanic is ready to browse"""
223 224 225 226 227 228 229 230 231
    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
232

233
        try:
prx's avatar
prx committed
234
            retval = requests.get("http://localhost:{}".format(port))
235

236 237 238
            # If we are here, Don't Panic is already running
            running = True
            logger.warning("{} is already running".format(progname))
Tankypon's avatar
Tankypon committed
239

prx's avatar
prx committed
240
        except Exception as e:
Tankypon's avatar
Tankypon committed
241
            # If we are here, Don't Panic is not running
prx's avatar
prx committed
242
            logger.warning(e)
Tankypon's avatar
Tankypon committed
243

244
    return running
245

prx's avatar
prx committed
246

247 248 249 250
def lock():
    """Allow just one instance"""
    if not is_running():
        # If we are here, Don't Panic is not running
251 252 253 254
        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))
255 256
        return port
    else:
257
        return False
prx's avatar
prx committed
258 259


260 261
def get_free_port():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Tankypon's avatar
Tankypon committed
262
    s.bind(("", 0))
263 264
    port = s.getsockname()[1]
    s.close()
Tankypon's avatar
Tankypon committed
265

Tankypon's avatar
Tankypon committed
266
    return port
267

268

prx's avatar
prx committed
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
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



289 290
def setup_logging(verbose):
    if verbose == 1:
291
        level = logging.INFO
292
    elif verbose > 1:
293
        level = logging.DEBUG
294
    else:
295
        level = logging.WARNING
296

297
    # to uncomment! 
prx's avatar
prx committed
298
    logging.basicConfig(filename=logfile,
299 300
                        format='%(asctime)s %(module)s:%(funcName)s:%(message)s',
                        datefmt='%H:%M:%S',
301
                        level=level)
302 303
    logging.info("Logging level set to {}".format(logging.getLevelName(logging.root.getEffectiveLevel())))

304

305
# Dictionnary containing every string to translate in templates
Tankypon's avatar
Tankypon committed
306 307
tpl_msg = {'tpl_about': _("About"),
           'tpl_back_to_main': _('Back to main page'),
308 309 310 311 312 313 314 315 316
           '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
317
           'tpl_apply_changes': _("Apply General & Proxy changes"),
318 319 320
           'tpl_config_restart': _("Don't Panic must be restarted for some options to apply"),
           'tpl_footer_bg': _("Background image"),
           'tpl_footer_your': _("Your page"),
321 322
           'tpl_storage': _("Storage"),
           'tpl_general': _("General"),
323 324 325
           'tpl_admin': _("Administration"),
           'tpl_stopdp': _("Stop Don't Panic"),
           'tpl_yourpage': _("This is your page"),
326 327
           'tpl_unsubscribe': _("Unsubscribe"),
           'tpl_logout': _("Log out"),
328 329 330 331 332 333 334 335 336 337
           '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
338
           'tpl_watchnow': _("Watch now"),
prx's avatar
prx committed
339
           'tpl_provided': _("Provided by"),
Tankypon's avatar
Tankypon committed
340
           'tpl_all': _("all"),
341
           'tpl_search': _("Search"),
prx's avatar
prx committed
342
           'tpl_clean': _("clean"),
prx's avatar
prx committed
343
           'tpl_google_translate': _("Translate with google"),
344
           'tpl_watch_nothing': _("At the moment you have seen nothing. "
prx's avatar
prx committed
345
                                  "Put yourself comfortable and try to watch something!"),
346
           'tpl_favourite_search_engine': _("Default search engine"),
prx's avatar
prx committed
347 348 349 350
           '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
351 352 353 354 355 356 357 358 359 360
           '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
361
                                       "</a>."),
prx's avatar
prx committed
362
           'tpl_not_last_version': _("> Upgrade dontpanic")
363
           }
364

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