python-library-ff14-the-hunt 0.0.2__tar.gz → 0.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/.cursor/skills/ff14_the_hunt-package-changelog/SKILL.md +2 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/PKG-INFO +1 -1
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/README.md +1 -1
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/ff14_the_hunt.py +2 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/cn.py +1 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/en.py +1 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/models.py +1 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/poll/loop.py +12 -1
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/pyproject.toml +1 -4
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_ff14_the_hunt_service.py +14 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_locale_cn.py +1 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/.cursor/skills/ff14_the_hunt-package-design/SKILL.md +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/.cursor/skills/ff14_the_hunt-package-preload/SKILL.md +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/.gitignore +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/example/__main__.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/example/spawn_map_io.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/example.bat +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/__init__.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/bear_tracker/__init__.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/bear_tracker/client.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/bear_tracker/enrich.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/bear_tracker/fate_timer.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/bear_tracker/resources.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/bear_tracker/spawn_points.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/bear_tracker/spawn_window.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/bear_tracker/timer_theme.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/__init__.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/data/__init__.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/data/hunts_zh.json +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/data/regions_zh.json +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/detect.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/display.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/names.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/spawn_map_display.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/tag.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/poll/__init__.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/poll/monitor_mode.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/poll/scheduler.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/poll/sleep_plan.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/poll/sleep_settings.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/poll/spawn_dedup.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/poll/window_remaining.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/spawn_map/__init__.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/spawn_map/attach.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/spawn_map/coordinates.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/spawn_map/layout.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/spawn_map/png_meta.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/spawn_map/points.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/spawn_map/region_fetch.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/spawn_map/region_image.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/test.bat +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/__init__.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_fate_timer.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_monitor_mode.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_poll_scheduler.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_poll_sleep.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_spawn_dedup.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_spawn_map_data.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_spawn_map_points.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_spawn_window.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_untimed_marks_filter.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tools/build_locale_data.py +0 -0
- {python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/update.bat +0 -0
|
@@ -9,6 +9,8 @@ description: ff14_the_hunt 包:要求与决议;最新在上。
|
|
|
9
9
|
|
|
10
10
|
## 2026-06-08
|
|
11
11
|
|
|
12
|
+
- **决议**:``wait_or_stop`` 改为分段 ``Event.wait``(默认 1 秒一片),便于 ``stop()`` / Ctrl+C 尽快打断长睡。
|
|
13
|
+
- **决议**:发布 ``0.0.3``:``HuntCrawlPacket`` 增加 ``next_fetch_at``(按计划下次爬取的 Unix 秒);locale 导出同步。
|
|
12
14
|
- **决议**:发布 ``0.0.2``:包级导出 ``HuntCrawlPacket``、locale、poll 等;与 ff14hub 首版所需 API 对齐。
|
|
13
15
|
|
|
14
16
|
## 2026-06-07
|
|
@@ -333,8 +333,10 @@ class FF14TheHunt:
|
|
|
333
333
|
crawled_at = self._scheduler.last_crawl_at
|
|
334
334
|
if crawled_at is None:
|
|
335
335
|
crawled_at = time.time()
|
|
336
|
+
wait_seconds = self._scheduler.seconds_until_next_fetch(now=crawled_at)
|
|
336
337
|
return HuntCrawlPacket(
|
|
337
338
|
crawled_at=crawled_at,
|
|
339
|
+
next_fetch_at=crawled_at + wait_seconds,
|
|
338
340
|
marks=marks,
|
|
339
341
|
query=self._query,
|
|
340
342
|
)
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/cn.py
RENAMED
|
@@ -186,6 +186,7 @@ def crawl_packet_to_display_dict(
|
|
|
186
186
|
payload: dict[str, object] = {
|
|
187
187
|
"配置": query_to_display_dict(packet.query),
|
|
188
188
|
"爬取时间": packet.crawled_at,
|
|
189
|
+
"下次爬取时间": packet.next_fetch_at,
|
|
189
190
|
"怪物": [_mark_dict(mark) for mark in packet.marks],
|
|
190
191
|
}
|
|
191
192
|
if recently_spawned is not None:
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/locale/en.py
RENAMED
|
@@ -172,6 +172,7 @@ def crawl_packet_to_display_dict(
|
|
|
172
172
|
payload: dict[str, object] = {
|
|
173
173
|
"query": query_to_display_dict(packet.query),
|
|
174
174
|
"crawled_at": packet.crawled_at,
|
|
175
|
+
"next_fetch_at": packet.next_fetch_at,
|
|
175
176
|
"marks": [_mark_dict(mark) for mark in packet.marks],
|
|
176
177
|
}
|
|
177
178
|
if recently_spawned is not None:
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/models.py
RENAMED
|
@@ -189,6 +189,7 @@ class HuntCrawlPacket(BaseModel):
|
|
|
189
189
|
model_config = ConfigDict(extra="ignore")
|
|
190
190
|
|
|
191
191
|
crawled_at: float = Field(description="爬取完成时的 Unix 秒")
|
|
192
|
+
next_fetch_at: float = Field(description="按计划下次爬取的 Unix 秒")
|
|
192
193
|
marks: list[HuntMarkRecord] = Field(default_factory=list, description="解析后的狩猎记录")
|
|
193
194
|
query: HuntQueryFilter = Field(description="本次爬取使用的筛选条件")
|
|
194
195
|
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/poll/loop.py
RENAMED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import threading
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
_WAIT_SLICE_SECONDS = 1.0
|
|
4
7
|
|
|
5
8
|
|
|
6
9
|
def wait_or_stop(stop_event: threading.Event, seconds: float) -> bool:
|
|
@@ -15,4 +18,12 @@ def wait_or_stop(stop_event: threading.Event, seconds: float) -> bool:
|
|
|
15
18
|
"""
|
|
16
19
|
if seconds <= 0:
|
|
17
20
|
return stop_event.is_set()
|
|
18
|
-
|
|
21
|
+
deadline = time.monotonic() + seconds
|
|
22
|
+
while not stop_event.is_set():
|
|
23
|
+
remaining = deadline - time.monotonic()
|
|
24
|
+
if remaining <= 0:
|
|
25
|
+
return False
|
|
26
|
+
slice_seconds = min(remaining, _WAIT_SLICE_SECONDS)
|
|
27
|
+
if stop_event.wait(timeout=slice_seconds):
|
|
28
|
+
return True
|
|
29
|
+
return True
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-library-ff14-the-hunt"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.3"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
dependencies = [
|
|
10
10
|
"pydantic>=2.0",
|
|
@@ -15,6 +15,3 @@ dev = ["pytest>=8.0"]
|
|
|
15
15
|
|
|
16
16
|
[tool.hatch.build.targets.wheel]
|
|
17
17
|
packages = ["ff14_the_hunt"]
|
|
18
|
-
|
|
19
|
-
[tool.hatch.build.targets.wheel.force-include]
|
|
20
|
-
"ff14_the_hunt/locale/data" = "ff14_the_hunt/locale/data"
|
|
@@ -73,6 +73,7 @@ def test_crawl_once_returns_packet() -> None:
|
|
|
73
73
|
assert isinstance(packet, HuntCrawlPacket)
|
|
74
74
|
assert packet.query is hunt.query
|
|
75
75
|
assert len(packet.marks) == 1
|
|
76
|
+
assert packet.next_fetch_at >= packet.crawled_at
|
|
76
77
|
|
|
77
78
|
|
|
78
79
|
def test_start_stop_poll_service() -> None:
|
|
@@ -107,3 +108,16 @@ def test_wait_or_stop() -> None:
|
|
|
107
108
|
assert wait_or_stop(stop_event, 0.1) is False
|
|
108
109
|
stop_event.set()
|
|
109
110
|
assert wait_or_stop(stop_event, 1.0) is True
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_wait_or_stop_wakes_early_on_stop() -> None:
|
|
114
|
+
stop_event = threading.Event()
|
|
115
|
+
|
|
116
|
+
def _set_stop() -> None:
|
|
117
|
+
time.sleep(0.05)
|
|
118
|
+
stop_event.set()
|
|
119
|
+
|
|
120
|
+
threading.Thread(target=_set_stop, daemon=True).start()
|
|
121
|
+
started = time.monotonic()
|
|
122
|
+
assert wait_or_stop(stop_event, 30.0) is True
|
|
123
|
+
assert time.monotonic() - started < 2.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/example/__main__.py
RENAMED
|
File without changes
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/example/spawn_map_io.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/ff14_the_hunt/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_fate_timer.py
RENAMED
|
File without changes
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_monitor_mode.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_poll_sleep.py
RENAMED
|
File without changes
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_spawn_dedup.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tests/test_spawn_window.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_library_ff14_the_hunt-0.0.2 → python_library_ff14_the_hunt-0.0.3}/tools/build_locale_data.py
RENAMED
|
File without changes
|
|
File without changes
|