summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--module/gui/Overview.py8
-rw-r--r--module/gui/Queue.py51
-rw-r--r--module/network/RequestFactory.py7
-rw-r--r--module/network/XDCCRequest.py132
-rw-r--r--module/plugins/hoster/EasyShareCom.py69
-rw-r--r--module/plugins/hoster/FilesonicCom.py7
-rw-r--r--module/plugins/hoster/Xdcc.py46
7 files changed, 296 insertions, 24 deletions
diff --git a/module/gui/Overview.py b/module/gui/Overview.py
index 205d85234..533c6faa8 100644
--- a/module/gui/Overview.py
+++ b/module/gui/Overview.py
@@ -160,10 +160,10 @@ class OverviewDelegate(QItemDelegate):
size = "%s KiB" % kbytes
return size
- #if progress == 100:
- sizeline = QString(_("Size: %s") % formatSize(maxSize))
- #else:
- # sizeline = QString(_("Size: %s/%s") % (formatSize(currentSize), formatSize(maxSize)))
+ if progress in (0,100):
+ sizeline = QString(_("Size: %s") % formatSize(maxSize))
+ else:
+ sizeline = QString(_("Size: %s / %s") % (formatSize(currentSize), formatSize(maxSize)))
f = painter.font()
f.setPointSize(12)
diff --git a/module/gui/Queue.py b/module/gui/Queue.py
index 9751b652f..1b9f98259 100644
--- a/module/gui/Queue.py
+++ b/module/gui/Queue.py
@@ -23,10 +23,22 @@ from time import sleep, time
from module.gui.Collector import CollectorModel, Package, Link, CollectorView, statusMap, statusMapReverse
+def formatSize(size):
+ """formats size of bytes"""
+ size = int(size)
+ steps = 0
+ sizes = ["B", "KB", "MB", "GB", "TB"]
+
+ while size > 1000:
+ size /= 1024.0
+ steps += 1
+
+ return "%.2f %s" % (size, sizes[steps])
+
class QueueModel(CollectorModel):
def __init__(self, view, connector):
CollectorModel.__init__(self, view, connector)
- self.cols = 6
+ self.cols = 9
self.wait_dict = {}
self.updater = self.QueueUpdater(self.interval)
@@ -106,8 +118,14 @@ class QueueModel(CollectorModel):
elif section == 3:
return QVariant(_("Priority"))
elif section == 4:
- return QVariant(_("ETA"))
+ return QVariant(_("Current"))
elif section == 5:
+ return QVariant(_("Left"))
+ elif section == 6:
+ return QVariant(_("Size"))
+ elif section == 7:
+ return QVariant(_("ETA"))
+ elif section == 8:
return QVariant(_("Progress"))
return QVariant()
@@ -216,6 +234,26 @@ class QueueModel(CollectorModel):
item = index.internalPointer()
if isinstance(item, Link):
if item.data["downloading"]:
+ return QVariant("%s" % formatSize(item.data["size"]-item.data["downloading"]["bleft"]))
+ elif isinstance(item, Package):
+ return QVariant("packRecv")
+ elif index.column() == 5:
+ item = index.internalPointer()
+ if isinstance(item, Link):
+ if item.data["downloading"]:
+ return QVariant("%s" % formatSize(item.data["downloading"]["bleft"]))
+ elif isinstance(item, Package):
+ return QVariant("packLeft")
+ elif index.column() == 6:
+ item = index.internalPointer()
+ if isinstance(item, Link):
+ return QVariant("%s" % item.data["format_size"])
+ elif isinstance(item, Package):
+ return QVariant("packSize")
+ elif index.column() == 7:
+ item = index.internalPointer()
+ if isinstance(item, Link):
+ if item.data["downloading"]:
return QVariant(item.data["downloading"]["format_eta"])
elif role == Qt.EditRole:
if index.column() == 0:
@@ -236,13 +274,14 @@ class QueueView(CollectorView):
self.setColumnWidth(1, 100)
self.setColumnWidth(2, 150)
self.setColumnWidth(3, 50)
- self.setColumnWidth(4, 70)
- self.setColumnWidth(5, 80)
+ self.setColumnWidth(4, 80)
+ self.setColumnWidth(5, 70)
+ self.setColumnWidth(6, 80)
self.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.delegate = QueueProgressBarDelegate(self, self.model())
- self.setItemDelegateForColumn(5, self.delegate)
+ self.setItemDelegateForColumn(8, self.delegate)
class QueueProgressBarDelegate(QItemDelegate):
def __init__(self, parent, queue):
@@ -252,7 +291,7 @@ class QueueProgressBarDelegate(QItemDelegate):
def paint(self, painter, option, index):
if not index.isValid():
return
- if index.column() == 5:
+ if index.column() == 8:
item = index.internalPointer()
w = self.queue.getWaitingProgress(item)
wait = None
diff --git a/module/network/RequestFactory.py b/module/network/RequestFactory.py
index 8340d06f7..90a48fe3c 100644
--- a/module/network/RequestFactory.py
+++ b/module/network/RequestFactory.py
@@ -24,6 +24,8 @@ from Bucket import Bucket
from HTTPRequest import HTTPRequest
from CookieJar import CookieJar
+from XDCCRequest import XDCCRequest
+
class RequestFactory():
def __init__(self, core):
self.lock = Lock()
@@ -35,9 +37,12 @@ class RequestFactory():
def iface(self):
return self.core.config["download"]["interface"]
- def getRequest(self, pluginName, account=None):
+ def getRequest(self, pluginName, account=None, type="HTTP"):
self.lock.acquire()
+ if type == "XDCC":
+ return XDCCRequest(proxies=self.getProxies())
+
req = Browser(self.iface(), self.bucket, self.getProxies())
if account:
diff --git a/module/network/XDCCRequest.py b/module/network/XDCCRequest.py
new file mode 100644
index 000000000..126662bb8
--- /dev/null
+++ b/module/network/XDCCRequest.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: jeix
+"""
+
+import socket
+import re
+
+from os.path import exists
+
+from time import time
+
+import struct
+from select import select
+
+class XDCCError(Exception):
+ pass
+
+class XDCCRequest():
+ def __init__(self, timeout=30, proxies={}):
+
+ self.proxies = proxies
+ self.timeout = timeout
+
+ self.filesize = 0
+ self.recv = 0
+ self.speed = 0
+
+ self.abort = False
+
+
+ def createSocket(self):
+ # proxytype = None
+ # proxy = None
+ # if self.proxies.has_key("socks5"):
+ # proxytype = socks.PROXY_TYPE_SOCKS5
+ # proxy = self.proxies["socks5"]
+ # elif self.proxies.has_key("socks4"):
+ # proxytype = socks.PROXY_TYPE_SOCKS4
+ # proxy = self.proxies["socks4"]
+ # if proxytype:
+ # sock = socks.socksocket()
+ # t = _parse_proxy(proxy)
+ # sock.setproxy(proxytype, addr=t[3].split(":")[0], port=int(t[3].split(":")[1]), username=t[1], password=t[2])
+ # else:
+ # sock = socket.socket()
+ # return sock
+
+ return socket.socket()
+
+ def download(self, ip, port, filename, progressNotify=None):
+
+ lastRecv = time()
+
+ dccsock = self.createSocket()
+
+ dccsock.settimeout(self.timeout)
+ dccsock.connect((ip, port))
+
+ if exists(filename):
+ i = 0
+ nameParts = filename.rpartition(".")
+ while True:
+ newfilename = "%s-%d%s%s" % (nameParts[0], i, nameParts[1], nameParts[2])
+ i += 1
+
+ if not exists(newfilename):
+ filename = newfilename
+ break
+
+ fh = open(filename, "wb")
+
+ # recv loop for dcc socket
+ while True:
+ if self.abort:
+ break
+
+ data = dccsock.recv(4096)
+ dataLen = len(data)
+ self.recv += dataLen
+
+ now = time()
+ timespan = now - lastRecv
+ if timespan:
+ self.speed = dataLen / timespan
+ if progressNotify:
+ progressNotify(self.percent)
+ lastRecv = now
+
+ if not data:
+ break
+
+ fh.write(data)
+
+ # acknowledge data by sending number of recceived bytes
+ dccsock.send(struct.pack('!I', self.recv))
+
+ dccsock.close()
+ fh.close()
+
+ return filename
+
+
+ @property
+ def size(self):
+ return self.filesize
+
+ @property
+ def arrived(self):
+ return self.recv
+
+ @property
+ def percent(self):
+ if not self.filesize: return 0
+ return (self.recv * 100) / self.filesize
+
+ def close(self):
+ pass
diff --git a/module/plugins/hoster/EasyShareCom.py b/module/plugins/hoster/EasyShareCom.py
new file mode 100644
index 000000000..9d185f4b5
--- /dev/null
+++ b/module/plugins/hoster/EasyShareCom.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import re
+from module.plugins.Hoster import Hoster
+from module.plugins.ReCaptcha import ReCaptcha
+
+class EasyShareCom(Hoster):
+ __name__ = "EasyShareCom"
+ __type__ = "hoster"
+ __pattern__ = r"http://[\w\d\.]*?easy-share\.com/(\d{6}).*"
+ __version__ = "0.1"
+ __description__ = """easy-share.com One-Klick Hoster"""
+ __author_name__ = ("jeix")
+ __author_mail__ = ("jeix@hasnomail.de")
+
+
+ def setup(self):
+ self.multiDL = False
+ self.html = None
+
+ def process(self, pyfile):
+ self.pyfile = pyfile
+
+ self.html = self.load(self.pyfile.url)
+ self.pyfile.name = self.getFileName()
+
+ self.download( self.getFileUrl() )
+
+
+ def getFileName(self):
+ return re.search(r'requesting:</span>\s*(.*?)<', self.html).group(1)
+
+
+ def getFileUrl(self):
+
+ if "There is another download in progress from your IP" in self.html:
+ self.log.info("%s: IP blocked, retry in 5 minutes." % self.__name__)
+ self.setWait(5 * 60)
+ self.wait()
+ self.retry()
+
+ if "You need a premium membership to download this file" in self.html:
+ self.fail("You need a premium membership to download this file.")
+
+
+ wait = re.search(r"w='(\d+)'", self.html)
+ if wait:
+ wait = int( wait.group(1).strip() )
+ self.log.info("%s: Waiting %d seconds." % (self.__name__, wait))
+ self.setWait(wait)
+ self.wait()
+
+ tempurl = self.pyfile.url
+ if not tempurl.endswith("/"):
+ tempurl += "/"
+ id = re.search(r'http://[\w\d\.]*?easy-share\.com/(\d+)/', tempurl).group(1)
+ self.html = self.load("http://www.easy-share.com/file_contents/captcha/" + id)
+
+ challenge = re.search(r'Recaptcha\.create\("(.*?)"', self.html).group(1)
+ re_captcha = ReCaptcha(self)
+ challenge, result = re_captcha.challenge(challenge)
+
+ link = re.search(r'<form\s+method="post"\s+action="(http://[\w\d\.]*?easy-share.com/file_contents/.*?)">', self.html).group(1)
+ id = re.search(r'file/id/(\d+)/', link)
+ self.download( link, post={"id" : id,
+ "recaptcha_challenge_field" : challenge,
+ "recaptcha_response_field": result} )
+
diff --git a/module/plugins/hoster/FilesonicCom.py b/module/plugins/hoster/FilesonicCom.py
index 5e2c10219..5bd38655a 100644
--- a/module/plugins/hoster/FilesonicCom.py
+++ b/module/plugins/hoster/FilesonicCom.py
@@ -11,7 +11,7 @@ class FilesonicCom(Hoster):
__name__ = "FilesonicCom"
__type__ = "hoster"
__pattern__ = r"http://[\w\.]*?(sharingmatrix|filesonic)\.(com|net)/.*?file/([0-9]+(/.+)?|[a-z0-9]+/[0-9]+(/.+)?)"
- __version__ = "0.1"
+ __version__ = "0.2"
__description__ = """FilesonicCom und Sharingmatrix Download Hoster"""
__author_name__ = ("jeix")
__author_mail__ = ("jeix@hasnomail.de")
@@ -25,11 +25,14 @@ class FilesonicCom(Hoster):
self.url = self.convertURL(self.pyfile.url)
self.html = self.load(self.url, cookies=False)
- name = re.search(r'Filename:\s*</span>\s*<strong>(.*?)<', self.html)
+ name = re.search(r'<title>Download (.*?) for free on Filesonic.com</title>', self.html)
if name:
self.pyfile.name = name.group(1)
else:
self.offline()
+
+ if 'The page you are trying to access was not found.' in self.html:
+ self.offline()
if self.account:
self.download(pyfile.url)
diff --git a/module/plugins/hoster/Xdcc.py b/module/plugins/hoster/Xdcc.py
index bc35cf6ea..4ed718823 100644
--- a/module/plugins/hoster/Xdcc.py
+++ b/module/plugins/hoster/Xdcc.py
@@ -25,13 +25,14 @@ import sys
import time
import socket, struct
from select import select
+from module.utils import save_join
from module.plugins.Hoster import Hoster
class Xdcc(Hoster):
__name__ = "Xdcc"
- __version__ = "0.2"
+ __version__ = "0.3"
__pattern__ = r'xdcc://.*?(/#?.*?)?/.*?/#?\d+/?' # xdcc://irc.Abjects.net/#channel/[XDCC]|Shit/#0004/
__type__ = "hoster"
__config__ = [
@@ -44,11 +45,16 @@ class Xdcc(Hoster):
__author_mail__ = ("jeix@hasnomail.com")
def setup(self):
- self.debug = 0 #0,1,2
+ self.debug = 2 #0,1,2
self.timeout = 10
self.multiDL = False
+
+
def process(self, pyfile):
+ # change request type
+ self.req = pyfile.m.core.requestFactory.getRequest(self.__name__, type="XDCC")
+
self.pyfile = pyfile
for i in range(0,3):
try:
@@ -142,7 +148,7 @@ class Xdcc(Hoster):
readbuffer = temp.pop()
for line in temp:
- if self.debug is 2: print "*> " + line
+ if self.debug is 2: print "*> " + unicode(line, errors='ignore')
line = line.rstrip()
first = line.split()
@@ -182,6 +188,7 @@ class Xdcc(Hoster):
if self.debug is 1:
print "%s: %s" % (msg["origin"], msg["text"])
+ # You already requested that pack
if "You already requested that pack" in msg["text"]:
retry = time.time() + 300
@@ -189,27 +196,44 @@ class Xdcc(Hoster):
self.fail("Wrong channel")
m = re.match('\x01DCC SEND (.*?) (\d+) (\d+)(?: (\d+))?\x01', msg["text"])
- if m is not None:
+ if m != None:
done = True
# get connection data
ip = socket.inet_ntoa(struct.pack('L', socket.ntohl(int(m.group(2)))))
port = int(m.group(3))
- packname = m.group(1)
+ packname = m.group(1)
if len(m.groups()) > 3:
- self.req.dl_size = int(m.group(4))
+ self.req.filesize = int(m.group(4))
self.pyfile.name = packname
+ filename = save_join(location, packname)
self.log.info("XDCC: Downloading %s from %s:%d" % (packname, ip, port))
-
+
self.pyfile.setStatus("downloading")
- newname = self.req.download(ip, port, location, packname)
- self.pyfile.size = self.req.dl_size
+ newname = self.req.download(ip, port, filename, self.pyfile.progress.setValue)
+ if newname and newname != filename:
+ self.log.info("%(name)s saved as %(newname)s" % {"name": self.pyfile.name, "newname": newname})
+ filename = newname
# kill IRC socket
# sock.send("QUIT :byebye\r\n")
sock.close()
- if newname:
- self.pyfile.name = newname
+ if self.core.config["permission"]["change_file"]:
+ chmod(filename, int(self.core.config["permission"]["file"],8))
+
+ if self.core.config["permission"]["change_dl"] and os.name != "nt":
+ try:
+ uid = getpwnam(self.config["permission"]["user"])[2]
+ gid = getgrnam(self.config["permission"]["group"])[2]
+
+ chown(filename, uid, gid)
+ except Exception,e:
+ self.log.warning(_("Setting User and Group failed: %s") % str(e))
+
+ self.lastDownload = filename
+ return self.lastDownload
+
+