3 Commits

Author SHA1 Message Date
8012d9b8ed fix(gismeteo): add max_date validation 2026-06-14 10:23:38 +03:00
3a6faa85be fix(gismeteo): add new variants to sky parser 2026-06-14 10:23:13 +03:00
1af61aa3c7 feat(easel): add sky details tooltip 2026-06-14 10:22:43 +03:00
5 changed files with 39 additions and 9 deletions

View File

@@ -54,7 +54,7 @@
</tr>
<tr>
{% for value in response.values %}
<td class="cloudness">
<td class="cloudness" data-bs-toggle="tooltip" data-bs-title="{{ value.sky }}">
{% for icon in value.sky | cloudness_icon %}
<div class="icon">{{icon}}</div>
{% endfor %}

View File

@@ -4,6 +4,7 @@ import logging
from typing import Any
from bs4 import BeautifulSoup
from fastapi import HTTPException, status
from gallery.sketch.source import ApiSource
from gallery.sketch.weather.api import WeatherApi
@@ -99,6 +100,11 @@ class GismeteoApi(WeatherApi):
return result
async def get_day(self, location_id: str, date: datetime.date) -> WeatherResponse:
max_date = datetime.date.today() + datetime.timedelta(days=9)
if date > max_date:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail={"max_date": max_date.strftime("%Y-%m-%d")}
)
data = await self.SOURCE.request(f"weather-{location_id}/{datehelp.dump(date)}")
return self._parse_oneday(date, data)

View File

@@ -1,4 +1,5 @@
import datetime
import logging
import re
from typing import Iterable
@@ -15,6 +16,8 @@ from gallery.sketch.weather.model import (
from .core import BaseWidgetParser, RowParser
logger = logging.getLogger("gismeteo")
ONE_DAY_PARSER = BaseWidgetParser(".widget.widget-oneday .widget-items")
DAYS_PARSER = BaseWidgetParser(".widget.widget-days .widget-items")
@@ -57,6 +60,7 @@ class SkyParser(RowParser[Sky]):
CLOUDNESS_MAP: dict[str, Cloudness] = {
"ясно": Cloudness.CLEAR,
"безоблачно": Cloudness.CLEAR,
"малооблачно": Cloudness.PARTLY_CLOUDY,
"облачно": Cloudness.CLOUDY,
"пасмурно": Cloudness.MAINLY_CLOUDY,
@@ -64,8 +68,10 @@ class SkyParser(RowParser[Sky]):
PRECIPITATION_MAP: dict[str, Precipitation] = {
"без осадков": Precipitation.NO,
"небольшой дождь": Precipitation.SMALL_RAIN,
"небольшой дождь": Precipitation.SMALL_RAIN, # TODO: remove it?
"небольшой дождь": Precipitation.SMALL_RAIN,
"сильный дождь": Precipitation.HEAVY_RAIN,
"ливневый дождь": Precipitation.SHOWER,
"дождь": Precipitation.RAIN,
"ливень": Precipitation.SHOWER,
"снег": Precipitation.SNOW,
@@ -78,22 +84,35 @@ class SkyParser(RowParser[Sky]):
"небольшой мокрый снег": Precipitation.SNOW,
}
THUNDER = "гроза"
FOG = "дымка"
def parse_row(self, tag: Tag) -> Iterable[Sky]:
for item in tag.select(".widget-row[data-row=icon-tooltip] > .row-item"):
sky_str = item.attrs["data-tooltip"]
values = {item.strip().lower() for item in sky_str.split(",")}
cloudness = Cloudness.CLEAR
precipitation = Precipitation.NO
thunder = "гроза" in values
fog = "дымка" in values
thunder = False
fog = False
if self.THUNDER in values:
thunder = True
values.remove(self.THUNDER)
if self.FOG in values:
fog = True
values.remove(self.FOG)
for k, v in self.CLOUDNESS_MAP.items():
if k in values:
cloudness = v
values.remove(k)
break
for k, v in self.PRECIPITATION_MAP.items():
if k in values:
precipitation = v
values.remove(k)
break
if values:
logger.warning("unknown sky values: %s:", values)
yield Sky(
cloudness=cloudness,
precipitation=precipitation,

View File

@@ -1,5 +1,10 @@
import "./main.scss";
import "bootstrap";
import "./theme";
import "./language";
import * as bootstrap from "bootstrap";
import "./components";
import "./language";
import "./main.scss";
import "./theme";
document.addEventListener("DOMContentLoaded", (event) => {
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
const tooltipList = [...tooltipTriggerList].map((tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl));
});

View File

@@ -37,7 +37,7 @@
//@import "bootstrap/scss/close";
//@import "bootstrap/scss/toasts";
//@import "bootstrap/scss/modal";
//@import "bootstrap/scss/tooltip";
@import "bootstrap/scss/tooltip";
//@import "bootstrap/scss/popover";
//@import "bootstrap/scss/carousel";
//@import "bootstrap/scss/spinners";