~vincent-vandevyvre/+junk/Qarte

« back to all changes in this revision

Viewing changes to loaders.py

  • Committer: Vincent Vande Vyvre
  • Date: 2012-02-28 06:48:42 UTC
  • Revision ID: vincent.vandevyvre@swing.be-20120228064842-40t0ddv8f9gdxl9p
Begin serie 1.x development

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
import sys
 
4
import os
 
5
import time
 
6
import re
 
7
import subprocess
 
8
import select
 
9
import datetime
 
10
import urllib2
 
11
 
 
12
import BeautifulSoup as BS
 
13
 
 
14
from PyQt4.QtCore import QObject, pyqtSignal, QString, QLocale
 
15
from PyQt4.QtGui import QApplication
 
16
 
 
17
 
 
18
class PlusLoader(QObject):
 
19
    loadProgress = pyqtSignal(float)
 
20
    loadingFailed = pyqtSignal(str, str)
 
21
    def __init__(self, main):
 
22
        super(PlusLoader, self).__init__()
 
23
        self.main = main
 
24
        self.lang = main.lang
 
25
        self.is_loading = False
 
26
        self.kill_request = False
 
27
        self.url = None
 
28
        self.target = None
 
29
        self.pid = None
 
30
 
 
31
    def set_url(self, url):
 
32
        self.url = url
 
33
 
 
34
    def set_target(self, target):
 
35
        self.target = target.encode(sys.getfilesystemencoding(), 'ignore')
 
36
 
 
37
    def set_destination(self, dest):
 
38
        self.dest = dest.encode(sys.getfilesystemencoding(), 'ignore')
 
39
 
 
40
    def load(self):
 
41
        print "Loading ..."
 
42
        print "URL: %s" % self.url
 
43
        print "Tgt: %s" % self.target
 
44
        print "Dst: %s" % self.dest
 
45
        try:
 
46
            for percent in self.rtmp_download(self.url, self.target):
 
47
                if percent == -1.0:
 
48
                    raise IOError()
 
49
                self.loadProgress.emit(percent)
 
50
                if self.main.abort_download or self.main.stop:
 
51
                    if self.pid is not None:
 
52
                        try:
 
53
                            os.kill(self.pid, signal.SIGINT)
 
54
                        except:
 
55
                            # Not sure is still alive
 
56
                            pass
 
57
                        break
 
58
 
 
59
        except IOError, why:
 
60
            print "Downloading error :", why
 
61
            self.loadingFailed.emit('Error', str(why))
 
62
        try:
 
63
            os.rename(self.target, self.dest)
 
64
        except Exception as e:
 
65
            print "Renaming error: ", e
 
66
        else:
 
67
            print "File %s renamed %s " % (self.target, self.dest)
 
68
 
 
69
    def rtmp_download(self, link, destination="/dev/null", try_resume=True, 
 
70
                                                            resuming=False):
 
71
        some_dl_done = False
 
72
        need_more_dl = True
 
73
        if try_resume and os.path.isfile(destination):
 
74
            for percent in self.rtmp_download(link, destination, False, True):
 
75
                if percent != -1:
 
76
                    some_dl_done = True
 
77
                    need_more_dl = percent != 100.0
 
78
                    yield percent
 
79
                else:
 
80
                    break
 
81
        cmd = "".join(['flvstreamer -r "', self.url, '" '])
 
82
        cmd_dl = "".join([cmd, '--flv "', self.target, '"'])
 
83
        cmd_resume = "".join([cmd,  '--resume --flv "', self.target, '"'])
 
84
        cmd_resume_skip = "".join([cmd,  '--resume --skip 1 --flv "',
 
85
                                                        self.target, '"'])
 
86
        SECONDS_TO_WAIT = 3
 
87
        max_skip_cnt = 10
 
88
        percent_re = re.compile("\((.+)%\)$")
 
89
 
 
90
        ret_code = None
 
91
        if some_dl_done or resuming:
 
92
            cmd = cmd_resume
 
93
        else:
 
94
            cmd = cmd_dl
 
95
        while need_more_dl:
 
96
            stderr_buff = ""
 
97
            whole_stderr_buff = ""
 
98
            p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE, 
 
99
                                                            close_fds=True)
 
100
            self.pid = p.pid + 1
 
101
            while ret_code is None:
 
102
                fds_read, fds_write, fds_exception = select.select([p.stderr],
 
103
                                                    [], [], SECONDS_TO_WAIT)
 
