-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser_directed.py
More file actions
100 lines (79 loc) · 2.85 KB
/
Copy pathparser_directed.py
File metadata and controls
100 lines (79 loc) · 2.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import re
from datetime import datetime
from callsign_utils import normalize_callsign
LOCAL_SNR_TOKEN_RE = re.compile(r"^[-+]?\d+$")
def parse_dt(date_str, time_str):
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M"):
try:
return datetime.strptime(f"{date_str} {time_str}", fmt)
except ValueError:
pass
return None
def parse_directed_line(line):
"""
Parse a JS8Call DIRECTED.TXT line.
Important:
The local heard SNR is the 4th numeric field in the line, e.g.
2026-02-27 16:05:57 27.245000 1607 -19 161OS487: 19LV002 SNR +27
In that example:
- local heard SNR = -19 (what this station heard)
- message payload contains "SNR +27" which is remote content and must NOT
overwrite the local heard SNR.
"""
raw = line.replace("♢", "").strip()
if not raw:
return None
tokens = raw.split()
if len(tokens) < 6:
return None
date_str = tokens[0]
time_str = tokens[1]
freq = tokens[2]
# JS8Call local monitor SNR is the token immediately before the sender token.
# Typical structure:
# DATE TIME FREQ OFFSET LOCALSNR SENDER: MESSAGE...
sender = None
sender_idx = None
for i, tok in enumerate(tokens):
if tok.endswith(":"):
sender = tok[:-1].upper()
sender_idx = i
break
if not sender or sender_idx is None:
return None
# Need at least one token before sender for local SNR
if sender_idx < 1:
return None
local_snr_token = tokens[sender_idx - 1]
if not LOCAL_SNR_TOKEN_RE.match(local_snr_token):
return None
try:
snr = int(local_snr_token)
except ValueError:
return None
receiver = ""
message_tokens = []
if sender_idx + 1 < len(tokens):
first_after_sender = str(tokens[sender_idx + 1] or "").strip()
first_after_sender_upper = first_after_sender.upper()
if re.match(r"^(JR|JRN|JRS)(?:[.|]|$)", first_after_sender_upper):
receiver = ""
message_tokens = tokens[sender_idx + 1:]
else:
receiver = first_after_sender_upper
message_tokens = tokens[sender_idx + 2:]
msg_text = " ".join(message_tokens).strip()
dt = parse_dt(date_str, time_str)
return {
"date": date_str,
"time": time_str,
"datetime": dt,
"from": sender, # exact heard form
"to": receiver, # exact heard form
"from_norm": normalize_callsign(sender),
"to_norm": normalize_callsign(receiver),
"msg": msg_text, # preserve full payload exactly
"freq": freq,
"snr": snr, # local heard SNR only
"raw": raw,
}