-added new configuration: Restart failed after 10 minutes
[enigma2-plugins.git] / rsdownloader / src / plugin.py
1 ##
2 ## RS Downloader
3 ## by AliAbdul
4 ##
5 ##
6 from base64 import encodestring
7 from Components.ActionMap import ActionMap
8 from Components.config import config, ConfigInteger, ConfigText, ConfigYesNo, ConfigClock, ConfigSubsection, getConfigListEntry
9 from Components.ConfigList import ConfigListScreen
10 from Components.Label import Label
11 from Components.Language import language
12 from Components.MenuList import MenuList
13 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
14 from Components.ScrollLabel import ScrollLabel
15 from decrypt import decrypt
16 from enigma import eListboxPythonMultiContent, eTimer, gFont, RT_HALIGN_CENTER, RT_HALIGN_RIGHT
17 from os import environ, listdir, remove
18 from Plugins.Plugin import PluginDescriptor
19 from Screens.ChoiceBox import ChoiceBox
20 from Screens.MessageBox import MessageBox
21 from Screens.Screen import Screen
22 from Screens.VirtualKeyBoard import VirtualKeyBoard
23 from time import localtime, sleep, strftime, time
24 from Tools.Directories import resolveFilename, SCOPE_SKIN_IMAGE, SCOPE_LANGUAGE, SCOPE_PLUGINS
25 from Tools.Downloader import HTTPProgressDownloader
26 from Tools.LoadPixmap import LoadPixmap
27 from twisted.internet import reactor
28 from twisted.python import failure
29 from twisted.web.client import getPage
30 from urlparse import urlparse, urlunparse
31 import gettext, re, socket, urllib2
32 \r
33 ##############################################################################
34
35 config.plugins.RSDownloader = ConfigSubsection()
36 config.plugins.RSDownloader.onoff = ConfigYesNo(default=True)\r
37 config.plugins.RSDownloader.username = ConfigText(default="", fixed_size=False)\r
38 config.plugins.RSDownloader.password = ConfigText(default="", fixed_size=False)\r
39 config.plugins.RSDownloader.lists_directory = ConfigText(default="/media/hdd/rs/lists/", fixed_size=False)\r
40 config.plugins.RSDownloader.downloads_directory = ConfigText(default="/media/hdd/rs/downloads", fixed_size=False)
41 config.plugins.RSDownloader.ignore_time = ConfigYesNo(default=False)\r
42 config.plugins.RSDownloader.start_time = ConfigClock(default=time())\r
43 config.plugins.RSDownloader.end_time = ConfigClock(default=time())
44 config.plugins.RSDownloader.download_monday = ConfigYesNo(default=True)
45 config.plugins.RSDownloader.download_tuesday = ConfigYesNo(default=True)
46 config.plugins.RSDownloader.download_wednesday = ConfigYesNo(default=True)
47 config.plugins.RSDownloader.download_thursday = ConfigYesNo(default=True)
48 config.plugins.RSDownloader.download_friday = ConfigYesNo(default=True)
49 config.plugins.RSDownloader.download_saturday = ConfigYesNo(default=True)
50 config.plugins.RSDownloader.download_sunday = ConfigYesNo(default=True)\r
51 config.plugins.RSDownloader.count_downloads = ConfigInteger(default=3, limits=(1, 6))
52 config.plugins.RSDownloader.write_log = ConfigYesNo(default=True)
53 config.plugins.RSDownloader.reconnect_fritz = ConfigYesNo(default=False)
54 config.plugins.RSDownloader.autorestart_failed = ConfigYesNo(default=False)
55
56 ##############################################################################\r
57
58 def localeInit():
59         lang = language.getLanguage()
60         environ["LANGUAGE"] = lang[:2]\r
61         gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))\r
62         gettext.textdomain("enigma2")
63         gettext.bindtextdomain("RSDownloader", "%s%s"%(resolveFilename(SCOPE_PLUGINS), "Extensions/RSDownloader/locale/"))
64
65 def _(txt):\r
66         t = gettext.dgettext("RSDownloader", txt)\r
67         if t == txt:\r
68                 t = gettext.gettext(txt)\r
69         return t
70
71 localeInit()\r
72 language.addCallback(localeInit)
73
74 ##############################################################################
75
76 def writeLog(message):
77         if config.plugins.RSDownloader.write_log.value:
78                 try:\r
79                         f = open("/tmp/rapidshare.log", "a")\r
80                         f.write(strftime("%c", localtime(time())) + " - " + message + "\n")\r
81                         f.close()
82                 except:
83                         pass
84
85 ##############################################################################
86
87 def _parse(url):
88         url = url.strip()
89         parsed = urlparse(url)
90         scheme = parsed[0]
91         path = urlunparse(('','') + parsed[2:])
92         host, port = parsed[1], 80
93         if '@' in host:
94                 username, host = host.split('@')
95                 if ':' in username:
96                         username, password = username.split(':')
97                 else:
98                         password = ""
99         else:
100                 username = ""
101                 password = ""
102         if ':' in host:
103                 host, port = host.split(':')
104                 port = int(port)
105         if path == "":
106                 path = "/"
107         return scheme, host, port, path, username, password
108
109 class ProgressDownload():
110         def __init__(self, url, outputfile, contextFactory=None, *args, **kwargs):
111                 scheme, host, port, path, username, password = _parse(url)
112                 if username and password:
113                         url = scheme + '://' + host + ':' + str(port) + path
114                         basicAuth = encodestring("%s:%s"%(username, password))
115                         authHeader = "Basic " + basicAuth.strip()
116                         AuthHeaders = {"Authorization": authHeader}
117                         if kwargs.has_key("headers"):
118                                 kwargs["headers"].update(AuthHeaders)
119                         else:
120                                 kwargs["headers"] = AuthHeaders
121                 self.factory = HTTPProgressDownloader(url, outputfile, *args, **kwargs)
122                 self.connection = reactor.connectTCP(host, port, self.factory)
123
124         def start(self):
125                 return self.factory.deferred
126
127         def stop(self):
128                 self.connection.disconnect()
129
130         def addProgress(self, progress_callback):
131                 self.factory.progress_callback = progress_callback
132
133 ##############################################################################
134
135 def get(url):
136         try:
137                 data = urllib2.urlopen(url)
138                 return data.read()
139         except:
140                 return ""
141    
142 def post(url, data):
143         try:
144                 return urllib2.urlopen(url, data).read()
145         except:
146                 return ""
147
148 def matchGet(rex, string):
149         match = re.search(rex, string)
150         if match:
151                 if len(match.groups()) == 0:
152                         return string[match.span()[0]:match.span()[1]]
153                 if len(match.groups()) == 1:
154                         return match.groups()[0]
155         else:
156                 return False
157
158 ##############################################################################
159
160 def reconnect(host='fritz.box', port=49000):
161         http_body = '\r\n'.join((
162                 '<?xml version="1.0" encoding="utf-8"?>',
163                 '<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">',
164                 '  <s:Body>',
165                 '    <u:ForceTermination xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"/>',
166                 '  </s:Body>',
167                 '</s:Envelope>'))
168         http_data = '\r\n'.join((
169                 'POST /upnp/control/WANIPConn1 HTTP/1.1',
170                 'Host: %s:%d'%(host, port),
171                 'SoapAction: urn:schemas-upnp-org:service:WANIPConnection:1#ForceTermination',
172                 'Content-Type: text/xml; charset="utf-8"',
173                 'Content-Length: %d'%len(http_body),
174                 '',
175                 http_body))
176         try:
177                 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
178                 s.connect((host, port))
179                 s.send(http_data)
180                 s.close()
181         except:
182                 pass
183
184 ##############################################################################
185
186 class RSDownload():
187         def __init__(self, url):
188                 writeLog("Adding: %s"%url)
189                 self.url = url
190                 self.download = None
191                 self.downloading = False
192                 self.progress = 0
193                 self.size = 0
194                 self.status = _("Waiting")
195                 self.name = self.url.split("/")[-1]
196                 
197                 self.freeDownloadUrl = ""
198                 self.freeDownloadTimer = eTimer()
199                 self.freeDownloadTimer.callback.append(self.freeDownloadStart)
200                 self.checkTimer = eTimer()
201                 self.checkTimer.callback.append(self.doCheckTimer)
202                 self.restartFailedTimer = eTimer()
203                 self.restartFailedTimer.callback.append(self.restartFailedCheck)
204                 
205                 self.finishCallbacks = []
206
207         def start(self):
208                 writeLog("Downloading: %s"%self.url)
209                 self.downloading = True
210                 self.progress = 0
211                 self.size = 0
212                 username = config.plugins.RSDownloader.username.value
213                 password = config.plugins.RSDownloader.password.value
214                 if self.url.__contains__("rapidshare.com") and username == "" and password == "":
215                         writeLog("Free RS-Download: %s"%self.url)
216                         self.status = _("Checking")
217                         if config.plugins.RSDownloader.reconnect_fritz.value:
218                                 reconnect()
219                                 sleep(3)
220                         data = get(self.url)
221                         url = matchGet('<form[^>]+action="([^"]+)', data)
222                         if not url:
223                                 writeLog("Failed: %s"%self.url)
224                                 self.httpFailed(True, "Failed to get download page url: %s"%self.url)
225                         else:
226                                 data = post(url, "dl.start=Free")
227                                 seconds = matchGet('var c=([0-9]+)', data)
228                                 if not seconds:
229                                         self.httpFailed(True, "Failed to get download page url: %s"%self.url)
230                                 else:
231                                         writeLog("Free RS-download... must wait %s seconds: %s"%(seconds, self.url))
232                                         self.status = "%s %s"%(_("Waiting"), seconds)
233                                         url = matchGet('"dlf" action="([^"]+)', data)
234                                         if not url:
235                                                 self.httpFailed(True, "Failed to get download page url: %s"%self.url)
236                                         else:
237                                                 self.freeDownloadUrl = url
238                                                 self.freeDownloadTimer.start((int(seconds) + 2) * 1000, 1)
239                 else:
240                         if self.url.__contains__("rapidshare.com"):
241                                 url = self.url.replace("http://", "http://" + username + ":" + password + "@")
242                         else:
243                                 url = self.url
244                         self.status = _("Downloading")
245                         self.download = ProgressDownload(url, ("%s/%s"%(config.plugins.RSDownloader.downloads_directory.value, self.name)).replace("//", "/").replace(".html", ""))
246                         self.download.addProgress(self.httpProgress)
247                         self.download.start().addCallback(self.httpFinished).addErrback(self.httpFailed)
248
249         def freeDownloadStart(self):
250                 self.status = _("Downloading")
251                 self.download = ProgressDownload(self.freeDownloadUrl, ("%s/%s"%(config.plugins.RSDownloader.downloads_directory.value, self.name)).replace("//", "/").replace(".html", ""))
252                 self.download.addProgress(self.httpProgress)
253                 self.download.start().addCallback(self.httpFinished).addErrback(self.httpFailed)
254
255         def httpProgress(self, recvbytes, totalbytes):
256                 if self.size == 0:
257                         self.size = int((totalbytes / 1024) / 1024)
258                 self.progress = int(100.0 * float(recvbytes) / float(totalbytes))
259                 if self.progress == 100:
260                         writeLog("Finished: %s"%self.url)
261                         self.status = _("Finished")
262                         self.execFinishCallbacks()
263
264         def httpFinished(self, string=""):
265                 if string is not None:
266                         writeLog("Failed: %s"%self.url)
267                         writeLog("Error: %s"%string)
268                 self.status = _("Checking")
269                 self.checkTimer.start(10000, 1)
270
271         def doCheckTimer(self):
272                 if self.size == 0:
273                         self.status = _("Failed")
274                         if config.plugins.RSDownloader.autorestart_failed.value:
275                                 self.restartFailedTimer.start(10000*60, 1)
276                 elif self.progress == 100:
277                         self.status = _("Finished")
278                 self.downloading = False
279                 self.execFinishCallbacks()
280
281         def restartFailedCheck(self):
282                 if self.status == _("Failed"): # check if user didn't restart already
283                         self.download = None
284                         self.status = _("Waiting")
285
286         def execFinishCallbacks(self):
287                 for x in self.finishCallbacks:
288                         x()
289
290         def httpFailed(self, failure=None, error=""):
291                 if failure:
292                         if error == "":
293                                 error = failure.getErrorMessage()
294                         if error != "" and not error.startswith("[Errno 2]"):
295                                 writeLog("Failed: %s"%self.url)
296                                 writeLog("Error: %s"%error)
297                                 self.status = _("Checking")
298                 self.checkTimer.start(10000, 1)
299
300         def stop(self):
301                 self.progress = 0
302                 self.downloading = False
303                 self.status = _("Waiting")
304                 if self.download:
305                         writeLog("Stopping download: %s"%self.url)
306                         self.download.stop()
307
308 ##############################################################################
309
310 class RS():
311         def __init__(self):
312                 self.downloads = []
313                 self.checkTimer = eTimer()
314                 self.checkTimer.callback.append(self.startDownloading)
315                 self.checkTimer.start(5000*60, False)
316
317         def mayDownload(self):
318                 if config.plugins.RSDownloader.onoff.value == False:
319                         writeLog("RS Downloader is turned off...")
320                         return False
321                 elif config.plugins.RSDownloader.ignore_time.value:
322                         return True
323                 else:\r
324                         start = config.plugins.RSDownloader.start_time.value\r
325                         end = config.plugins.RSDownloader.end_time.value\r
326                         t = localtime()
327                         weekday = t[6]
328                         if weekday == 0 and config.plugins.RSDownloader.download_monday.value == False:
329                                 return False
330                         elif weekday == 1 and config.plugins.RSDownloader.download_tuesday.value == False:
331                                 return False
332                         elif weekday == 2 and config.plugins.RSDownloader.download_wednesday.value == False:
333                                 return False
334                         elif weekday == 3 and config.plugins.RSDownloader.download_thursday.value == False:
335                                 return False
336                         elif weekday == 4 and config.plugins.RSDownloader.download_friday.value == False:
337                                 return False
338                         elif weekday == 5 and config.plugins.RSDownloader.download_saturday.value == False:
339                                 return False
340                         elif weekday == 6 and config.plugins.RSDownloader.download_sunday.value == False:
341                                 return False
342                         else:\r
343                                 hour_now = t[3]\r
344                                 minute_now = t[4]\r
345                                 hour_start = start[0]\r
346                                 minute_start = start[1]\r
347                                 hour_end = end[0]\r
348                                 minute_end = end[1]\r
349                                 if start == end: # Same start and end-time\r
350                                         return True\r
351                                 elif hour_end < hour_start: # Different days!!!\r
352                                         if hour_now > hour_start or hour_now < hour_end:\r
353                                                 return True\r
354                                         elif hour_now == hour_start and minute_now > minute_start:\r
355                                                 return True\r
356                                         elif hour_now == hour_end and minute_now < minute_end:\r
357                                                 return True
358                                         else:
359                                                 return False\r
360                                 elif hour_now > hour_start and hour_now < hour_end: # Same day...\r
361                                         return True\r
362                                 elif hour_now == hour_start and minute_now > minute_start: # Same day, same start-hour...\r
363                                         return True\r
364                                 elif hour_now == hour_end and minute_now < minute_end: # Same day, same end-hour...\r
365                                         return True\r
366                                 else:\r
367                                         return False
368
369         def allDownloadsFinished(self):
370                 allDone = True
371                 for download in self.downloads:
372                         if (download.status != _("Failed")) and (download.status != _("Finished")):
373                                 allDone = False
374                 return allDone
375
376         def startDownloading(self):
377                 if self.mayDownload() == True:
378                         if self.allDownloadsFinished() == True:
379                                 self.readLists()
380                         downloadCount = 0
381                         for download in self.downloads:
382                                 if download.downloading == True:
383                                         downloadCount += 1 # Count the downloaded files
384                         if config.plugins.RSDownloader.username.value == "" and config.plugins.RSDownloader.password.value == "":
385                                 if downloadCount < 1: # Allow one download if without account
386                                         for download in self.downloads:
387                                                 if download.downloading == False and download.status.startswith(_("Waiting")):
388                                                         download.start() # Start first download in the list
389                                                         break
390                         else:
391                                 mayDownloadCount = config.plugins.RSDownloader.count_downloads.value - downloadCount
392                                 for download in self.downloads:
393                                         if download.downloading == False:
394                                                 if mayDownloadCount > 0 and download.status == _("Waiting"):
395                                                         download.start()
396                                                         mayDownloadCount -= 1
397
398         def addDownload(self, url):
399                 error = False
400                 for download in self.downloads:
401                         if download.url == url:
402                                 error = True
403                 if error:
404                         return False
405                 else:
406                         download = RSDownload(url)
407                         download.finishCallbacks.append(self.cleanLists)
408                         self.downloads.append(download)
409                         return True
410
411         def readLists(self):\r
412                 writeLog("Reading all lists...")\r
413                 path = config.plugins.RSDownloader.lists_directory.value\r
414                 if not path.endswith("/"):\r
415                         path = path + "/"\r
416                 writeLog("Directory: " + path)\r
417                 try:\r
418                         file_list = listdir(path)\r
419                         writeLog("Count of lists: " + str(len(file_list)))\r
420                 except:\r
421                         file_list = []\r
422                         writeLog("Could not find any list!")\r
423                 for x in file_list:\r
424                         list = path + x
425                         if list.endswith(".txt"):\r
426                                 try:\r
427                                         writeLog("Reading list %s..."%list)\r
428                                         f = open(list, "r")
429                                         count = 0\r
430                                         for l in f:\r
431                                                 if l.startswith("http://"):\r
432                                                         if (self.addDownload(l.replace("\n", "").replace("\r", ""))) == True:
433                                                                 count += 1\r
434                                         f.close()
435                                         if count == 0:
436                                                 writeLog("Empty list or downloads already in download list: %s"%list)
437                                         else:
438                                                 writeLog("Added %d files from list %s..."%(count, list))\r
439                                 except:\r
440                                         writeLog("Error while reading list %s!"%list)
441                         else:
442                                 writeLog("No *.txt file: %s!"%list)
443
444         def cleanLists(self):
445                 writeLog("Cleaning lists...")\r
446                 path = config.plugins.RSDownloader.lists_directory.value\r
447                 if not path.endswith("/"):\r
448                         path = path + "/"\r
449                 try:\r
450                         file_list = listdir(path)\r
451                 except:\r
452                         file_list = []\r
453                 for x in file_list:\r
454                         list = path + x\r
455                         try:\r
456                                 f = open(list, "r")\r
457                                 content = f.read()\r
458                                 f.close()
459                                 for download in self.downloads:
460                                         if download.status == _("Finished") and content.__contains__(download.url):\r
461                                                 content = content.replace(download.url, "")\r
462                                                 content = content.replace("\n\n", "\n").replace("\r\r", "\r")\r
463                                 f = open(list, "w")\r
464                                 f.write(content)\r
465                                 f.close()\r
466                         except:\r
467                                 writeLog("Error while cleaning list %s!"%list)
468                 self.startDownloading()
469
470         def removeDownload(self, url):
471                 tmp = []
472                 for download in self.downloads:
473                         if download.url == url:
474                                 download.stop()
475                         else:
476                                 tmp.append(download)
477                 del self.downloads
478                 self.downloads = tmp
479                 self.removeFromLists(url)
480
481         def removeFromLists(self, url):\r
482                 path = config.plugins.RSDownloader.lists_directory.value\r
483                 if not path.endswith("/"):\r
484                         path = path + "/"\r
485                 try:\r
486                         file_list = listdir(path)\r
487                 except:\r
488                         file_list = []\r
489                 for x in file_list:\r
490                         list = path + x\r
491                         try:\r
492                                 f = open(list, "r")\r
493                                 content = f.read()\r
494                                 f.close()
495                                 if content.__contains__(url):\r
496                                         content = content.replace(url, "")\r
497                                         content = content.replace("\n\n", "\n").replace("\r\r", "\r")\r
498                                 f = open(list, "w")\r
499                                 f.write(content)\r
500                                 f.close()\r
501                         except:\r
502                                 pass
503
504         def clearFinishedDownload(self, url):
505                 idx = 0
506                 for x in self.downloads:
507                         if x.url == url:
508                                 del self.downloads[idx]
509                                 break
510                         else:
511                                 idx += 1
512
513         def clearFinishedDownloads(self):
514                 tmp = []
515                 for download in self.downloads:
516                         if download.status != _("Finished"):
517                                 tmp.append(download)
518                 del self.downloads
519                 self.downloads = tmp
520
521         def deleteFailedDownloads(self):
522                 tmp = []
523                 for download in self.downloads:
524                         if download.status == _("Failed"):
525                                 self.removeFromLists(download.url)
526                         else:
527                                 tmp.append(download)
528                 del self.downloads
529                 self.downloads = tmp
530
531         def restartFailedDownloads(self):
532                 tmp = []
533                 for download in self.downloads:
534                         if download.status == _("Failed"):
535                                 download.download = None
536                                 download.downloading = False
537                                 download.progress = 0
538                                 download.size = 0
539                                 download.status = _("Waiting")
540                         tmp.append(download)
541                 del self.downloads
542                 self.downloads = tmp
543                 self.startDownloading()
544
545 rapidshare = RS()
546
547 ##############################################################################
548
549 class ChangedScreen(Screen):
550         def __init__(self, session, parent=None):\r
551                 Screen.__init__(self, session, parent)\r
552                 self.onLayoutFinish.append(self.setScreenTitle)\r
553 \r
554         def setScreenTitle(self):\r
555                 self.setTitle(_("RS Downloader"))
556
557 ##############################################################################
558
559 class RSConfig(ConfigListScreen, ChangedScreen):\r
560         skin = """\r
561                 <screen position="center,center" size="560,450" title="RS Downloader">\r
562                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" transparent="1" alphatest="on" />\r
563                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" transparent="1" alphatest="on" />\r
564                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" transparent="1" alphatest="on" />\r
565                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" transparent="1" alphatest="on" />\r
566                         <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />\r
567                         <widget name="config" position="0,45" size="560,400" scrollbarMode="showOnDemand" />\r
568                 </screen>"""\r
569 \r
570         def __init__(self, session):\r
571                 ChangedScreen.__init__(self, session)\r
572                 \r
573                 self["key_green"] = Label(_("Save"))\r
574                 \r
575                 ConfigListScreen.__init__(self, [\r
576                         getConfigListEntry(_("Download in the background:"), config.plugins.RSDownloader.onoff),\r
577                         getConfigListEntry(_("Username:"), config.plugins.RSDownloader.username),\r
578                         getConfigListEntry(_("Password:"), config.plugins.RSDownloader.password),\r
579                         getConfigListEntry(_("Lists directory:"), config.plugins.RSDownloader.lists_directory),\r
580                         getConfigListEntry(_("Downloads directory:"), config.plugins.RSDownloader.downloads_directory),\r
581                         getConfigListEntry(_("Ignore download times:"), config.plugins.RSDownloader.ignore_time),\r
582                         getConfigListEntry(_("Allow downloading on monday:"), config.plugins.RSDownloader.download_monday),\r
583                         getConfigListEntry(_("Allow downloading on tuesday:"), config.plugins.RSDownloader.download_tuesday),\r
584                         getConfigListEntry(_("Allow downloading on wednesday:"), config.plugins.RSDownloader.download_wednesday),\r
585                         getConfigListEntry(_("Allow downloading on thursday:"), config.plugins.RSDownloader.download_thursday),\r
586                         getConfigListEntry(_("Allow downloading on friday:"), config.plugins.RSDownloader.download_friday),\r
587                         getConfigListEntry(_("Allow downloading on saturday:"), config.plugins.RSDownloader.download_saturday),\r
588                         getConfigListEntry(_("Allow downloading on sunday:"), config.plugins.RSDownloader.download_sunday),
589                         getConfigListEntry(_("Don't download before:"), config.plugins.RSDownloader.start_time),\r
590                         getConfigListEntry(_("Don't download after:"), config.plugins.RSDownloader.end_time),\r
591                         getConfigListEntry(_("Maximal downloads:"), config.plugins.RSDownloader.count_downloads),\r
592                         getConfigListEntry(_("Write log:"), config.plugins.RSDownloader.write_log),
593                         getConfigListEntry(_("Reconnect fritz.Box before downloading:"), config.plugins.RSDownloader.reconnect_fritz),
594                         getConfigListEntry(_("Restart failed after 10 minutes:"), config.plugins.RSDownloader.autorestart_failed)])\r
595                 \r
596                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], {"green": self.save, "cancel": self.exit}, -1)\r
597 \r
598         def save(self):\r
599                 for x in self["config"].list:\r
600                         x[1].save()\r
601                 self.close()\r
602 \r
603         def exit(self):\r
604                 for x in self["config"].list:\r
605                         x[1].cancel()\r
606                 self.close()
607
608 ##############################################################################
609
610 class RSSearch(Screen):
611         skin = """
612                 <screen position="center,center" size="560,450" title="Searching... please wait!">
613                         <widget name="list" position="0,0" size="570,450" scrollbarMode="showOnDemand" />
614                 </screen>"""
615
616         def __init__(self, session, searchFor):
617                 Screen.__init__(self, session)
618                 self.session = session
619                 
620                 self.searchFor = searchFor.replace(" ", "%2B")
621                 self.maxPage = 1
622                 self.curPage = 1
623                 self.files = []
624                 
625                 self["list"] = MenuList([])
626                 
627                 self["actions"] = ActionMap(["OkCancelActions", "InfobarChannelSelection"],
628                         {
629                                 "historyBack": self.previousPage,
630                                 "historyNext": self.nextPage,
631                                 "ok": self.okClicked,
632                                 "cancel": self.close
633                         }, -1)
634                 
635                 self.onLayoutFinish.append(self.search)
636
637         def okClicked(self):
638                 if len(self.files) > 0:
639                         idx = self["list"].getSelectedIndex()
640                         url = self.files[idx]
641                         try:
642                                 f = open(("%s/search.txt" % config.plugins.RSDownloader.lists_directory.value).replace("//", "/"), "a")
643                                 f.write("%s\n"%url)
644                                 f.close()
645                                 self.session.open(MessageBox, (_("Added %s to the download-list.") % url), MessageBox.TYPE_INFO)
646                         except:
647                                 self.session.open(MessageBox, (_("Error while adding %s to the download-list!") % url), MessageBox.TYPE_ERROR)
648
649         def search(self):
650                 getPage("http://rapidshare-search-engine.com/index-s_submit=Search&sformval=1&s_type=0&what=1&s=%s&start=%d.html"%(self.searchFor, self.curPage)).addCallback(self.searchCallback).addErrback(self.searchError)
651
652         def searchCallback(self, html=""):
653                 list = []
654                 files = []
655                 
656                 if html.__contains__("Nothing found, sorry."):
657                         self.session.open(MessageBox, (_("Error while searching http://rapidshare-search-engine.com!\n\nError: Nothing found, sorry.")), MessageBox.TYPE_ERROR)
658                         self.instance.setTitle(_("Nothing found, sorry."))
659                 else:
660                         tmp = html
661                         while tmp.__contains__("goPg('"):
662                                 idx = tmp.index("goPg('")
663                                 tmp = tmp[idx+6:]
664                                 idx = tmp.index("'")
665                                 pageNumber = tmp[:idx]
666                                 \r
667                                 try:
668                                         pageNumber = int(pageNumber)
669                                         if pageNumber > self.maxPage:
670                                                 self.maxPage = pageNumber
671                                 except:
672                                         pass
673                                 
674                                 self.instance.setTitle(_("Page %d / %d. Push < > to switch the page...")%(self.curPage, self.maxPage))
675                         
676                         while html.__contains__('title="Download"'):
677                                 idx = html.index('title="Download"')
678                                 html = html[idx:]
679                                 idx = html.index('value="')
680                                 html = html[idx+7:]
681                                 idx = html.index('"')
682                                 size = html[:idx]
683                                 idx = html.index('http://rapidshare.com/')
684                                 html = html[idx:]
685                                 idx = html.index('"')
686                                 url = html[:idx]
687                                 
688                                 files.append(url) 
689                                 try:
690                                         urllist = url.split("/")
691                                         idx = len(urllist) - 1
692                                         name = urllist[idx]
693                                         list.append("%s - %s"%(size, name))
694                                 except:
695                                         list.append("%s - %s"%(size, url))
696                 
697                 self.files = files
698                 self["list"].setList(list)
699
700         def searchError(self, error=""):
701                 self.session.open(MessageBox, (_("Error while searching http://rapidshare-search-engine.com!\n\nError: %s")%str(error)), MessageBox.TYPE_ERROR)
702
703         def previousPage(self):
704                 if self.curPage > 1:
705                         self.curPage -= 1
706                         self.instance.setTitle(_("Loading previous page... please wait!"))
707                         self.search()
708
709         def nextPage(self):
710                 if self.curPage < self.maxPage:
711                         self.curPage += 1
712                         self.instance.setTitle(_("Loading next page... please wait!"))
713                         self.search()
714
715 ##############################################################################
716
717 class RSLogScreen(ChangedScreen):
718         skin = """
719                 <screen position="center,center" size="560,450" title="RS Downloader">
720                         <widget name="label" position="0,0" size="560,450" font="Regular;20" />
721                 </screen>"""
722
723         def __init__(self, session):
724                 ChangedScreen.__init__(self, session)
725                 
726                 try:
727                         f = open("/tmp/rapidshare.log")
728                         log = f.read()
729                         f.close()
730                 except:
731                         log = ""
732                 self["label"] = ScrollLabel(log)
733                 
734                 self["actions"] = ActionMap(["WizardActions"],
735                         {
736                                 "ok": self.close,
737                                 "back": self.close,
738                                 "up": self["label"].pageUp,
739                                 "down": self["label"].pageDown,
740                                 "left": self["label"].pageUp,
741                                 "right": self["label"].pageDown
742                         }, -1)
743
744 ##############################################################################
745
746 class RSContainerSelector(ChangedScreen):
747         skin = """
748                 <screen position="center,center" size="560,450" title="RS Downloader">
749                         <widget name="list" position="0,0" size="560,450" />
750                 </screen>"""
751
752         def __init__(self, session, list):
753                 ChangedScreen.__init__(self, session)
754                 self["list"] = MenuList(list)
755                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.okClicked, "cancel": self.close}, -1)
756
757         def okClicked(self):
758                 cur = self["list"].getCurrent()
759                 self.close(cur)
760
761 ##############################################################################
762
763 class RSList(MenuList):
764         def __init__(self, list):
765                 MenuList.__init__(self, list, False, eListboxPythonMultiContent)
766                 self.l.setItemHeight(25)
767                 self.l.setFont(0, gFont("Regular", 20))
768
769 ##############################################################################
770
771 def RSListEntry(download):
772         res = [(download)]
773         res.append(MultiContentEntryText(pos=(0, 0), size=(170, 25), font=0, text=download.name))
774         res.append(MultiContentEntryText(pos=(175, 0), size=(75, 25), font=0, text="%d%s"%(download.size, "MB"), flags=RT_HALIGN_CENTER))
775         res.append(MultiContentEntryPixmapAlphaTest(pos=(260, 9), size=(84, 7), png=LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/progress_bg.png"))))
776         res.append(MultiContentEntryPixmapAlphaTest(pos=(260, 10), size=(int(0.84 * download.progress), 5), png=LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/progress_small.png"))))
777         res.append(MultiContentEntryText(pos=(360, 0), size=(60, 25), font=0, text="%d%s"%(download.progress, "%"), flags=RT_HALIGN_CENTER))
778         res.append(MultiContentEntryText(pos=(420, 0), size=(140, 25), font=0, text=download.status, flags=RT_HALIGN_RIGHT))
779         return res
780
781 ##############################################################################
782
783 class RSMain(ChangedScreen):
784         skin = """
785                 <screen position="center,center" size="560,450" title="RS Downloader">
786                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" transparent="1" alphatest="on" />
787                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" transparent="1" alphatest="on" />
788                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" transparent="1" alphatest="on" />
789                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" transparent="1" alphatest="on" />
790                         <widget name="key_red" position="0,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
791                         <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
792                         <widget name="key_yellow" position="280,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
793                         <widget name="key_blue" position="420,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
794                         <widget name="list" position="0,40" size="560,400" scrollbarMode="showNever" />
795                 </screen>"""
796
797         def __init__(self, session):
798                 ChangedScreen.__init__(self, session)
799                 self.session = session
800                 
801                 self["key_red"] = Label(_("Delete"))
802                 self["key_green"] = Label(_("Search"))
803                 self["key_yellow"] = Label(_("Add"))
804                 self["key_blue"] = Label(_("Config"))
805                 self["list"] = RSList([])
806                 
807                 self.refreshTimer = eTimer()
808                 self.refreshTimer.callback.append(self.updateList)
809                 
810                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "InfobarMenuActions"],
811                         {
812                                 "mainMenu": self.menu,
813                                 "cancel": self.close,
814                                 "red": self.delete,
815                                 "green": self.search,
816                                 "yellow": self.add,
817                                 "blue": self.config
818                         }, prio=-1)
819                 
820                 self.onLayoutFinish.append(self.updateList)
821
822         def menu(self):
823                 list = []
824                 #TODO: Add sort list functions
825                 list.append((_("Delete download"), self.delete))
826                 list.append((_("Use search engine"), self.search))
827                 list.append((_("Add downloads from txt files"), self.add))
828                 list.append((_("Add files from container"), self.addContainer))
829                 list.append((_("Delete failed downloads"), self.deleteFailed))
830                 list.append((_("Restart failed downloads"), self.restartFailed))
831                 list.append((_("Clear finished downloads"), self.clearFinished))
832                 list.append((_("Show log"), self.showLog))
833                 list.append((_("Delete log"), self.deleteLog))
834                 list.append((_("Close plugin"), self.close))
835                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title=_("Please choose a function..."), list=list)
836
837         def menuCallback(self, callback=None):
838                 if callback is not None:
839                         callback[1]()
840
841         def deleteFailed(self):
842                 rapidshare.deleteFailedDownloads()
843
844         def restartFailed(self):
845                 rapidshare.restartFailedDownloads()
846
847         def clearFinished(self):
848                 rapidshare.clearFinishedDownloads()
849
850         def showLog(self):
851                 self.session.open(RSLogScreen)
852
853         def deleteLog(self):
854                 try:
855                         remove("/tmp/rapidshare.log")
856                 except:
857                         pass
858
859         def updateList(self):
860                 list = []
861                 for download in rapidshare.downloads:
862                         list.append(RSListEntry(download))
863                 self["list"].setList(list)
864                 self.refreshTimer.start(2000, 1)
865
866         def delete(self):
867                 cur = self["list"].getCurrent()
868                 if cur:
869                         cur = cur[0]
870                         if cur.status == _("Finished"):
871                                 rapidshare.clearFinishedDownload(cur.url)
872                         else:
873                                 self.session.openWithCallback(self.deleteCallback, MessageBox, (_("Delete %s?")%cur.name))
874
875         def deleteCallback(self, callback):
876                 if callback:
877                         rapidshare.removeDownload(self["list"].getCurrent()[0].url)
878                         self.refreshTimer.stop()
879                         self.updateList()
880
881         def search(self):
882                 self.session.openWithCallback(self.searchCallback, VirtualKeyBoard, title=_("Search http://rapidshare-search-engine.com for:"))
883
884         def searchCallback(self, callback):
885                 if callback is not None and callback != "":
886                         self.session.openWithCallback(self.searchScreenCallback, RSSearch, callback)
887
888
889         def searchScreenCallback(self):
890                 self.refreshTimer.stop()
891                 rapidshare.startDownloading()
892                 self.updateList()
893
894         def add(self):
895                 self.refreshTimer.stop()
896                 rapidshare.startDownloading()
897                 self.updateList()
898
899         def config(self):
900                 self.session.openWithCallback(self.configCallback, RSConfig)
901
902         def configCallback(self):
903                 if config.plugins.RSDownloader.onoff.value:
904                         rapidshare.startDownloading()
905                 else:
906                         for download in rapidshare.downloads:
907                                 if download.downloading:
908                                         download.stop()
909                 self.updateList()
910
911         def addContainer(self):
912                 try:\r
913                         file_list = listdir(config.plugins.RSDownloader.lists_directory.value)\r
914                 except:\r
915                         file_list = []
916                 list = []
917                 for file in file_list:
918                         if file.lower().endswith(".ccf") or file.lower().endswith(".dlc") or file.lower().endswith(".rsdf"):
919                                 list.append(file)
920                 list.sort()
921                 self.session.openWithCallback(self.addContainerCallback, RSContainerSelector, list)
922
923         def addContainerCallback(self, callback=None):
924                 if callback:
925                         file = "%s/%s"%(config.plugins.RSDownloader.lists_directory.value, callback)
926                         file = file.replace("//", "/")
927                         links = decrypt(file)
928                         try:
929                                 f = open(("%s/%s.txt" % (config.plugins.RSDownloader.lists_directory.value, callback)).replace("//", "/"), "w")
930                                 for link in links:
931                                         if link.endswith(".html"):
932                                                 link = link[:-5]
933                                         elif link.endswith(".htm"):
934                                                 link = link[:-4]
935                                         f.write("%s\n"%link)
936                                 f.close()
937                         except:
938                                 pass
939                         self.refreshTimer.stop()
940                         rapidshare.startDownloading()
941                         self.updateList()
942
943 ##############################################################################
944
945 def autostart(reason, **kwargs):\r
946         if reason == 0:\r
947                 rapidshare.startDownloading()\r
948 \r
949 ##############################################################################\r
950 \r
951 def main(session, **kwargs):\r
952         session.open(RSMain)\r
953 \r
954 ##############################################################################\r
955 \r
956 def Plugins(**kwargs):\r
957         return [
958                 PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, fnc=autostart),\r
959                 PluginDescriptor(name=_("RS Downloader"), description=_("Download files from rapidshare"), where=[PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU], icon="rs.png", fnc=main)]
960