mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2026-10-25 01:06:05 +03:00
[2051] And a few more, with timezones
This commit is contained in:
4 files changed
+105
-64
No files matched your search
+2
-1
@@ -11,6 +11,7 @@ import json
|
||||
import sys
|
||||
import time
|
||||
import tkinter as tk
|
||||
from calendar import timegm
|
||||
from os.path import getsize, isdir, isfile, join
|
||||
from typing import Any, cast
|
||||
from watchdog.observers.api import BaseObserver
|
||||
@@ -182,7 +183,7 @@ class Dashboard(FileSystemEventHandler):
|
||||
if data: # Can be empty if polling while the file is being re-written
|
||||
entry = json.loads(data)
|
||||
# Status file is shared between beta and live. Filter out status not in this game session.
|
||||
entry_timestamp = time.mktime(time.strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ'))
|
||||
entry_timestamp = timegm(time.strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ'))
|
||||
if entry_timestamp >= self.session_start and self.status != entry:
|
||||
self.status = entry
|
||||
self.root.event_generate('<<DashboardEvent>>', when="tail")
|
||||
|
||||
+18
-16
@@ -1,13 +1,17 @@
|
||||
"""Export ship loadout in Companion API json format."""
|
||||
"""
|
||||
loadout.py - Export ship loadout in Companion API json format.
|
||||
|
||||
Copyright (c) EDCD, All Rights Reserved
|
||||
Licensed under the GNU General Public License.
|
||||
See LICENSE file.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import time
|
||||
from os import listdir
|
||||
from os.path import join
|
||||
from typing import Optional
|
||||
|
||||
import companion
|
||||
import util_ships
|
||||
from config import config
|
||||
@@ -16,7 +20,7 @@ from EDMCLogging import get_main_logger
|
||||
logger = get_main_logger()
|
||||
|
||||
|
||||
def export(data: companion.CAPIData, requested_filename: Optional[str] = None) -> None:
|
||||
def export(data: companion.CAPIData, requested_filename: str | None = None) -> None:
|
||||
"""
|
||||
Write Ship Loadout in Companion API JSON format.
|
||||
|
||||
@@ -32,15 +36,14 @@ def export(data: companion.CAPIData, requested_filename: Optional[str] = None) -
|
||||
with open(requested_filename, 'wt') as h:
|
||||
h.write(string)
|
||||
return
|
||||
|
||||
elif not requested_filename:
|
||||
if not requested_filename:
|
||||
logger.error(f"{requested_filename=} is not valid")
|
||||
return
|
||||
|
||||
# Look for last ship of this type
|
||||
ship = util_ships.ship_file_name(data['ship'].get('shipName'), data['ship']['name'])
|
||||
regexp = re.compile(re.escape(ship) + r'\.\d\d\d\d\-\d\d\-\d\dT\d\d\.\d\d\.\d\d\.txt')
|
||||
oldfiles = sorted([x for x in os.listdir(config.get_str('outdir')) if regexp.match(x)])
|
||||
regexp = re.compile(re.escape(ship) + r'\.\d\d\d\d-\d\d-\d\dT\d\d\.\d\d\.\d\d\.txt')
|
||||
oldfiles = sorted([x for x in listdir(config.get_str('outdir')) if regexp.match(x)])
|
||||
if oldfiles:
|
||||
with open(join(config.get_str('outdir'), oldfiles[-1]), 'rU') as h:
|
||||
if h.read() == string:
|
||||
@@ -50,10 +53,9 @@ def export(data: companion.CAPIData, requested_filename: Optional[str] = None) -
|
||||
|
||||
# Write
|
||||
|
||||
with open(
|
||||
pathlib.Path(config.get_str('outdir')) / pathlib.Path(
|
||||
ship + '.' + time.strftime('%Y-%m-%dT%H.%M.%S', time.localtime(query_time)) + '.txt'
|
||||
),
|
||||
'wt'
|
||||
) as h:
|
||||
output_directory = config.get_str('outdir')
|
||||
ship_time = time.strftime('%Y-%m-%dT%H.%M.%S', time.localtime(query_time))
|
||||
file_path = join(output_directory, f"{ship}.{ship_time}.txt")
|
||||
|
||||
with open(file_path, 'wt') as h:
|
||||
h.write(string)
|
||||
+51
-28
@@ -1,12 +1,17 @@
|
||||
"""protocol handler for cAPI authorisation."""
|
||||
# spell-checker: words ntdll GURL alloc wfile instantiatable pyright
|
||||
"""
|
||||
protocol.py - Protocol Handler for cAPI Auth.
|
||||
|
||||
Copyright (c) EDCD, All Rights Reserved
|
||||
Licensed under the GNU General Public License.
|
||||
See LICENSE file.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from typing import TYPE_CHECKING, Optional, Type
|
||||
from urllib import parse
|
||||
from typing import TYPE_CHECKING, Type
|
||||
|
||||
from config import config
|
||||
from constants import appname, protocolhandler_redirect
|
||||
@@ -34,7 +39,7 @@ class GenericProtocolHandler:
|
||||
def __init__(self) -> None:
|
||||
self.redirect = protocolhandler_redirect # Base redirection URL
|
||||
self.master: 'tkinter.Tk' = None # type: ignore
|
||||
self.lastpayload: Optional[str] = None
|
||||
self.lastpayload: str | None = None
|
||||
|
||||
def start(self, master: 'tkinter.Tk') -> None:
|
||||
"""Start Protocol Handler."""
|
||||
@@ -42,7 +47,6 @@ class GenericProtocolHandler:
|
||||
|
||||
def close(self) -> None:
|
||||
"""Stop / Close Protocol Handler."""
|
||||
pass
|
||||
|
||||
def event(self, url: str) -> None:
|
||||
"""Generate an auth event."""
|
||||
@@ -75,7 +79,7 @@ if sys.platform == 'darwin' and getattr(sys, 'frozen', False): # noqa: C901 # i
|
||||
def start(self, master: 'tkinter.Tk') -> None:
|
||||
"""Start Protocol Handler."""
|
||||
GenericProtocolHandler.start(self, master)
|
||||
self.lasturl: Optional[str] = None
|
||||
self.lasturl: str | None = None
|
||||
self.eventhandler = EventHandler.alloc().init()
|
||||
|
||||
def poll(self) -> None:
|
||||
@@ -106,12 +110,11 @@ if sys.platform == 'darwin' and getattr(sys, 'frozen', False): # noqa: C901 # i
|
||||
|
||||
def handleEvent_withReplyEvent_(self, event, replyEvent) -> None: # noqa: N802 N803 # Required to override
|
||||
"""Actual event handling from NSAppleEventManager."""
|
||||
protocolhandler.lasturl = urllib.parse.unquote( # noqa: F821: type: ignore # It's going to be a DPH in
|
||||
# this code
|
||||
protocolhandler.lasturl = parse.unquote(
|
||||
event.paramDescriptorForKeyword_(keyDirectObject).stringValue()
|
||||
).strip()
|
||||
|
||||
protocolhandler.master.after(DarwinProtocolHandler.POLL, protocolhandler.poll) # noqa: F821 # type: ignore
|
||||
protocolhandler.master.after(DarwinProtocolHandler.POLL, protocolhandler.poll)
|
||||
|
||||
|
||||
elif (config.auth_force_edmc_protocol
|
||||
@@ -124,9 +127,8 @@ elif (config.auth_force_edmc_protocol
|
||||
# This could be false if you use auth_force_edmc_protocol, but then you get to keep the pieces
|
||||
assert sys.platform == 'win32'
|
||||
# spell-checker: words HBRUSH HICON WPARAM wstring WNDCLASS HMENU HGLOBAL
|
||||
from ctypes import windll # type: ignore
|
||||
from ctypes import ( # type: ignore
|
||||
POINTER, WINFUNCTYPE, Structure, byref, c_long, c_void_p, create_unicode_buffer, wstring_at
|
||||
windll, POINTER, WINFUNCTYPE, Structure, byref, c_long, c_void_p, create_unicode_buffer, wstring_at
|
||||
)
|
||||
from ctypes.wintypes import (
|
||||
ATOM, BOOL, DWORD, HBRUSH, HGLOBAL, HICON, HINSTANCE, HMENU, HWND, INT, LPARAM, LPCWSTR, LPMSG, LPVOID, LPWSTR,
|
||||
@@ -271,7 +273,7 @@ elif (config.auth_force_edmc_protocol
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.thread: Optional[threading.Thread] = None
|
||||
self.thread: threading.Thread | None = None
|
||||
|
||||
def start(self, master: 'tkinter.Tk') -> None:
|
||||
"""Start the DDE thread."""
|
||||
@@ -342,7 +344,7 @@ elif (config.auth_force_edmc_protocol
|
||||
|
||||
if args.lower().startswith('open("') and args.endswith('")'):
|
||||
logger.trace_if('frontier-auth.windows', f'args are: {args}')
|
||||
url = urllib.parse.unquote(args[6:-2]).strip()
|
||||
url = parse.unquote(args[6:-2]).strip()
|
||||
if url.startswith(self.redirect):
|
||||
logger.debug(f'Message starts with {self.redirect}')
|
||||
self.event(url)
|
||||
@@ -381,7 +383,7 @@ else: # Linux / Run from source
|
||||
if not os.getenv("EDMC_NO_UI"):
|
||||
logger.info(f'Web server listening on {self.redirect}')
|
||||
|
||||
self.thread: Optional[threading.Thread] = None
|
||||
self.thread: threading.Thread | None = None
|
||||
|
||||
def start(self, master: 'tkinter.Tk') -> None:
|
||||
"""Start the HTTP server thread."""
|
||||
@@ -420,15 +422,14 @@ else: # Linux / Run from source
|
||||
def parse(self) -> bool:
|
||||
"""Parse a request."""
|
||||
logger.trace_if('frontier-auth.http', f'Got message on path: {self.path}')
|
||||
url = urllib.parse.unquote(self.path)
|
||||
url = parse.unquote(self.path)
|
||||
if url.startswith('/auth'):
|
||||
logger.debug('Request starts with /auth, sending to protocolhandler.event()')
|
||||
protocolhandler.event(url) # noqa: F821
|
||||
protocolhandler.event(url)
|
||||
self.send_response(200)
|
||||
return True
|
||||
else:
|
||||
self.send_response(404) # Not found
|
||||
return False
|
||||
self.send_response(404) # Not found
|
||||
return False
|
||||
|
||||
def do_HEAD(self) -> None: # noqa: N802 # Required to override
|
||||
"""Handle HEAD Request."""
|
||||
@@ -440,14 +441,37 @@ else: # Linux / Run from source
|
||||
if self.parse():
|
||||
self.send_header('Content-Type', 'text/html')
|
||||
self.end_headers()
|
||||
self.wfile.write('<html><head><title>Authentication successful</title></head>'.encode('utf-8'))
|
||||
self.wfile.write('<body><p>Authentication successful</p></body>'.encode('utf-8'))
|
||||
self.wfile.write(self._generate_auth_response().encode('utf-8'))
|
||||
else:
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
|
||||
def log_request(self, code: int | str = '-', size: int | str = '-') -> None:
|
||||
"""Override to prevent logging."""
|
||||
pass
|
||||
|
||||
def _generate_auth_response(self) -> str:
|
||||
"""
|
||||
Generate the authentication response HTML.
|
||||
|
||||
:return: The HTML content of the authentication response.
|
||||
"""
|
||||
return (
|
||||
'<html>'
|
||||
'<head>'
|
||||
'<title>Authentication successful - Elite: Dangerous</title>'
|
||||
'<style>'
|
||||
'body { background-color: #000; color: #fff; font-family: "Helvetica Neue", Arial, sans-serif; }'
|
||||
'h1 { text-align: center; margin-top: 100px; }'
|
||||
'p { text-align: center; }'
|
||||
'</style>'
|
||||
'</head>'
|
||||
'<body>'
|
||||
'<h1>Authentication successful</h1>'
|
||||
'<p>Thank you for authenticating.</p>'
|
||||
'<p>Please close this browser tab now.</p>'
|
||||
'</body>'
|
||||
'</html>'
|
||||
)
|
||||
|
||||
|
||||
def get_handler_impl() -> Type[GenericProtocolHandler]:
|
||||
@@ -459,14 +483,13 @@ def get_handler_impl() -> Type[GenericProtocolHandler]:
|
||||
if sys.platform == 'darwin' and getattr(sys, 'frozen', False):
|
||||
return DarwinProtocolHandler # pyright: reportUnboundVariable=false
|
||||
|
||||
elif (
|
||||
if (
|
||||
(sys.platform == 'win32' and config.auth_force_edmc_protocol)
|
||||
or (getattr(sys, 'frozen', False) and not is_wine and not config.auth_force_localserver)
|
||||
):
|
||||
return WindowsProtocolHandler
|
||||
|
||||
else:
|
||||
return LinuxProtocolHandler
|
||||
return LinuxProtocolHandler
|
||||
|
||||
|
||||
# *late init* singleton
|
||||
|
||||
+34
-19
@@ -1,5 +1,9 @@
|
||||
"""
|
||||
A clickable ttk label for HTTP links.
|
||||
ttkHyperlinkLabel.py - Clickable ttk labels.
|
||||
|
||||
Copyright (c) EDCD, All Rights Reserved
|
||||
Licensed under the GNU General Public License.
|
||||
See LICENSE file.
|
||||
|
||||
In addition to standard ttk.Label arguments, takes the following arguments:
|
||||
url: The URL as a string that the user will be sent to on clicking on
|
||||
@@ -14,6 +18,8 @@ In addition to standard ttk.Label arguments, takes the following arguments:
|
||||
|
||||
May be imported by plugins
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import tkinter as tk
|
||||
import webbrowser
|
||||
@@ -26,14 +32,22 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
# FIXME: Split this into multi-file module to separate the platforms
|
||||
class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label, object): # type: ignore
|
||||
class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label): # type: ignore
|
||||
"""Clickable label for HTTP links."""
|
||||
|
||||
def __init__(self, master: tk.Frame | None = None, **kw: Any) -> None:
|
||||
self.url = 'url' in kw and kw.pop('url') or None
|
||||
"""
|
||||
Initialize the HyperlinkLabel.
|
||||
|
||||
:param master: The master widget.
|
||||
:param kw: Additional keyword arguments.
|
||||
"""
|
||||
self.font_u: tk_font.Font
|
||||
self.font_n = None
|
||||
self.url = kw.pop('url', None)
|
||||
self.popup_copy = kw.pop('popup_copy', False)
|
||||
self.underline = kw.pop('underline', None) # override ttk.Label's underline
|
||||
self.foreground = kw.get('foreground') or 'blue'
|
||||
self.foreground = kw.get('foreground', 'blue')
|
||||
self.disabledforeground = kw.pop('disabledforeground', ttk.Style().lookup(
|
||||
'TLabel', 'foreground', ('disabled',))) # ttk.Label doesn't support disabledforeground option
|
||||
|
||||
@@ -44,11 +58,11 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label, object)
|
||||
tk.Label.__init__(self, master, **kw)
|
||||
|
||||
else:
|
||||
ttk.Label.__init__(self, master, **kw) # type: ignore
|
||||
ttk.Label.__init__(self, master, **kw)
|
||||
|
||||
self.bind('<Button-1>', self._click)
|
||||
|
||||
self.menu = tk.Menu(None, tearoff=tk.FALSE)
|
||||
self.menu = tk.Menu(tearoff=tk.FALSE)
|
||||
# LANG: Label for 'Copy' as in 'Copy and Paste'
|
||||
self.menu.add_command(label=_('Copy'), command=self.copy) # As in Copy and Paste
|
||||
self.bind(sys.platform == 'darwin' and '<Button-2>' or '<Button-3>', self._contextmenu)
|
||||
@@ -74,29 +88,30 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label, object)
|
||||
setattr(self, thing, kw[thing])
|
||||
|
||||
# Emulate disabledforeground option for ttk.Label
|
||||
if kw.get('state') == tk.DISABLED:
|
||||
if 'foreground' not in kw:
|
||||
if 'state' in kw:
|
||||
state = kw['state']
|
||||
if state == tk.DISABLED and 'foreground' not in kw:
|
||||
kw['foreground'] = self.disabledforeground
|
||||
elif 'state' in kw:
|
||||
if 'foreground' not in kw:
|
||||
elif state != tk.DISABLED and 'foreground' not in kw:
|
||||
kw['foreground'] = self.foreground
|
||||
|
||||
if 'font' in kw:
|
||||
self.font_n = kw['font']
|
||||
self.font_u = tk_font.Font(font=self.font_n)
|
||||
self.font_u.configure(underline=True)
|
||||
kw['font'] = self.underline is True and self.font_u or self.font_n
|
||||
kw['font'] = self.font_u if self.underline is True else self.font_n
|
||||
|
||||
if 'cursor' not in kw:
|
||||
if (kw['state'] if 'state' in kw else str(self['state'])) == tk.DISABLED:
|
||||
state = kw.get('state', str(self['state']))
|
||||
if state == tk.DISABLED:
|
||||
kw['cursor'] = 'arrow' # System default
|
||||
elif self.url and (kw['text'] if 'text' in kw else self['text']):
|
||||
kw['cursor'] = sys.platform == 'darwin' and 'pointinghand' or 'hand2'
|
||||
kw['cursor'] = 'pointinghand' if sys.platform == 'darwin' else 'hand2'
|
||||
else:
|
||||
kw['cursor'] = (sys.platform == 'darwin' and 'notallowed') or (
|
||||
sys.platform == 'win32' and 'no') or 'circle'
|
||||
kw['cursor'] = 'notallowed' if sys.platform == 'darwin' else (
|
||||
'no' if sys.platform == 'win32' else 'circle')
|
||||
|
||||
return super(HyperlinkLabel, self).configure(cnf, **kw)
|
||||
return super().configure(cnf, **kw)
|
||||
|
||||
def __setitem__(self, key: str, value: Any) -> None:
|
||||
"""
|
||||
@@ -105,15 +120,15 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label, object)
|
||||
:param key: option name
|
||||
:param value: option value
|
||||
"""
|
||||
self.configure(None, **{key: value})
|
||||
self.configure(**{key: value})
|
||||
|
||||
def _enter(self, event: tk.Event) -> None:
|
||||
if self.url and self.underline is not False and str(self['state']) != tk.DISABLED:
|
||||
super(HyperlinkLabel, self).configure(font=self.font_u)
|
||||
super().configure(font=self.font_u)
|
||||
|
||||
def _leave(self, event: tk.Event) -> None:
|
||||
if not self.underline:
|
||||
super(HyperlinkLabel, self).configure(font=self.font_n)
|
||||
super().configure(font=self.font_n)
|
||||
|
||||
def _click(self, event: tk.Event) -> None:
|
||||
if self.url and self['text'] and str(self['state']) != tk.DISABLED:
|
||||
|
||||
Reference in new issue
Block a user