104
                if len(fds_read) == 1:
 
105
                    c = p.stderr.read(1)
 
106
                    #print "p.stderr.read", p.stderr.read()
 
107
                    whole_stderr_buff += c
 
108
                    #print "whole_stderr_buff", c
 
109
                    if c in ("\n","\r"):
 
110
                        match = percent_re.search(stderr_buff)
 
111
                        if match is not None:
 
112
                            # If anyframe was retreived, then reset available 
 
113
                            # skip count
 
114
                            max_skip_cnt = 10
 
115
                            yield float(match.group(1))
 
116
                        stderr_buff = ""
 
117
                    else:
 
118
                        stderr_buff += c
 
119
                ret_code = p.poll()
 
120
            whole_stderr_buff += p.stderr.read()
 
121
            self.pid = None
 
122
            if ret_code == 0:
 
123
                yield 100.0
 
124
                break
 
125
            elif ret_code == 2:
 
126
                cmd = cmd_resume
 
127
            else:
 
128
                must_resume = False
 
129
                for line in whole_stderr_buff.split("\n"):
 
130
                    if line.find("Couldn't resume FLV file, try --skip 1") != -1:
 
131
                        must_resume = True
 
132
                        break
 
133
                if must_resume and max_skip_cnt >= 0:
 
134
                    max_skip_cnt -= 1
 
135
                    cmd = cmd_resume_skip
 
136
                else:
 
137
                    #print whole_stderr_buff
 
138
                    yield -1.0
 
139
            ret_code = None
 
140
 
 
141
 
 
142
class LiveLoader(QObject):
 
143
    loadProgress = pyqtSignal(float)
 
144
    loadComplete = pyqtSignal(str, str, str)
 
145
    def __init__(self, main):
 
146
        super(LiveLoader, self).__init__()
 
147
        self.main = main
 
148
        self.is_loading = False
 
149
        self.kill_request = False
 
150
        self.url = None
 
151
        self.target = None
 
152
        self.pattern = re.compile("(?P<scheme>[^:]*)://(?P<host>[^/^:]*):"
 
153
                                    "{0,1}(?P<port>[^/]*)/(?P<app>.*?)/"
 
154
                                    "(?P<playpath>\w*?\:.*)", re.DOTALL)
 
155
 
 
156
    def set_url(self, url):
 
157
        self.url = url
 
158
 
 
159
    def set_target(self, target):
 
160
        self.target = target.encode(sys.getfilesystemencoding(), 'ignore')
 
161
 
 
162
    def set_destination(self, dest):
 
163
        self.dest = dest.encode(sys.getfilesystemencoding(), 'ignore')
 
164
 
 
165
    def format_command(self):
 
166
        match = re.match(self.pattern, self.url)
 
167
        cmd = ""
 
168
        print "Format command: ", self.url
 
169
        if match != None:
 
170
            cmd = "rtmpdump --host %host% --port %port% --protocol %scheme% --app %app% --playpath %playpath%"
 
171
            cmd = cmd.replace( "%scheme%", match.group( "scheme" ) ).replace( "%host%", match.group( "host" ) ).replace( "%app%", match.group( "app" ) ).replace( "%playpath%", match.group( "playpath" ) )
 
172
            if( match.group( "port" ) != "" ):
 
173
                cmd = cmd.replace("%port%", match.group("port"))
 
174
            elif(self.url[ :6 ] == "rtmpte"):
 
175
                cmd = cmd.replace( "%port%", "80")
 
176
            elif(self.url[ :5 ] == "rtmpe"):
 
177
                cmd = cmd.replace( "%port%", "1935")
 
178
            elif(self.url[ :5 ] == "rtmps"):
 
179
                cmd = cmd.replace( "%port%", "443")
 
180
            elif(self.url[ :5 ] == "rtmpt"):
 
181
                cmd = cmd.replace("%port%", "80")
 
182
            else:
 
183
                cmd = cmd.replace("%port%", "1935")
 
184
        else:
 
185
            cmd = "rtmpdump -r " + self.url
 
186
        return cmd
 
187
 
 
188
    def load(self):
 
189
        if(self.url[ :4 ] == "rtmp"):
 
190
            cmd = self.format_command()
 
191
            cmd = "".join([cmd, " -o ", self.target])
 
192
        elif(self.url[:4] == "http" or self.url[:3] == "ftp" or self.url[:3] == "mms"):
 
193
            cmd = "".join(["msdl -c ", self.url, " -o ", self.target])
 
