@nomadamas/k-skill 0.2.5 → 0.4.0
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.
- package/package.json +1 -1
- package/skills/bok-ecos-stats/instruction.md +1 -1
- package/skills/bunjang-search/references/DISCLAIMER.md +23 -0
- package/skills/coupang-product-search/references/DISCLAIMER.md +23 -0
- package/skills/daangn-cars-search/references/DISCLAIMER.md +23 -0
- package/skills/daangn-jobs-search/references/DISCLAIMER.md +23 -0
- package/skills/daangn-realty-search/references/DISCLAIMER.md +23 -0
- package/skills/daangn-used-goods-search/references/DISCLAIMER.md +23 -0
- package/skills/daishin-report-search/references/DISCLAIMER.md +23 -0
- package/skills/daiso-product-search/references/DISCLAIMER.md +23 -0
- package/skills/danawa-price-search/references/DISCLAIMER.md +23 -0
- package/skills/delivery-tracking/references/DISCLAIMER.md +23 -0
- package/skills/express-bus-booking/references/DISCLAIMER.md +23 -0
- package/skills/fine-dust-location/skill.json +1 -7
- package/skills/flight-ticket-search/references/DISCLAIMER.md +23 -0
- package/skills/foresttrip-vacancy/references/DISCLAIMER.md +23 -0
- package/skills/intercity-bus-booking/references/DISCLAIMER.md +23 -0
- package/skills/job-posting-match/references/DISCLAIMER.md +23 -0
- package/skills/jobkorea-talent-search/references/DISCLAIMER.md +23 -0
- package/skills/k-skill-setup/skill.json +1 -7
- package/skills/kakao-bar-nearby/references/DISCLAIMER.md +15 -0
- package/skills/kakao-map/references/DISCLAIMER.md +15 -0
- package/skills/kakaotalk-mac/references/DISCLAIMER.md +15 -0
- package/skills/kbl-results/references/DISCLAIMER.md +13 -0
- package/skills/kbo-results/references/DISCLAIMER.md +13 -0
- package/skills/keris-academic-search/references/DISCLAIMER.md +13 -0
- package/skills/keris-academic-search/references/TRADEMARK-LEGAL-STATEMENT.md +7 -0
- package/skills/kleague-results/references/DISCLAIMER.md +13 -0
- package/skills/kopis-performance-search/references/DISCLAIMER.md +13 -0
- package/skills/kopis-performance-search/references/TRADEMARK-LEGAL-STATEMENT.md +7 -0
- package/skills/kopis-performance-search/skill.json +3 -4
- package/skills/korean-cinema-search/references/DISCLAIMER.md +13 -0
- package/skills/korean-stock-search/references/DISCLAIMER.md +14 -0
- package/skills/korean-stock-search/references/TRADEMARK-LEGAL-STATEMENT.md +7 -0
- package/skills/korean-transit-route/references/DISCLAIMER.md +13 -0
- package/skills/ktx-booking/instruction.md +38 -221
- package/skills/ktx-booking/references/AUTOMATION-LEGAL-STATEMENT.md +10 -0
- package/skills/ktx-booking/references/DISCLAIMER.md +14 -0
- package/skills/ktx-booking/scripts/ktx_booking.py +176 -1274
- package/skills/ktx-booking/scripts/ktx_booking.py.lock +27 -0
- package/skills/ktx-booking/scripts/ktx_timetable.py +141 -0
- package/skills/ktx-booking/skill.json +3 -11
- package/skills/lck-analytics/references/DISCLAIMER.md +13 -0
- package/skills/lotto-results/references/DISCLAIMER.md +13 -0
- package/skills/market-kurly-search/references/DISCLAIMER.md +13 -0
- package/skills/myrealtrip-search/instruction.md +3 -1
- package/skills/myrealtrip-search/references/DISCLAIMER.md +13 -0
- package/skills/myrealtrip-search/scripts/myrealtrip_mcp.py +30 -8
- package/skills/myrealtrip-search/scripts/test_myrealtrip_mcp.py +62 -0
- package/skills/naver-ad-performance/references/DISCLAIMER.md +13 -0
- package/skills/naver-blog-research/references/DISCLAIMER.md +13 -0
- package/skills/naver-news-search/references/DISCLAIMER.md +13 -0
- package/skills/naver-shopping-search/references/DISCLAIMER.md +13 -0
- package/skills/ohou-today-deal/references/DISCLAIMER.md +13 -0
- package/skills/olive-young-search/references/DISCLAIMER.md +13 -0
- package/skills/popbill/references/DISCLAIMER.md +13 -0
- package/skills/saramin-talent-search/references/DISCLAIMER.md +13 -0
- package/skills/seoul-weather-risk/instruction.md +28 -35
- package/skills/seoul-weather-risk/scripts/seoul_weather_risk.py +15 -68
- package/skills/seoul-weather-risk/skill.json +2 -2
- package/skills/srt-booking/instruction.md +48 -154
- package/skills/srt-booking/references/AUTOMATION-LEGAL-STATEMENT.md +25 -0
- package/skills/srt-booking/references/DISCLAIMER.md +13 -0
- package/skills/srt-booking/scripts/srt_booking.py +134 -235
- package/skills/srt-booking/scripts/srt_booking.py.lock +207 -0
- package/skills/srt-booking/skill.json +3 -15
- package/skills/store-longevity-radar/scripts/__pycache__/store_longevity_download.cpython-312.pyc +0 -0
- package/skills/ticket-availability/references/DISCLAIMER.md +13 -0
- package/skills/{toss-securities → toss-investment}/instruction.md +1 -1
- package/skills/toss-investment/references/DISCLAIMER.md +14 -0
- package/skills/{toss-securities → toss-investment}/references/TRADEMARK-LEGAL-STATEMENT.md +1 -1
- package/skills/{toss-securities → toss-investment}/skill.json +2 -2
- package/src/assemble.js +1 -1
- package/src/execute.js +13 -3
- package/skills/lovebug-report/instruction.md +0 -185
- package/skills/lovebug-report/skill.json +0 -9
- package/skills/srt-booking/scripts/srt_seats.py +0 -156
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import re
|
|
5
|
-
from typing import TypedDict
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class SrtCar(TypedDict):
|
|
9
|
-
car_no: int
|
|
10
|
-
car_no_raw: str
|
|
11
|
-
room_class: str
|
|
12
|
-
available: bool
|
|
13
|
-
current: bool
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class SrtSeat(TypedDict):
|
|
17
|
-
seat: str
|
|
18
|
-
seat_no: str
|
|
19
|
-
available: bool
|
|
20
|
-
direction: str
|
|
21
|
-
position: str
|
|
22
|
-
notes: list[str]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
CAR_RE = re.compile(
|
|
26
|
-
r'<li class="scar-(?P<car>\d+)(?P<class>[^"]*)">(?P<body>.*?)</li>',
|
|
27
|
-
re.DOTALL,
|
|
28
|
-
)
|
|
29
|
-
SEAT_LINK_RE = re.compile(
|
|
30
|
-
r"<a[^>]+selectSeatInfo\(this,\s*'(?P<seat_no>[^']+)',\s*'(?P<seat>[^']+)'\)[^>]*>"
|
|
31
|
-
r".*?<em>\((?P<detail>[^)]*)\)</em>",
|
|
32
|
-
re.DOTALL,
|
|
33
|
-
)
|
|
34
|
-
SEAT_SPAN_RE = re.compile(
|
|
35
|
-
r"<span>\s*(?P<seat>\d+[A-Z])\s*<strong><em>\((?P<detail>[^)]*)\)</em></strong></span>",
|
|
36
|
-
re.DOTALL,
|
|
37
|
-
)
|
|
38
|
-
TAG_RE = re.compile(r"<[^>]+>")
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def strip_tags(value: str) -> str:
|
|
42
|
-
return TAG_RE.sub(" ", value).replace("\xa0", " ").strip()
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def parse_detail(detail: str) -> tuple[str, str, list[str]]:
|
|
46
|
-
parts = [part.strip() for part in detail.split(",")]
|
|
47
|
-
direction = next((part for part in parts if part in {"정방향", "역방향"}), "unknown")
|
|
48
|
-
position = next((part for part in parts if part in {"창측", "내측", "1인석"}), "unknown")
|
|
49
|
-
notes = [part for part in parts if part not in {direction, position} and part]
|
|
50
|
-
return direction, position, notes
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def parse_cars(html: str) -> list[SrtCar]:
|
|
54
|
-
cars: list[SrtCar] = []
|
|
55
|
-
for match in CAR_RE.finditer(html):
|
|
56
|
-
body = match.group("body")
|
|
57
|
-
text = strip_tags(body)
|
|
58
|
-
room_class = "특실" if "특실" in text else "일반실"
|
|
59
|
-
css_class = match.group("class")
|
|
60
|
-
has_link = "selectScarInfo" in body
|
|
61
|
-
cars.append(
|
|
62
|
-
{
|
|
63
|
-
"car_no": int(match.group("car")),
|
|
64
|
-
"car_no_raw": f"{int(match.group('car')):04d}",
|
|
65
|
-
"room_class": room_class,
|
|
66
|
-
"available": has_link and "off" not in css_class.split(),
|
|
67
|
-
"current": "on" in css_class.split(),
|
|
68
|
-
}
|
|
69
|
-
)
|
|
70
|
-
return cars
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def parse_seats(html: str) -> list[SrtSeat]:
|
|
74
|
-
seats: list[SrtSeat] = []
|
|
75
|
-
seen: set[str] = set()
|
|
76
|
-
for match in SEAT_LINK_RE.finditer(html):
|
|
77
|
-
direction, position, notes = parse_detail(match.group("detail"))
|
|
78
|
-
seat = match.group("seat")
|
|
79
|
-
seen.add(seat)
|
|
80
|
-
seats.append(
|
|
81
|
-
{
|
|
82
|
-
"seat": seat,
|
|
83
|
-
"seat_no": match.group("seat_no"),
|
|
84
|
-
"available": True,
|
|
85
|
-
"direction": direction,
|
|
86
|
-
"position": position,
|
|
87
|
-
"notes": notes,
|
|
88
|
-
}
|
|
89
|
-
)
|
|
90
|
-
for match in SEAT_SPAN_RE.finditer(html):
|
|
91
|
-
seat = match.group("seat")
|
|
92
|
-
if seat in seen:
|
|
93
|
-
continue
|
|
94
|
-
direction, position, notes = parse_detail(match.group("detail"))
|
|
95
|
-
seats.append(
|
|
96
|
-
{
|
|
97
|
-
"seat": seat,
|
|
98
|
-
"seat_no": "",
|
|
99
|
-
"available": False,
|
|
100
|
-
"direction": direction,
|
|
101
|
-
"position": position,
|
|
102
|
-
"notes": notes,
|
|
103
|
-
}
|
|
104
|
-
)
|
|
105
|
-
return seats
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def parse_seat_label(seat_label: str) -> tuple[int | None, str]:
|
|
109
|
-
match = re.match(r"^(\d+)([A-Z])$", seat_label)
|
|
110
|
-
if match is None:
|
|
111
|
-
return None, ""
|
|
112
|
-
return int(match.group(1)), match.group(2)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def car_center_priority(car: SrtCar, car_numbers: list[int]) -> tuple[float, int]:
|
|
116
|
-
if not car_numbers:
|
|
117
|
-
return (0.0, car["car_no"])
|
|
118
|
-
center = (min(car_numbers) + max(car_numbers)) / 2
|
|
119
|
-
return (abs(car["car_no"] - center), car["car_no"])
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def sort_cars_for_booking(cars: list[SrtCar], priority: str = "center") -> list[SrtCar]:
|
|
123
|
-
match priority:
|
|
124
|
-
case "center":
|
|
125
|
-
car_numbers = [car["car_no"] for car in cars]
|
|
126
|
-
return sorted(cars, key=lambda car: car_center_priority(car, car_numbers))
|
|
127
|
-
case "low":
|
|
128
|
-
return sorted(cars, key=lambda car: car["car_no"])
|
|
129
|
-
case "high":
|
|
130
|
-
return sorted(cars, key=lambda car: car["car_no"], reverse=True)
|
|
131
|
-
case _:
|
|
132
|
-
raise ValueError(f"unsupported car priority: {priority}")
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def seat_preference_key(seat: SrtSeat, priority: str = "forward-window") -> tuple[int, int, int, str]:
|
|
136
|
-
row, column = parse_seat_label(seat["seat"])
|
|
137
|
-
forward_rank = 0 if seat["direction"] == "정방향" else 1
|
|
138
|
-
window_rank = 0 if seat["position"] in {"창측", "1인석"} else 1
|
|
139
|
-
row_rank = 999 if row is None else row
|
|
140
|
-
match priority:
|
|
141
|
-
case "forward-window":
|
|
142
|
-
return (forward_rank, window_rank, row_rank, column)
|
|
143
|
-
case "window-forward":
|
|
144
|
-
return (window_rank, forward_rank, row_rank, column)
|
|
145
|
-
case "row-low":
|
|
146
|
-
return (row_rank, forward_rank, window_rank, column)
|
|
147
|
-
case _:
|
|
148
|
-
raise ValueError(f"unsupported seat priority: {priority}")
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def sort_seats_for_booking(seats: list[SrtSeat], priority: str = "forward-window") -> list[SrtSeat]:
|
|
152
|
-
return sorted(seats, key=lambda seat: seat_preference_key(seat, priority))
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
sort_cars = sort_cars_for_booking
|
|
156
|
-
sort_seats = sort_seats_for_booking
|