diff --git a/AutoAnswer/aans.py b/AutoAnswer/aans.py deleted file mode 100644 index 2f2268a..0000000 --- a/AutoAnswer/aans.py +++ /dev/null @@ -1,45 +0,0 @@ -import plugin_super_class -from PyQt5 import QtGui, QtWidgets -import json - - -class AutoAnswer(plugin_super_class.PluginSuperClass): - - def __init__(self, *args): - super(AutoAnswer, self).__init__('AutoAnswer', 'aans', *args) - self._data = json.loads(self.load_settings()) - self._tmp = None - - def get_description(self): - return QtWidgets.QApplication.translate("aans", 'Plugin which allows you to auto answer on calls.') - - def start(self): - self._tmp = self._profile.incoming_call - - def func(audio, video, friend_number): - if self._profile.get_friend_by_number(friend_number).tox_id in self._data['id']: - self._profile.accept_call(friend_number, audio, video) - else: - self._tmp(friend_number, audio, video) - - self._profile.incoming_call = func - - def stop(self): - self._profile.incoming_call = self._tmp - - def get_menu(self, menu, num): - friend = self._profile.get_friend(num) - if friend.tox_id in self._data['id']: - text = 'Disallow auto answer' - else: - text = 'Allow auto answer' - act = QtWidgets.QAction(QtWidgets.QApplication.translate("aans", text), menu) - act.triggered.connect(lambda: self.toggle(friend.tox_id)) - return [act] - - def toggle(self, tox_id): - if tox_id in self._data['id']: - self._data['id'].remove(tox_id) - else: - self._data['id'].append(tox_id) - self.save_settings(json.dumps(self._data)) diff --git a/AutoAnswer/aans/settings.json b/AutoAnswer/aans/settings.json deleted file mode 100644 index fd74b36..0000000 --- a/AutoAnswer/aans/settings.json +++ /dev/null @@ -1 +0,0 @@ -{"id": ["20E3E1DEB598C1A6B49B2D2F6BF1C181F4FE9C977B9098903F176269F32CEF1D"]} \ No newline at end of file diff --git a/AutoAwayStatusLinux/awayl.py b/AutoAwayStatusLinux/awayl.py deleted file mode 100644 index 7a3067a..0000000 --- a/AutoAwayStatusLinux/awayl.py +++ /dev/null @@ -1,105 +0,0 @@ -import plugin_super_class -import threading -import time -from PyQt5 import QtCore, QtWidgets -from subprocess import check_output -import json - - -class InvokeEvent(QtCore.QEvent): - EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) - - def __init__(self, fn, *args, **kwargs): - QtCore.QEvent.__init__(self, InvokeEvent.EVENT_TYPE) - self.fn = fn - self.args = args - self.kwargs = kwargs - - -class Invoker(QtCore.QObject): - - def event(self, event): - event.fn(*event.args, **event.kwargs) - return True - -_invoker = Invoker() - - -def invoke_in_main_thread(fn, *args, **kwargs): - QtCore.QCoreApplication.postEvent(_invoker, InvokeEvent(fn, *args, **kwargs)) - - -class AutoAwayStatusLinux(plugin_super_class.PluginSuperClass): - - def __init__(self, *args): - super().__init__('AutoAwayStatusLinux', 'awayl', *args) - self._thread = None - self._exec = None - self._active = False - self._time = json.loads(self.load_settings())['time'] - self._prev_status = 0 - - def close(self): - self.stop() - - def stop(self): - self._exec = False - if self._active: - self._thread.join() - - def start(self): - self._exec = True - self._thread = threading.Thread(target=self.loop) - self._thread.start() - - def save(self): - self.save_settings('{"time": ' + str(self._time) + '}') - - def change_status(self, status=1): - if self._profile.status in (0, 2): - self._prev_status = self._profile.status - if status is not None: - invoke_in_main_thread(self._profile.set_status, status) - - def get_window(self): - inst = self - - class Window(QtWidgets.QWidget): - def __init__(self): - super(Window, self).__init__() - self.setGeometry(QtCore.QRect(450, 300, 350, 100)) - self.label = QtWidgets.QLabel(self) - self.label.setGeometry(QtCore.QRect(20, 0, 310, 35)) - self.label.setText(QtWidgets.QApplication.translate("AutoAwayStatusLinux", "Auto away time in minutes\n(0 - to disable)")) - self.time = QtWidgets.QLineEdit(self) - self.time.setGeometry(QtCore.QRect(20, 40, 310, 25)) - self.time.setText(str(inst._time)) - self.setWindowTitle("AutoAwayStatusLinux") - self.ok = QtWidgets.QPushButton(self) - self.ok.setGeometry(QtCore.QRect(20, 70, 310, 25)) - self.ok.setText( - QtWidgets.QApplication.translate("AutoAwayStatusLinux", "Save")) - self.ok.clicked.connect(self.update) - - def update(self): - try: - t = int(self.time.text()) - except: - t = 0 - inst._time = t - inst.save() - self.close() - - return Window() - - def loop(self): - self._active = True - while self._exec: - time.sleep(5) - d = check_output(['xprintidle']) - d = int(d) // 1000 - if self._time: - if d > 60 * self._time: - self.change_status() - elif self._profile.status == 1: - self.change_status(self._prev_status) \ No newline at end of file diff --git a/AutoAwayStatusLinux/awayl/readme.txt b/AutoAwayStatusLinux/awayl/readme.txt deleted file mode 100644 index 788dca5..0000000 --- a/AutoAwayStatusLinux/awayl/readme.txt +++ /dev/null @@ -1 +0,0 @@ -Required package: xprintidle (sudo apt-get install xprintidle) diff --git a/AutoAwayStatusLinux/awayl/settings.json b/AutoAwayStatusLinux/awayl/settings.json deleted file mode 100644 index da28fd0..0000000 --- a/AutoAwayStatusLinux/awayl/settings.json +++ /dev/null @@ -1 +0,0 @@ -{"time": 5} diff --git a/AutoAwayStatusWindows/awayw.py b/AutoAwayStatusWindows/awayw.py index 5c4b768..cda1be7 100644 --- a/AutoAwayStatusWindows/awayw.py +++ b/AutoAwayStatusWindows/awayw.py @@ -1,7 +1,7 @@ import plugin_super_class import threading import time -from PyQt5 import QtCore, QtWidgets +from PySide import QtCore, QtGui from ctypes import Structure, windll, c_uint, sizeof, byref import json @@ -49,7 +49,6 @@ class AutoAwayStatusWindows(plugin_super_class.PluginSuperClass): self._exec = None self._active = False self._time = json.loads(self.load_settings())['time'] - self._prev_status = 0 def close(self): self.stop() @@ -67,29 +66,27 @@ class AutoAwayStatusWindows(plugin_super_class.PluginSuperClass): def save(self): self.save_settings('{"time": ' + str(self._time) + '}') - def change_status(self, status=1): - if self._profile.status != 1: - self._prev_status = self._profile.status - invoke_in_main_thread(self._profile.set_status, status) + def change_status(self): + invoke_in_main_thread(self._profile.set_status, 1) def get_window(self): inst = self - class Window(QtWidgets.QWidget): + class Window(QtGui.QWidget): def __init__(self): super(Window, self).__init__() self.setGeometry(QtCore.QRect(450, 300, 350, 100)) - self.label = QtWidgets.QLabel(self) + self.label = QtGui.QLabel(self) self.label.setGeometry(QtCore.QRect(20, 0, 310, 35)) - self.label.setText(QtWidgets.QApplication.translate("AutoAwayStatusWindows", "Auto away time in minutes\n(0 - to disable)")) - self.time = QtWidgets.QLineEdit(self) + self.label.setText(QtGui.QApplication.translate("AutoAwayStatusWindows", "Auto away time in minutes\n(0 - to disable)", None, QtGui.QApplication.UnicodeUTF8)) + self.time = QtGui.QLineEdit(self) self.time.setGeometry(QtCore.QRect(20, 40, 310, 25)) self.time.setText(str(inst._time)) self.setWindowTitle("AutoAwayStatusWindows") - self.ok = QtWidgets.QPushButton(self) + self.ok = QtGui.QPushButton(self) self.ok.setGeometry(QtCore.QRect(20, 70, 310, 25)) self.ok.setText( - QtWidgets.QApplication.translate("AutoAwayStatusWindows", "Save")) + QtGui.QApplication.translate("AutoAwayStatusWindows", "Save", None, QtGui.QApplication.UnicodeUTF8)) self.ok.clicked.connect(self.update) def update(self): @@ -106,10 +103,7 @@ class AutoAwayStatusWindows(plugin_super_class.PluginSuperClass): def loop(self): self._active = True while self._exec: - time.sleep(5) + time.sleep(30) d = get_idle_duration() - if self._time: - if d > 60 * self._time: - self.change_status() - elif self._profile.status == 1: - self.change_status(self._prev_status) + if self._time and d > 60 * self._time: + self.change_status() diff --git a/AvatarEncryption/ae.py b/AvatarEncryption/ae.py deleted file mode 100644 index ec12827..0000000 --- a/AvatarEncryption/ae.py +++ /dev/null @@ -1,75 +0,0 @@ -import plugin_super_class -import json -import settings -import os - - -class AvatarEncryption(plugin_super_class.PluginSuperClass): - - def __init__(self, *args): - super(AvatarEncryption, self).__init__('AvatarEncryption', 'ae', *args) - self._path = settings.ProfileHelper.get_path() + 'avatars/' - self._contacts = self._profile._contacts[:] - - def close(self): - if not self._encrypt_save.has_password(): - return - i, data = 1, {} - - self.save_contact_avatar(data, self._profile, 0) - for friend in self._contacts: - self.save_contact_avatar(data, friend, i) - i += 1 - self.save_settings(json.dumps(data)) - - def start(self): - if not self._encrypt_save.has_password(): - return - data = json.loads(self.load_settings()) - - self.load_contact_avatar(data, self._profile) - for friend in self._contacts: - self.load_contact_avatar(data, friend) - self._profile.update() - - def save_contact_avatar(self, data, contact, i): - tox_id = contact.tox_id[:64] - data[str(tox_id)] = str(i) - path = self._path + tox_id + '.png' - if os.path.isfile(path): - with open(path, 'rb') as fl: - avatar = fl.read() - encr_avatar = self._encrypt_save.pass_encrypt(avatar) - with open(self._path + self._settings.name + '_' + str(i) + '.png', 'wb') as fl: - fl.write(encr_avatar) - os.remove(path) - - def load_contact_avatar(self, data, contact): - tox_id = str(contact.tox_id[:64]) - if tox_id not in data: - return - path = self._path + self._settings.name + '_' + data[tox_id] + '.png' - if os.path.isfile(path): - with open(path, 'rb') as fl: - avatar = fl.read() - decr_avatar = self._encrypt_save.pass_decrypt(avatar) - with open(self._path + str(tox_id) + '.png', 'wb') as fl: - fl.write(decr_avatar) - os.remove(path) - contact.load_avatar() - - def load_settings(self): - try: - with open(plugin_super_class.path_to_data(self._short_name) + self._settings.name + '.json', 'rb') as fl: - data = fl.read() - return str(self._encrypt_save.pass_decrypt(data), 'utf-8') if data else '{}' - except: - return '{}' - - def save_settings(self, data): - try: - data = self._encrypt_save.pass_encrypt(bytes(data, 'utf-8')) - with open(plugin_super_class.path_to_data(self._short_name) + self._settings.name + '.json', 'wb') as fl: - fl.write(data) - except: - pass diff --git a/AvatarEncryption/ae/readme.txt b/AvatarEncryption/ae/readme.txt deleted file mode 100644 index 7fe7851..0000000 --- a/AvatarEncryption/ae/readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -Plugin for avatars encryption. Works with encrypted profiles only. -Note that it breaks compability with other clients. diff --git a/BirthDay/bday.py b/BirthDay/bday.py index 5fa0457..5428db3 100644 --- a/BirthDay/bday.py +++ b/BirthDay/bday.py @@ -1,5 +1,5 @@ import plugin_super_class -from PyQt5 import QtWidgets, QtCore +from PySide import QtGui, QtCore import json import importlib @@ -22,8 +22,9 @@ class BirthDay(plugin_super_class.PluginSuperClass): if int(arr[0]) == now.day and int(arr[1]) == now.month: today[key] = now.year - int(arr[2]) if len(today): - msgbox = QtWidgets.QMessageBox() - title = QtWidgets.QApplication.translate('BirthDay', "Birthday!") + msgbox = QtGui.QMessageBox() + title = QtGui.QApplication.translate('BirthDay', "Birthday!", None, + QtGui.QApplication.UnicodeUTF8) msgbox.setWindowTitle(title) text = ', '.join(self._profile.get_friend_by_number(self._tox.friend_by_public_key(x)).name + ' ({})'.format(today[x]) for x in today) msgbox.setText('Birthdays: ' + text) @@ -33,23 +34,23 @@ class BirthDay(plugin_super_class.PluginSuperClass): inst = self x = self._profile.tox_id[:64] - class Window(QtWidgets.QWidget): + class Window(QtGui.QWidget): def __init__(self): super(Window, self).__init__() self.setGeometry(QtCore.QRect(450, 300, 350, 150)) - self.send = QtWidgets.QCheckBox(self) + self.send = QtGui.QCheckBox(self) self.send.setGeometry(QtCore.QRect(20, 10, 310, 25)) - self.send.setText(QtWidgets.QApplication.translate('BirthDay', "Send my birthday date to contacts")) - self.setWindowTitle(QtWidgets.QApplication.translate('BirthDay', "Birthday")) + self.send.setText(QtGui.QApplication.translate('BirthDay', "Send my birthday date to contacts", None, QtGui.QApplication.UnicodeUTF8)) + self.setWindowTitle(QtGui.QApplication.translate('BirthDay', "Birthday", None, QtGui.QApplication.UnicodeUTF8)) self.send.clicked.connect(self.update) self.send.setChecked(inst._data['send_date']) - self.date = QtWidgets.QLineEdit(self) + self.date = QtGui.QLineEdit(self) self.date.setGeometry(QtCore.QRect(20, 50, 310, 25)) - self.date.setPlaceholderText(QtWidgets.QApplication.translate('BirthDay', "Date in format dd.mm.yyyy")) - self.set_date = QtWidgets.QPushButton(self) + self.date.setPlaceholderText(QtGui.QApplication.translate('BirthDay', "Date in format dd.mm.yyyy", None, QtGui.QApplication.UnicodeUTF8)) + self.set_date = QtGui.QPushButton(self) self.set_date.setGeometry(QtCore.QRect(20, 90, 310, 25)) - self.set_date.setText(QtWidgets.QApplication.translate('BirthDay', "Save date")) + self.set_date.setText(QtGui.QApplication.translate('BirthDay', "Save date", None, QtGui.QApplication.UnicodeUTF8)) self.set_date.clicked.connect(self.save_curr_date) self.date.setText(inst._data[x] if x in inst._data else '') @@ -83,4 +84,3 @@ class BirthDay(plugin_super_class.PluginSuperClass): timer.stop() if self._profile.get_friend_by_number(friend_number).tox_id not in self._data: self.send_lossless('', friend_number) - diff --git a/Bot/bot.py b/Bot/bot.py index 71f12dd..9616331 100644 --- a/Bot/bot.py +++ b/Bot/bot.py @@ -1,5 +1,5 @@ import plugin_super_class -from PyQt5 import QtCore +from PySide import QtCore import time @@ -69,3 +69,4 @@ class Bot(plugin_super_class.PluginSuperClass): message = self._message invoke_in_main_thread(self._profile.send_message, message, friend_number) + diff --git a/Chess/chess.py b/Chess/chess.py deleted file mode 100644 index 1d3b5ff..0000000 --- a/Chess/chess.py +++ /dev/null @@ -1,1684 +0,0 @@ -# -*- coding: utf-8 -*- - -import collections -import re -import math -import plugin_super_class - -from PyQt5.QtCore import * -from PyQt5.QtWidgets import * -from PyQt5.QtGui import * -from PyQt5.QtSvg import * - - -START_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" - - -def opposite_color(color): - """:return: The opposite color. - - :param color: - "w", "white, "b" or "black". - """ - if color == "w": - return "b" - elif color == "white": - return "black" - elif color == "b": - return "w" - elif color == "black": - return "white" - else: - raise ValueError("Expected w, b, white or black, got: %s." % color) - - -class Piece(object): - - __cache = dict() - - def __init__(self, symbol): - self.__symbol = symbol - - self.__color = "w" if symbol != symbol.lower() else "b" - self.__full_color = "white" if self.__color == "w" else "black" - - self.__type = symbol.lower() - if self.__type == "p": - self.__full_type = "pawn" - elif self.__type == "n": - self.__full_type = "knight" - elif self.__type == "b": - self.__full_type = "bishop" - elif self.__type == "r": - self.__full_type = "rook" - elif self.__type == "q": - self.__full_type = "queen" - elif self.__type == "k": - self.__full_type = "king" - else: - raise ValueError("Expected valid piece symbol, got: %s." % symbol) - - self.__hash = ord(self.__symbol) - - @classmethod - def from_color_and_type(cls, color, type): - """Creates a piece object from color and type. - """ - if type == "p" or type == "pawn": - symbol = "p" - elif type == "n" or type == "knight": - symbol = "n" - elif type == "b" or type == "bishop": - symbol = "b" - elif type == "r" or type == "rook": - symbol = "r" - elif type == "q" or type == "queen": - symbol = "q" - elif type == "k" or type == "king": - symbol = "k" - else: - raise ValueError("Expected piece type, got: %s." % type) - - if color == "w" or color == "white": - return cls(symbol.upper()) - elif color == "b" or color == "black": - return cls(symbol) - else: - raise ValueError("Expected w, b, white or black, got: %s." % color) - - @property - def symbol(self): - return self.__symbol - - @property - def color(self): - """The color of the piece as `"b"` or `"w"`.""" - return self.__color - - @property - def full_color(self): - """The full color of the piece as `"black"` or `"white`.""" - return self.__full_color - - @property - def type(self): - """The type of the piece as `"p"`, `"b"`, `"n"`, `"r"`, `"k"`, - or `"q"` for pawn, bishop, knight, rook, king or queen. - """ - return self.__type - - @property - def full_type(self): - """The full type of the piece as `"pawn"`, `"bishop"`, - `"knight"`, `"rook"`, `"king"` or `"queen"`. - """ - return self.__full_type - - def __str__(self): - return self.__symbol - - def __repr__(self): - return "Piece('%s')" % self.__symbol - - def __eq__(self, other): - return isinstance(other, Piece) and self.__symbol == other.symbol - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return self.__hash - - -class Square(object): - """Represents a square on the chess board. - - :param name: The name of the square in algebraic notation. - - Square objects that represent the same square compare as equal. - """ - - __cache = dict() - - def __init__(self, name): - if not len(name) == 2: - raise ValueError("Expected square name, got: %s." % repr(name)) - self.__name = name - - if not name[0] in ["a", "b", "c", "d", "e", "f", "g", "h"]: - raise ValueError("Expected file, got: %s." % repr(name[0])) - self.__file = name[0] - self.__x = ord(self.__name[0]) - ord("a") - - if not name[1] in ["1", "2", "3", "4", "5", "6", "7", "8"]: - raise ValueError("Expected rank, got: %s." % repr(name[1])) - self.__rank = int(name[1]) - self.__y = ord(self.__name[1]) - ord("1") - - self.__x88 = self.__x + 16 * (7 - self.__y) - - @classmethod - def from_x88(cls, x88): - """Creates a square object from an `x88 `_ - index. - - :param x88: - The x88 index as integer between 0 and 128. - """ - if x88 < 0 or x88 > 128: - raise ValueError("x88 index is out of range: %s." % repr(x88)) - - if x88 & 0x88: - raise ValueError("x88 is not on the board: %s." % repr(x88)) - - return cls("abcdefgh"[x88 & 7] + "87654321"[x88 >> 4]) - - @classmethod - def from_rank_and_file(cls, rank, file): - """Creates a square object from rank and file. - - :param rank: - An integer between 1 and 8. - :param file: - The rank as a letter between `"a"` and `"h"`. - """ - if rank < 1 or rank > 8: - raise ValueError("Expected rank to be between 1 and 8: %s." % repr(rank)) - - if not file in ["a", "b", "c", "d", "e", "f", "g", "h"]: - raise ValueError("Expected the file to be a letter between 'a' and 'h': %s." % repr(file)) - - return cls(file + str(rank)) - - @classmethod - def from_x_and_y(cls, x, y): - """Creates a square object from x and y coordinates. - - :param x: - An integer between 0 and 7 where 0 is the a-file. - :param y: - An integer between 0 and 7 where 0 is the first rank. - """ - return cls("abcdefgh"[x] + "12345678"[y]) - - @property - def name(self): - """The algebraic name of the square.""" - return self.__name - - @property - def file(self): - """The file as a letter between `"a"` and `"h"`.""" - return self.__file - - @property - def x(self): - """The x-coordinate, starting with 0 for the a-file.""" - return self.__x - - @property - def rank(self): - """The rank as an integer between 1 and 8.""" - return self.__rank - - @property - def y(self): - """The y-coordinate, starting with 0 for the first rank.""" - return self.__y - - @property - def x88(self): - """The `x88 `_ - index of the square.""" - return self.__x88 - - def is_dark(self): - """:return: Whether it is a dark square.""" - return (self.__x - self.__y % 2) == 0 - - def is_light(self): - """:return: Whether it is a light square.""" - return not self.is_dark() - - def is_backrank(self): - """:return: Whether the square is on either sides backrank.""" - return self.__y == 0 or self.__y == 7 - - def __str__(self): - return self.__name - - def __repr__(self): - return "Square('%s')" % self.__name - - def __eq__(self, other): - return isinstance(other, Square) and self.__name == other.name - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return self.__x88 - - -class Move(object): - """Represents a move. - """ - - __uci_move_regex = re.compile(r"^([a-h][1-8])([a-h][1-8])([rnbq]?)$") - - def __init__(self, source, target, promotion=None): - if not isinstance(source, Square): - raise TypeError("Expected source to be a Square.") - self.__source = source - - if not isinstance(target, Square): - raise TypeError("Expected target to be a Square.") - self.__target = target - - if not promotion: - self.__promotion = None - self.__full_promotion = None - else: - promotion = promotion.lower() - if promotion == "n" or promotion == "knight": - self.__promotion = "n" - self.__full_promotion = "knight" - elif promotion == "b" or promotion == "bishop": - self.__promotion = "b" - self.__full_promotion = "bishop" - elif promotion == "r" or promotion == "rook": - self.__promotion = "r" - self.__full_promotion = "rook" - elif promotion == "q" or promotion == "queen": - self.__promotion = "q" - self.__full_promotion = "queen" - else: - raise ValueError("Expected promotion type, got: %s." % repr(promotion)) - - @classmethod - def from_uci(cls, uci): - """The UCI move string like `"a1a2"` or `"b7b8q"`.""" - if uci == "0000": - return cls.get_null() - - match = cls.__uci_move_regex.match(uci) - - return cls( - source=Square(match.group(1)), - target=Square(match.group(2)), - promotion=match.group(3) or None) - - @classmethod - def get_null(cls): - """:return: A null move.""" - return cls(Square("a1"), Square("a1")) - - @property - def source(self): - """The source square.""" - return self.__source - - @property - def target(self): - """The target square.""" - return self.__target - - @property - def promotion(self): - """The promotion type as `None`, `"r"`, `"n"`, `"b"` or `"q"`.""" - return self.__promotion - - @property - def full_promotion(self): - """Like `promotion`, but with full piece type names.""" - return self.__full_promotion - - @property - def uci(self): - """The UCI move string like `"a1a2"` or `"b7b8q"`.""" - if self.is_null(): - return "0000" - else: - if self.__promotion: - return self.__source.name + self.__target.name + self.__promotion - else: - return self.__source.name + self.__target.name - - def is_null(self): - """:return: Whether the move is a null move.""" - return self.__source == self.__target - - def __nonzero__(self): - return not self.is_null() - - def __str__(self): - return self.uci - - def __repr__(self): - return "Move.from_uci(%s)" % repr(self.uci) - - def __eq__(self, other): - return isinstance(other, Move) and self.uci == other.uci - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return hash(self.uci) - - -MoveInfo = collections.namedtuple("MoveInfo", [ - "move", - "piece", - "captured", - "san", - "is_enpassant", - "is_king_side_castle", - "is_queen_side_castle", - "is_castle", - "is_check", - "is_checkmate"]) - - -class Position(object): - """Represents a chess position. - - :param fen: - Optional. The FEN of the position. Defaults to the standard - chess start position. - """ - - __san_regex = re.compile('^([NBKRQ])?([a-h])?([1-8])?x?([a-h][1-8])(=[NBRQ])?(\+|#)?$') - - def __init__(self, fen=START_FEN): - self.__castling = "KQkq" - self.fen = fen - - def copy(self): - """Gets a copy of the position. The copy will not change when the - original instance is changed. - - :return: - An exact copy of the positon. - """ - return Position(self.fen) - - def __get_square_index(self, square_or_int): - if type(square_or_int) is int: - # Validate the index by passing it through the constructor. - return Square.from_x88(square_or_int).x88 - elif isinstance(square_or_int, str): - return Square(square_or_int).x88 - elif type(square_or_int) is Square: - return square_or_int.x88 - else: - raise TypeError( - "Expected integer or Square, got: %s." % repr(square_or_int)) - - def __getitem__(self, key): - return self.__board[self.__get_square_index(key)] - - def __setitem__(self, key, value): - if value is None or type(value) is Piece: - self.__board[self.__get_square_index(key)] = value - else: - raise TypeError("Expected Piece or None, got: %s." % repr(value)) - - def __delitem__(self, key): - self.__board[self.__get_square_index(key)] = None - - def clear_board(self): - """Removes all pieces from the board.""" - self.__board = [None] * 128 - - def reset(self): - """Resets to the standard chess start position.""" - self.set_fen(START_FEN) - - def __get_disambiguator(self, move): - same_rank = False - same_file = False - piece = self[move.source] - - for m in self.get_legal_moves(): - ambig_piece = self[m.source] - if (piece == ambig_piece and move.source != m.source and - move.target == m.target): - if move.source.rank == m.source.rank: - same_rank = True - - if move.source.file == m.source.file: - same_file = True - - if same_rank and same_file: - break - - if same_rank and same_file: - return move.source.name - elif same_file: - return str(move.source.rank) - elif same_rank: - return move.source.file - else: - return "" - - def get_move_from_san(self, san): - """Gets a move from standard algebraic notation. - - :param san: - A move string in standard algebraic notation. - - :return: - A Move object. - - :raise Exception: - If not exactly one legal move matches. - """ - # Castling moves. - if san == "O-O" or san == "O-O-O": - rank = 1 if self.turn == "w" else 8 - if san == "O-O": - return Move( - source=Square.from_rank_and_file(rank, 'e'), - target=Square.from_rank_and_file(rank, 'g')) - else: - return Move( - source=Square.from_rank_and_file(rank, 'e'), - target=Square.from_rank_and_file(rank, 'c')) - # Regular moves. - else: - matches = Position.__san_regex.match(san) - if not matches: - raise ValueError("Invalid SAN: %s." % repr(san)) - - piece = Piece.from_color_and_type( - color=self.turn, - type=matches.group(1).lower() if matches.group(1) else 'p') - target = Square(matches.group(4)) - - source = None - for m in self.get_legal_moves(): - if self[m.source] != piece or m.target != target: - continue - - if matches.group(2) and matches.group(2) != m.source.file: - continue - if matches.group(3) and matches.group(3) != str(m.source.rank): - continue - - # Move matches. Assert it is not ambiguous. - if source: - raise Exception( - "Move is ambiguous: %s matches %s and %s." - % san, source, m) - source = m.source - - if not source: - raise Exception("No legal move matches %s." % san) - - return Move(source, target, matches.group(5) or None) - - def get_move_info(self, move): - """Gets information about a move. - - :param move: - The move to get information about. - - :return: - A named tuple with these properties: - - `move`: - The move object. - `piece`: - The piece that has been moved. - `san`: - The standard algebraic notation of the move. - `captured`: - The piece that has been captured or `None`. - `is_enpassant`: - A boolean indicating if the move is an en-passant - capture. - `is_king_side_castle`: - Whether it is a king-side castling move. - `is_queen_side_castle`: - Whether it is a queen-side castling move. - `is_castle`: - Whether it is a castling move. - `is_check`: - Whether the move gives check. - `is_checkmate`: - Whether the move gives checkmate. - - :raise Exception: - If the move is not legal in the position. - """ - resulting_position = self.copy().make_move(move) - - capture = self[move.target] - piece = self[move.source] - - # Pawn moves. - enpassant = False - if piece.type == "p": - # En-passant. - if move.target.file != move.source.file and not capture: - enpassant = True - capture = Piece.from_color_and_type( - color=resulting_position.turn, type='p') - - # Castling. - if piece.type == "k": - is_king_side_castle = move.target.x - move.source.x == 2 - is_queen_side_castle = move.target.x - move.source.x == -2 - else: - is_king_side_castle = is_queen_side_castle = False - - # Checks. - is_check = resulting_position.is_check() - is_checkmate = resulting_position.is_checkmate() - - # Generate the SAN. - san = "" - if is_king_side_castle: - san += "o-o" - elif is_queen_side_castle: - san += "o-o-o" - else: - if piece.type != 'p': - san += piece.type.upper() - - san += self.__get_disambiguator(move) - - if capture: - if piece.type == 'p': - san += move.source.file - san += "x" - san += move.target.name - - if move.promotion: - san += "=" - san += move.promotion.upper() - - if is_checkmate: - san += "#" - elif is_check: - san += "+" - - if enpassant: - san += " (e.p.)" - - # Return the named tuple. - return MoveInfo( - move=move, - piece=piece, - captured=capture, - san=san, - is_enpassant=enpassant, - is_king_side_castle=is_king_side_castle, - is_queen_side_castle=is_queen_side_castle, - is_castle=is_king_side_castle or is_queen_side_castle, - is_check=is_check, - is_checkmate=is_checkmate) - - def make_move(self, move, validate=True): - """Makes a move. - - :param move: - The move to make. - :param validate: - Defaults to `True`. Whether the move should be validated. - - :return: - Making a move changes the position object. The same - (changed) object is returned for chainability. - - :raise Exception: - If the validate parameter is `True` and the move is not - legal in the position. - """ - if validate and move not in self.get_legal_moves(): - raise Exception( - "%s is not a legal move in the position %s." % (move, self.fen)) - piece = self[move.source] - capture = self[move.target] - - # Move the piece. - self[move.target] = self[move.source] - del self[move.source] - - # It is the next players turn. - self.toggle_turn() - - # Pawn moves. - self.ep_file = None - if piece.type == "p": - # En-passant. - if move.target.file != move.source.file and not capture: - if self.turn == "w": - self[move.target.x88 - 16] = None - else: - self[move.target.x88 + 16] = None - capture = True - # If big pawn move, set the en-passant file. - if abs(move.target.rank - move.source.rank) == 2: - if self.get_theoretical_ep_right(move.target.file): - self.ep_file = move.target.file - - # Promotion. - if move.promotion: - self[move.target] = Piece.from_color_and_type( - color=piece.color, type=move.promotion) - - # Potential castling. - if piece.type == "k": - steps = move.target.x - move.source.x - if abs(steps) == 2: - # Queen-side castling. - if steps == -2: - rook_target = move.target.x88 + 1 - rook_source = move.target.x88 - 2 - # King-side castling. - else: - rook_target = move.target.x88 - 1 - rook_source = move.target.x88 + 1 - self[rook_target] = self[rook_source] - del self[rook_source] - - # Increment the half move counter. - if piece.type == "p" or capture: - self.half_moves = 0 - else: - self.half_moves += 1 - - # Increment the move number. - if self.turn == "w": - self.ply += 1 - - # Update castling rights. - for type in ["K", "Q", "k", "q"]: - if not self.get_theoretical_castling_right(type): - self.set_castling_right(type, False) - - return self - - @property - def turn(self): - """Whos turn it is as `"w"` or `"b"`.""" - return self.__turn - - @turn.setter - def turn(self, value): - if value not in ["w", "b"]: - raise ValueError( - "Expected 'w' or 'b' for turn, got: %s." % repr(value)) - self.__turn = value - - def toggle_turn(self): - """Toggles whos turn it is.""" - self.turn = opposite_color(self.turn) - - def get_castling_right(self, type): - """Checks the castling rights. - - :param type: - The castling move to check. "K" for king-side castling of - the white player, "Q" for queen-side castling of the white - player. "k" and "q" for the corresponding castling moves of - the black player. - - :return: - A boolean indicating whether the player has that castling - right. - """ - if not type in ["K", "Q", "k", "q"]: - raise KeyError( - "Expected 'K', 'Q', 'k' or 'q' as a castling type, got: %s." % repr(type)) - return type in self.__castling - - def get_theoretical_castling_right(self, type): - """Checks if a player could have a castling right in theory from - looking just at the piece positions. - - :param type: - The castling move to check. See - `Position.get_castling_right(type)` for values. - - :return: - A boolean indicating whether the player could theoretically - have that castling right. - """ - if not type in ["K", "Q", "k", "q"]: - raise KeyError( - "Expected 'K', 'Q', 'k' or 'q' as a castling type, got: %s." - % repr(type)) - if type == "K" or type == "Q": - if self["e1"] != Piece("K"): - return False - if type == "K": - return self["h1"] == Piece("R") - elif type == "Q": - return self["a1"] == Piece("R") - elif type == "k" or type == "q": - if self["e8"] != Piece("k"): - return False - if type == "k": - return self["h8"] == Piece("r") - elif type == "q": - return self["a8"] == Piece("r") - - def get_theoretical_ep_right(self, file): - """Checks if a player could have an ep-move in theory from - looking just at the piece positions. - - :param file: - The file to check as a letter between `"a"` and `"h"`. - - :return: - A boolean indicating whether the player could theoretically - have that en-passant move. - """ - if not file in ["a", "b", "c", "d", "e", "f", "g", "h"]: - raise KeyError( - "Expected a letter between 'a' and 'h' for the file, got: %s." - % repr(file)) - - # Check there is a pawn. - pawn_square = Square.from_rank_and_file( - rank=4 if self.turn == "b" else 5, file=file) - opposite_color_pawn = Piece.from_color_and_type( - color=opposite_color(self.turn), type="p") - if self[pawn_square] != opposite_color_pawn: - return False - - # Check the square below is empty. - square_below = Square.from_rank_and_file( - rank=3 if self.turn == "b" else 6, file=file) - if self[square_below]: - return False - - # Check there is a pawn of the other color on a neighbor file. - f = ord(file) - ord("a") - p = Piece("p") - P = Piece("P") - if self.turn == "b": - if f > 0 and self[Square.from_x_and_y(f - 1, 3)] == p: - return True - elif f < 7 and self[Square.from_x_and_y(f + 1, 3)] == p: - return True - else: - if f > 0 and self[Square.from_x_and_y(f - 1, 4)] == P: - return True - elif f < 7 and self[Square.from_x_and_y(f + 1, 4)] == P: - return True - return False - - def set_castling_right(self, type, status): - """Sets a castling right. - - :param type: - `"K"`, `"Q"`, `"k"`, or `"q"` as used by - `Position.get_castling_right(type)`. - :param status: - A boolean indicating whether that castling right should be - granted or denied. - """ - if not type in ["K", "Q", "k", "q"]: - raise KeyError( - "Expected 'K', 'Q', 'k' or 'q' as a castling type, got: %s." - % repr(type)) - - castling = "" - for t in ["K", "Q", "k", "q"]: - if type == t: - if status: - castling += t - elif self.get_castling_right(t): - castling += t - self.__castling = castling - - @property - def ep_file(self): - """The en-passant file as a lowercase letter between `"a"` and - `"h"` or `None`.""" - return self.__ep_file - - @ep_file.setter - def ep_file(self, value): - if not value in ["a", "b", "c", "d", "e", "f", "g", "h", None]: - raise ValueError( - "Expected None or a letter between 'a' and 'h' for the " - "en-passant file, got: %s." % repr(value)) - - self.__ep_file = value - - @property - def half_moves(self): - """The number of half-moves since the last capture or pawn move.""" - return self.__half_moves - - @half_moves.setter - def half_moves(self, value): - if type(value) is not int: - raise TypeError( - "Expected integer for half move count, got: %s." % repr(value)) - if value < 0: - raise ValueError("Half move count must be >= 0.") - - self.__half_moves = value - - @property - def ply(self): - """The number of this move. The game starts at 1 and the counter - is incremented every time white moves. - """ - return self.__ply - - @ply.setter - def ply(self, value): - if type(value) is not int: - raise TypeError( - "Expected integer for ply count, got: %s." % repr(value)) - if value < 1: - raise ValueError("Ply count must be >= 1.") - self.__ply = value - - def get_piece_counts(self, color = "wb"): - """Counts the pieces on the board. - - :param color: - Defaults to `"wb"`. A color to filter the pieces by. Valid - values are "w", "b", "wb" and "bw". - - :return: - A dictionary of piece counts, keyed by lowercase piece type - letters. - """ - if not color in ["w", "b", "wb", "bw"]: - raise KeyError( - "Expected color filter to be one of 'w', 'b', 'wb', 'bw', " - "got: %s." % repr(color)) - - counts = { - "p": 0, - "b": 0, - "n": 0, - "r": 0, - "k": 0, - "q": 0, - } - for piece in self.__board: - if piece and piece.color in color: - counts[piece.type] += 1 - return counts - - def get_king(self, color): - """Gets the square of the king. - - :param color: - `"w"` for the white players king. `"b"` for the black - players king. - - :return: - The first square with a matching king or `None` if that - player has no king. - """ - if not color in ["w", "b"]: - raise KeyError("Invalid color: %s." % repr(color)) - - for x88, piece in enumerate(self.__board): - if piece and piece.color == color and piece.type == "k": - return Square.from_x88(x88) - - @property - def fen(self): - """The FEN string representing the position.""" - # Board setup. - empty = 0 - fen = "" - for y in range(7, -1, -1): - for x in range(0, 8): - square = Square.from_x_and_y(x, y) - - # Add pieces. - if not self[square]: - empty += 1 - else: - if empty > 0: - fen += str(empty) - empty = 0 - fen += self[square].symbol - - # Boarder of the board. - if empty > 0: - fen += str(empty) - if not (x == 7 and y == 0): - fen += "/" - empty = 0 - - if self.ep_file and self.get_theoretical_ep_right(self.ep_file): - ep_square = self.ep_file + ("3" if self.turn == "b" else "6") - else: - ep_square = "-" - - # Join the parts together. - return " ".join([ - fen, - self.turn, - self.__castling if self.__castling else "-", - ep_square, - str(self.half_moves), - str(self.__ply)]) - - @fen.setter - def fen(self, fen): - # Split into 6 parts. - tokens = fen.split() - if len(tokens) != 6: - raise Exception("A FEN does not consist of 6 parts.") - - # Check that the position part is valid. - rows = tokens[0].split("/") - assert len(rows) == 8 - for row in rows: - field_sum = 0 - previous_was_number = False - for char in row: - if char in "12345678": - if previous_was_number: - raise Exception( - "Position part of the FEN is invalid: " - "Multiple numbers immediately after each other.") - field_sum += int(char) - previous_was_number = True - elif char in "pnbrkqPNBRKQ": - field_sum += 1 - previous_was_number = False - else: - raise Exception( - "Position part of the FEN is invalid: " - "Invalid character in the position part of the FEN.") - - if field_sum != 8: - Exception( - "Position part of the FEN is invalid: " - "Row with invalid length.") - - # Check that the other parts are valid. - if not tokens[1] in ["w", "b"]: - raise Exception( - "Turn part of the FEN is invalid: Expected b or w.") - if not re.compile(r"^(KQ?k?q?|Qk?q?|kq?|q|-)$").match(tokens[2]): - raise Exception("Castling part of the FEN is invalid.") - if not re.compile(r"^(-|[a-h][36])$").match(tokens[3]): - raise Exception("En-passant part of the FEN is invalid.") - if not re.compile(r"^(0|[1-9][0-9]*)$").match(tokens[4]): - raise Exception("Half move part of the FEN is invalid.") - if not re.compile(r"^[1-9][0-9]*$").match(tokens[5]): - raise Exception("Ply part of the FEN is invalid.") - - # Set pieces on the board. - self.__board = [None] * 128 - i = 0 - for symbol in tokens[0]: - if symbol == "/": - i += 8 - elif symbol in "12345678": - i += int(symbol) - else: - self.__board[i] = Piece(symbol) - i += 1 - - # Set the turn. - self.__turn = tokens[1] - - # Set the castling rights. - for type in ["K", "Q", "k", "q"]: - self.set_castling_right(type, type in tokens[2]) - - # Set the en-passant file. - if tokens[3] == "-": - self.__ep_file = None - else: - self.__ep_file = tokens[3][0] - - # Set the move counters. - self.__half_moves = int(tokens[4]) - self.__ply = int(tokens[5]) - - def is_king_attacked(self, color): - """:return: Whether the king of the given color is attacked. - - :param color: `"w"` or `"b"`. - """ - square = self.get_king(color) - if square: - return self.is_attacked(opposite_color(color), square) - else: - return False - - def get_pseudo_legal_moves(self): - """:yield: Pseudo legal moves in the current position.""" - PAWN_OFFSETS = { - "b": [16, 32, 17, 15], - "w": [-16, -32, -17, -15] - } - - PIECE_OFFSETS = { - "n": [-18, -33, -31, -14, 18, 33, 31, 14], - "b": [-17, -15, 17, 15], - "r": [-16, 1, 16, -1], - "q": [-17, -16, -15, 1, 17, 16, 15, -1], - "k": [-17, -16, -15, 1, 17, 16, 15, -1] - } - - for x88, piece in enumerate(self.__board): - # Skip pieces of the opponent. - if not piece or piece.color != self.turn: - continue - - square = Square.from_x88(x88) - - # Pawn moves. - if piece.type == "p": - # Single square ahead. Do not capture. - target = Square.from_x88(x88 + PAWN_OFFSETS[self.turn][0]) - if not self[target]: - # Promotion. - if target.is_backrank(): - for promote_to in "bnrq": - yield Move(square, target, promote_to) - else: - yield Move(square, target) - - # Two squares ahead. Do not capture. - if (self.turn == "w" and square.rank == 2) or (self.turn == "b" and square.rank == 7): - target = Square.from_x88(square.x88 + PAWN_OFFSETS[self.turn][1]) - if not self[target]: - yield Move(square, target) - - # Pawn captures. - for j in [2, 3]: - target_index = square.x88 + PAWN_OFFSETS[self.turn][j] - if target_index & 0x88: - continue - target = Square.from_x88(target_index) - if self[target] and self[target].color != self.turn: - # Promotion. - if target.is_backrank(): - for promote_to in "bnrq": - yield Move(square, target, promote_to) - else: - yield Move(square, target) - # En-passant. - elif not self[target] and target.file == self.ep_file: - yield Move(square, target) - # Other pieces. - else: - for offset in PIECE_OFFSETS[piece.type]: - target_index = square.x88 - while True: - target_index += offset - if target_index & 0x88: - break - target = Square.from_x88(target_index) - if not self[target]: - yield Move(square, target) - else: - if self[target].color == self.turn: - break - yield Move(square, target) - break - - # Knight and king do not go multiple times in their - # direction. - if piece.type in ["n", "k"]: - break - - opponent = opposite_color(self.turn) - - # King-side castling. - k = "k" if self.turn == "b" else "K" - if self.get_castling_right(k): - of = self.get_king(self.turn).x88 - to = of + 2 - if not self[of + 1] and not self[to] and not self.is_check() and not self.is_attacked(opponent, Square.from_x88(of + 1)) and not self.is_attacked(opponent, Square.from_x88(to)): - yield Move(Square.from_x88(of), Square.from_x88(to)) - - # Queen-side castling - q = "q" if self.turn == "b" else "Q" - if self.get_castling_right(q): - of = self.get_king(self.turn).x88 - to = of - 2 - - if not self[of - 1] and not self[of - 2] and not self[of - 3] and not self.is_check() and not self.is_attacked(opponent, Square.from_x88(of - 1)) and not self.is_attacked(opponent, Square.from_x88(to)): - yield Move(Square.from_x88(of), Square.from_x88(to)) - - def get_legal_moves(self): - """:yield: All legal moves in the current position.""" - for move in self.get_pseudo_legal_moves(): - potential_position = self.copy() - potential_position.make_move(move, False) - if not potential_position.is_king_attacked(self.turn): - yield move - - def get_attackers(self, color, square): - """Gets the attackers of a specific square. - - :param color: - Filter attackers by this piece color. - :param square: - The square to check for. - - :yield: - Source squares of the attack. - """ - if color not in ["b", "w"]: - raise KeyError("Invalid color: %s." % repr(color)) - - ATTACKS = [ - 20, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 20, 0, - 0, 20, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 20, 0, 0, - 0, 0, 20, 0, 0, 0, 0, 24, 0, 0, 0, 0, 20, 0, 0, 0, - 0, 0, 0, 20, 0, 0, 0, 24, 0, 0, 0, 20, 0, 0, 0, 0, - 0, 0, 0, 0, 20, 0, 0, 24, 0, 0, 20, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 20, 2, 24, 2, 20, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 53, 56, 53, 2, 0, 0, 0, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 56, 0, 56, 24, 24, 24, 24, 24, 24, 0, - 0, 0, 0, 0, 0, 2, 53, 56, 53, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 20, 2, 24, 2, 20, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 20, 0, 0, 24, 0, 0, 20, 0, 0, 0, 0, 0, - 0, 0, 0, 20, 0, 0, 0, 24, 0, 0, 0, 20, 0, 0, 0, 0, - 0, 0, 20, 0, 0, 0, 0, 24, 0, 0, 0, 0, 20, 0, 0, 0, - 0, 20, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 20, 0, 0, - 20, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 20 - ] - - RAYS = [ - 17, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 15, 0, - 0, 17, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 15, 0, 0, - 0, 0, 17, 0, 0, 0, 0, 16, 0, 0, 0, 0, 15, 0, 0, 0, - 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 15, 0, 0, 0, 0, - 0, 0, 0, 0, 17, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 17, 0, 16, 0, 15, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 17, 16, 15, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1, 0, - 0, 0, 0, 0, 0, 0, -15, -16, -17, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, -15, 0, -16, 0, -17, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, -15, 0, 0, -16, 0, 0, -17, 0, 0, 0, 0, 0, - 0, 0, 0, -15, 0, 0, 0, -16, 0, 0, 0, -17, 0, 0, 0, 0, - 0, 0, -15, 0, 0, 0, 0, -16, 0, 0, 0, 0, -17, 0, 0, 0, - 0, -15, 0, 0, 0, 0, 0, -16, 0, 0, 0, 0, 0, -17, 0, 0, - -15, 0, 0, 0, 0, 0, 0, -16, 0, 0, 0, 0, 0, 0, -17 - ] - - SHIFTS = { - "p": 0, - "n": 1, - "b": 2, - "r": 3, - "q": 4, - "k": 5 - } - - for x88, piece in enumerate(self.__board): - if not piece or piece.color != color: - continue - source = Square.from_x88(x88) - - difference = source.x88 - square.x88 - index = difference + 119 - - if ATTACKS[index] & (1 << SHIFTS[piece.type]): - # Handle pawns. - if piece.type == "p": - if difference > 0: - if piece.color == "w": - yield source - else: - if piece.color == "b": - yield source - continue - - # Handle knights and king. - if piece.type in ["n", "k"]: - yield source - - # Handle the others. - offset = RAYS[index] - j = source.x88 + offset - blocked = False - while j != square.x88: - if self[j]: - blocked = True - break - j += offset - if not blocked: - yield source - - def is_attacked(self, color, square): - """Checks whether a square is attacked. - - :param color: - Check if this player is attacking. - :param square: - The square the player might be attacking. - - :return: - A boolean indicating whether the given square is attacked - by the player of the given color. - """ - x = list(self.get_attackers(color, square)) - return len(x) > 0 - - def is_check(self): - """:return: Whether the current player is in check.""" - return self.is_king_attacked(self.turn) - - def is_checkmate(self): - """:return: Whether the current player has been checkmated.""" - if not self.is_check(): - return False - else: - arr = list(self.get_legal_moves()) - return len(arr) == 0 - - def is_stalemate(self): - """:return: Whether the current player is in stalemate.""" - if self.is_check(): - return False - else: - arr = list(self.get_legal_moves()) - return len(arr) == 0 - - def is_insufficient_material(self): - """Checks if there is sufficient material to mate. - - Mating is impossible in: - - * A king versus king endgame. - * A king with bishop versus king endgame. - * A king with knight versus king endgame. - * A king with bishop versus king with bishop endgame, where both - bishops are on the same color. Same goes for additional - bishops on the same color. - - Assumes that the position is valid and each player has exactly - one king. - - :return: - Whether there is insufficient material to mate. - """ - piece_counts = self.get_piece_counts() - if sum(piece_counts.values()) == 2: - # King versus king. - return True - elif sum(piece_counts.values()) == 3: - # King and knight or bishop versus king. - if piece_counts["b"] == 1 or piece_counts["n"] == 1: - return True - elif sum(piece_counts.values()) == 2 + piece_counts["b"]: - # Each player with only king and any number of bishops, where all - # bishops are on the same color. - white_has_bishop = self.get_piece_counts("w")["b"] != 0 - black_has_bishop = self.get_piece_counts("b")["b"] != 0 - if white_has_bishop and black_has_bishop: - color = None - for x88, piece in enumerate(self.__board): - if piece and piece.type == "b": - square = Square.from_x88(x88) - if color is not None and color != square.is_light(): - return False - color = square.is_light() - return True - return False - - def is_game_over(self): - """Checks if the game is over. - - :return: - Whether the game is over by the rules of chess, - disregarding that players can agree on a draw, claim a draw - or resign. - """ - return (self.is_checkmate() or self.is_stalemate() or - self.is_insufficient_material()) - - def __str__(self): - return self.fen - - def __repr__(self): - return "Position.from_fen(%s)" % repr(self.fen) - - def __eq__(self, other): - return self.fen == other.fen - - def __ne__(self, other): - return self.fen != other.fen - - -class Board(QWidget): - - def __init__(self, parent): - super(Board, self).__init__() - self.margin = 0.1 - self.padding = 0.06 - self.showCoordinates = True - self.lightSquareColor = QColor(255, 255, 255) - self.darkSquareColor = QColor(100, 100, 255) - self.borderColor = QColor(100, 100, 200) - self.shadowWidth = 2 - self.rotation = 0 - self.ply = 1 - self.setWindowTitle('Chess') - self.backgroundPixmap = QPixmap(plugin_super_class.path_to_data('chess') + "background.png") - - self.draggedSquare = None - self.dragPosition = None - - self.position = Position() - - self.parent = parent - - # Load piece set. - self.pieceRenderers = dict() - for symbol in "PNBRQKpnbrqk": - piece = Piece(symbol) - self.pieceRenderers[piece] = QSvgRenderer(plugin_super_class.path_to_data('chess') + "classic-pieces/%s-%s.svg" % (piece.full_color, piece.full_type)) - - def update_title(self, my_move=False): - if self.position.is_checkmate(): - self.setWindowTitle('Checkmate') - elif self.position.is_stalemate(): - self.setWindowTitle('Stalemate') - else: - self.setWindowTitle('Chess' + (' [Your move]' if my_move else '')) - - def mousePressEvent(self, e): - self.dragPosition = e.pos() - square = self.squareAt(e.pos()) - if self.canDragSquare(square): - self.draggedSquare = square - - def mouseMoveEvent(self, e): - if self.draggedSquare: - self.dragPosition = e.pos() - self.repaint() - - def mouseReleaseEvent(self, e): - if self.draggedSquare: - dropSquare = self.squareAt(e.pos()) - if dropSquare == self.draggedSquare: - self.onSquareClicked(self.draggedSquare) - elif dropSquare: - move = self.moveFromDragDrop(self.draggedSquare, dropSquare) - if move: - self.position.make_move(move) - self.parent.move(move) - self.ply += 1 - self.draggedSquare = None - self.repaint() - - def closeEvent(self, *args): - self.parent.stop_game() - - def paintEvent(self, event): - painter = QPainter() - painter.begin(self) - - # Light shines from upper left. - if math.cos(math.radians(self.rotation)) >= 0: - lightBorderColor = self.borderColor.lighter() - darkBorderColor = self.borderColor.darker() - else: - lightBorderColor = self.borderColor.darker() - darkBorderColor = self.borderColor.lighter() - - # Draw the background. - backgroundBrush = QBrush(Qt.red, self.backgroundPixmap) - backgroundBrush.setStyle(Qt.TexturePattern) - painter.fillRect(QRect(QPoint(0, 0), self.size()), backgroundBrush) - - # Do the rotation. - painter.save() - painter.translate(self.width() / 2, self.height() / 2) - painter.rotate(self.rotation) - - # Draw the border. - frameSize = min(self.width(), self.height()) * (1 - self.margin * 2) - borderSize = min(self.width(), self.height()) * self.padding - painter.translate(-frameSize / 2, -frameSize / 2) - painter.fillRect(QRect(0, 0, frameSize, frameSize), self.borderColor) - painter.setPen(QPen(QBrush(lightBorderColor), self.shadowWidth)) - painter.drawLine(0, 0, 0, frameSize) - painter.drawLine(0, 0, frameSize, 0) - painter.setPen(QPen(QBrush(darkBorderColor), self.shadowWidth)) - painter.drawLine(frameSize, 0, frameSize, frameSize) - painter.drawLine(0, frameSize, frameSize, frameSize) - - # Draw the squares. - painter.translate(borderSize, borderSize) - squareSize = (frameSize - 2 * borderSize) / 8.0 - for x in range(0, 8): - for y in range(0, 8): - rect = QRect(x * squareSize, y * squareSize, squareSize, squareSize) - if (x - y) % 2 == 0: - painter.fillRect(rect, QBrush(self.lightSquareColor)) - else: - painter.fillRect(rect, QBrush(self.darkSquareColor)) - - # Draw the inset. - painter.setPen(QPen(QBrush(darkBorderColor), self.shadowWidth)) - painter.drawLine(0, 0, 0, squareSize * 8) - painter.drawLine(0, 0, squareSize * 8, 0) - painter.setPen(QPen(QBrush(lightBorderColor), self.shadowWidth)) - painter.drawLine(squareSize * 8, 0, squareSize * 8, squareSize * 8) - painter.drawLine(0, squareSize * 8, squareSize * 8, squareSize * 8) - - # Display coordinates. - if self.showCoordinates: - painter.setPen(QPen(QBrush(self.borderColor.lighter()), self.shadowWidth)) - coordinateSize = min(borderSize, squareSize) - font = QFont() - font.setPixelSize(coordinateSize * 0.6) - painter.setFont(font) - for i, rank in enumerate(["8", "7", "6", "5", "4", "3", "2", "1"]): - pos = QRect(-borderSize, squareSize * i, borderSize, squareSize).center() - painter.save() - painter.translate(pos.x(), pos.y()) - painter.rotate(-self.rotation) - painter.drawText(QRect(-coordinateSize / 2, -coordinateSize / 2, coordinateSize, coordinateSize), Qt.AlignCenter, rank) - painter.restore() - for i, file in enumerate(["a", "b", "c", "d", "e", "f", "g", "h"]): - pos = QRect(squareSize * i, squareSize * 8, squareSize, borderSize).center() - painter.save() - painter.translate(pos.x(), pos.y()) - painter.rotate(-self.rotation) - painter.drawText(QRect(-coordinateSize / 2, -coordinateSize / 2, coordinateSize, coordinateSize), Qt.AlignCenter, file) - painter.restore() - - # Draw pieces. - for x in range(0, 8): - for y in range(0, 8): - square = Square.from_x_and_y(x, 7 - y) - piece = self.position[square] - if piece and square != self.draggedSquare: - painter.save() - painter.translate((x + 0.5) * squareSize, (y + 0.5) * squareSize) - painter.rotate(-self.rotation) - self.pieceRenderers[piece].render(painter, QRect(-squareSize / 2, -squareSize / 2, squareSize, squareSize)) - painter.restore() - - # Draw a floating piece. - painter.restore() - if self.draggedSquare: - piece = self.position[self.draggedSquare] - if piece: - painter.save() - painter.translate(self.dragPosition.x(), self.dragPosition.y()) - painter.rotate(-self.rotation) - self.pieceRenderers[piece].render(painter, QRect(-squareSize / 2, -squareSize / 2, squareSize, squareSize)) - painter.restore() - - painter.end() - - def squareAt(self, point): - # Undo the rotation. - transform = QTransform() - transform.translate(self.width() / 2, self.height() / 2) - transform.rotate(self.rotation) - logicalPoint = transform.inverted()[0].map(point) - - frameSize = min(self.width(), self.height()) * (1 - self.margin * 2) - borderSize = min(self.width(), self.height()) * self.padding - squareSize = (frameSize - 2 * borderSize) / 8.0 - x = int(logicalPoint.x() / squareSize + 4) - y = 7 - int(logicalPoint.y() / squareSize + 4) - try: - return Square.from_x_and_y(x, y) - except IndexError: - return None - - def canDragSquare(self, square): - if (self.ply % 2 == 0 and self.parent.white) or (self.ply % 2 == 1 and not self.parent.white): - return False - for move in self.position.get_legal_moves(): - if move.source == square: - return True - return False - - def onSquareClicked(self, square): - pass - - def moveFromDragDrop(self, source, target): - for move in self.position.get_legal_moves(): - if move.source == source and move.target == target: - if move.promotion: - dialog = PromotionDialog(self.position[move.source].color, self) - if dialog.exec_(): - return Move(source, target, dialog.selectedType()) - else: - return move - return move - - -class PromotionDialog(QDialog): - - def __init__(self, color, parent=None): - super(PromotionDialog, self).__init__(parent) - - self.promotionTypes = ["q", "n", "r", "b"] - - grid = QGridLayout() - hbox = QHBoxLayout() - grid.addLayout(hbox, 0, 0) - - # Add the piece buttons. - self.buttonGroup = QButtonGroup(self) - for i, promotionType in enumerate(self.promotionTypes): - # Create an icon for the piece. - piece = Piece.from_color_and_type(color, promotionType) - renderer = QSvgRenderer(plugin_super_class.path_to_data('chess') + "classic-pieces/%s-%s.svg" % (piece.full_color, piece.full_type)) - pixmap = QPixmap(32, 32) - pixmap.fill(Qt.transparent) - painter = QPainter() - painter.begin(pixmap) - renderer.render(painter, QRect(0, 0, 32, 32)) - painter.end() - - # Add the button. - button = QPushButton(QIcon(pixmap), '', self) - button.setCheckable(True) - self.buttonGroup.addButton(button, i) - hbox.addWidget(button) - - self.buttonGroup.button(0).setChecked(True) - - # Add the ok and cancel buttons. - buttons = QDialogButtonBox(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) - buttons.rejected.connect(self.reject) - buttons.accepted.connect(self.accept) - grid.addWidget(buttons, 1, 0) - - self.setLayout(grid) - self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) - - def selectedType(self): - return self.promotionTypes[self.buttonGroup.checkedId()] - - -class Chess(plugin_super_class.PluginSuperClass): - - def __init__(self, *args): - super(Chess, self).__init__('Chess', 'chess', *args) - self.game = -1 - self.board = None - self.white = True - self.pre = None - self.last_move = None - self.is_my_move = False - - def get_description(self): - return QApplication.translate("Chess", 'Plugin which allows you to play chess with your friends.') - - def lossless_packet(self, data, friend_number): - if data == 'new': - self.pre = None - friend = self._profile.get_friend_by_number(friend_number) - reply = QMessageBox.question(None, - 'New chess game', - 'Friend {} wants to play chess game against you. Start?'.format(friend.name), - QMessageBox.Yes, - QMessageBox.No) - if reply != QMessageBox.Yes: - self.send_lossless('no', friend_number) - else: - self.send_lossless('yes', friend_number) - self.board = Board(self) - self.board.show() - self.game = friend_number - self.white = False - self.is_my_move = False - elif data == 'yes' and friend_number == self.game: - self.board = Board(self) - self.board.show() - self.board.update_title(True) - self.is_my_move = True - self.last_move = None - elif data == 'no': - self.game = -1 - elif data != self.pre: # move - self.pre = data - self.is_my_move = True - self.last_move = None - a = Square.from_x_and_y(ord(data[0]) - ord('a'), ord(data[1]) - ord('1')) - b = Square.from_x_and_y(ord(data[2]) - ord('a'), ord(data[3]) - ord('1')) - self.board.position.make_move(Move(a, b, data[4] if len(data) == 5 else None)) - self.board.repaint() - self.board.update_title(True) - self.board.ply += 1 - - def start_game(self, num): - self.white = True - self.send_lossless('new', num) - self.game = num - - def resend_move(self): - if self.is_my_move or self.last_move is None: - return - self.send_lossless(str(self.last_move), self.game) - QTimer.singleShot(1000, self.resend_move) - - def stop_game(self): - self.last_move = None - - def move(self, move): - self.is_my_move = False - self.last_move = move - self.send_lossless(str(move), self.game) - self.board.update_title() - QTimer.singleShot(1000, self.resend_move) - - def get_menu(self, menu, num): - act = QAction(QApplication.translate("Chess", "Start chess game"), menu) - act.triggered.connect(lambda: self.start_game(num)) - return [act] diff --git a/Chess/chess/background.png b/Chess/chess/background.png deleted file mode 100644 index f68ed40..0000000 Binary files a/Chess/chess/background.png and /dev/null differ diff --git a/Chess/chess/classic-pieces/black-bishop.svg b/Chess/chess/classic-pieces/black-bishop.svg deleted file mode 100644 index 4ce248f..0000000 --- a/Chess/chess/classic-pieces/black-bishop.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - diff --git a/Chess/chess/classic-pieces/black-king.svg b/Chess/chess/classic-pieces/black-king.svg deleted file mode 100644 index d90dc73..0000000 --- a/Chess/chess/classic-pieces/black-king.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - diff --git a/Chess/chess/classic-pieces/black-knight.svg b/Chess/chess/classic-pieces/black-knight.svg deleted file mode 100644 index 7f73c43..0000000 --- a/Chess/chess/classic-pieces/black-knight.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - diff --git a/Chess/chess/classic-pieces/black-pawn.svg b/Chess/chess/classic-pieces/black-pawn.svg deleted file mode 100644 index 072f2fe..0000000 --- a/Chess/chess/classic-pieces/black-pawn.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Chess/chess/classic-pieces/black-queen.svg b/Chess/chess/classic-pieces/black-queen.svg deleted file mode 100644 index 6f1e4a5..0000000 --- a/Chess/chess/classic-pieces/black-queen.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/Chess/chess/classic-pieces/black-rook.svg b/Chess/chess/classic-pieces/black-rook.svg deleted file mode 100644 index 337af8f..0000000 --- a/Chess/chess/classic-pieces/black-rook.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/Chess/chess/classic-pieces/white-bishop.svg b/Chess/chess/classic-pieces/white-bishop.svg deleted file mode 100644 index 0f28d08..0000000 --- a/Chess/chess/classic-pieces/white-bishop.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - diff --git a/Chess/chess/classic-pieces/white-king.svg b/Chess/chess/classic-pieces/white-king.svg deleted file mode 100644 index 8b2d7b7..0000000 --- a/Chess/chess/classic-pieces/white-king.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - diff --git a/Chess/chess/classic-pieces/white-knight.svg b/Chess/chess/classic-pieces/white-knight.svg deleted file mode 100644 index 0500630..0000000 --- a/Chess/chess/classic-pieces/white-knight.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - diff --git a/Chess/chess/classic-pieces/white-pawn.svg b/Chess/chess/classic-pieces/white-pawn.svg deleted file mode 100644 index 1142516..0000000 --- a/Chess/chess/classic-pieces/white-pawn.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Chess/chess/classic-pieces/white-queen.svg b/Chess/chess/classic-pieces/white-queen.svg deleted file mode 100644 index 97043c5..0000000 --- a/Chess/chess/classic-pieces/white-queen.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/Chess/chess/classic-pieces/white-rook.svg b/Chess/chess/classic-pieces/white-rook.svg deleted file mode 100644 index 8d2d932..0000000 --- a/Chess/chess/classic-pieces/white-rook.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - diff --git a/CopyableToxId/toxid.py b/CopyableToxId/toxid.py index 0808f68..be79803 100644 --- a/CopyableToxId/toxid.py +++ b/CopyableToxId/toxid.py @@ -1,5 +1,5 @@ import plugin_super_class -from PyQt5 import QtCore, QtWidgets +from PySide import QtGui, QtCore import json @@ -15,25 +15,25 @@ class CopyableToxId(plugin_super_class.PluginSuperClass): self.load_translator() def get_description(self): - return QtWidgets.QApplication.translate("TOXID", 'Plugin which allows you to copy TOX ID of your friend easily.') + return QtGui.QApplication.translate("TOXID", 'Plugin which allows you to copy TOX ID of your friend easily.', None, QtGui.QApplication.UnicodeUTF8) def get_window(self): inst = self - class Window(QtWidgets.QWidget): + class Window(QtGui.QWidget): def __init__(self): super(Window, self).__init__() self.setGeometry(QtCore.QRect(450, 300, 350, 100)) - self.send = QtWidgets.QCheckBox(self) + self.send = QtGui.QCheckBox(self) self.send.setGeometry(QtCore.QRect(20, 10, 310, 25)) - self.send.setText(QtWidgets.QApplication.translate("TOXID", "Send my TOX ID to contacts")) - self.setWindowTitle(QtWidgets.QApplication.translate("TOXID", "CopyableToxID")) + self.send.setText(QtGui.QApplication.translate("TOXID", "Send my TOX ID to contacts", None, QtGui.QApplication.UnicodeUTF8)) + self.setWindowTitle(QtGui.QApplication.translate("TOXID", "CopyableToxID", None, QtGui.QApplication.UnicodeUTF8)) self.send.clicked.connect(self.update) self.send.setChecked(inst._data['send_id']) - self.help = QtWidgets.QPushButton(self) + self.help = QtGui.QPushButton(self) self.help.setGeometry(QtCore.QRect(20, 40, 200, 25)) - self.help.setText(QtWidgets.QApplication.translate("TOXID", "List of commands")) + self.help.setText(QtGui.QApplication.translate("TOXID", "List of commands", None, QtGui.QApplication.UnicodeUTF8)) self.help.clicked.connect(lambda: inst.command('help')) def update(self): @@ -49,17 +49,17 @@ class CopyableToxId(plugin_super_class.PluginSuperClass): if self._copy: self._timer.stop() self._copy = False - clipboard = QtWidgets.QApplication.clipboard() + clipboard = QtGui.QApplication.clipboard() clipboard.setText(data) self.save_settings(json.dumps(self._data)) elif self._data['send_id']: self.send_lossless(self._tox.self_get_address(), friend_number) def error(self): - msgbox = QtWidgets.QMessageBox() - title = QtWidgets.QApplication.translate("TOXID", "Error") + msgbox = QtGui.QMessageBox() + title = QtGui.QApplication.translate("TOXID", "Error", None, QtGui.QApplication.UnicodeUTF8) msgbox.setWindowTitle(title.format(self._name)) - text = QtWidgets.QApplication.translate("TOXID", "Tox ID cannot be copied") + text = QtGui.QApplication.translate("TOXID", "Tox ID cannot be copied", None, QtGui.QApplication.UnicodeUTF8) msgbox.setText(text) msgbox.exec_() @@ -70,7 +70,7 @@ class CopyableToxId(plugin_super_class.PluginSuperClass): self._curr = -1 arr = list(filter(lambda x: x.startswith(public_key), self._data['id'])) if len(arr): - clipboard = QtWidgets.QApplication.clipboard() + clipboard = QtGui.QApplication.clipboard() clipboard.setText(arr[0]) else: self.error() @@ -97,15 +97,15 @@ class CopyableToxId(plugin_super_class.PluginSuperClass): self._copy = False return elif text == 'help': - msgbox = QtWidgets.QMessageBox() - title = QtWidgets.QApplication.translate("TOXID", "List of commands for plugin CopyableToxID") + msgbox = QtGui.QMessageBox() + title = QtGui.QApplication.translate("TOXID", "List of commands for plugin CopyableToxID", None, QtGui.QApplication.UnicodeUTF8) msgbox.setWindowTitle(title) - text = QtWidgets.QApplication.translate("TOXID", """Commands: + text = QtGui.QApplication.translate("TOXID", """Commands: copy: copy TOX ID of current friend copy : copy TOX ID of friend with specified number enable: allow send your TOX ID to friends disable: disallow send your TOX ID to friends -help: show this help""") +help: show this help""", None, QtGui.QApplication.UnicodeUTF8) msgbox.setText(text) msgbox.exec_() return @@ -114,7 +114,7 @@ help: show this help""") public_key = self._tox.friend_get_public_key(num) arr = list(filter(lambda x: x.startswith(public_key), self._data['id'])) if self._profile.get_friend_by_number(num).status is None and len(arr): - clipboard = QtWidgets.QApplication.clipboard() + clipboard = QtGui.QApplication.clipboard() clipboard.setText(arr[0]) elif self._profile.get_friend_by_number(num).status is not None: self._copy = True @@ -125,7 +125,7 @@ help: show this help""") self.error() def get_menu(self, menu, num): - act = QtWidgets.QAction(QtWidgets.QApplication.translate("TOXID", "Copy TOX ID"), menu) + act = QtGui.QAction(QtGui.QApplication.translate("TOXID", "Copy TOX ID", None, QtGui.QApplication.UnicodeUTF8), menu) friend = self._profile.get_friend(num) act.connect(act, QtCore.SIGNAL("triggered()"), lambda: self.command('copy ' + str(friend.number))) return [act] diff --git a/Garland/garland.py b/Garland/garland.py deleted file mode 100644 index 49d13b8..0000000 --- a/Garland/garland.py +++ /dev/null @@ -1,64 +0,0 @@ -import plugin_super_class -import threading -import time -from PyQt5 import QtCore - - -class InvokeEvent(QtCore.QEvent): - EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) - - def __init__(self, fn, *args, **kwargs): - QtCore.QEvent.__init__(self, InvokeEvent.EVENT_TYPE) - self.fn = fn - self.args = args - self.kwargs = kwargs - - -class Invoker(QtCore.QObject): - - def event(self, event): - event.fn(*event.args, **event.kwargs) - return True - -_invoker = Invoker() - - -def invoke_in_main_thread(fn, *args, **kwargs): - QtCore.QCoreApplication.postEvent(_invoker, InvokeEvent(fn, *args, **kwargs)) - - -class Garland(plugin_super_class.PluginSuperClass): - - def __init__(self, *args): - super(Garland, self).__init__('Garland', 'grlnd', *args) - self._thread = None - self._exec = None - self._time = 3 - - def close(self): - self.stop() - - def stop(self): - self._exec = False - self._thread.join() - - def start(self): - self._exec = True - self._thread = threading.Thread(target=self.change_status) - self._thread.start() - - def command(self, command): - if command.startswith('time'): - self._time = max(int(command.split(' ')[1]), 300) / 1000 - else: - super().command(command) - - def update(self): - self._profile.set_status((self._profile.status + 1) % 3) - - def change_status(self): - time.sleep(5) - while self._exec: - invoke_in_main_thread(self.update) - time.sleep(self._time) - diff --git a/MarqueeStatus/mrq.py b/MarqueeStatus/mrq.py index 5a312a1..e71ff00 100644 --- a/MarqueeStatus/mrq.py +++ b/MarqueeStatus/mrq.py @@ -1,7 +1,7 @@ import plugin_super_class import threading import time -from PyQt5 import QtCore +from PySide import QtCore class InvokeEvent(QtCore.QEvent): @@ -34,7 +34,6 @@ class MarqueeStatus(plugin_super_class.PluginSuperClass): self._thread = None self._exec = None self.active = False - self.left = True def close(self): self.stop() @@ -49,18 +48,9 @@ class MarqueeStatus(plugin_super_class.PluginSuperClass): self._thread = threading.Thread(target=self.change_status) self._thread.start() - def command(self, command): - if command == 'rev': - self.left = not self.left - else: - super(MarqueeStatus, self).command(command) - def set_status_message(self): message = self._profile.status_message - if self.left: - self._profile.set_status_message(bytes(message[1:] + message[0], 'utf-8')) - else: - self._profile.set_status_message(bytes(message[-1] + message[:-1], 'utf-8')) + self._profile.set_status_message(bytes(message[1:] + message[0], 'utf-8')) def init_status(self): self._profile.status_message = bytes(self._profile.status_message.strip() + ' ', 'utf-8') @@ -76,4 +66,3 @@ class MarqueeStatus(plugin_super_class.PluginSuperClass): invoke_in_main_thread(self.set_status_message) invoke_in_main_thread(self._profile.set_status_message, bytes(tmp, 'utf-8')) self.active = False - diff --git a/README.md b/README.md index 8489b44..68e04a6 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,15 @@ # Plugins -Repo with plugins for [Toxygen](https://github.com/toxygen-project/toxygen/) +Repo with plugins for [Toxygen](https://github.com/xveduk/toxygen/) -For more info visit [plugins.md](https://github.com/toxygen-project/toxygen/blob/master/docs/plugins.md) and [plugin_api.md](https://github.com/toxygen-project/toxygen/blob/master/docs/plugin-api.md) +For more info visit [plugins.md](https://github.com/xveduk/toxygen/blob/master/docs/plugins.md) and [plugin_api.md](https://github.com/xveduk/toxygen/blob/master/docs/plugin-api.md) # Plugins list: - ToxId - share your Tox ID and copy friend's Tox ID easily. - MarqueeStatus - create ticker from your status message. -- BirthDay - get notifications on your friends' birthdays. -- Bot - bot which can communicate with your friends when you are away. -- SearchPlugin - select text in message and find it in search engine. -- AutoAwayStatusLinux - sets "Away" status when user is inactive (Linux only). -- AutoAwayStatusWindows - sets "Away" status when user is inactive (Windows only). -- Chess - play chess with your friends using Tox. -- Garland - changes your status like it's garland. -- AutoAnswer - calls auto answering. -- uToxInlineSending - send inlines with the same name as uTox does. -- AvatarEncryption - encrypt all avatars using profile password +- BirthDay - get notifications on your friends' birthdays +- Bot - bot which can communicate with your friends when you are away +- SearchPlugin - select text in message and find it in search engine + + diff --git a/SearchPlugin/srch.py b/SearchPlugin/srch.py index 12ed855..ea2ed97 100644 --- a/SearchPlugin/srch.py +++ b/SearchPlugin/srch.py @@ -1,5 +1,5 @@ import plugin_super_class -from PyQt5 import QtGui, QtCore, QtWidgets +from PySide import QtGui, QtCore class SearchPlugin(plugin_super_class.PluginSuperClass): @@ -8,23 +8,23 @@ class SearchPlugin(plugin_super_class.PluginSuperClass): super(SearchPlugin, self).__init__('SearchPlugin', 'srch', *args) def get_message_menu(self, menu, text): - google = QtWidgets.QAction( - QtWidgets.QApplication.translate("srch", "Find in Google"), + google = QtGui.QAction( + QtGui.QApplication.translate("srch", "Find in Google", None, QtGui.QApplication.UnicodeUTF8), menu) google.triggered.connect(lambda: self.google(text)) - duck = QtWidgets.QAction( - QtWidgets.QApplication.translate("srch", "Find in DuckDuckGo"), + duck = QtGui.QAction( + QtGui.QApplication.translate("srch", "Find in DuckDuckGo", None, QtGui.QApplication.UnicodeUTF8), menu) duck.triggered.connect(lambda: self.duck(text)) - yandex = QtWidgets.QAction( - QtWidgets.QApplication.translate("srch", "Find in Yandex"), + yandex = QtGui.QAction( + QtGui.QApplication.translate("srch", "Find in Yandex", None, QtGui.QApplication.UnicodeUTF8), menu) yandex.triggered.connect(lambda: self.yandex(text)) - bing = QtWidgets.QAction( - QtWidgets.QApplication.translate("srch", "Find in Bing"), + bing = QtGui.QAction( + QtGui.QApplication.translate("srch", "Find in Bing", None, QtGui.QApplication.UnicodeUTF8), menu) bing.triggered.connect(lambda: self.bing(text)) @@ -32,20 +32,16 @@ class SearchPlugin(plugin_super_class.PluginSuperClass): def google(self, text): url = QtCore.QUrl('https://www.google.com/search?q=' + text) - self.open_url(url) + QtGui.QDesktopServices.openUrl(url) def duck(self, text): url = QtCore.QUrl('https://duckduckgo.com/?q=' + text) - self.open_url(url) + QtGui.QDesktopServices.openUrl(url) def yandex(self, text): url = QtCore.QUrl('https://yandex.com/search/?text=' + text) - self.open_url(url) + QtGui.QDesktopServices.openUrl(url) def bing(self, text): url = QtCore.QUrl('https://www.bing.com/search?q=' + text) - self.open_url(url) - - def open_url(self, url): QtGui.QDesktopServices.openUrl(url) - diff --git a/uToxInlineSending/uin.py b/uToxInlineSending/uin.py deleted file mode 100644 index 10becc8..0000000 --- a/uToxInlineSending/uin.py +++ /dev/null @@ -1,19 +0,0 @@ -import plugin_super_class - - -class uToxInlineSending(plugin_super_class.PluginSuperClass): - - def __init__(self, *args): - super(uToxInlineSending, self).__init__('uToxInlineSending', 'uin', *args) - self._tmp = None - - def stop(self): - self._profile.send_screenshot = self._tmp - - def start(self): - self._tmp = self._profile.send_screenshot - - def func(data): - self._profile.send_inline(data, 'utox-inline.png') - - self._profile.send_screenshot = func