diff --git a/ChangeLog.md b/ChangeLog.md index f23e7806..25fc8188 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,40 @@ This is the master changelog for Elite Dangerous Market Connector. Entries are in reverse chronological order (latest first). --- +Release 4.2.1 +=== + + This is a bug-fix release. + +* Updated translations. Thanks once again to all those contributing as per + [Translations](https://github.com/EDCD/EDMarketConnector/wiki/Translations). + +* PLUGINS.md: Clarify when `CargoJSON` is populated. + +* macOS: `pip install -r requirements.txt` will now include `pyobjc` so that + running this application works at all. Check the updated [Running from + source](https://github.com/EDCD/EDMarketConnector/wiki/Running-from-source) + for some advice if attempting to run on macOS. + +* JournalLock: Handle when the Journal directory isn't set at all, rather than + erroring. Fixes [#910 - Not launching (Linux)](https://github.com/EDCD/EDMarketConnector/issues/910). + +* Extra logging added to track down cause of [#909 - Authentication not possible (PC)](https://github.com/EDCD/EDMarketConnector/issues/909) + . The debug log file might now indicate what's wrong, or we might need + you to run + + ``` + "c:\Program Files (x86)\EDMarketConnector/EDMarketConnector.exe" --trace + ``` + in order to increase the log level and gather some extra information. + Caution is advised if sharing a `--trace` log file as it will now contain + some of the actual auth data returned from Frontier. + +* Ensure that 'Save Raw Data' will work. Fixes [#908 - Raw export of CAPI data broken](https://github.com/EDCD/EDMarketConnector/issues/908). + +* Prevent EDDN plugin from erroring when we determine if the commander has + Horizons. Fixes [#907 - Modules is a list not a dict on damaged stations](https://github.com/EDCD/EDMarketConnector/issues/907) + Release 4.2.0 === diff --git a/EDMarketConnector.py b/EDMarketConnector.py index bcc64c80..05aedc8d 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -33,7 +33,7 @@ if __name__ == '__main__': # After the redirect in case config does logging setup from config import appversion, appversion_nobuild, config, copyright from EDMCLogging import edmclogger, logger, logging -from journal_lock import JournalLock +from journal_lock import JournalLock, JournalLockResult if __name__ == '__main__': # noqa: C901 # Command-line arguments @@ -72,16 +72,14 @@ if __name__ == '__main__': # noqa: C901 config.set_auth_force_localserver() def handle_edmc_callback_or_foregrounding(): # noqa: CCR001 - """ - Handle any edmc:// auth callback, else foreground existing window. - """ + """Handle any edmc:// auth callback, else foreground existing window.""" logger.trace('Begin...') if platform == 'win32': # If *this* instance hasn't locked, then another already has and we # now need to do the edmc:// checks for auth callback - if not locked: + if locked != JournalLockResult.LOCKED: import ctypes from ctypes.wintypes import BOOL, HWND, INT, LPARAM, LPCWSTR, LPWSTR @@ -190,7 +188,7 @@ if __name__ == '__main__': # noqa: C901 handle_edmc_callback_or_foregrounding() - if not locked: + if locked == JournalLockResult.ALREADY_LOCKED: # There's a copy already running. logger.info("An EDMarketConnector.exe process was already running, exiting.") @@ -697,7 +695,7 @@ class AppWindow(object): system=data['lastSystem']['name'], station=data['commander'].get('docked') and '.' + data['lastStarport']['name'] or '', timestamp=strftime('%Y-%m-%dT%H.%M.%S', localtime())), 'wb') as h: - h.write(json.dumps(data, + h.write(json.dumps(dict(data), ensure_ascii=False, indent=2, sort_keys=True, @@ -920,6 +918,7 @@ class AppWindow(object): # cAPI auth def auth(self, event=None): + logger.debug('Received "<>') try: companion.session.auth_callback() # Successfully authenticated with the Frontier website @@ -927,14 +926,18 @@ class AppWindow(object): if platform == 'darwin': self.view_menu.entryconfigure(0, state=tk.NORMAL) # Status self.file_menu.entryconfigure(0, state=tk.NORMAL) # Save Raw Data + else: self.file_menu.entryconfigure(0, state=tk.NORMAL) # Status self.file_menu.entryconfigure(1, state=tk.NORMAL) # Save Raw Data + except companion.ServerError as e: self.status['text'] = str(e) + except Exception as e: logger.debug('Frontier CAPI Auth:', exc_info=e) self.status['text'] = str(e) + self.cooldown() # Handle Status event @@ -1119,7 +1122,7 @@ class AppWindow(object): initialfile=f'{last_system}{last_starport}.{timestamp}') if f: with open(f, 'wb') as h: - h.write(json.dumps(data, + h.write(json.dumps(dict(data), ensure_ascii=False, indent=2, sort_keys=True, diff --git a/L10n/cs.strings b/L10n/cs.strings index fad071e0..253b8d23 100644 --- a/L10n/cs.strings +++ b/L10n/cs.strings @@ -46,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "Procházet..."; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI: Nebyla vrácena žádná data komandéra"; + /* Federation rank. [stats.py] */ "Cadet" = "Cadet"; @@ -226,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "Klávesová zkratka"; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "Ignorovat"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Přihlašovací údaje k Inaře"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "Adresář deníku je již uzamčen"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "Klávesová zkratka"; @@ -409,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "Poznámky k verzi"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "Opakovat"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "Role"; @@ -454,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "Loděnice"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "Vypínání..."; + /* Empire rank. [stats.py] */ "Squire" = "Squire"; @@ -475,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "Systém"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "Nové umístění adresáře deníku je již uzamčeno. {CR} Můžete zkusit tento problém vyřešit a Opakovat, nebo Ignorovat."; + /* Appearance setting. [prefs.py] */ "Theme" = "Schéma"; diff --git a/L10n/de.strings b/L10n/de.strings index 73239607..492de5de 100644 --- a/L10n/de.strings +++ b/L10n/de.strings @@ -46,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "Durchsuchen..."; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI: Keine Kommandanten-Daten erhalten"; + /* Federation rank. [stats.py] */ "Cadet" = "Kadett"; @@ -226,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "Hotkey"; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "Ignorieren"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Inara-Anmeldedaten"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "Journal-Ordner bereits gesperrt"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "Makro"; @@ -409,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "Anmerkungen"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "Wiederholen"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "Rolle"; @@ -454,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "Werft"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "Programm schließt..."; + /* Empire rank. [stats.py] */ "Squire" = "Knappe"; @@ -475,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "System"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "Der neue Journal-Ordnerpfad ist bereits gesperrt.{CR}Du kannst entweder versuchen, das zu beheben und es nochmal zu probieren, oder diese Meldung ignorieren."; + /* Appearance setting. [prefs.py] */ "Theme" = "Theme"; diff --git a/L10n/fi.strings b/L10n/fi.strings index e3e5eacb..98782961 100644 --- a/L10n/fi.strings +++ b/L10n/fi.strings @@ -454,6 +454,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "Telakka"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "Sulkeutuu..."; + /* Empire rank. [stats.py] */ "Squire" = "Squire"; diff --git a/L10n/it.strings b/L10n/it.strings index 0706161f..c6f9258c 100644 --- a/L10n/it.strings +++ b/L10n/it.strings @@ -1,3 +1,9 @@ +/* Label for 'UI Scaling' option [prefs.py] */ +"UI Scale Percentage" = "Percentuale zoom della UI"; + +/* Text describing that value '100' means 'default', and changes require a restart [prefs.py] */ +"100 means Default{CR}Restart Required for{CR}changes to take effect!" = "100 significa Default{CR}Riavvio Richiesto per{CR}applicare i cambiamenti!"; + /* Language name */ "!Language" = "Italiano"; @@ -40,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "Sfoglia..."; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI: Nessun dato sul commandante"; + /* Federation rank. [stats.py] */ "Cadet" = "Cadet"; @@ -220,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "Hotkey"; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "Ignora"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Credenziali per Inara"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "cartella Journal già bloccata"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "Scorciatoia di tastiera"; @@ -403,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "Note di rilascio"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "Riprova"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "Ruolo"; @@ -448,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "Spazioporto"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "Spegnimento..."; + /* Empire rank. [stats.py] */ "Squire" = "Squire"; @@ -469,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "Sistema"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "La nuova cartella dove risiede il Journal è già bloccata.{CR}Puoi provare a risolvere Riprovando, oppure scegliere di ignorare la cosa."; + /* Appearance setting. [prefs.py] */ "Theme" = "Tema"; diff --git a/L10n/ja.strings b/L10n/ja.strings index 64bca474..3e933735 100644 --- a/L10n/ja.strings +++ b/L10n/ja.strings @@ -46,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "参照..."; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI: コマンダーのデータが返ってきませんでした"; + /* Federation rank. [stats.py] */ "Cadet" = "Cadet"; @@ -226,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "ホットキー"; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "無視"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Inara認証情報"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "ジャーナルディレクトリは既にロックされています"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "ショートカット"; @@ -409,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "リリースノート"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "再試行"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "役割"; @@ -454,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "造船所"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "終了します..."; + /* Empire rank. [stats.py] */ "Squire" = "Squire"; @@ -475,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "星系"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "新しいジャーナルディレクトリは既にロックされています。{CR}この問題を解決して再試行するか、無視するかを選択してください。"; + /* Appearance setting. [prefs.py] */ "Theme" = "テーマ"; diff --git a/L10n/pl.strings b/L10n/pl.strings index ee8d58a9..7f41bbdd 100644 --- a/L10n/pl.strings +++ b/L10n/pl.strings @@ -1,3 +1,9 @@ +/* Label for 'UI Scaling' option [prefs.py] */ +"UI Scale Percentage" = "Skalowanie UI"; + +/* Text describing that value '100' means 'default', and changes require a restart [prefs.py] */ +"100 means Default{CR}Restart Required for{CR}changes to take effect!" = "100 oznacza wartość domyślną{CR}Zmiany zostaną wprowadzone po{CR}ponownym uruchomieniu programu!"; + /* Language name */ "!Language" = "Polski"; @@ -40,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "Przeglądaj..."; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI: Nie zwrócono danych dowódcy"; + /* Federation rank. [stats.py] */ "Cadet" = "Cadet"; @@ -101,7 +110,7 @@ "Delay sending until docked" = "Czekaj z wysłaniem na zadokowanie"; /* Option to disabled Automatic Check For Updates whilst in-game [prefs.py] */ -"Disable Automatic Application Updates Check when in-game" = "Wyłącz Sprawdzanie Aktualnej Wersji Aplikacji, gdy jesteś w grze"; +"Disable Automatic Application Updates Check when in-game" = "Wyłącz automatyczne wyszukiwanie aktualizacji, gdy jesteś w grze"; /* List of plugins in settings. [prefs.py] */ "Disabled Plugins" = "Pluginy wyłączone"; @@ -220,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "Skr. Klaw."; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "Zignoruj"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Inara - uprawnienia"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "Katalog dziennika zablokowany"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "Skrót klawiaturowy"; @@ -403,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "Informacje o wersji"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "Ponów"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "Rola"; @@ -448,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "Stocznia"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "Wyłączanie..."; + /* Empire rank. [stats.py] */ "Squire" = "Squire"; @@ -469,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "System"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "Nowa pozycja katalogu dziennika jest zablokowana. {CR}Możesz spróbować to rozwiązać na własną rękę lub zignorować."; + /* Appearance setting. [prefs.py] */ "Theme" = "Schemat kolorystyczny"; @@ -525,3 +549,6 @@ /* Shortcut settings prompt on OSX. [prefs.py] */ "{APP} needs permission to use shortcuts" = "{APP} wymaga uprawnień by{CR}móc korzystać ze skrótów klawiszowych."; + +/* Label for user configured level of logging [prefs.py] */ +"Log Level" = "Poziom logowania"; diff --git a/L10n/pt-PT.strings b/L10n/pt-PT.strings index 79542cf1..9b5ec61e 100644 --- a/L10n/pt-PT.strings +++ b/L10n/pt-PT.strings @@ -46,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "Procurar..."; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI: Dados do Comandante não recebidos"; + /* Federation rank. [stats.py] */ "Cadet" = "Cadete"; @@ -226,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "Tecla Rápida"; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "Ignorar"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Credenciais Inara"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "Directório do Diário já se encontra bloqueado"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "Atalho de Teclado"; @@ -409,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "Notas da Versão"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "Tentar Novamente"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "Função"; @@ -454,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "Estaleiro"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "A Desligar..."; + /* Empire rank. [stats.py] */ "Squire" = "Escudeiro"; @@ -475,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "Sistema"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "O novo directório do Diário já se encontra bloqueado.{CR}Pode tentar resolver este problema e depois Tentar Novamente, ou Ignorar isto."; + /* Appearance setting. [prefs.py] */ "Theme" = "Tema"; diff --git a/L10n/ru.strings b/L10n/ru.strings index 64a8c6dc..934ab0b8 100644 --- a/L10n/ru.strings +++ b/L10n/ru.strings @@ -46,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "Просмотреть..."; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI: Нет данных пилота"; + /* Federation rank. [stats.py] */ "Cadet" = "Кадет"; @@ -226,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "Горячая клавиша"; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "Игнорировать"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Учётные данные Inara"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "Каталог журнала уже заблокирован"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "Сочетание клавиш"; @@ -409,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "Заметки о текущем релизе"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "Повтор"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "Роль"; @@ -454,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "Верфи"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "Выключение..."; + /* Empire rank. [stats.py] */ "Squire" = "Оруженосец"; @@ -475,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "Система"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "Каталог журнала заблокирован..{CR}Вы можете устранить ошибку и нажать \"Повтор\", или игнорировать эту ошибку."; + /* Appearance setting. [prefs.py] */ "Theme" = "Тема оформления"; diff --git a/L10n/sr-Latn-BA.strings b/L10n/sr-Latn-BA.strings index 70c6e66b..d9dba531 100644 --- a/L10n/sr-Latn-BA.strings +++ b/L10n/sr-Latn-BA.strings @@ -46,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "Potraži..."; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI: Nema podataka o komandantu"; + /* Federation rank. [stats.py] */ "Cadet" = "Cadet"; @@ -226,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "Prečica"; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "Ignoriši"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Kredencijali za Inara"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "Journal direktorijum je već zaključan"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "Prečica"; @@ -409,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "Informacije o verziji"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "Probaj ponovo"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "Uloga"; @@ -454,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "Brodogradilište"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "Zatvaranje programa..."; + /* Empire rank. [stats.py] */ "Squire" = "Squire"; @@ -475,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "Sistem"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "Novi journal direktorijum je već zaključan.{CR}Možete pokušati da riješite problem i Probate ponovo ili da ga Ignorišete."; + /* Appearance setting. [prefs.py] */ "Theme" = "Tema"; diff --git a/L10n/sr-Latn.strings b/L10n/sr-Latn.strings index 39f5bce3..9154e070 100644 --- a/L10n/sr-Latn.strings +++ b/L10n/sr-Latn.strings @@ -46,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "Potraži..."; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI: Nema podataka o komandiru"; + /* Federation rank. [stats.py] */ "Cadet" = "Cadet"; @@ -226,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "Skraćenica"; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "Ignoriši"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Inara kredencijali"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "Žurnal direktorijum je već zaključan"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "Skraćenica"; @@ -409,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "Informacije o ovoj verziji"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "Probaj ponovo"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "Uloga"; @@ -454,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "Shipyard"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "Gasim..."; + /* Empire rank. [stats.py] */ "Squire" = "Squire"; @@ -475,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "Sistem"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "Novi Žurnal direktorijum je već zaključan.{CR}Možete probati da rešite problem i probate ponovo ili da ga ignorišete."; + /* Appearance setting. [prefs.py] */ "Theme" = "Tema"; diff --git a/L10n/zh-Hans.strings b/L10n/zh-Hans.strings index 68827d9d..16d3102d 100644 --- a/L10n/zh-Hans.strings +++ b/L10n/zh-Hans.strings @@ -1,3 +1,9 @@ +/* Label for 'UI Scaling' option [prefs.py] */ +"UI Scale Percentage" = "UI 缩放比例"; + +/* Text describing that value '100' means 'default', and changes require a restart [prefs.py] */ +"100 means Default{CR}Restart Required for{CR}changes to take effect!" = "100 为默认设置{CR}需要重启应用{CR}以使修改生效"; + /* Language name */ "!Language" = "简体中文"; @@ -40,6 +46,9 @@ /* Folder selection button on Windows. [prefs.py] */ "Browse..." = "浏览…"; +/* No 'commander' data in CAPI [EDMarketConnector.py] */ +"CAPI: No commander data returned" = "CAPI:没有指挥官数据"; + /* Federation rank. [stats.py] */ "Cadet" = "Cadet"; @@ -50,7 +59,7 @@ "Change..." = "更改…"; /* Menu item. [EDMarketConnector.py] */ -"Check for Updates..." = "检查可用更新…"; +"Check for Updates..." = "检查版本更新…"; /* Federation rank. [stats.py] */ "Chief Petty Officer" = "Chief Petty Officer"; @@ -100,6 +109,9 @@ /* Output setting under 'Send system and scan data to the Elite Dangerous Data Network' new in E:D 2.2. [eddn.py] */ "Delay sending until docked" = "延时更新,靠站时再发送"; +/* Option to disabled Automatic Check For Updates whilst in-game [prefs.py] */ +"Disable Automatic Application Updates Check when in-game" = "当我在玩游戏时,禁止此应用自动检查版本更新。"; + /* List of plugins in settings. [prefs.py] */ "Disabled Plugins" = "已禁用插件"; @@ -217,9 +229,15 @@ /* Hotkey/Shortcut settings prompt on Windows. [prefs.py] */ "Hotkey" = "快捷键"; +/* Changed journal update_lock failed [monitor.py] */ +"Ignore" = "忽略"; + /* Section heading in settings. [inara.py] */ "Inara credentials" = "Inara 授权凭证"; +/* Changed journal update_lock failed [monitor.py] */ +"Journal directory already locked" = "日志目录已被锁定"; + /* Hotkey/Shortcut settings prompt on OSX. [prefs.py] */ "Keyboard shortcut" = "键盘快捷键"; @@ -334,6 +352,18 @@ /* Section heading in settings. [prefs.py] */ "Plugins folder" = "插件文件夹"; +/* Popup title: Warning about plugins without Python 3.x support [EDMarketConnector.py] */ +"EDMC: Plugins Without Python 3.x Support" = "EDMC:不支持 Python 3.x 的插件"; + +/* Popup body: Warning about plugins without Python 3.x support [EDMarketConnector.py] */ +"One or more of your enabled plugins do not yet have support for Python 3.x. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an updated version available, else alert the developer that they need to update the code for Python 3.x.\r\n\r\nYou can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name." = "一项或多项你所启用的插件尚不支持 Python 3.x,详情请见 {FILE} > {SETTINGS} > {PLUGINS}。请检查上述插件是否有可用的更新,若没有,则应与插件的开发者就 Python 3.x 的支持问题取得联系。\n\n你也可以禁用某一项插件,只需在其文件夹名称的末尾添加 {DISABLED} 即可。"; + +/* Settings>Plugins>Plugins without Python 3.x support [prefs.py] */ +"Plugins Without Python 3.x Support" = "不支持 Python 3.x 的插件"; + +/* Settings>Plugins>Information on migrating plugins [prefs.py] */ +"Information on migrating plugins" = "关于插件迁移"; + /* Federation rank. [stats.py] */ "Post Captain" = "Post Captain"; @@ -388,6 +418,9 @@ /* Help menu item. [EDMarketConnector.py] */ "Release Notes" = "更新说明"; +/* Changed journal update_lock failed [monitor.py] */ +"Retry" = "重试"; + /* Multicrew role label in main window. [EDMarketConnector.py] */ "Role" = "角色"; @@ -433,6 +466,9 @@ /* Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis. [prefs.py] */ "Shipyard" = "配船"; +/* Status line text that appears when process exit sequence starts [EDMarketConnector.py] */ +"Shutting down..." = "应用关闭中…"; + /* Empire rank. [stats.py] */ "Squire" = "Squire"; @@ -454,6 +490,9 @@ /* Main window. [EDMarketConnector.py] */ "System" = "星系"; +/* Changed journal update_lock failed [monitor.py] */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "新的日志目录位置已被锁定。{CR}你可以尝试解锁并“重试”以解决此问题,或者选择“忽略”。"; + /* Appearance setting. [prefs.py] */ "Theme" = "主题"; @@ -475,6 +514,9 @@ /* Update button in main window. [EDMarketConnector.py] */ "Update" = "更新"; +/* Option to use alternate URL method on shipyard links [prefs.py] */ +"Use alternate URL method" = "若链接过长无法打开,请勾选此项"; + /* Status dialog subtitle - CR value of ship. [stats.py] */ "Value" = "价值"; @@ -508,3 +550,5 @@ /* Shortcut settings prompt on OSX. [prefs.py] */ "{APP} needs permission to use shortcuts" = "{APP} 需要权限以使用快捷键"; +/* Label for user configured level of logging [prefs.py] */ +"Log Level" = "诊断模式"; diff --git a/PLUGINS.md b/PLUGINS.md index 14c46ada..337c80ed 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -460,8 +460,13 @@ typically about once a second when in orbital flight. New in version 4.1.6: -`CargoJSON` contains the raw data from the last read of `cargo.json` passed through json.load. -It contains more information about the cargo contents, such as the mission ID for mission specific cargo +`CargoJSON` contains the raw data from the last read of `Cargo.json` passed +through json.load. It contains more information about the cargo contents, such +as the mission ID for mission specific cargo + +**NB: Because this is only the data loaded from the `Cargo.json` file, and that +is not written at Commander login (instead the in-Journal `Cargo` event +contains all the data), this will not be populated at login.** #### Getting Commander Data diff --git a/companion.py b/companion.py index 850f3a7a..36fb62cb 100644 --- a/companion.py +++ b/companion.py @@ -263,6 +263,7 @@ class Auth(object): except (ValueError, requests.RequestException, ): logger.exception(f"Frontier CAPI Auth: Can't refresh token for \"{self.cmdr}\"") + self.dump(r) else: logger.error(f"Frontier CAPI Auth: No token for \"{self.cmdr}\"") @@ -360,7 +361,11 @@ class Auth(object): # noinspection PyMethodMayBeStatic def dump(self, r: requests.Response) -> None: """Dump details of HTTP failure from oAuth attempt.""" - logger.debug(f'Frontier CAPI Auth: {r.url} {r.status_code} {r.reason if r.reason else "None"} {r.text}') + if r: + logger.debug(f'Frontier CAPI Auth: {r.url} {r.status_code} {r.reason if r.reason else "None"} {r.text}') + + else: + logger.debug(f'Frontier CAPI Auth: failed with `r` False: {r!r}') # noinspection PyMethodMayBeStatic def base64_url_encode(self, text: bytes) -> str: @@ -432,8 +437,8 @@ class Session(object): # Callback from protocol handler def auth_callback(self) -> None: - """Handle callback from edmc:// handler.""" - logger.debug('Handling callback from edmc:// handler') + """Handle callback from edmc:// or localhost:/auth handler.""" + logger.debug('Handling auth callback') if self.state != Session.STATE_AUTH: # Shouldn't be getting a callback logger.debug('Got an auth callback while not doing auth') diff --git a/config.py b/config.py index 0f2144bb..f611043f 100644 --- a/config.py +++ b/config.py @@ -13,7 +13,7 @@ appcmdname = 'EDMC' # appversion **MUST** follow Semantic Versioning rules: # # Major.Minor.Patch(-prerelease)(+buildmetadata) -appversion = '4.2.0' #-rc1+a872b5f' +appversion = '4.2.1' #-rc1+a872b5f' # For some things we want appversion without (possible) +build metadata appversion_nobuild = str(semantic_version.Version(appversion).truncate('prerelease')) copyright = u'© 2015-2019 Jonathan Harris, 2020 EDCD' diff --git a/journal_lock.py b/journal_lock.py index 33279c76..51f94f89 100644 --- a/journal_lock.py +++ b/journal_lock.py @@ -2,6 +2,7 @@ import pathlib import tkinter as tk +from enum import Enum from os import getpid as os_getpid from sys import platform from tkinter import ttk @@ -17,23 +18,49 @@ if TYPE_CHECKING: return x +class JournalLockResult(Enum): + """Enumeration of possible outcomes of trying to lock the Journal Directory.""" + + LOCKED = 1 + JOURNALDIR_NOTEXIST = 2 + JOURNALDIR_READONLY = 3 + ALREADY_LOCKED = 4 + JOURNALDIR_IS_NONE = 5 + + class JournalLock: """Handle locking of journal directory.""" def __init__(self) -> None: """Initialise where the journal directory and lock file are.""" self.journal_dir: str = config.get('journaldir') or config.default_journal_dir - self.journal_dir_path = pathlib.Path(self.journal_dir) + self.journal_dir_path: Optional[pathlib.Path] = None + self.set_path_from_journaldir() self.journal_dir_lockfile_name: Optional[pathlib.Path] = None # We never test truthiness of this, so let it be defined when first assigned. Avoids type hint issues. # self.journal_dir_lockfile: Optional[IO] = None + self.locked = False - def obtain_lock(self) -> bool: + def set_path_from_journaldir(self): + if self.journal_dir is None: + self.journal_dir_path = None + + else: + try: + self.journal_dir_path = pathlib.Path(self.journal_dir) + + except Exception: + logger.exception("Couldn't make pathlib.Path from journal_dir") + + def obtain_lock(self) -> JournalLockResult: """ Attempt to obtain a lock on the journal directory. - :return: bool - True if we successfully obtained the lock + :return: LockResult - See the class Enum definition """ + if self.journal_dir_path is None: + return JournalLockResult.JOURNALDIR_IS_NONE + self.journal_dir_lockfile_name = self.journal_dir_path / 'edmc-journal-lock.txt' logger.trace(f'journal_dir_lockfile_name = {self.journal_dir_lockfile_name!r}') try: @@ -44,7 +71,7 @@ class JournalLock: except Exception as e: # For remote FS this could be any of a wide range of exceptions logger.warning(f"Couldn't open \"{self.journal_dir_lockfile_name}\" for \"w+\"" f" Aborting duplicate process checks: {e!r}") - return False + return JournalLockResult.JOURNALDIR_READONLY if platform == 'win32': logger.trace('win32, using msvcrt') @@ -57,7 +84,7 @@ class JournalLock: except Exception as e: logger.info(f"Exception: Couldn't lock journal directory \"{self.journal_dir}\"" f", assuming another process running: {e!r}") - return False + return JournalLockResult.ALREADY_LOCKED else: logger.trace('NOT win32, using fcntl') @@ -67,7 +94,7 @@ class JournalLock: except ImportError: logger.warning("Not on win32 and we have no fcntl, can't use a file lock!" "Allowing multiple instances!") - return True # Lie about being locked + return JournalLockResult.LOCKED try: fcntl.flock(self.journal_dir_lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB) @@ -75,20 +102,25 @@ class JournalLock: except Exception as e: logger.info(f"Exception: Couldn't lock journal directory \"{self.journal_dir}\", " f"assuming another process running: {e!r}") - return False + return JournalLockResult.ALREADY_LOCKED self.journal_dir_lockfile.write(f"Path: {self.journal_dir}\nPID: {os_getpid()}\n") self.journal_dir_lockfile.flush() logger.trace('Done') - return True + self.locked = True + + return JournalLockResult.LOCKED def release_lock(self) -> bool: """ Release lock on journal directory. - :return: bool - Success of unlocking operation. + :return: bool - Whether we're now unlocked. """ + if not self.locked: + return True # We weren't locked, and still aren't + unlocked = False if platform == 'win32': logger.trace('win32, using msvcrt') @@ -206,8 +238,9 @@ class JournalLock: self.release_lock() self.journal_dir = current_journaldir - self.journal_dir_path = pathlib.Path(self.journal_dir) - if not self.obtain_lock(): + self.set_path_from_journaldir() + + if self.obtain_lock() == JournalLockResult.ALREADY_LOCKED: # Pop-up message asking for Retry or Ignore self.retry_popup = self.JournalAlreadyLocked(parent, self.retry_lock) @@ -225,7 +258,7 @@ class JournalLock: current_journaldir = config.get('journaldir') or config.default_journal_dir self.journal_dir = current_journaldir - self.journal_dir_path = pathlib.Path(self.journal_dir) - if not self.obtain_lock(): + self.set_path_from_journaldir() + if self.obtain_lock() == JournalLockResult.ALREADY_LOCKED: # Pop-up message asking for Retry or Ignore self.retry_popup = self.JournalAlreadyLocked(parent, self.retry_lock) diff --git a/plugins/eddn.py b/plugins/eddn.py index 29de4910..a8a34b48 100644 --- a/plugins/eddn.py +++ b/plugins/eddn.py @@ -789,8 +789,30 @@ MAP_STR_ANY = Mapping[str, Any] def is_horizons(economies: MAP_STR_ANY, modules: MAP_STR_ANY, ships: MAP_STR_ANY) -> bool: - return ( - any(economy['name'] == 'Colony' for economy in economies.values()) or - any(module.get('sku') == HORIZ_SKU for module in modules.values()) or - any(ship.get('sku') == HORIZ_SKU for ship in (ships['shipyard_list'] or {}).values()) - ) + economies_colony = False + modules_horizons = False + ship_horizons = False + + if isinstance(economies, dict): + economies_colony = any(economy['name'] == 'Colony' for economy in economies.values()) + + else: + logger.error(f'economies type is {type(economies)}') + + if isinstance(modules, dict): + modules_horizons = any(module.get('sku') == HORIZ_SKU for module in modules.values()) + + else: + logger.error(f'modules type is {type(modules)}') + + if isinstance(ships, dict): + if ships.get('shipyard_list') is not None: + ship_horizons = any(ship.get('sku') == HORIZ_SKU for ship in ships['shipyard_list'].values()) + + else: + logger.debug('No ships["shipyard_list"] - Damaged station or FC ?') + + else: + logger.error(f'ships type is {type(ships)}') + + return economies_colony or modules_horizons or ship_horizons diff --git a/protocol.py b/protocol.py index 9dd9aba5..dcaa8b99 100644 --- a/protocol.py +++ b/protocol.py @@ -36,7 +36,9 @@ class GenericProtocolHandler(object): def event(self, url): self.lastpayload = url + logger.trace(f'Payload: {self.lastpayload}') if not config.shutting_down: + logger.debug('event_generate("<>"') self.master.event_generate('<>', when="tail") @@ -190,12 +192,16 @@ elif sys.platform == 'win32' and getattr(sys, 'frozen', False) and not is_wine a None) msg = MSG() while GetMessage(byref(msg), None, 0, 0) != 0: + logger.trace(f'DDE message of type: {msg.message}') if msg.message == WM_DDE_EXECUTE: args = wstring_at(GlobalLock(msg.lParam)).strip() GlobalUnlock(msg.lParam) if args.lower().startswith('open("') and args.endswith('")'): + logger.trace(f'args are: {args}') url = urllib.parse.unquote(args[6:-2]).strip() + logger.trace(f'Parsed url: {url}') if url.startswith(self.redirect): + logger.debug(f'Message starts with {self.redirect}') self.event(url) SetForegroundWindow(GetParent(self.master.winfo_id())) # raise app window PostMessage(msg.wParam, WM_DDE_ACK, hwnd, PackDDElParam(WM_DDE_ACK, 0x80, msg.lParam)) @@ -242,8 +248,10 @@ else: # Linux / Run from source class HTTPRequestHandler(BaseHTTPRequestHandler): def parse(self): + logger.trace(f'Got message on path: {self.path}') url = urllib.parse.unquote(self.path) if url.startswith('/auth'): + logger.debug('Request starts with /auth, sending to protocolhandler.event()') protocolhandler.event(url) self.send_response(200) return True diff --git a/requirements.txt b/requirements.txt index 7f6952ba..a7079592 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,6 @@ watchdog==0.10.3 # argh==0.26.2 watchdog dep # pyyaml==5.3.1 watchdog dep semantic-version==2.8.5 + +# Base requirement for MacOS +pyobjc; sys_platform == 'darwin'