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