Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion fetch_stock.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
actually open, else exit 1 so the previous cached line (last
close of whichever market was live) just stays on screen
(default: 005930,000660 — Samsung Electronics, SK hynix)
Exits non-zero on failure so refresh_stock.sh keeps the previous cache.
Exits non-zero on failure so refresh_stock.sh keeps the previous cache — also
used deliberately when KOSPI's own marketStatus says CLOSE (weekend/holiday/
off-hours) and a line is already cached, to skip the extra top5/stock lookup
below (see NEWSLINE_STOCK_HAS_CACHE, set by refresh_stock.sh).
Test override: NEWSLINE_STOCK_HOUR forces the "auto" local hour (0-23).
"""
import os
Expand Down Expand Up @@ -116,6 +119,17 @@ def main():
index = fetch_json(INDEX_URL)["datas"][0]
except Exception:
return 1

# KRX marketStatus catches weekends/holidays/off-hours WITHOUT us hardcoding
# a KR holiday calendar (lunar-based, changes yearly). Closed + already have
# a cached line -> nothing will have changed, so skip the extra top5/stock
# lookup below entirely and just keep that cache (refresh_stock.sh handles
# a non-zero exit by leaving the previous file untouched). Closed + no cache
# yet (fresh install off-hours) still falls through and builds a full line
# from the last real data, same as always.
if index.get("marketStatus") != "OPEN" and os.environ.get("NEWSLINE_STOCK_HAS_CACHE") == "1":
return 1

parts = [fmt_item(index, "https://finance.naver.com/sise/sise_index.naver?code=KOSPI")]

if top_n:
Expand Down
36 changes: 29 additions & 7 deletions newsline
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,18 @@ cmd_init() {
[ "$rotate" -ge 1 ] 2>/dev/null || rotate=6
fi
if [ "$stock_set" = "0" ]; then
# KOSPI top-5 ticker line, shown below the news — off by default
local cur_stock; cur_stock=$(cfg_get stock); [ "$cur_stock" = "on" ] || cur_stock="off"
echo "Show KOSPI top 5 stock ticker below the news?" >&2
choose "$cur_stock" on "Yes" off "No"
stock="$CHOICE"
# KOSPI top-5 ticker line, shown below the news — off by default, and only
# offered at all when the effective language/region is Korean (KOSPI is a
# KR-only index; asking non-KR users about it is just noise).
local eff_lang="$lang"; [ "$eff_lang" = "auto" ] && eff_lang="$detected"
if [ "$eff_lang" = "ko" ]; then
local cur_stock; cur_stock=$(cfg_get stock); [ "$cur_stock" = "on" ] || cur_stock="off"
echo "Show KOSPI top 5 stock ticker below the news?" >&2
choose "$cur_stock" on "Yes" off "No"
stock="$CHOICE"
else
stock="off"
fi
fi
else
# --yes: keep a color previously set via init/`newsline color`; magenta on first run
Expand All @@ -227,14 +234,29 @@ cmd_init() {
if [ "$rotate_set" = "0" ]; then
local saved_rotate; saved_rotate=$(cfg_get rotate); [ -n "$saved_rotate" ] && rotate="$saved_rotate"
fi
# keep an existing stock setting on re-init unless --stock was given; off on first run
# keep an existing stock setting on re-init unless --stock was given; off on
# first run, and off unconditionally once the effective language isn't ko
# (e.g. re-init switched language away from Korean)
if [ "$stock_set" = "0" ]; then
stock=$(cfg_get stock); [ -n "$stock" ] || stock="off"
local eff_lang="$lang"; [ "$eff_lang" = "auto" ] && eff_lang="$detected"
if [ "$eff_lang" = "ko" ]; then
stock=$(cfg_get stock); [ -n "$stock" ] || stock="off"
else
stock="off"
fi
fi
fi
[ -n "$stock_codes" ] || stock_codes=$(cfg_get stock_codes)
[ -n "$stock_codes" ] || stock_codes="top5"

# Safety net for the explicit --stock flag: KOSPI is Korea-only, so refuse to
# turn it on for a non-Korean effective language even when passed explicitly.
eff_lang="$lang"; [ "$eff_lang" = "auto" ] && eff_lang="$detected"
if [ "$eff_lang" != "ko" ] && [ "$stock" = "on" ]; then
echo "ℹ KOSPI ticker is Korea-only (lang=$eff_lang); ignoring --stock on" >&2
stock="off"
fi

# Always KEEP an existing status line and show newsline below it (no prompt).
# Only --no-compose (or an explicit --base) changes this.
local existing base="" base_obj=""
Expand Down
8 changes: 7 additions & 1 deletion refresh_stock.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@ fi
if ! mkdir "$LOCK" 2>/dev/null; then exit 0; fi
trap 'rmdir "$LOCK" 2>/dev/null' EXIT

# Tell fetch_stock.py whether we already have a line cached — on a closed
# market (holiday/weekend/off-hours) with nothing cached yet it still builds
# a full line from the last real data; with a cache already in place it can
# skip straight past the extra top5 lookup (see fetch_stock.py).
has_cache=0; [ -s "$CACHE_FILE" ] && has_cache=1

# --- fetch + parse + build the line; write atomically, keep old cache on failure ---
if python3 "$HERE/fetch_stock.py" "$CODES" > "$CACHE_FILE.tmp" 2>/dev/null \
if NEWSLINE_STOCK_HAS_CACHE="$has_cache" python3 "$HERE/fetch_stock.py" "$CODES" > "$CACHE_FILE.tmp" 2>/dev/null \
&& [ -s "$CACHE_FILE.tmp" ]; then
mv -f "$CACHE_FILE.tmp" "$CACHE_FILE"
else
Expand Down
18 changes: 13 additions & 5 deletions statusline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,27 @@ stock_enabled() {
*) return 1 ;;
esac
}
# KRX cash session (09:00-15:30), local wall clock — outside this window we never
# hit the API; the last fetched line (i.e. the 15:30 close) just stays on screen as-is.
# Test overrides: NEWSLINE_STOCK_HOUR / NEWSLINE_STOCK_MINUTE force the clock.
# KRX cash session (Mon-Fri 09:00-15:30), local wall clock — outside this window
# we never hit the API; the last fetched line (Friday's 15:30 close, over the
# whole weekend) just stays on screen as-is.
# Test overrides: NEWSLINE_STOCK_HOUR / NEWSLINE_STOCK_MINUTE / NEWSLINE_STOCK_DOW
# (1=Mon..7=Sun) force the clock.
stock_market_hours() {
local dow="${NEWSLINE_STOCK_DOW:-$(date +%u)}"
case "$dow" in 6|7) return 1 ;; esac # KRX doesn't trade weekends
local h="${NEWSLINE_STOCK_HOUR:-$(date +%H)}" m="${NEWSLINE_STOCK_MINUTE:-$(date +%M)}"
local mins=$((10#$h * 60 + 10#$m))
[ "$mins" -ge $((9 * 60)) ] && [ "$mins" -lt $((15 * 60 + 30)) ]
}
STOCK_FILE="$CACHE_DIR/stock.line"
if stock_enabled && stock_market_hours; then
# Refresh during the cash session on the usual TTL cadence; outside it, still
# fetch ONCE if we have no cache at all (e.g. first install at 21:00) so the
# ticker isn't blank until the next 09:00 open — then leave that last-close
# line on screen untouched until the session reopens.
if stock_enabled && { stock_market_hours || [ ! -s "$STOCK_FILE" ]; }; then
STOCK_TTL="${NEWSLINE_STOCK_TTL:-30}" # prices move faster than headlines
stock_needs_refresh=1
if [ -f "$STOCK_FILE" ]; then
if [ -s "$STOCK_FILE" ] && stock_market_hours; then
now=$(date +%s)
smtime=$(stat -f %m "$STOCK_FILE" 2>/dev/null || stat -c %Y "$STOCK_FILE" 2>/dev/null || echo 0)
[ $((now - smtime)) -lt "$STOCK_TTL" ] && stock_needs_refresh=0
Expand Down