16 KiB
source_url, ingested, sha256, discovered_from, score
| source_url | ingested | sha256 | discovered_from | score | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| https://github.com/yutakobayashidev/edcb-tools | 2026-06-29 | f9f2d326d774a922b3a96b590a9b49734bd847a60099d869a3fc3adf223164ed |
|
2 |
edcb-tools
Rust client library, command line interface, and MCP server for EDCB/EpgTimer CtrlCmd.
This crate currently provides a Tokio-based TCP client, binary codec, edcb
CLI, and edcb-mcp stdio MCP server for CtrlCmd APIs used by EDCB
integrations. The implementation is ported from xtne6f/edcb.py, with
KonomiTV's async usage used as a secondary reference.
Distribution
Nix flake is the primary distribution surface. The default package builds both first-class binaries:
edcbedcb-mcp
Run the CLI directly from GitHub:
nix run github:yutakobayashidev/edcb-tools#edcb -- --host 127.0.0.1 services
Run the stdio MCP server directly from GitHub:
nix run github:yutakobayashidev/edcb-tools#edcb-mcp -- --host 127.0.0.1 --port 4510
Install both binaries into a Nix profile:
nix profile install github:yutakobayashidev/edcb-tools#edcb-tools
Use the package from another flake:
{
inputs.edcb-tools.url = "github:yutakobayashidev/edcb-tools";
outputs = { edcb-tools, ... }: {
# edcb-tools.packages.${system}.default
# edcb-tools.packages.${system}.edcb-tools
# edcb-tools.apps.${system}.edcb
# edcb-tools.apps.${system}.edcb-mcp
};
}
The Rust client library is intended to be consumed from this repository, not published to crates.io:
[dependencies]
edcb-tools = { git = "https://github.com/yutakobayashidev/edcb-tools" }
Supported in v1
- TCP transport
edcbcommand line interface- stdio MCP server surface
- EDCB primitive, string, vector, struct, and
SYSTEMTIMEcodec - Service, EPG, reserve, recorded-file, tuner, plugin, auto-add, manual-add, and notify-status read APIs
- Program search, timetable retrieval, recorded item detail retrieval, reservation detail retrieval, and event-based reservation preview/create/update/delete with recording options
- Utility parsers for
ChSet5.txt,LogoData.ini, logo directory indexes, and program extended text
Architecture
EdcbClient is a raw CtrlCmd client: its methods map closely to EDCB commands
and wire data structures. Application-level operations such as program search
and event-based reservation preview/create are exported from the crate root. The
CLI and MCP server call these operations instead of embedding CtrlCmd
orchestration directly. TCP transport is isolated behind an internal transport
boundary so additional transports can be added without rewriting command
encoding.
To Do
- Unix domain socket transport
- Windows named pipe transport
- View app stream / SrvPipe stream helpers
- Recorded-file, auto-add, and manual-add mutation APIs
- MCP server surface
- HTTP MCP transport
Example
use std::time::Duration;
use edcb_tools::{ConnectionConfig, EdcbClient};
#[tokio::main]
async fn main() -> edcb_tools::Result<()> {
let client = EdcbClient::new(
ConnectionConfig::new("127.0.0.1", 4510).with_timeout(Duration::from_secs(5)),
);
let services = client.enum_service().await?;
for service in services {
println!("{}: {}", service.sid, service.service_name);
}
Ok(())
}
Command Line Interface
Run the edcb CLI through the flake:
nix run .#edcb -- --host 127.0.0.1 --port 4510 services
During development, the same CLI can be run with Cargo:
cargo run --bin edcb -- --host 127.0.0.1 --port 4510 services
The same connection settings can be supplied through environment variables:
EDCB_HOST=127.0.0.1 EDCB_PORT=4510 EDCB_TIMEOUT_SECONDS=15 cargo run --bin edcb -- services
CLI options take precedence over environment variables. Defaults are
127.0.0.1, port 4510, and a 15 second timeout.
Output is a stable line-based summary by default. Use --json for full
structured output.
Run edcb --help, edcb help, or edcb help <command> for clap-generated
usage, options, and examples from the current build.
Available commands:
servicesreservesrecorded listrecorded get <info-id>programs search [search options]programs timetable [timetable options]channelsrecording defaultsrecording presetsreservation-conditionsreservation-conditions get <condition-id>reservation-conditions create [search options] [recording options] --yesreservation-conditions update <condition-id> [search options] [recording options] --yesreservation-conditions delete <condition-id> --yesreserves get <reserve-id>reserves preview --event <onid:tsid:sid:eid> [recording options]reserves create --event <onid:tsid:sid:eid> [recording options] --yesreserves update <reserve-id> [recording options] --yesreserves delete <reserve-id> --yestuner-reservestuner-processesplugins <write|rec_name>notify-status
reserves preview is a client-side preview that fetches the EDCB default
reservation settings and the target event, then builds the ReserveData that
would be sent. EDCB does not expose a reservation dry-run command. Use
reserves create ... --yes to send the actual add-reservation command. After
creation, the CLI fetches reservations again and returns the newly assigned
reservation ID when it can be resolved from the before/after difference.
reserves update ... --yes fetches the existing reservation, applies recording
option changes, sends the full updated reservation to EDCB, and returns the
updated reservation data.
reserves delete ... --yes first fetches the reservation by ID, then sends the
delete command and returns the deleted reservation data.
programs search prints event keys as onid:tsid:sid:eid, which can be passed
to reserves preview or reserves create.
Preview JSON has the same ReserveData shape that create/get return. The
previewed reservation has not been sent to EDCB yet. Abridged example:
{
"reserve_id": 0,
"onid": 32736,
"tsid": 32736,
"sid": 1024,
"eid": 4208,
"start_time": "2026-06-29T22:00:00+09:00",
"duration_second": 1800,
"station_name": "Example Service",
"title": "Example Program",
"rec_setting": {
"rec_mode": 1,
"priority": 2
}
}
Useful reservation preview selectors:
edcb --json reserves preview --event 32736:32736:1024:4208 \
| jq '{event: "\(.onid):\(.tsid):\(.sid):\(.eid)", start_time, title, priority: .rec_setting.priority}'
Program search uses EDCB's SearchKeyInfo/SearchPg semantics. Date ranges are
recurring weekday/time-of-day ranges, not absolute datetimes. If no service is
specified, the CLI first fetches EDCB's service list and searches those services.
Use programs timetable when you want the program table for services/time
windows instead of keyword search.
reservation-conditions manages EDCB keyword auto reservations (AutoAddData)
with the same search options and recording options. EDCB does not return the
newly assigned AutoAdd ID from the add command, so create returns the condition
payload that was sent with id set to 0; list or get conditions afterwards to
see assigned IDs.
Program search options:
--keyword <text>--exclude-keyword <text>--title-only--case-sensitive--regex--fuzzy--service <onid:tsid:sid>(repeatable)--genre <major:middle[:user_nibble]>(repeatable)--exclude-genre-ranges--date-range <start-dow:HH:MM-end-dow:HH:MM>(repeatable,0is Sunday)--exclude-date-ranges--duration-min <minutes>and--duration-max <minutes>--free-ca <all|free|paid>--search-enable/--search-disable--duplicate-title-check <none|same-channel|all-channels>--duplicate-title-check-days <days>
Examples:
edcb programs search --keyword news --title-only
edcb programs search --keyword news --genre 0:1
edcb programs search --keyword news --date-range 1:19:00-1:23:00
edcb programs search --keyword news --duration-min 30 --duration-max 120 --free-ca free
edcb reservation-conditions create --keyword news --genre 0:1 --priority 4 --yes
edcb reservation-conditions update 77 --keyword news --duplicate-title-check same-channel --yes
Program timetable uses EDCB's EnumPgInfoEx semantics. It returns programs
grouped by service, nests short same-TS subchannels under their main channel,
and attaches reservation metadata when a matching reservation can be found.
JSON output includes reservation_metadata_status; if reservation lookup fails,
programs are still returned and the status contains the failure message.
Timetable options:
--service <onid:tsid:sid>(repeatable)--start-time <RFC3339 datetime>--end-time <RFC3339 datetime>--channel-type <gr|bs|cs|catv|sky|bs4k>
Examples:
edcb programs timetable --channel-type gr
edcb programs timetable --service 32736:32736:1024 --start-time 2026-06-29T19:00:00+09:00 --end-time 2026-06-29T23:00:00+09:00
Timetable JSON nests program details under channels[].programs[].event.
Reservation metadata is optional per program; check
reservation_metadata_status before treating reservation: null as definitive.
Abridged example:
{
"channels": [
{
"service": {
"onid": 32736,
"tsid": 32736,
"sid": 1024,
"service_name": "Example Service"
},
"programs": [
{
"event": {
"onid": 32736,
"tsid": 32736,
"sid": 1024,
"eid": 4208,
"start_time": "2026-06-29T22:00:00+09:00",
"short_info": {
"event_name": "Example Program"
}
},
"reservation": {
"id": 77,
"status": "Reserved",
"recording_availability": "Full"
}
}
],
"subchannels": null
}
],
"date_range": {
"earliest": "2026-06-29T19:00:00+09:00",
"latest": "2026-06-29T23:00:00+09:00"
},
"reservation_metadata_status": "Ok"
}
Useful timetable selectors:
edcb --json programs timetable --channel-type gr \
| jq -r '.channels[].programs[] | [.event.onid, .event.tsid, .event.sid, .event.eid, .event.start_time, .event.short_info.event_name, (.reservation != null)] | @tsv'
edcb --json programs timetable --channel-type gr \
| jq -r '.channels[].programs[] | select(.reservation == null) | "\(.event.onid):\(.event.tsid):\(.event.sid):\(.event.eid)\t\(.event.start_time)\t\(.event.short_info.event_name)"'
channels returns a DB-free KonomiTV-style channel snapshot built from
ChSet5.txt and EnumService. It includes display_channel_id, channel type,
service key, remocon ID, subchannel/radio flags, and watchability flags. Because
it is stateless, it does not preserve recorded-only historical channels, pinned
channels, jikkyo state, or viewer counts. Plain output is still one line per
channel; JSON output wraps the list in channels and includes
epg_service_status so callers can distinguish missing EPG metadata from an
empty channel list.
edcb channels
edcb --json channels
recording defaults decodes the EDCB default reservation settings returned by
GetReserve2(0x7fffffff). recording presets reads EpgTimerSrv.ini through
FileCopy2 and returns global defaults plus recording presets, including ID 0.
If EDCB returns an empty EpgTimerSrv.ini, use recording defaults for the
effective reservation default.
edcb recording defaults
edcb --json recording presets
Common recording options:
--priority <1-5>--enable/--disable--recording-mode <all|all-without-decoding|specified|specified-without-decoding|view>--start-margin <seconds>and--end-margin <seconds>--caption <default|enable|disable>and--data <default|enable|disable>--post-recording <default|nothing|standby|standby-and-reboot|suspend|suspend-and-reboot|shutdown>
MCP Server
Run the edcb-mcp stdio MCP server through the flake:
nix run .#edcb-mcp -- --host 127.0.0.1 --port 4510 --timeout-seconds 15
During development, the same server can be run with Cargo:
cargo run --bin edcb-mcp -- --host 127.0.0.1 --port 4510 --timeout-seconds 15
The same connection settings can be supplied through environment variables:
EDCB_HOST=127.0.0.1 EDCB_PORT=4510 EDCB_TIMEOUT_SECONDS=15 cargo run --bin edcb-mcp
CLI options take precedence over environment variables. Defaults are
127.0.0.1, port 4510, and a 15 second timeout.
Run edcb-mcp --help for clap-generated server options from the current build.
Exposed MCP tools:
list_serviceslist_reservesget_reservationlist_recordedget_recorded_infolist_channelsget_recording_defaultsget_recording_presetssearch_programsget_timetablelist_reservation_conditionsget_reservation_conditioncreate_reservation_conditionupdate_reservation_conditiondelete_reservation_conditionpreview_reservationcreate_reservationupdate_reservationdelete_reservationlist_tuner_reserveslist_tuner_processeslist_pluginsget_notify_status
preview_reservation does not mutate EDCB state. create_reservation creates
one reservation from an event key and the server's default reservation settings.
Both accept an optional options object using KonomiTV-style recording setting
names:
{
"event": "32737:32737:1032:9285",
"options": {
"priority": 4,
"recording_start_margin": 60,
"recording_end_margin": 120
}
}
update_reservation accepts reserve_id and required options.
delete_reservation fetches the reservation before deleting it and returns the
deleted reservation data.
search_programs accepts KonomiTV-style search condition fields:
{
"is_enabled": true,
"keyword": "news",
"exclude_keyword": "sports",
"is_title_only": true,
"is_case_sensitive": false,
"is_fuzzy_search_enabled": true,
"is_regex_search_enabled": false,
"service_ranges": [
{
"network_id": 32736,
"transport_stream_id": 32736,
"service_id": 1024
}
],
"genre_ranges": [
{
"major": 0,
"middle": 1,
"user_nibble": null
}
],
"is_exclude_genre_ranges": false,
"date_ranges": [
{
"start_day_of_week": 1,
"start_hour": 19,
"start_minute": 0,
"end_day_of_week": 1,
"end_hour": 23,
"end_minute": 0
}
],
"is_exclude_date_ranges": false,
"duration_range_min": 30,
"duration_range_max": 120,
"broadcast_type": "FreeOnly",
"duplicate_title_check_scope": "None",
"duplicate_title_check_period_days": 6
}
create_reservation_condition accepts a required condition object with the
same fields as search_programs and an optional options object with recording
settings. update_reservation_condition accepts condition_id, optional
condition, and optional options.
get_timetable accepts service/time/channel filters and returns channels with
programs, optional nested subchannels, and best-effort reservation metadata. The
response includes reservation_metadata_status so callers can distinguish "no
matching reservation" from "reservation lookup failed":
{
"start_time": "2026-06-29T19:00:00+09:00",
"end_time": "2026-06-29T23:00:00+09:00",
"channel_type": "GR",
"services": [
{
"network_id": 32736,
"transport_stream_id": 32736,
"service_id": 1024
}
]
}
Development
Use the Nix dev shell through direnv, then run:
nix fmt
nix build
nix run .#edcb -- --version
cargo test
cargo fmt --check
cargo clippy --all-targets -- -D warnings