#!/usr/bin/env python3 import random 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 apiurl = API_URL+"?source=pythonapi&apikey="+API_KEY+"&" offlinemessage = "Click \"Start\" to fetch next captcha." 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.timerLabel = QLabel("30 Sek") # self.timerLabel.setAlignment(Qt.AlignCenter) # self.timerProgress = QProgressBar() # self.timerProgress.setRange(0,30) # self.timerProgress.setValue(23.65) # self.timerProgress.setTextVisible(True) # self.timerProgress.text = "Bla und so" self.statsLabel = QLabel("online stats") self.statsLabel.setAlignment(Qt.AlignRight) # self.timerLabel.setStyleSheet("QLabel { color: darkred; }") # self.timerLabel.setStyleSheet("QLabel { background-color: gray; }") 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.captchaLabel = QLabel("Captcha:") 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.captchaLabel) 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") # 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 in Queue" % (self.currentCommited, self.currentSkipped, self.currentQueued) 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.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.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 self.captchaImage.setText("") 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': status = self.captchaImage.text()+"." self.captchaImage.setText(status) QTimer.singleShot(1000, self.getCaptchaID) elif not content.isnumeric(): self.captchaImage.setText("Unknown error? ID not 'NO CAPTCHA' nor number") else: self.currentCaptchaID = int(content) self.getCaptchaIMG() 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()