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