kinozal v2.7, repo update
29
.gitignore
vendored
@ -1,19 +1,12 @@
|
||||
/engines/kinozal.cookie
|
||||
/engines/kinozal.json
|
||||
/engines/nnmclub.cookie
|
||||
/engines/nnmclub.ico
|
||||
/engines/nnmclub.json
|
||||
/engines/rutor.ico
|
||||
/engines/rutor.json
|
||||
/engines/rutracker.cookie
|
||||
/engines/rutracker.json
|
||||
/modules
|
||||
/tests
|
||||
/kinozal.cookie
|
||||
/kinozal.cookie.bak
|
||||
/kinozal.ico
|
||||
/kinozal.json
|
||||
/kinozal.json.bak
|
||||
/nnmclub.cookie
|
||||
/nnmclub.cookie.bak
|
||||
/nnmclub.ico
|
||||
/nnmclub.json
|
||||
/nnmclub.json.bak
|
||||
/proxylist.txt
|
||||
/rutor.ico
|
||||
/rutor.json
|
||||
/rutracker.cookie
|
||||
/rutracker.cookie.bak
|
||||
/rutracker.ico
|
||||
/rutracker.json
|
||||
/rutracker.json.bak
|
||||
/proxylist.txt
|
@ -26,7 +26,7 @@ According of the name of search plugin:
|
||||
* Then follow [official tutorial](https://github.com/qbittorrent/search-plugins/wiki/Install-search-plugins).
|
||||
* _After installation you can change your settings with `*.json` file which will be created automatically in:_
|
||||
* Windows: `%localappdata%\qBittorrent\nova3\engines`
|
||||
* Linux: `~/.local/share/data/qBittorrent/nova3/engines`
|
||||
* Linux: `~/.local/share/qBittorrent/nova3/engines`
|
||||
* OS X: `~/Library/Application Support/qBittorrent/nova3/engines`
|
||||
|
||||
**For update just reinstall `*.py` file.**
|
||||
|
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 752 B |
@ -1,4 +1,4 @@
|
||||
# VERSION: 2.6
|
||||
# VERSION: 2.7
|
||||
# AUTHORS: imDMG [imdmgg@gmail.com]
|
||||
|
||||
# Kinozal.tv search engine plugin for qBittorrent
|
||||
@ -8,15 +8,16 @@ import gzip
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures.thread import ThreadPoolExecutor
|
||||
from dataclasses import dataclass, field
|
||||
from functools import partial
|
||||
from html import unescape
|
||||
from http.cookiejar import MozillaCookieJar
|
||||
from pathlib import Path
|
||||
from tempfile import NamedTemporaryFile
|
||||
from typing import Union, Optional
|
||||
from urllib.error import URLError, HTTPError
|
||||
from urllib.parse import urlencode, unquote
|
||||
from urllib.request import build_opener, HTTPCookieProcessor, ProxyHandler
|
||||
@ -27,39 +28,29 @@ except ImportError:
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.absolute()))
|
||||
from novaprinter import prettyPrinter
|
||||
|
||||
# default config
|
||||
config = {
|
||||
"torrentDate": True,
|
||||
"username": "USERNAME",
|
||||
"password": "PASSWORD",
|
||||
"proxy": False,
|
||||
"proxies": {
|
||||
"http": "",
|
||||
"https": ""
|
||||
},
|
||||
"magnet": True,
|
||||
"ua": "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0 "
|
||||
}
|
||||
# setup logging
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s %(name)-12s %(levelname)-8s %(message)s",
|
||||
datefmt="%m-%d %H:%M",
|
||||
level=logging.DEBUG
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
FILE = Path(__file__)
|
||||
BASEDIR = FILE.parent.absolute()
|
||||
|
||||
FILENAME = FILE.name[:-3]
|
||||
FILE_J, FILE_C = [BASEDIR / (FILENAME + fl) for fl in ['.json', '.cookie']]
|
||||
FILE_J, FILE_C = [BASEDIR / (FILENAME + fl) for fl in (".json", ".cookie")]
|
||||
|
||||
PAGES = 50
|
||||
|
||||
|
||||
def rng(t):
|
||||
return range(1, -(-t // PAGES))
|
||||
|
||||
|
||||
RE_TORRENTS = re.compile(
|
||||
r'nam"><a\s+?href="/(.+?)"\s+?class="r\d">(.+?)</a>.+?s\'>.+?s\'>(.+?)<.+?'
|
||||
r'sl_s\'>(\d+?)<.+?sl_p\'>(\d+?)<.+?s\'>(.+?)</td>', re.S
|
||||
)
|
||||
RE_RESULTS = re.compile(r'</span>Найдено\s+?(\d+?)\s+?раздач', re.S)
|
||||
PATTERNS = ('%sbrowse.php?s=%s&c=%s', "%s&page=%s")
|
||||
RE_RESULTS = re.compile(r"</span>Найдено\s+?(\d+?)\s+?раздач", re.S)
|
||||
PATTERNS = ("%sbrowse.php?s=%s&c=%s", "%s&page=%s")
|
||||
|
||||
# base64 encoded image
|
||||
ICON = ("AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAA"
|
||||
@ -85,75 +76,104 @@ ICON = ("AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAA"
|
||||
"gEc7/4BHO/+ARztMAAAAAIBHO0yARzv/gEc7/4BHO0wAAAAACCEAAAABAAAAAQAAAAEAAI"
|
||||
"ADAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAACAAwAAAAEAAAABAAAAAQAACCEAAA== ")
|
||||
|
||||
# setup logging
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s %(name)-12s %(levelname)-8s %(message)s",
|
||||
datefmt="%m-%d %H:%M",
|
||||
level=logging.DEBUG
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
def rng(t: int) -> range:
|
||||
return range(1, -(-t // PAGES))
|
||||
|
||||
try:
|
||||
config = json.loads(FILE_J.read_text())
|
||||
logger.debug("Config is loaded.")
|
||||
except OSError as e:
|
||||
logger.error(e)
|
||||
# if file doesn't exist, we'll create it
|
||||
FILE_J.write_text(json.dumps(config, indent=4, sort_keys=False))
|
||||
# also write/rewrite ico file
|
||||
(BASEDIR / (FILENAME + '.ico')).write_bytes(base64.b64decode(ICON))
|
||||
logger.debug("Write files.")
|
||||
|
||||
@dataclass
|
||||
class Config:
|
||||
username: str = "USERNAME"
|
||||
password: str = "PASSWORD"
|
||||
torrent_date: bool = True
|
||||
magnet: bool = False
|
||||
proxy: bool = False
|
||||
# dynamic_proxy: bool = True
|
||||
proxies: dict = field(default_factory=lambda: {"http": "", "https": ""})
|
||||
ua: str = ("Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 "
|
||||
"Firefox/38.0 ")
|
||||
|
||||
def __post_init__(self):
|
||||
try:
|
||||
if not self._validate_json(json.loads(FILE_J.read_text())):
|
||||
raise ValueError("Incorrect json scheme.")
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
FILE_J.write_text(self.to_str())
|
||||
(BASEDIR / f"{FILENAME}.ico").write_bytes(base64.b64decode(ICON))
|
||||
|
||||
def to_str(self) -> str:
|
||||
return json.dumps(self.to_dict(), indent=4, sort_keys=False)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {self._to_camel(k): v for k, v in self.__dict__.items()}
|
||||
|
||||
def _validate_json(self, obj: dict) -> bool:
|
||||
is_valid = True
|
||||
for k, v in self.__dict__.items():
|
||||
_val = obj.get(self._to_camel(k))
|
||||
if type(_val) is not type(v):
|
||||
is_valid = False
|
||||
continue
|
||||
setattr(self, k, _val)
|
||||
return is_valid
|
||||
|
||||
@staticmethod
|
||||
def _to_camel(s: str) -> str:
|
||||
return "".join(x.title() if i else x
|
||||
for i, x in enumerate(s.split("_")))
|
||||
|
||||
|
||||
config = Config()
|
||||
|
||||
|
||||
class Kinozal:
|
||||
name = 'Kinozal'
|
||||
url = 'http://kinozal.tv/'
|
||||
name = "Kinozal"
|
||||
url = "http://kinozal.tv/"
|
||||
url_dl = url.replace("//", "//dl.")
|
||||
url_login = url + 'takelogin.php'
|
||||
supported_categories = {'all': '0',
|
||||
'movies': '1002',
|
||||
'tv': '1001',
|
||||
'music': '1004',
|
||||
'games': '23',
|
||||
'anime': '20',
|
||||
'software': '32'}
|
||||
url_login = url + "takelogin.php"
|
||||
supported_categories = {"all": "0",
|
||||
"movies": "1002",
|
||||
"tv": "1001",
|
||||
"music": "1004",
|
||||
"games": "23",
|
||||
"anime": "20",
|
||||
"software": "32"}
|
||||
|
||||
# error message
|
||||
error: Optional[str] = None
|
||||
# cookies
|
||||
mcj = MozillaCookieJar()
|
||||
# establish connection
|
||||
session = build_opener(HTTPCookieProcessor(mcj))
|
||||
|
||||
def __init__(self):
|
||||
# error message
|
||||
self.error = None
|
||||
|
||||
# establish connection
|
||||
self.session = build_opener()
|
||||
|
||||
# add proxy handler if needed
|
||||
if config['proxy']:
|
||||
if any(config['proxies'].values()):
|
||||
self.session.add_handler(ProxyHandler(config['proxies']))
|
||||
if config.proxy:
|
||||
if any(config.proxies.values()):
|
||||
self.session.add_handler(ProxyHandler(config.proxies))
|
||||
logger.debug("Proxy is set!")
|
||||
else:
|
||||
self.error = "Proxy enabled, but not set!"
|
||||
|
||||
# change user-agent
|
||||
self.session.addheaders = [('User-Agent', config['ua'])]
|
||||
self.session.addheaders = [("User-Agent", config.ua)]
|
||||
|
||||
# load local cookies
|
||||
mcj = MozillaCookieJar()
|
||||
try:
|
||||
mcj.load(FILE_C, ignore_discard=True)
|
||||
if 'uid' in [cookie.name for cookie in mcj]:
|
||||
self.mcj.load(FILE_C, ignore_discard=True)
|
||||
if "uid" in [cookie.name for cookie in self.mcj]:
|
||||
# if cookie.expires < int(time.time())
|
||||
logger.info("Local cookies is loaded")
|
||||
self.session.add_handler(HTTPCookieProcessor(mcj))
|
||||
else:
|
||||
logger.info("Local cookies expired or bad")
|
||||
logger.debug(f"That we have: {[cookie for cookie in mcj]}")
|
||||
mcj.clear()
|
||||
self.login(mcj)
|
||||
logger.debug(f"That we have: {[cookie for cookie in self.mcj]}")
|
||||
self.mcj.clear()
|
||||
self.login()
|
||||
except FileNotFoundError:
|
||||
self.login(mcj)
|
||||
self.login()
|
||||
|
||||
def search(self, what, cat='all'):
|
||||
def search(self, what: str, cat: str = "all") -> None:
|
||||
if self.error:
|
||||
self.pretty_error(what)
|
||||
return None
|
||||
@ -174,24 +194,24 @@ class Kinozal:
|
||||
logger.debug(f"--- {time.time() - t0} seconds ---")
|
||||
logger.info(f"Found torrents: {total}")
|
||||
|
||||
def download_torrent(self, url: str):
|
||||
def download_torrent(self, url: str) -> None:
|
||||
# choose download method
|
||||
if config.get("magnet"):
|
||||
if config.magnet:
|
||||
url = "%sget_srv_details.php?action=2&id=%s" % (self.url,
|
||||
url.split('=')[1])
|
||||
url.split("=")[1])
|
||||
|
||||
response = self._catch_error_request(url)
|
||||
response = self._request(url)
|
||||
if self.error:
|
||||
self.pretty_error(url)
|
||||
return None
|
||||
|
||||
if config.get("magnet"):
|
||||
if config.magnet:
|
||||
if response.startswith(b"\x1f\x8b\x08"):
|
||||
response = gzip.decompress(response)
|
||||
path = 'magnet:?xt=urn:btih:' + response.decode()[18:58]
|
||||
path = "magnet:?xt=urn:btih:" + response.decode()[18:58]
|
||||
else:
|
||||
# Create a torrent file
|
||||
with NamedTemporaryFile(suffix='.torrent', delete=False) as fd:
|
||||
with NamedTemporaryFile(suffix=".torrent", delete=False) as fd:
|
||||
fd.write(response)
|
||||
path = fd.name
|
||||
|
||||
@ -199,55 +219,62 @@ class Kinozal:
|
||||
logger.debug(path + " " + url)
|
||||
print(path + " " + url)
|
||||
|
||||
def login(self, mcj):
|
||||
def login(self) -> None:
|
||||
if self.error:
|
||||
return None
|
||||
self.session.add_handler(HTTPCookieProcessor(mcj))
|
||||
|
||||
form_data = {"username": config['username'],
|
||||
"password": config['password']}
|
||||
form_data = {"username": config.username, "password": config.password}
|
||||
logger.debug(f"Login. Data before: {form_data}")
|
||||
# so we first encode vals to cp1251 then do default decode whole string
|
||||
data_encoded = urlencode(
|
||||
{k: v.encode('cp1251') for k, v in form_data.items()}
|
||||
).encode()
|
||||
# encoding to cp1251 then do default decode whole string
|
||||
data_encoded = urlencode(form_data, encoding="cp1251").encode()
|
||||
logger.debug(f"Login. Data after: {data_encoded}")
|
||||
|
||||
self._catch_error_request(self.url_login, data_encoded)
|
||||
self._request(self.url_login, data_encoded)
|
||||
if self.error:
|
||||
return None
|
||||
logger.debug(f"That we have: {[cookie for cookie in mcj]}")
|
||||
if 'uid' in [cookie.name for cookie in mcj]:
|
||||
mcj.save(FILE_C, ignore_discard=True, ignore_expires=True)
|
||||
logger.info('We successfully authorized')
|
||||
logger.debug(f"That we have: {[cookie for cookie in self.mcj]}")
|
||||
if "uid" in [cookie.name for cookie in self.mcj]:
|
||||
self.mcj.save(FILE_C, ignore_discard=True, ignore_expires=True)
|
||||
logger.info("We successfully authorized")
|
||||
else:
|
||||
self.error = "We not authorized, please check your credentials!"
|
||||
logger.warning(self.error)
|
||||
|
||||
def searching(self, query, first=False):
|
||||
response = self._catch_error_request(query)
|
||||
if not response:
|
||||
def searching(self, query: str, first: bool = False) -> Union[None, int]:
|
||||
response = self._request(query)
|
||||
if self.error:
|
||||
return None
|
||||
if response.startswith(b"\x1f\x8b\x08"):
|
||||
response = gzip.decompress(response)
|
||||
page, torrents_found = response.decode('cp1251'), -1
|
||||
page, torrents_found = response.decode("cp1251"), -1
|
||||
if first:
|
||||
# check login status
|
||||
if "Гость! ( Зарегистрируйтесь )" in page:
|
||||
logger.debug("Looks like we lost session id, lets login")
|
||||
self.mcj.clear()
|
||||
self.login()
|
||||
if self.error:
|
||||
return None
|
||||
# firstly we check if there is a result
|
||||
torrents_found = int(RE_RESULTS.search(page)[1])
|
||||
result = RE_RESULTS.search(page)
|
||||
if not result:
|
||||
self.error = "Unexpected page content"
|
||||
return None
|
||||
torrents_found = int(result[1])
|
||||
if not torrents_found:
|
||||
return 0
|
||||
self.draw(page)
|
||||
|
||||
return torrents_found
|
||||
|
||||
def draw(self, html: str):
|
||||
def draw(self, html: str) -> None:
|
||||
torrents = RE_TORRENTS.findall(html)
|
||||
_part = partial(time.strftime, "%y.%m.%d")
|
||||
# yeah this is yesterday
|
||||
yesterday = _part(time.localtime(time.time() - 86400))
|
||||
for tor in torrents:
|
||||
torrent_date = ""
|
||||
if config['torrentDate']:
|
||||
if config.torrent_date:
|
||||
ct = tor[5].split()[0]
|
||||
if "сегодня" in ct:
|
||||
torrent_date = _part()
|
||||
@ -255,10 +282,10 @@ class Kinozal:
|
||||
torrent_date = yesterday
|
||||
else:
|
||||
torrent_date = _part(time.strptime(ct, "%d.%m.%Y"))
|
||||
torrent_date = f'[{torrent_date}] '
|
||||
torrent_date = f"[{torrent_date}] "
|
||||
|
||||
# replace size units
|
||||
table = {'Т': 'T', 'Г': 'G', 'М': 'M', 'К': 'K', 'Б': 'B'}
|
||||
table = {"Т": "T", "Г": "G", "М": "M", "К": "K", "Б": "B"}
|
||||
|
||||
prettyPrinter({
|
||||
"engine_url": self.url,
|
||||
@ -271,31 +298,31 @@ class Kinozal:
|
||||
})
|
||||
del torrents
|
||||
|
||||
def _catch_error_request(self, url=None, data=None, repeated=False):
|
||||
url = url or self.url
|
||||
|
||||
def _request(
|
||||
self, url: str, data: Optional[bytes] = None, repeated: bool = False
|
||||
) -> Union[bytes, None]:
|
||||
try:
|
||||
with self.session.open(url, data, 5) as r:
|
||||
# checking that tracker isn't blocked
|
||||
if r.url.startswith((self.url, self.url_dl)):
|
||||
if r.geturl().startswith((self.url, self.url_dl)):
|
||||
return r.read()
|
||||
raise URLError(f"{self.url} is blocked. Try another proxy.")
|
||||
except (socket.error, socket.timeout) as err:
|
||||
if not repeated:
|
||||
return self._catch_error_request(url, data, True)
|
||||
logger.error(err)
|
||||
self.error = f"{self.url} is not response! Maybe it is blocked."
|
||||
if "no host given" in err.args:
|
||||
self.error = "Proxy is bad, try another!"
|
||||
self.error = f"{url} is blocked. Try another proxy."
|
||||
except (URLError, HTTPError) as err:
|
||||
logger.error(err.reason)
|
||||
self.error = err.reason
|
||||
if hasattr(err, 'code'):
|
||||
error = str(err.reason)
|
||||
if "timed out" in error and not repeated:
|
||||
logger.debug("Repeating request...")
|
||||
return self._request(url, data, True)
|
||||
if "no host given" in error:
|
||||
self.error = "Proxy is bad, try another!"
|
||||
elif hasattr(err, "code"):
|
||||
self.error = f"Request to {url} failed with status: {err.code}"
|
||||
else:
|
||||
self.error = f"{url} is not response! Maybe it is blocked."
|
||||
|
||||
return None
|
||||
|
||||
def pretty_error(self, what):
|
||||
def pretty_error(self, what: str) -> None:
|
||||
prettyPrinter({"engine_url": self.url,
|
||||
"desc_link": "https://github.com/imDMG/qBt_SE",
|
||||
"name": f"[{unquote(what)}][Error]: {self.error}",
|
||||
@ -311,9 +338,9 @@ class Kinozal:
|
||||
kinozal = Kinozal
|
||||
|
||||
if __name__ == "__main__":
|
||||
if BASEDIR.parent.joinpath('settings_gui.py').exists():
|
||||
if BASEDIR.parent.joinpath("settings_gui.py").exists():
|
||||
from settings_gui import EngineSettingsGUI
|
||||
|
||||
EngineSettingsGUI(FILENAME)
|
||||
engine = kinozal()
|
||||
engine.search('doctor')
|
||||
engine.search("doctor")
|
Before Width: | Height: | Size: 912 B After Width: | Height: | Size: 912 B |
Before Width: | Height: | Size: 761 B After Width: | Height: | Size: 761 B |
@ -245,9 +245,9 @@ class Rutor:
|
||||
rutor = Rutor
|
||||
|
||||
if __name__ == "__main__":
|
||||
if BASEDIR.parent.joinpath('settings_gui.py').exists():
|
||||
from settings_gui import EngineSettingsGUI
|
||||
|
||||
EngineSettingsGUI(FILENAME)
|
||||
# if BASEDIR.parent.joinpath('settings_gui.py').exists():
|
||||
# from settings_gui import EngineSettingsGUI
|
||||
#
|
||||
# EngineSettingsGUI(FILENAME)
|
||||
engine = rutor()
|
||||
engine.search('doctor')
|
BIN
engines/rutracker.png
Normal file
After Width: | Height: | Size: 788 B |
@ -5,33 +5,31 @@ import threading
|
||||
from concurrent.futures.thread import ThreadPoolExecutor
|
||||
from urllib.request import build_opener, ProxyHandler
|
||||
|
||||
HOST = "https://rutracker.org/forum/"
|
||||
HOST = "http://rutor.info"
|
||||
SCHEME = HOST[:HOST.rfind("://")]
|
||||
PROXY_FILE = "proxylist1.txt" # one address per line
|
||||
PROXY_FILE = "proxylist.txt" # one address per line
|
||||
|
||||
|
||||
async def is_good_proxy_aio(loop, proxy: str) -> bool:
|
||||
async def is_good_proxy_aio(proxy: str) -> bool:
|
||||
try:
|
||||
await asyncio.sleep(.1)
|
||||
opener = build_opener(ProxyHandler({f"{SCHEME}": proxy}))
|
||||
opener.addheaders = [("User-agent", "Mozilla/5.0")]
|
||||
_part = functools.partial(opener.open, HOST, timeout=3)
|
||||
res = await loop.run_in_executor(None, _part)
|
||||
if not res.geturl().startswith(HOST):
|
||||
# res = await loop.run_in_executor(None, _part)
|
||||
if not _part().geturl().startswith(HOST):
|
||||
raise Exception()
|
||||
print(proxy)
|
||||
return True
|
||||
except Exception as e:
|
||||
# print(e)
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
async def run_aio(proxies):
|
||||
loop = asyncio.get_event_loop()
|
||||
for proxy in proxies:
|
||||
await is_good_proxy_aio(loop, proxy)
|
||||
await asyncio.gather(*[is_good_proxy(proxy) for proxy in proxies])
|
||||
|
||||
|
||||
def run_thread(proxies):
|
||||
def run_thread(proxies: list) -> None:
|
||||
tasks = []
|
||||
for proxy in proxies:
|
||||
task = threading.Thread(target=is_good_proxy, args=(proxy,))
|
||||
@ -41,20 +39,19 @@ def run_thread(proxies):
|
||||
t.join()
|
||||
|
||||
|
||||
def run_pool(proxies):
|
||||
def run_pool(proxies: list) -> None:
|
||||
with ThreadPoolExecutor(len(proxies)) as executor:
|
||||
executor.map(is_good_proxy, proxies, timeout=30)
|
||||
executor.map(is_good_proxy, proxies, timeout=3)
|
||||
|
||||
|
||||
def is_good_proxy(proxy):
|
||||
def is_good_proxy(proxy: str) -> bool:
|
||||
try:
|
||||
opener = build_opener(ProxyHandler({f"{SCHEME}": proxy}))
|
||||
opener.addheaders = [("User-agent", "Mozilla/5.0")]
|
||||
req = opener.open(HOST, timeout=3)
|
||||
if not req.geturl().startswith(HOST):
|
||||
raise Exception()
|
||||
except Exception as e:
|
||||
# print(e)
|
||||
with opener.open(HOST, timeout=3) as r:
|
||||
if not r.geturl().startswith(HOST):
|
||||
raise Exception()
|
||||
except OSError:
|
||||
return False
|
||||
else:
|
||||
print(proxy)
|
||||
@ -63,8 +60,14 @@ def is_good_proxy(proxy):
|
||||
|
||||
def main():
|
||||
t0 = time.time()
|
||||
with open(PROXY_FILE) as f:
|
||||
proxy_list = [x.rstrip() for x in f]
|
||||
|
||||
if PROXY_FILE.startswith("http"):
|
||||
opener = build_opener()
|
||||
with opener.open(PROXY_FILE) as r:
|
||||
proxy_list = [x.rstrip().decode("utf-8") for x in r]
|
||||
else:
|
||||
with open(PROXY_FILE) as f:
|
||||
proxy_list = [x.rstrip() for x in f]
|
||||
|
||||
print("Working proxies:")
|
||||
# run_thread(proxy_list)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import json
|
||||
import tkinter as tk
|
||||
from pathlib import Path
|
||||
from tkinter import *
|
||||
from tkinter import ttk, messagebox
|
||||
|
||||
|
||||
@ -11,64 +11,65 @@ class EngineSettingsGUI:
|
||||
if self.cfg_file.exists():
|
||||
self.config = json.loads(self.cfg_file.read_text())
|
||||
|
||||
self.window = Tk()
|
||||
self.window.title(engine_name + " Settings")
|
||||
self.window = tk.Tk()
|
||||
self.window.title(engine_name.capitalize() + " Settings")
|
||||
|
||||
mainframe = ttk.Frame(self.window, padding="10")
|
||||
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
|
||||
mainframe.grid(column=0, row=0, sticky=tk.N)
|
||||
self.window.columnconfigure(0, weight=1)
|
||||
self.window.rowconfigure(0, weight=1)
|
||||
|
||||
self.username = StringVar(value=self.config.get('username', ''))
|
||||
self.password = StringVar(value=self.config.get('password', ''))
|
||||
self.proxy_http = StringVar(
|
||||
value=self.config.get('proxies').get('http', '')
|
||||
self.username = tk.StringVar(value=self.config.get("username", ""))
|
||||
self.password = tk.StringVar(value=self.config.get("password", ""))
|
||||
self.proxy_http = tk.StringVar(
|
||||
value=self.config.get("proxies").get("http", "")
|
||||
)
|
||||
self.proxy_https = StringVar(
|
||||
value=self.config.get('proxies').get('https', '')
|
||||
self.proxy_https = tk.StringVar(
|
||||
value=self.config.get("proxies").get("https", "")
|
||||
)
|
||||
|
||||
self.date = BooleanVar(value=self.config.get('torrentDate', True))
|
||||
self.magnet = BooleanVar(value=self.config.get('magnet', False))
|
||||
self.proxy = BooleanVar(value=self.config.get('proxy', False))
|
||||
self.date = tk.BooleanVar(value=self.config.get("torrentDate", True))
|
||||
self.magnet = tk.BooleanVar(value=self.config.get("magnet", False))
|
||||
self.proxy = tk.BooleanVar(value=self.config.get("proxy", False))
|
||||
|
||||
ttk.Label(mainframe, text="Username:").grid(column=0, row=0, sticky=W)
|
||||
ttk.Label(mainframe, text="Password:").grid(column=0, row=1, sticky=W,
|
||||
rowspan=2)
|
||||
ttk.Label(mainframe, text="Username:").grid(
|
||||
column=0, row=0, sticky=tk.W)
|
||||
ttk.Label(mainframe, text="Password:").grid(
|
||||
column=0, row=1, sticky=tk.W, rowspan=2)
|
||||
|
||||
ttk.Entry(mainframe, width=25, textvariable=self.username).grid(
|
||||
column=1, row=0, sticky=(W, E), padx=(0, 5)
|
||||
column=1, row=0, sticky=tk.EW, padx=(0, 5)
|
||||
)
|
||||
ttk.Entry(mainframe, width=25, textvariable=self.password).grid(
|
||||
column=1, row=1, rowspan=2, sticky=(W, E), padx=(0, 5)
|
||||
column=1, row=1, rowspan=2, sticky=tk.EW, padx=(0, 5)
|
||||
)
|
||||
|
||||
ttk.Checkbutton(
|
||||
mainframe, text="Date before torrent", variable=self.date,
|
||||
onvalue=True
|
||||
).grid(column=2, row=0, sticky=W)
|
||||
).grid(column=2, row=0, sticky=tk.W)
|
||||
ttk.Checkbutton(
|
||||
mainframe, text="Use magnet link", variable=self.magnet,
|
||||
onvalue=True
|
||||
).grid(column=2, row=1, sticky=W)
|
||||
).grid(column=2, row=1, sticky=tk.W)
|
||||
ttk.Checkbutton(
|
||||
mainframe, text="Proxy", variable=self.proxy, onvalue=True,
|
||||
command=self.proxy_action
|
||||
).grid(column=2, row=2, sticky=W)
|
||||
).grid(column=2, row=2, sticky=tk.W)
|
||||
|
||||
ttk.Label(mainframe, text="HTTP:").grid(column=0, row=3, sticky=W)
|
||||
ttk.Label(mainframe, text="HTTPS:").grid(column=0, row=4, sticky=W)
|
||||
ttk.Label(mainframe, text="HTTP:").grid(column=0, row=3, sticky=tk.W)
|
||||
ttk.Label(mainframe, text="HTTPS:").grid(column=0, row=4, sticky=tk.W)
|
||||
|
||||
proxy_state = NORMAL if self.proxy.get() else DISABLED
|
||||
proxy_state = tk.NORMAL if self.proxy.get() else tk.DISABLED
|
||||
self.http_entry = ttk.Entry(
|
||||
mainframe, textvariable=self.proxy_http, state=proxy_state
|
||||
)
|
||||
self.http_entry.grid(column=1, row=3, sticky=(W, E),
|
||||
self.http_entry.grid(column=1, row=3, sticky=tk.EW,
|
||||
padx=(0, 5), pady=(0, 5))
|
||||
self.https_entry = ttk.Entry(
|
||||
mainframe, textvariable=self.proxy_https, state=proxy_state
|
||||
)
|
||||
self.https_entry.grid(column=1, row=4, sticky=(W, E), padx=(0, 5))
|
||||
self.https_entry.grid(column=1, row=4, sticky=tk.EW, padx=(0, 5))
|
||||
|
||||
ttk.Button(
|
||||
mainframe, text="Save", command=self.close
|
||||
@ -76,37 +77,37 @@ class EngineSettingsGUI:
|
||||
|
||||
self.window.mainloop()
|
||||
|
||||
def proxy_action(self):
|
||||
state = ("!" if self.proxy.get() else "") + DISABLED
|
||||
def proxy_action(self) -> None:
|
||||
state = ("!" if self.proxy.get() else "") + tk.DISABLED
|
||||
self.http_entry.state([state])
|
||||
self.https_entry.state([state])
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
if not (self.username.get() or self.password.get()):
|
||||
messagebox.showinfo('Error', "Some fields is empty!")
|
||||
messagebox.showinfo("Error", "Some fields is empty!")
|
||||
return None
|
||||
|
||||
if self.proxy.get() and not (self.http_entry.get()
|
||||
or self.https_entry.get()):
|
||||
messagebox.showinfo('Error', "Some fields is empty!")
|
||||
messagebox.showinfo("Error", "Some fields is empty!")
|
||||
return None
|
||||
|
||||
self.config['username'] = self.username.get()
|
||||
self.config['password'] = self.password.get()
|
||||
self.config['proxy'] = self.proxy.get()
|
||||
if self.config['proxy']:
|
||||
self.config['proxies'] = {
|
||||
'http': self.http_entry.get(),
|
||||
'https': self.https_entry.get()
|
||||
self.config["username"] = self.username.get()
|
||||
self.config["password"] = self.password.get()
|
||||
self.config["proxy"] = self.proxy.get()
|
||||
if self.config["proxy"]:
|
||||
self.config["proxies"] = {
|
||||
"http": self.http_entry.get(),
|
||||
"https": self.https_entry.get()
|
||||
}
|
||||
self.config['torrentDate'] = self.date.get()
|
||||
self.config['magnet'] = self.magnet.get()
|
||||
self.config["torrentDate"] = self.date.get()
|
||||
self.config["magnet"] = self.magnet.get()
|
||||
self.cfg_file.write_text(
|
||||
json.dumps(self.config, indent=4, sort_keys=False)
|
||||
)
|
||||
self.window.destroy()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
settings = EngineSettingsGUI("kinozal")
|
||||
print(settings.config)
|
||||
|