200 lines
6.4 KiB
Python
200 lines
6.4 KiB
Python
|
from datetime import datetime, timedelta
|
||
|
from typing import Optional, List, Tuple
|
||
|
from locale import setlocale, LC_ALL
|
||
|
|
||
|
import re
|
||
|
|
||
|
from .location import Location
|
||
|
from .cruise import Cruise
|
||
|
from .flag import Flag
|
||
|
from .shipline import ShipLine
|
||
|
from ..const import IMAGE_BASE_PATH, TEMP_REGEX, HTML_REGEX, DEGREES_REGEX, SPEED_REGEX, GUST_REGEX
|
||
|
|
||
|
|
||
|
class Ship:
|
||
|
id: Optional[int]
|
||
|
name: Optional[str]
|
||
|
url: Optional[str]
|
||
|
url_deckplans: Optional[str]
|
||
|
url_staterooms: Optional[str]
|
||
|
image: Optional[str]
|
||
|
flag: Optional[Flag]
|
||
|
line: Optional[ShipLine]
|
||
|
spec_length: Optional[int] # stored in meters
|
||
|
spec_passengers: Optional[int]
|
||
|
year_built: Optional[int]
|
||
|
last_report: Optional[str]
|
||
|
imo: Optional[int]
|
||
|
mmsi: Optional[int]
|
||
|
latitude: Optional[float]
|
||
|
longitude: Optional[float]
|
||
|
cog: Optional[int] # Course over Ground
|
||
|
sog: Optional[int] # Speed over Ground
|
||
|
heading: Optional[int]
|
||
|
timestamp: Optional[datetime]
|
||
|
icon: Optional[int]
|
||
|
hover: Optional[str]
|
||
|
cruise: Optional[Cruise]
|
||
|
path: Optional[List[Optional[Location]]]
|
||
|
ports: Optional[List[Optional[Tuple[Optional[datetime], Optional[Location]]]]]
|
||
|
destination: Optional[str]
|
||
|
eta: Optional[datetime]
|
||
|
current_temperature: Optional[float] # Celsius
|
||
|
minimum_temperature: Optional[float] # Celsius
|
||
|
maximum_temperature: Optional[float] # Celsius
|
||
|
wind_degrees: Optional[float]
|
||
|
wind_speed: Optional[float] # m/s
|
||
|
wind_gust: Optional[float] # m/s
|
||
|
localtime: Optional[str]
|
||
|
|
||
|
@classmethod
|
||
|
def from_dict(cls, indict: dict):
|
||
|
obj = cls()
|
||
|
|
||
|
obj.id = indict.get("id")
|
||
|
obj.name = indict.get("name", indict.get("ship_name"))
|
||
|
obj.url = indict.get("url")
|
||
|
obj.url_deckplans = indict.get("url_deckplans")
|
||
|
obj.url_staterooms = indict.get("url_staterooms")
|
||
|
|
||
|
if "image" in indict:
|
||
|
obj.image = f"{IMAGE_BASE_PATH}{indict.get('image')}"
|
||
|
|
||
|
if "flag" in indict:
|
||
|
obj.flag = Flag(
|
||
|
code=indict["flag"].get("code"),
|
||
|
name=indict["flag"].get("name")
|
||
|
)
|
||
|
elif "ship_flag" in indict:
|
||
|
obj.flag = Flag(
|
||
|
code=indict.get("ship_flag")
|
||
|
)
|
||
|
|
||
|
if "line" in indict:
|
||
|
obj.line = ShipLine(
|
||
|
id=int(indict["line"]["id"]),
|
||
|
title=indict["line"].get("title"),
|
||
|
url=indict["line"].get("url")
|
||
|
)
|
||
|
elif "ship_line_id" in indict:
|
||
|
obj.line = ShipLine(
|
||
|
id=indict.get("ship_line_id"),
|
||
|
title=indict.get("ship_line_title")
|
||
|
)
|
||
|
|
||
|
if "spec_length" in indict:
|
||
|
parts = indict["spec_length"].split("/")
|
||
|
for part in parts:
|
||
|
if "m" in part:
|
||
|
try:
|
||
|
obj.spec_length = float(part.strip().split()[0])
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
if "spec_passengers" in indict:
|
||
|
obj.spec_passengers = int(indict["spec_passengers"])
|
||
|
|
||
|
if "year_of_built" in indict: # Those field names... 🤦
|
||
|
obj.year_built = int(indict["year_of_built"])
|
||
|
|
||
|
obj.last_report = indict.get("last_report")
|
||
|
|
||
|
if "imo" in indict:
|
||
|
obj.imo = int(indict["imo"])
|
||
|
|
||
|
if "mmsi" in indict:
|
||
|
obj.mmsi = int(indict["mmsi"])
|
||
|
|
||
|
if "lat" in indict and "lon" in indict:
|
||
|
obj.location = Location(indict["lat"], indict["lon"])
|
||
|
|
||
|
if "cog" in indict:
|
||
|
obj.cog = int(indict["cog"])
|
||
|
|
||
|
if "sog" in indict:
|
||
|
obj.sog = int(indict["sog"])
|
||
|
|
||
|
if "heading" in indict:
|
||
|
obj.heading = int(indict["heading"])
|
||
|
|
||
|
if "ts" in indict:
|
||
|
obj.timestamp = datetime.fromtimestamp(indict[ts])
|
||
|
|
||
|
obj.icon = indict.get("icon")
|
||
|
obj.hover = indict.get("hover")
|
||
|
|
||
|
if "cruise" in indict:
|
||
|
obj.cruise = Cruise.from_dict(indict["cruise"])
|
||
|
|
||
|
if "path" in indict:
|
||
|
if "points" in indict["path"]:
|
||
|
obj.path = list()
|
||
|
|
||
|
for point in indict["path"]["points"]:
|
||
|
lon, lat = point
|
||
|
obj.path.append(Location(lat, lon))
|
||
|
|
||
|
if "ports" in indict["path"]:
|
||
|
obj.ports = list()
|
||
|
|
||
|
for port in indict["path"]["ports"]:
|
||
|
if "dep_datetime" in port:
|
||
|
departure = datetime.strptime(
|
||
|
port["dep_datetime"], "%Y-%m-%d %H:%M:%S")
|
||
|
else:
|
||
|
departure = None
|
||
|
|
||
|
if "lat" in port and "lon" in port:
|
||
|
location = Location(port["lat"], port["lon"])
|
||
|
else:
|
||
|
location = None
|
||
|
|
||
|
obj.ports.append(departure, location)
|
||
|
|
||
|
obj.destination = indict.get("destination")
|
||
|
|
||
|
if "eta" in indict:
|
||
|
try:
|
||
|
previous = setlocale(LC_ALL)
|
||
|
setlocale(LC_ALL, "C")
|
||
|
obj.eta = datetime.strptime(date_string, "%d %B, %H:%M")
|
||
|
setlocale(LC_ALL, previous)
|
||
|
except:
|
||
|
obj.eta = None
|
||
|
|
||
|
if "weather" in indict:
|
||
|
temp_regex = re.compile(TEMP_REGEX)
|
||
|
html_regex = re.compile(HTML_REGEX)
|
||
|
degrees_regex = re.compile(DEGREES_REGEX)
|
||
|
speed_regex = re.compile(SPEED_REGEX)
|
||
|
gust_regex = re.compile(GUST_REGEX)
|
||
|
|
||
|
if "temperature" in indict["weather"]:
|
||
|
obj.current_temperature = float(re.search(temp_regex, re.sub(
|
||
|
html_regex, "", indict["weather"]["temperature"])).groups()[0])
|
||
|
if "wind" in indict["weather"]:
|
||
|
try:
|
||
|
obj.wind_degrees = int(
|
||
|
re.search(degrees_regex, indict["weather"]["wind"]).groups()[0])
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
try:
|
||
|
obj.wind_speed = float(
|
||
|
re.search(speed_regex, indict["weather"]["wind"]).groups()[0])
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
try:
|
||
|
obj.wind_gust = float(
|
||
|
re.search(speed_regex, indict["weather"]["wind"]).groups()[0])
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
obj.localtime = indict["weather"].get("localtime")
|
||
|
|
||
|
return obj
|
||
|
|
||
|
def __repr__(self):
|
||
|
return self.__dict__.__repr__()
|