194
        else:
 
195
            return
 
196
        arguments = cmd.split()
 
197
        print "\nDownloading ......\n %s\n" % arguments
 
198
        try:
 
199
            reply = subprocess.Popen(arguments, universal_newlines=True,
 
200
                                    stdout=subprocess.PIPE, 
 
201
                                    stderr=subprocess.STDOUT)
 
202
            self.is_loading = True
 
203
        except (IOError, OSError) as exc:
 
204
            self.loadComplete.emit(self.target, "0", exc)
 
205
            self.is_loading = False
 
206
            return
 
207
        percent = "0"
 
208
        duration = "0"
 
209
        err = ""
 
210
        while 1:
 
211
            text = reply.stdout.readline()[:-1]
 
212
            if type(text) != str or text == '' and reply.poll() != None:
 
213
                self.is_loading = False 
 
214
                break
 
215
            elif type(text) == str and len(text) > 6:
 
216
                if "ERROR:" in text:
 
217
                    self.is_loading = False
 
218
                    err = text
 
219
                    break
 
220
                elif " sec (" in text:
 
221
                    chains = text.split(" ")
 
222
                    try:
 
223
                        duration = chains[3]
 
224
                    except:
 
225
                        pass
 
226
                    try:
 
227
                        percent = float(chains[5][1:-2])
 
228
                    except Exception as exc:
 
229
                        print "Loading error in percent: ", exc
 
230
                        percent = 2
 
231
                    self.loadProgress.emit(percent)
 
232
                print "text: %s >> %s" % (text, int(percent))
 
233
            if self.kill_request:
 
234
                reply.kill()
 
235
                self.is_loading = False
 
236
                err = "Loading aborted by user"
 
237
                break
 
238
            time.sleep(0.5)
 
239
        print "Process break: ", text, reply.poll()
 
240
        print "Done at: %s renaming ..." % datetime.datetime.now()
 
241
        print "\\t %s" % self.target
 
242
        print "\\t >> %s" % self.dest
 
243
        self.loadComplete.emit(self.target, duration, err)
 
244
        try:
 
245
            os.rename(self.target, self.dest)
 
246
        except Exception as e:
 
247
            print "Warning Renaming error: ", e
 
248
        else:
 
249
            print "File %s renamed %s " % (self.target, self.dest)
 
250
 
 
251
class RateCounter(object):
 
252
    def __init__(self, site, fname):
 
253
        """Calculate and show the downloading rate.
 
254
 
 
255
        Arguments :
 
256
        site -- ArtePlus or ArteLiveWeb instance
 
257
        movie -- instance of movie
 
258
        """
 
259
        self.site = site
 
260
        lang = QLocale.system().name()
 
261
        self.locale = QLocale(lang)
 
262
        self.target = fname
 
263
        self.time_base = time.time()
 
264
        self.size = 0
 
265
        if os.path.isfile(self.target):
 
266
            inf = os.stat(self.target)
 
267
            self.size = inf.st_size
 
268
 
 
269
    def counter(self, p):
 
270
        """Evaluate the rate of downloading.
 
271
 
 
272
        Arguments :
 
273
        p -- percent
 
274
 
 
275
        Returns:
 
276
        Bandwidth, estimated remaining time
 
277
        """
 
278
        loop = 0
 
279
        size = 0
 
280
        while loop < 3:
 
281
            try:
 
282
                size = os.path.getsize(self.target)
 
283
            except OSError, why:
 
284
                loop += 1
 
285
                #print why
 
286
                time.sleep(0.3)
 
287
            else:
 
288
                break
 
289
        if not size:
 
290
            return "", ""
 
291
        delta = size - self.size
 
292
        t =  time.time() - self.time_base
 
293
        r = int ((size / t) / 1024)
 
294
        rate = self.locale.toString(r)
 
295
        rem = ((t / p) * 100) - t
 
296
        m, s = divmod(rem, 60)
 
297
        st = QString(QApplication.translate("MainWindow", 
 
298
                        "Speed:", None, 
 
299
                        QApplication.UnicodeUTF8))
 
300
        st2 = QString(QApplication.translate("MainWindow", 
 
301
                        "Remaining time:", None, 
 
302
                        QApplication.UnicodeUTF8))
 
303
        rate_txt = "%s %s Kio/sec." % (st, rate)
 
304
        rem_txt = "%s %s min. %s sec." % (st2, int(m), int(s))
 
305
        return rate_txt, rem_txt
 
306
 
 
307