read only *.txt lists
[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 startDownloading(self):
358                 if self.mayDownload() == True:
359                         self.readLists()
360                         downloadCount = 0
361                         for download in self.downloads:
362                                 if download.downloading == True:
363                                         downloadCount += 1 # Count the downloaded files
364                         if config.plugins.RSDownloader.username.value == "" and config.plugins.RSDownloader.password.value == "":
365                                 if downloadCount < 1: # Allow one download if without account
366                                         for download in self.downloads:
367                                                 if download.downloading == False and download.status.startswith(_("Waiting")):
368                                                         download.start() # Start first download in the list
369                                                         break
370                         else:
371                                 mayDownloadCount = config.plugins.RSDownloader.count_downloads.value - downloadCount
372                                 for download in self.downloads:
373                                         if download.downloading == False:
374                                                 if mayDownloadCount > 0 and download.status == _("Waiting"):
375                                                         download.start()
376                                                         mayDownloadCount -= 1
377
378         def addDownload(self, url):
379                 error = False
380                 for download in self.downloads:
381                         if download.url == url:
382                                 error = True
383                 if error:
384                         return False
385                 else:
386                         download = RSDownload(url)
387                         download.finishCallbacks.append(self.cleanLists)
388                         self.downloads.append(download)
389                         return True
390
391         def readLists(self):\r
392                 writeLog("Reading all lists...")\r
393                 path = config.plugins.RSDownloader.lists_directory.value\r
394                 if not path.endswith("/"):\r
395                         path = path + "/"\r
396                 writeLog("Directory: " + path)\r
397                 try:\r
398                         file_list = listdir(path)\r
399                         writeLog("Count of lists: " + str(len(file_list)))\r
400                 except:\r
401                         file_list = []\r
402                         writeLog("Could not find any list!")\r
403                 for x in file_list:\r
404                         list = path + x
405                         if list.endswith(".txt"):\r
406                                 try:\r
407                                         writeLog("Reading list %s..."%list)\r
408                                         f = open(list, "r")
409                                         count = 0\r
410                                         for l in f:\r
411                                                 if l.startswith("http://"):\r
412                                                         self.addDownload(l.replace("\n", "").replace("\r", ""))
413                                                         count += 1\r
414                                         f.close()
415                                         if count == 0:
416                                                 writeLog("Empty list: %s"%list)
417                                         else:
418                                                 writeLog("Added %d files from list %s..."%(count, list))\r
419                                 except:\r
420                                         writeLog("Error while reading list %s!"%list)
421
422         def cleanLists(self):
423                 writeLog("Cleaning lists...")\r
424                 path = config.plugins.RSDownloader.lists_directory.value\r
425                 if not path.endswith("/"):\r
426                         path = path + "/"\r
427                 try:\r
428                         file_list = listdir(path)\r
429                 except:\r
430                         file_list = []\r
431                 for x in file_list:\r
432                         list = path + x\r
433                         try:\r
434                                 f = open(list, "r")\r
435                                 content = f.read()\r
436                                 f.close()
437                                 for download in self.downloads:
438                                         if download.status == _("Finished") and content.__contains__(download.url):\r
439                                                 content = content.replace(download.url, "")\r
440                                                 content = content.replace("\n\n", "\n").replace("\r\r", "\r")\r
441                                 f = open(list, "w")\r
442                                 f.write(content)\r
443                                 f.close()\r
444                         except:\r
445                                 writeLog("Error while cleaning list %s!"%list)
446                 self.startDownloading()
447
448         def removeDownload(self, url):
449                 tmp = []
450                 for download in self.downloads:
451                         if download.url == url:
452                                 download.stop()
453                         else:
454                                 tmp.append(download)
455                 del self.downloads
456                 self.downloads = tmp
457                 self.removeFromLists(url)
458
459         def removeFromLists(self, url):\r
460                 path = config.plugins.RSDownloader.lists_directory.value\r
461                 if not path.endswith("/"):\r
462                         path = path + "/"\r
463                 try:\r
464                         file_list = listdir(path)\r
465                 except:\r
466                         file_list = []\r
467                 for x in file_list:\r
468                         list = path + x\r
469                         try:\r
470                                 f = open(list, "r")\r
471                                 content = f.read()\r
472                                 f.close()
473                                 if content.__contains__(url):\r
474                                         content = content.replace(url, "")\r
475                                         content = content.replace("\n\n", "\n").replace("\r\r", "\r")\r
476                                 f = open(list, "w")\r
477                                 f.write(content)\r
478                                 f.close()\r
479                         except:\r
480                                 pass
481
482         def clearFinishedDownload(self, url):
483                 idx = 0
484                 for x in self.downloads:
485                         if x.url == url:
486                                 del self.downloads[idx]
487                                 break
488                         else:
489                                 idx += 1
490
491         def clearFinishedDownloads(self):
492                 tmp = []
493                 for download in self.downloads:
494                         if download.status != _("Finished"):
495                                 tmp.append(download)
496                 del self.downloads
497                 self.downloads = tmp
498
499         def deleteFailedDownloads(self):
500                 tmp = []
501                 for download in self.downloads:
502                         if download.status == _("Failed"):
503                                 self.removeFromLists(download.url)
504                         else:
505                                 tmp.append(download)
506                 del self.downloads
507                 self.downloads = tmp
508
509         def restartFailedDownloads(self):
510                 tmp = []
511                 for download in self.downloads:
512                         if download.status == _("Failed"):
513                                 download.download = None
514                                 download.downloading = False
515                                 download.progress = 0
516                                 download.size = 0
517                                 download.status = _("Waiting")
518                         tmp.append(download)
519                 del self.downloads
520                 self.downloads = tmp
521                 self.startDownloading()
522
523 rapidshare = RS()
524
525 ##############################################################################
526
527 class ChangedScreen(Screen):
528         def __init__(self, session, parent=None):\r
529                 Screen.__init__(self, session, parent)\r
530                 self.onLayoutFinish.append(self.setScreenTitle)\r
531 \r
532         def setScreenTitle(self):\r
533                 self.setTitle(_("RS Downloader"))
534
535 ##############################################################################
536
537 class RSConfig(ConfigListScreen, ChangedScreen):\r
538         skin = """\r
539                 <screen position="center,center" size="560,450" title="RS Downloader">\r
540                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" transparent="1" alphatest="on" />\r
541                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" transparent="1" alphatest="on" />\r
542                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" transparent="1" alphatest="on" />\r
543                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" transparent="1" alphatest="on" />\r
544                         <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />\r
545                         <widget name="config" position="0,45" size="560,400" scrollbarMode="showOnDemand" />\r
546                 </screen>"""\r
547 \r
548         def __init__(self, session):\r
549                 ChangedScreen.__init__(self, session)\r
550                 \r
551                 self["key_green"] = Label(_("Save"))\r
552                 \r
553                 ConfigListScreen.__init__(self, [\r
554                         getConfigListEntry(_("Download in the background:"), config.plugins.RSDownloader.onoff),\r
555                         getConfigListEntry(_("Username:"), config.plugins.RSDownloader.username),\r
556                         getConfigListEntry(_("Password:"), config.plugins.RSDownloader.password),\r
557                         getConfigListEntry(_("Lists directory:"), config.plugins.RSDownloader.lists_directory),\r
558                         getConfigListEntry(_("Downloads directory:"), config.plugins.RSDownloader.downloads_directory),\r
559                         getConfigListEntry(_("Ignore download times:"), config.plugins.RSDownloader.ignore_time),\r
560                         getConfigListEntry(_("Allow downloading on monday:"), config.plugins.RSDownloader.download_monday),\r
561                         getConfigListEntry(_("Allow downloading on tuesday:"), config.plugins.RSDownloader.download_tuesday),\r
562                         getConfigListEntry(_("Allow downloading on wednesday:"), config.plugins.RSDownloader.download_wednesday),\r
563                         getConfigListEntry(_("Allow downloading on thursday:"), config.plugins.RSDownloader.download_thursday),\r
564                         getConfigListEntry(_("Allow downloading on friday:"), config.plugins.RSDownloader.download_friday),\r
565                         getConfigListEntry(_("Allow downloading on saturday:"), config.plugins.RSDownloader.download_saturday),\r
566                         getConfigListEntry(_("Allow downloading on sunday:"), config.plugins.RSDownloader.download_sunday),
567                         getConfigListEntry(_("Don't download before:"), config.plugins.RSDownloader.start_time),\r
568                         getConfigListEntry(_("Don't download after:"), config.plugins.RSDownloader.end_time),\r
569                         getConfigListEntry(_("Maximal downloads:"), config.plugins.RSDownloader.count_downloads),\r
570                         getConfigListEntry(_("Write log:"), config.plugins.RSDownloader.write_log),
571                         getConfigListEntry(_("Reconnect fritz.Box before downloading:"), config.plugins.RSDownloader.reconnect_fritz)])\r
572                 \r
573                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], {"green": self.save, "cancel": self.exit}, -1)\r
574 \r
575         def save(self):\r
576                 for x in self["config"].list:\r
577                         x[1].save()\r
578                 self.close()\r
579 \r
580         def exit(self):\r
581                 for x in self["config"].list:\r
582                         x[1].cancel()\r
583                 self.close()
584
585 ##############################################################################
586
587 class RSSearch(Screen):
588         skin = """
589                 <screen position="center,center" size="560,450" title="Searching... please wait!">
590                         <widget name="list" position="0,0" size="570,450" scrollbarMode="showOnDemand" />
591                 </screen>"""
592
593         def __init__(self, session, searchFor):
594                 Screen.__init__(self, session)
595                 self.session = session
596                 
597                 self.searchFor = searchFor.replace(" ", "%2B")
598                 self.maxPage = 1
599                 self.curPage = 1
600                 self.files = []
601                 
602                 self["list"] = MenuList([])
603                 
604                 self["actions"] = ActionMap(["OkCancelActions", "InfobarChannelSelection"],
605                         {
606                                 "historyBack": self.previousPage,
607                                 "historyNext": self.nextPage,
608                                 "ok": self.okClicked,
609                                 "cancel": self.close
610                         }, -1)
611                 
612                 self.onLayoutFinish.append(self.search)
613
614         def okClicked(self):
615                 if len(self.files) > 0:
616                         idx = self["list"].getSelectedIndex()
617                         url = self.files[idx]
618                         try:
619                                 f = open(("%s/search.txt" % config.plugins.RSDownloader.lists_directory.value).replace("//", "/"), "a")
620                                 f.write("%s\n"%url)
621                                 f.close()
622                                 self.session.open(MessageBox, (_("Added %s to the download-list.") % url), MessageBox.TYPE_INFO)
623                         except:
624                                 self.session.open(MessageBox, (_("Error while adding %s to the download-list!") % url), MessageBox.TYPE_ERROR)
625
626         def search(self):
627                 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)
628
629         def searchCallback(self, html=""):
630                 list = []
631                 files = []
632                 
633                 if html.__contains__("Nothing found, sorry."):
634                         self.session.open(MessageBox, (_("Error while searching http://rapidshare-search-engine.com!\n\nError: Nothing found, sorry.")), MessageBox.TYPE_ERROR)
635                         self.instance.setTitle(_("Nothing found, sorry."))
636                 else:
637                         tmp = html
638                         while tmp.__contains__("goPg('"):
639                                 idx = tmp.index("goPg('")
640                                 tmp = tmp[idx+6:]
641                                 idx = tmp.index("'")
642                                 pageNumber = tmp[:idx]
643                                 \r
644                                 try:
645                                         pageNumber = int(pageNumber)
646                                         if pageNumber > self.maxPage:
647                                                 self.maxPage = pageNumber
648                                 except:
649                                         pass
650                                 
651                                 self.instance.setTitle(_("Page %d / %d. Push < > to switch the page...")%(self.curPage, self.maxPage))
652                         
653                         while html.__contains__('title="Download"'):
654                                 idx = html.index('title="Download"')
655                                 html = html[idx:]
656                                 idx = html.index('value="')
657                                 html = html[idx+7:]
658                                 idx = html.index('"')
659                                 size = html[:idx]
660                                 idx = html.index('http://rapidshare.com/')
661                                 html = html[idx:]
662                                 idx = html.index('"')
663                                 url = html[:idx]
664                                 
665                                 files.append(url) 
666                                 try:
667                                         urllist = url.split("/")
668                                         idx = len(urllist) - 1
669                                         name = urllist[idx]
670                                         list.append("%s - %s"%(size, name))
671                                 except:
672                                         list.append("%s - %s"%(size, url))
673                 
674                 self.files = files
675                 self["list"].setList(list)
676
677         def searchError(self, error=""):
678                 self.session.open(MessageBox, (_("Error while searching http://rapidshare-search-engine.com!\n\nError: %s")%str(error)), MessageBox.TYPE_ERROR)
679
680         def previousPage(self):
681                 if self.curPage > 1:
682                         self.curPage -= 1
683                         self.instance.setTitle(_("Loading previous page... please wait!"))
684                         self.search()
685
686         def nextPage(self):
687                 if self.curPage < self.maxPage:
688                         self.curPage += 1
689                         self.instance.setTitle(_("Loading next page... please wait!"))
690                         self.search()
691
692 ##############################################################################
693
694 class RSLogScreen(ChangedScreen):
695         skin = """
696                 <screen position="center,center" size="560,450" title="RS Downloader">
697                         <widget name="label" position="0,0" size="560,450" font="Regular;20" />
698                 </screen>"""
699
700         def __init__(self, session):
701                 ChangedScreen.__init__(self, session)
702                 
703                 try:
704                         f = open("/tmp/rapidshare.log")
705                         log = f.read()
706                         f.close()
707                 except:
708                         log = ""
709                 self["label"] = ScrollLabel(log)
710                 
711                 self["actions"] = ActionMap(["WizardActions"],
712                         {
713                                 "ok": self.close,
714                                 "back": self.close,
715                                 "up": self["label"].pageUp,
716                                 "down": self["label"].pageDown,
717                                 "left": self["label"].pageUp,
718                                 "right": self["label"].pageDown
719                         }, -1)
720
721 ##############################################################################
722
723 class RSContainerSelector(ChangedScreen):
724         skin = """
725                 <screen position="center,center" size="560,450" title="RS Downloader">
726                         <widget name="list" position="0,0" size="560,450" />
727                 </screen>"""
728
729         def __init__(self, session, list):
730                 ChangedScreen.__init__(self, session)
731                 self["list"] = MenuList(list)
732                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.okClicked, "cancel": self.close}, -1)
733
734         def okClicked(self):
735                 cur = self["list"].getCurrent()
736                 self.close(cur)
737
738 ##############################################################################
739
740 class RSList(MenuList):
741         def __init__(self, list):
742                 MenuList.__init__(self, list, False, eListboxPythonMultiContent)
743                 self.l.setItemHeight(25)
744                 self.l.setFont(0, gFont("Regular", 20))
745
746 ##############################################################################
747
748 def RSListEntry(download):
749         res = [(download)]
750         res.append(MultiContentEntryText(pos=(0, 0), size=(170, 25), font=0, text=download.name))
751         res.append(MultiContentEntryText(pos=(175, 0), size=(75, 25), font=0, text="%d%s"%(download.size, "MB"), flags=RT_HALIGN_CENTER))
752         res.append(MultiContentEntryPixmapAlphaTest(pos=(260, 9), size=(84, 7), png=LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/progress_bg.png"))))
753         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"))))
754         res.append(MultiContentEntryText(pos=(360, 0), size=(60, 25), font=0, text="%d%s"%(download.progress, "%"), flags=RT_HALIGN_CENTER))
755         res.append(MultiContentEntryText(pos=(420, 0), size=(140, 25), font=0, text=download.status, flags=RT_HALIGN_RIGHT))
756         return res
757
758 ##############################################################################
759
760 class RSMain(ChangedScreen):
761         skin = """
762                 <screen position="center,center" size="560,450" title="RS Downloader">
763                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" transparent="1" alphatest="on" />
764                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" transparent="1" alphatest="on" />
765                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" transparent="1" alphatest="on" />
766                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" transparent="1" alphatest="on" />
767                         <widget name="key_red" position="0,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
768                         <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
769                         <widget name="key_yellow" position="280,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
770                         <widget name="key_blue" position="420,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
771                         <widget name="list" position="0,40" size="560,400" scrollbarMode="showNever" />
772                 </screen>"""
773
774         def __init__(self, session):
775                 ChangedScreen.__init__(self, session)
776                 self.session = session
777                 
778                 self["key_red"] = Label(_("Delete"))
779                 self["key_green"] = Label(_("Search"))
780                 self["key_yellow"] = Label(_("Add"))
781                 self["key_blue"] = Label(_("Config"))
782                 self["list"] = RSList([])
783                 
784                 self.refreshTimer = eTimer()
785                 self.refreshTimer.callback.append(self.updateList)
786                 
787                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "InfobarMenuActions"],
788                         {
789                                 "mainMenu": self.menu,
790                                 "cancel": self.close,
791                                 "red": self.delete,
792                                 "green": self.search,
793                                 "yellow": self.add,
794                                 "blue": self.config
795                         }, prio=-1)
796                 
797                 self.onLayoutFinish.append(self.updateList)
798
799         def menu(self):
800                 list = []
801                 #TODO: Add sort list functions
802                 list.append((_("Delete download"), self.delete))
803                 list.append((_("Use search engine"), self.search))
804                 list.append((_("Add downloads from txt files"), self.add))
805                 list.append((_("Add files from container"), self.addContainer))
806                 list.append((_("Delete failed downloads"), self.deleteFailed))
807                 list.append((_("Restart failed downloads"), self.restartFailed))
808                 list.append((_("Clear finished downloads"), self.clearFinished))
809                 list.append((_("Show log"), self.showLog))
810                 list.append((_("Delete log"), self.deleteLog))
811                 list.append((_("Close plugin"), self.close))
812                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title=_("Please choose a function..."), list=list)
813
814         def menuCallback(self, callback=None):
815                 if callback is not None:
816                         callback[1]()
817
818         def deleteFailed(self):
819                 rapidshare.deleteFailedDownloads()
820
821         def restartFailed(self):
822                 rapidshare.restartFailedDownloads()
823
824         def clearFinished(self):
825                 rapidshare.clearFinishedDownloads()
826
827         def showLog(self):
828                 self.session.open(RSLogScreen)
829
830         def deleteLog(self):
831                 try:
832                         remove("/tmp/rapidshare.log")
833                 except:
834                         pass
835
836         def updateList(self):
837                 list = []
838                 for download in rapidshare.downloads:
839                         list.append(RSListEntry(download))
840                 self["list"].setList(list)
841                 self.refreshTimer.start(2000, 1)
842
843         def delete(self):
844                 cur = self["list"].getCurrent()
845                 if cur:
846                         cur = cur[0]
847                         if cur.status == _("Finished"):
848                                 rapidshare.clearFinishedDownload(cur.url)
849                         else:
850                                 self.session.openWithCallback(self.deleteCallback, MessageBox, (_("Delete %s?")%cur.name))
851
852         def deleteCallback(self, callback):
853                 if callback:
854                         rapidshare.removeDownload(self["list"].getCurrent()[0].url)
855                         self.refreshTimer.stop()
856                         self.updateList()
857
858         def search(self):
859                 self.session.openWithCallback(self.searchCallback, VirtualKeyBoard, title=_("Search http://rapidshare-search-engine.com for:"))
860
861         def searchCallback(self, callback):
862                 if callback is not None and callback != "":
863                         self.session.openWithCallback(self.searchScreenCallback, RSSearch, callback)
864
865
866         def searchScreenCallback(self):
867                 self.refreshTimer.stop()
868                 rapidshare.startDownloading()
869                 self.updateList()
870
871         def add(self):
872                 self.refreshTimer.stop()
873                 rapidshare.startDownloading()
874                 self.updateList()
875
876         def config(self):
877                 self.session.openWithCallback(self.configCallback, RSConfig)
878
879         def configCallback(self):
880                 if config.plugins.RSDownloader.onoff.value:
881                         rapidshare.startDownloading()
882                 else:
883                         for download in rapidshare.downloads:
884                                 if download.downloading:
885                                         download.stop()
886                 self.updateList()
887
888         def addContainer(self):
889                 try:\r
890                         file_list = listdir(config.plugins.RSDownloader.lists_directory.value)\r
891                 except:\r
892                         file_list = []
893                 list = []
894                 for file in file_list:
895                         if file.lower().endswith(".ccf") or file.lower().endswith(".dlc") or file.lower().endswith(".rsdf"):
896                                 list.append(file)
897                 list.sort()
898                 self.session.openWithCallback(self.addContainerCallback, RSContainerSelector, list)
899
900         def addContainerCallback(self, callback=None):
901                 if callback:
902                         file = "%s/%s"%(config.plugins.RSDownloader.lists_directory.value, callback)
903                         file = file.replace("//", "/")
904                         links = decrypt(file)
905                         try:
906                                 f = open(("%s/%s.txt" % (config.plugins.RSDownloader.lists_directory.value, callback)).replace("//", "/"), "w")
907                                 for link in links:
908                                         if link.endswith(".html"):
909                                                 link = link[:-5]
910                                         elif link.endswith(".htm"):
911                                                 link = link[:-4]
912                                         f.write("%s\n"%link)
913                                 f.close()
914                         except:
915                                 pass
916                         self.refreshTimer.stop()
917                         rapidshare.startDownloading()
918                         self.updateList()
919
920 ##############################################################################
921
922 def autostart(reason, **kwargs):\r
923         if reason == 0:\r
924                 rapidshare.startDownloading()\r
925 \r
926 ##############################################################################\r
927 \r
928 def main(session, **kwargs):\r
929         session.open(RSMain)\r
930 \r
931 ##############################################################################\r
932 \r
933 def Plugins(**kwargs):\r
934         return [
935                 PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, fnc=autostart),\r
936                 PluginDescriptor(name=_("RS Downloader"), description=_("Download files from rapidshare"), where=[PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU], icon="rs.png", fnc=main)]
937