Si vous constatez la perte de tickets, de commentaires ou de projets, veuillez consulter la page https://status.framasoft.org/incident/626.

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

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

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

20 21 22
####################
# Global variables #
####################
Thuban's avatar
Thuban 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')
Thuban's avatar
lock  
Thuban committed
42
lock_file = os.path.join(confdir, 'lock')
Thuban's avatar
Thuban committed
43
logfile = os.path.join(tempdir, "dontpanic.log")
44
watchlist_file = os.path.join(confdir, 'watchlist.pkl')
Thuban's avatar
Thuban committed
45

46
# Util global variables
47
progname = "dontpanic"
Thuban's avatar
Thuban committed
48
progurl = "http://3hg.toile-libre.org/dontpanic"
Thuban's avatar
Thuban 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

Thuban's avatar
Thuban 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__)

Thuban's avatar
Thuban committed
71 72 73

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

Tankypon's avatar
Tankypon committed
76

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

Tankypon's avatar
PEP8  
Tankypon committed
81

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

Thuban's avatar
Thuban 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)
Thuban's avatar
Thuban committed
93 94
        else:
            p = p.encode('ascii')
95
            response = opener.open(url, p, timeout=10)
Thuban's avatar
Thuban 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)

Thuban's avatar
Thuban committed
103 104 105 106 107 108
def islastversion():
    """
    check if running version is the last one
    """
    v = 0
    try:
Thuban's avatar
Thuban committed
109
        response = htmlget("{}/version".format(progurl))
Thuban's avatar
Thuban 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

Thuban's avatar
Thuban committed
120
def convb(nbbyte):
Tankypon's avatar
Tankypon committed
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
Thuban's avatar
Thuban committed
129 130 131
    """
    l = len(str(nbbyte))
    if l < 4:
Tankypon's avatar
Tankypon committed
132
        return "{0:.2f} B".format(nbbyte)
Thuban's avatar
Thuban committed
133
    elif l < 7:
Tankypon's avatar
Tankypon committed
134
        return "{0:.2f} kB".format(nbbyte / 1000)
Thuban's avatar
Thuban committed
135
    elif l < 10:
Tankypon's avatar
Tankypon committed
136
        return "{0:.2f} MB".format(nbbyte / 1000000)
Thuban's avatar
Thuban committed
137
    else:
Tankypon's avatar
Tankypon committed
138
        return "{0:.2f} GB".format(nbbyte / 1000000000)
Thuban's avatar
Thuban committed
139 140 141 142


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

Thuban's avatar
Thuban 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)

Thuban's avatar
Thuban committed
151 152 153

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

Thuban's avatar
Thuban committed
155
    for f in os.listdir(tempdir):
Tankypon's avatar
Tankypon committed
156
        path = os.path.join(tempdir, f)
Thuban's avatar
Thuban 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

Thuban's avatar
Thuban committed
163
def simplifyname(name):
Tankypon's avatar
Tankypon committed
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

Thuban's avatar
Thuban committed
180 181

def save_config(confdic):
Tankypon's avatar
Tankypon committed
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)
Thuban's avatar
Thuban committed
194

Tankypon's avatar
Tankypon committed
195

Thuban's avatar
Thuban committed
196
def load_config():
197 198
    confdic = {}
    tosave = False
Thuban's avatar
Thuban 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')
Thuban's avatar
Thuban 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

Thuban's avatar
Thuban 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
PEP8  
Tankypon committed
231 232
    # stackoverflow.com/questions/2257441
    #   /random-string-generation-with-upper-case-letters-and-digits-in-python/23728630#23728630
Tankypon's avatar
Tankypon committed
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

Thuban's avatar
pep8  
Thuban committed
237

238
def is_running():
Thuban's avatar
Thuban 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:
Thuban's avatar
Thuban 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

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

261
    return running
262

Thuban's avatar
pep8  
Thuban 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
Thuban's avatar
pep8  
Thuban 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

Thuban's avatar
Thuban 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! 
Thuban's avatar
Thuban 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"),
Tankypon's avatar
Tankypon committed
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:"),
Thuban's avatar
Thuban committed
355
           'tpl_watchnow': _("Watch now"),
Thuban's avatar
Thuban committed
356
           'tpl_provided': _("Provided by"),
Tankypon's avatar
Tankypon committed
357
           'tpl_all': _("all"),
358
           'tpl_search': _("Search"),
Thuban's avatar
Thuban committed
359
           'tpl_clean': _("clean"),
Thuban's avatar
Thuban committed
360
           'tpl_google_translate': _("Translate with google"),
361
           'tpl_watch_nothing': _("At the moment you have seen nothing. "
Thuban's avatar
Thuban committed
362
                                  "Put yourself comfortable and try to watch something!"),
363
           'tpl_favourite_search_engine': _("Default search engine"),
Thuban's avatar
Thuban 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"
Thuban's avatar
Thuban committed
378
                                       "</a>."),
Thuban's avatar
Thuban committed
379
           'tpl_not_last_version': _("> Upgrade dontpanic")
380
           }
381

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