#!/usr/bin/env python3 import sys import time from PyQt5.QtCore import Qt, QTimer, QUrl from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtWidgets import QLayout, QHBoxLayout, QVBoxLayout, QSizePolicy from PyQt5.QtWidgets import QLabel, QLineEdit, QPushButton, QProgressBar from PyQt5.QtGui import QPixmap from PyQt5.QtMultimedia import QSound from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply API_URL = "http://www.9kw.eu/index.cgi" API_KEY = "" soundfile = "notify.wav" class CaptchaGUI(QWidget): sound = False # QSound() image = False # QImage() imageR = False # QImage() resized timer = False # QTimer() for 30sec timing running = False startCredits = None currentCredits = 0 currentCaptchaID = None currentCommited = 0 currentSkipped = 0 currentQueued = 0 currentWorker = 0 apiurl = API_URL+"?source=pythonapi&apikey="+API_KEY+"&" offlinemessage = "Click \"Start\" to fetch next captcha." waitingoncaptcha = 0 def __init__(self, parent=None): super(CaptchaGUI, self).__init__(parent) self.setMinimumWidth(400) # Top: Credits and Stats self.accountLabel = QLabel("credits") self.accountLabel.setAlignment(Qt.AlignLeft) self.statsLabel = QLabel("online stats") self.statsLabel.setAlignment(Qt.AlignRight) # self.timerLabel.setStyleSheet("QLabel { color: darkred; }") self.LayoutStats = QHBoxLayout() self.LayoutStats.addWidget(self.accountLabel) # self.LayoutStats.addWidget(self.timerLabel) # self.LayoutStats.addWidget(self.timerProgress) self.LayoutStats.addWidget(self.statsLabel) self.LayoutStats.sizeConstraint = QLayout.SetMinimumSize # Middle: Captchaimage self.captchaImage = QLabel("") self.captchaImage.setAlignment(Qt.AlignCenter) self.captchaImage.setMinimumHeight(400) self.captchaImage.setSizePolicy( QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding ) self.captchaBox = QHBoxLayout() self.captchaBox.addWidget(self.captchaImage) # Bottom: Input + Submit/Skip-Buttons self.captchaInputLine = QLineEdit() self.startstopButton = QPushButton("Start") self.startstopButton.setCheckable(True) self.submitButton = QPushButton("&Submit") self.skipButton = QPushButton("S&kip") self.startstopButton.clicked.connect(self.toggleRunning) self.submitButton.clicked.connect(self.submitCaptcha) self.skipButton.clicked.connect(self.skipCaptcha) self.LayoutSubmitLine = QHBoxLayout() self.LayoutSubmitLine.addWidget(self.startstopButton) self.LayoutSubmitLine.addWidget(self.captchaInputLine) self.LayoutSubmitButtons = QHBoxLayout() self.LayoutSubmitButtons.addWidget(self.submitButton) self.LayoutSubmitButtons.addWidget(self.skipButton) self.LayoutSubmit = QVBoxLayout() self.LayoutSubmit.addLayout(self.LayoutSubmitLine) self.LayoutSubmit.addLayout(self.LayoutSubmitButtons) # Compile layout mainLayout = QVBoxLayout() mainLayout.addLayout(self.LayoutStats) mainLayout.addLayout(self.captchaBox) mainLayout.addLayout(self.LayoutSubmit) self.setLayout(mainLayout) self.setWindowTitle("Captcha 9kw PyQt") if not API_KEY: self.captchaImage.setText("API_KEY is missing.\nPlease edit this file and enter your key at the top.") self.startstopButton.setEnabled(False) return # load soundfile self.sound = QSound(soundfile) # Initialize network self.NetworkManager = QNetworkAccessManager() QTimer.singleShot(500, self.getCredits) QTimer.singleShot(500, self.getQueue) QTimer.singleShot(500, self.getCaptchaID) self.timer = QTimer() self.timer.timeout.connect(self.onTimeout) self.timer.setSingleShot(True) ################################################## # Handle gui ################################################## def resizeEvent(self, evt=None): if self.image: self.imageR = self.image.scaled(self.captchaImage.size(), Qt.KeepAspectRatio) self.captchaImage.setPixmap(self.imageR) def updateStats(self): if self.startCredits: credittext = "%d ¥ (%s%d)" % (self.currentCredits, (self.currentCredits - self.startCredits > 0) and '+' or '', (self.currentCredits - self.startCredits)) else: credittext = "%d ¥" % (self.currentCredits) self.accountLabel.setText(credittext) labeltext = "%d Commited | %d Skipped | %d Queue | %d Worker" % (self.currentCommited, self.currentSkipped, self.currentQueued, self.currentWorker) self.statsLabel.setText(labeltext) def keyPressEvent(self, event): key = event.key() if key == Qt.Key_Escape: self.skipCaptcha() elif key == Qt.Key_Enter or key == Qt.Key_Return: if self.skipButton.hasFocus(): self.skipCaptcha() else: self.submitCaptcha() def setCaptchaImage(self, image=None): pixmap = QPixmap() result = pixmap.loadFromData(image) if result: self.image = pixmap self.imageR = self.image.scaled(self.captchaImage.size(), Qt.KeepAspectRatio) self.captchaImage.setPixmap(self.imageR) self.captchaInputLine.setFocus() self.sound.play() self.timer.start(30000) self.captchaImage.setText("") else: self.captchaImage.setText("Could not display image. Skip!") self.skipCaptcha() def removeCaptchaImage(self): self.image = False self.captchaImage.setPixmap(QPixmap()) def toggleRunning(self): self.running = not self.running self.captchaImage.setText("") self.offlinemessage = "Click \"Start\" to fetch next captcha." self.startstopButton.setText(self.running and "Stop" or "Start") self.startstopButton.setChecked(self.running) ################################################## # Handle network ################################################## def getCredits(self): url = QUrl(self.apiurl+"action=usercaptchaguthaben") self.networkCredits = QNetworkRequest(url) self.networkCreditsReply = self.NetworkManager.get(self.networkCredits) self.networkCreditsReply.finished.connect(self.getCreditsFinished) def getCreditsFinished(self): content = str(self.networkCreditsReply.readAll(), encoding='utf-8') if content.isnumeric(): self.currentCredits = int(content) if not self.startCredits: self.startCredits = self.currentCredits self.updateStats() else: self.accountLabel.setText("Error?") self.networkCreditsReply.deleteLater() QTimer.singleShot(10000, self.getCredits) def getQueue(self): url = QUrl("http://www.9kw.eu/grafik/servercheck.txt") self.networkQueue = QNetworkRequest(url) self.networkQueueReply = self.NetworkManager.get(self.networkQueue) self.networkQueueReply.finished.connect(self.getQueueFinished) def getQueueFinished(self): content = str(self.networkQueueReply.readAll(), encoding='utf-8') datatmp = content.split('|') data = dict() for stat in datatmp: tmp = stat.split('=') data[tmp[0]] = tmp[1] self.currentQueued = int(data['queue']) self.currentWorker = int(data['workertext']) self.updateStats() self.networkQueueReply.deleteLater() QTimer.singleShot(5000, self.getQueue) def getCaptchaID(self): if not self.running: self.captchaImage.setText(self.offlinemessage) QTimer.singleShot(500, self.getCaptchaID) return url = QUrl(self.apiurl+"action=usercaptchanew&text=yes&mouse=0&confirm=0") self.networkCaptchaID = QNetworkRequest(url) self.networkCaptchaIDReply = self.NetworkManager.get(self.networkCaptchaID) self.networkCaptchaIDReply.finished.connect(self.getCaptchaIDFinished) def getCaptchaIDFinished(self): content = str(self.networkCaptchaIDReply.readAll(), encoding='utf-8') self.networkCaptchaIDReply.deleteLater() if content == 'NO CAPTCHA': self.waitingoncaptcha += 1 status = "Server responded with 'NO CAPTCHA' "+str(self.waitingoncaptcha)+" times." self.captchaImage.setText(status) QTimer.singleShot(1000, self.getCaptchaID) elif content.isnumeric(): self.waitingoncaptcha = 0 print("New Captcha:", int(content)) self.currentCaptchaID = int(content) self.getCaptchaIMG() else: self.waitingoncaptcha += 1 print("Unknown error? ID not 'NO CAPTCHA' nor number") print(content) def getCaptchaIMG(self): url = QUrl(self.apiurl+"action=usercaptchashow&id="+str(self.currentCaptchaID)) self.networkCaptchaIMG = QNetworkRequest(url) self.networkCaptchaIMGReply = self.NetworkManager.get(self.networkCaptchaIMG) self.networkCaptchaIMGReply.finished.connect(self.getCaptchaIMGFinished) def getCaptchaIMGFinished(self): image = self.networkCaptchaIMGReply.readAll() self.setCaptchaImage(image) self.networkCaptchaIMGReply.deleteLater() def setCaptchaAnswer(self, answer, skip=False): if skip: url = QUrl(self.apiurl+"action=usercaptchaskip&id="+str(self.currentCaptchaID)) self.networkCaptchaAnswer = QNetworkRequest(url) self.networkCaptchaAnswerReply = self.NetworkManager.get(self.networkCaptchaAnswer) self.networkCaptchaAnswerReply.finished.connect(self.setCaptchaAnswerSkipped) else: url = QUrl(self.apiurl+"action=usercaptchacorrect&id="+str(self.currentCaptchaID)+"&antwort="+answer+"&extended=1") self.networkCaptchaAnswer = QNetworkRequest(url) self.networkCaptchaAnswerReply = self.NetworkManager.get(self.networkCaptchaAnswer) self.networkCaptchaAnswerReply.finished.connect(self.setCaptchaAnswerCommit) def setCaptchaAnswerCommit(self): message = str(self.networkCaptchaAnswerReply.readAll(), encoding='utf-8') self.networkCaptchaAnswerReply.deleteLater() if not message: # TODO: Server error? Retry! (Status 200 + no 'OK'?) self.networkCaptchaAnswerReply = self.NetworkManager.get(self.networkCaptchaAnswer) self.networkCaptchaAnswerReply.finished.connect(self.setCaptchaAnswerCommit) else: self.currentCommited += 1 self.currentCaptchaID = None if message.startswith('OK') and '|' in message: parts = message.split('|') creds = int(parts[1]) self.currentCredits += creds self.updateStats() self.getCaptchaID() def setCaptchaAnswerSkipped(self): message = str(self.networkCaptchaAnswerReply.readAll(), encoding='utf-8') self.networkCaptchaAnswerReply.deleteLater() if not message: # Server error? Retry! (Status 200 + no 'OK'?) self.networkCaptchaAnswerReply = self.NetworkManager.get(self.networkCaptchaAnswer) self.networkCaptchaAnswerReply.finished.connect(self.setCaptchaAnswerSkipped) else: self.currentSkipped += 1 self.currentCaptchaID = None self.updateStats() self.getCaptchaID() ################################################## # Handle logic ################################################## def skipCaptcha(self): self.submitCaptcha(skip=True) def submitCaptcha(self, skip=False): answer = self.captchaInputLine.text() if not answer: skip = True self.timer.stop() self.setCaptchaAnswer(answer, skip) self.captchaInputLine.setText("") self.removeCaptchaImage() def onTimeout(self): self.running = False self.offlinemessage = "30 seconds passed without input." self.startstopButton.setText(self.running and "Stop" or "Start") self.startstopButton.setChecked(self.running) self.skipCaptcha() def onQuit(self): if self.currentCaptchaID: self.running = False self.setCaptchaAnswer("", skip=True, queue=False) def main(): # NOTE(andre): urlopen() will first try ipv6, if available # hacky way to remove IPv6: http://stackoverflow.com/questions/2014534/force-python-mechanize-urllib2-to-only-use-a-requests/6319043 # better way: disable IPv6, if your isp does not support it # import pudb; pudb.set_trace() app = QApplication(sys.argv) screen = CaptchaGUI() screen.show() sys.exit(app.exec_()) if __name__ == '__main__': main()