Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spansh as a URL provider #2099

Merged
merged 2 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ def build() -> None:
"plugins/edsm.py",
"plugins/edsy.py",
"plugins/inara.py",
"plugins/spansh_core.py",
]
options: dict = {
"py2exe": {
Expand Down
4 changes: 2 additions & 2 deletions plugins/edsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,13 +199,13 @@ def plugin_start3(plugin_dir: str) -> str:
"""
Start the plugin.

:param plugin_dir: NAme of directory this was loaded from.
:param plugin_dir: Name of directory this was loaded from.
:return: Identifier string for this plugin.
"""
# Can't be earlier since can only call PhotoImage after window is created
this._IMG_KNOWN = tk.PhotoImage(data=IMG_KNOWN_B64) # green circle
this._IMG_UNKNOWN = tk.PhotoImage(data=IMG_UNKNOWN_B64) # red circle
this._IMG_NEW = tk.PhotoImage(data=IMG_NEW_B64)
this._IMG_NEW = tk.PhotoImage(data=IMG_NEW_B64) # yellow star
this._IMG_ERROR = tk.PhotoImage(data=IMG_ERR_B64) # BBC Mode 5 '?'

# Migrate old settings
Expand Down
195 changes: 195 additions & 0 deletions plugins/spansh_core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
"""
spansh_core.py - Spansh URL provider.

Copyright (c) EDCD, All Rights Reserved
Licensed under the GNU General Public License.
See LICENSE file.

This is an EDMC 'core' plugin.
All EDMC plugins are *dynamically* loaded at run-time.

We build for Windows using `py2exe`.
`py2exe` can't possibly know about anything in the dynamically loaded core plugins.

Thus, you **MUST** check if any imports you add in this file are only
referenced in this file (or only in any other core plugin), and if so...

YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
IN AN END-USER INSTALLATION ON WINDOWS.
"""
from __future__ import annotations

import tkinter as tk
from typing import Any, cast
import requests
from companion import CAPIData
from config import appname, config
from EDMCLogging import get_main_logger

logger = get_main_logger()


class This:
"""Holds module globals."""

def __init__(self):
self.parent: tk.Tk
self.shutting_down = False # Plugin is shutting down.
self.system_link: tk.Widget = None # type: ignore
C1701D marked this conversation as resolved.
Show resolved Hide resolved
self.system_name: str | None = None
self.system_address: str | None = None
self.system_population: int | None = None
self.station_link: tk.Widget = None # type: ignore
C1701D marked this conversation as resolved.
Show resolved Hide resolved
self.station_name = None
self.station_marketid = None
self.on_foot = False


this = This()
STATION_UNDOCKED: str = '×' # "Station" name to display when not docked = U+00D7


def plugin_start3(plugin_dir: str) -> str:
"""
Start the plugin.

:param plugin_dir: Name of directory this was loaded from.
:return: Identifier string for this plugin.
"""
return 'spansh'


def plugin_app(parent: tk.Tk) -> None:
"""
Construct this plugin's main UI, if any.

:param parent: The tk parent to place our widgets into.
:return: See PLUGINS.md#display
"""
this.parent = parent
this.system_link = parent.nametowidget(f".{appname.lower()}.system")
this.station_link = parent.nametowidget(f".{appname.lower()}.station")


def plugin_stop() -> None:
"""Plugin shutdown hook."""
this.shutting_down = True


def journal_entry(
cmdr: str, is_beta: bool, system: str, station: str, entry: dict[str, Any], state: dict[str, Any]
) -> str:
"""
Handle a new Journal event.

:param cmdr: Name of Commander.
:param is_beta: Whether game beta was detected.
:param system: Name of current tracked system.
:param station: Name of current tracked station location.
:param entry: The journal event.
:param state: `monitor.state`
:return: None if no error, else an error string.
"""
this.on_foot = state['OnFoot']
this.system_address = state['SystemAddress']
this.system_name = state['SystemName']
this.system_population = state['SystemPopulation']
this.station_name = state['StationName']
this.station_marketid = state['MarketID']

# Only actually change URLs if we are current provider.
if config.get_str('system_provider') == 'spansh':
this.system_link['text'] = this.system_name
# Do *NOT* set 'url' here, as it's set to a function that will call
# through correctly. We don't want a static string.
this.system_link.update_idletasks()

if config.get_str('station_provider') == 'spansh':
to_set: str = cast(str, this.station_name)
if not to_set:
if this.system_population is not None and this.system_population > 0:
to_set = STATION_UNDOCKED
else:
to_set = ''

this.station_link['text'] = to_set
# Do *NOT* set 'url' here, as it's set to a function that will call
# through correctly. We don't want a static string.
this.station_link.update_idletasks()

return ''


def cmdr_data(data: CAPIData, is_beta: bool) -> str | None:
"""
Process new CAPI data.

:param data: The latest merged CAPI data.
:param is_beta: Whether game beta was detected.
:return: Optional error string.
"""
# Always store initially, even if we're not the *current* system provider.
if not this.station_marketid and data['commander']['docked']:
this.station_marketid = data['lastStarport']['id']

# Only trust CAPI if these aren't yet set
if not this.system_name:
this.system_name = data['lastSystem']['name']
if not this.station_name and data['commander']['docked']:
this.station_name = data['lastStarport']['name']

# Override standard URL functions
if config.get_str('system_provider') == 'spansh':
this.system_link['text'] = this.system_name
# Do *NOT* set 'url' here, as it's set to a function that will call
# through correctly. We don't want a static string.
this.system_link.update_idletasks()
if config.get_str('station_provider') == 'spansh':
if data['commander']['docked'] or this.on_foot and this.station_name:
this.station_link['text'] = this.station_name
elif data['lastStarport']['name'] and data['lastStarport']['name'] != "":
this.station_link['text'] = STATION_UNDOCKED
else:
this.station_link['text'] = ''
# Do *NOT* set 'url' here, as it's set to a function that will call
# through correctly. We don't want a static string.
this.station_link.update_idletasks()

return ''


def system_url(system_name: str) -> str:
"""
Construct an appropriate spansh URL for the provided system.

:param system_name: Will be overridden with `this.system_address` if that
is set.
:return: The URL, empty if no data was available to construct it.
"""
if this.system_address:
return requests.utils.requote_uri(f'https://www.spansh.co.uk/system/{this.system_address}')

if system_name:
return requests.utils.requote_uri(f'https://www.spansh.co.uk/search/{system_name}')

return ''


def station_url(system_name: str, station_name: str) -> str:
"""
Construct an appropriate spansh URL for a station.

Ignores `station_name` in favour of `this.station_marketid`.

:param system_name: Name of the system the station is in.
:param station_name: **NOT USED**
:return: The URL, empty if no data was available to construct it.
"""
if this.station_marketid:
return requests.utils.requote_uri(f'https://www.spansh.co.uk/station/{this.station_marketid}')

if system_name:
return system_url(system_name)

return ''