FieldStation42 includes an On-Screen Display (OSD) that shows the channel number and name when you change channels. It runs as a separate process alongside field_player.
The OSD uses two config files:
osd/osd.json-- global display settings: text style, logo defaults, position, and timingconfs/<station>.json-- per-station logo settings inside each station'sstation_conf
Running the OSD
- Change to your FieldStation42 repo directory.
- Activate your virtual environment.
- Start the OSD:
DISPLAY=:0 python3 fs42/osd/main.py
The OSD updates automatically when you change channels.
To run in the background (useful during testing without tying up a terminal):
DISPLAY=:0 python3 fs42/osd/main.py 1>/dev/null 2>/dev/null & disown
To launch on boot, see the autostart guide to run it as a service.
Text Display
The OSD text overlay is configured in osd/osd.json. The default shows channel number and name in the top-left corner in green:
[
{
"halign": "LEFT",
"valign": "TOP",
"font_size": 40,
"text_color": [0, 255, 0, 200],
"format_text": "{channel_number} - {network_name}"
}
]
| Field | Type | Description |
|---|---|---|
halign |
string | Horizontal position: "LEFT", "RIGHT", or "CENTER". |
valign |
string | Vertical position: "TOP", "BOTTOM", or "CENTER". |
font_size |
integer | Font size in points. |
text_color |
array | RGBA color as [R, G, B, A], each value 0-255. The fourth value is opacity. |
format_text |
string | Display template. Available variables: {channel_number}, {network_name}. |
More examples are in osd/examples/ in the repo.
Logo Display
Logos are configured at two levels. osd.json sets global defaults; each station's config file enables and customizes logos for that station.
Quick Start
- Add a
LogoDisplayblock toosd/osd.json(see Global Settings below). - Put a logo file (
.png,.jpg, or.gif) into a directory, for examplecatalog/NBC/logos/. - Add these fields to that station's
station_confinconfs/<station>.json:
{
"station_conf": {
"logo_dir": "logos",
"show_logo": true,
"default_logo": "nbc_logo.png"
}
}
When both content_dir and logo_dir are set, the logo path resolves to <content_dir>/<logo_dir>. If only logo_dir is set, it resolves from the project root.
Global Settings (osd.json)
The LogoDisplay object lives in the same array as the text display config. Here is a complete osd.json with both:
[
{
"halign": "LEFT",
"valign": "TOP",
"font_size": 40,
"text_color": [0, 255, 0, 200],
"format_text": "{channel_number} - {network_name}"
},
{
"type": "LogoDisplay",
"halign": "RIGHT",
"valign": "BOTTOM",
"width": 0.112,
"height": 0.15,
"x_margin": 0.05,
"y_margin": 0.05,
"display_time": 5.0,
"always_show": false,
"default_logo": "fs42/osd/FS42.png",
"default_logo_alpha": 1.0,
"default_show_logo": true,
"default_logo_permanent": false
}
]
| Field | Type | Description |
|---|---|---|
type |
string | Required. Must be "LogoDisplay". |
halign |
string | Default horizontal alignment: "LEFT", "RIGHT", or "CENTER". |
valign |
string | Default vertical alignment: "TOP", "BOTTOM", or "CENTER". |
width |
float | Logo width as a fraction of half the screen width (e.g. 0.1 = 5% of screen). |
height |
float | Logo height as a fraction of half the screen height. |
x_margin |
float | Horizontal margin as a fraction of half the screen width. |
y_margin |
float | Vertical margin as a fraction of half the screen height. |
display_time |
float | Seconds to show the logo after a channel change or return to FEATURE content. |
always_show |
boolean | If true, ignores display_time and logo stays visible during all FEATURE content. |
default_logo |
string | Path to a global fallback logo file. |
default_logo_alpha |
float | Default logo opacity (e.g. 0.8 = 80% opacity). |
default_show_logo |
boolean | Whether to display the default_logo at all. |
default_logo_permanent |
boolean | If true, the default logo stays visible during FEATURE content regardless of display_time. |
Per-Station Settings (confs/<station>.json)
Each station can define its own logos and override any global display parameter:
{
"station_conf": {
"logo_dir": "logos",
"show_logo": true,
"default_logo": "station_static.png",
"logo_permanent": false,
"multi_logo": "off",
"logo_display_time": 10.0,
"logo_halign": "RIGHT",
"logo_valign": "TOP",
"logo_width": 0.1,
"logo_height": 0.12,
"logo_x_margin": 0.03,
"logo_y_margin": 0.03,
"logo_alpha": 0.75
}
}
| Field | Type | Description |
|---|---|---|
logo_dir |
string | Required for station logos. Directory where this station's logos are stored. |
show_logo |
boolean | Whether to show a logo for this station. |
default_logo |
string | Filename of this station's default logo. |
logo_permanent |
boolean | If true, logo stays visible during all FEATURE content (ignores timing). |
multi_logo |
string | Logo selection mode. "off" or "single" uses default_logo; "random" or "multi" randomly picks from all .png, .jpg, .gif files in logo_dir each time a logo is shown. |
logo_display_time |
float | Overrides display_time from osd.json. |
logo_halign |
string | Overrides halign from osd.json. |
logo_valign |
string | Overrides valign from osd.json. |
logo_width |
float | Overrides width from osd.json. |
logo_height |
float | Overrides height from osd.json. |
logo_x_margin |
float | Overrides x_margin from osd.json. |
logo_y_margin |
float | Overrides y_margin from osd.json. |
logo_alpha |
float | Overrides default_logo_alpha from osd.json. |
Automatic Logo Selection
Logos can change automatically based on tags, time of year, day of week, or day part -- without any changes to the station config. Create subdirectories under logo_dir and the OSD selects the right one based on context.
If none of these subdirectories exist, the OSD falls back to the flat logo_dir and behaves exactly as before.
Selection Hierarchy
The OSD checks for logos in this priority order:
- Tag-based --
logo_dir/<tag>/-- tag fromtags/tagin the station's schedule entry - Month + Weekday + DayPart --
logo_dir/<Month>/<Weekday>/<day_part>/-- e.g.logos/October/Friday/prime/ - Month + Weekday --
logo_dir/<Month>/<Weekday>/-- e.g.logos/October/Friday/ - Month + DayPart --
logo_dir/<Month>/<day_part>/-- e.g.logos/October/prime/ - Month only --
logo_dir/<Month>/or a date range likelogo_dir/<Month 1 - Month 31>/ - Weekday + DayPart --
logo_dir/<Weekday>/<day_part>/-- e.g.logos/Friday/morning/ - Weekday only --
logo_dir/<Weekday>/-- e.g.logos/Friday/ - DayPart only --
logo_dir/<day_part>/-- e.g.logos/prime/ - Base directory fallback --
logo_dir/, usingdefault_logoif set, otherwise a random file in that directory
When multiple logos exist in the chosen directory, one is selected randomly (or per the multi_logo setting).
Tag-driven Logos
Tags come from the station's existing schedule -- no new fields required. If the current hour is scheduled with a tag, the OSD looks for a matching subdirectory.
Example schedule entry:
"monday": {
"7": { "tags": "gameshow" },
"8": { "tags": "gameshow" },
"9": { "tags": "gameshow" },
"10": { "tags": "gameshow" }
}
Matching logo directory:
catalog/GSN/logos/gameshow/
└── gsn_gameshow_logo.png
When multiple tags are provided as a list, the first tag is used as the folder name: ["gameshow", "talkshow"] uses logos/gameshow/.
Day Parts
Day parts are defined in confs/main_config.json and referenced by name as subdirectories under logo_dir. Spaces in day part names are replaced with underscores.
{
"day_parts": {
"morning": {"start_hour": 6, "end_hour": 10},
"prime": {"start_hour": 18, "end_hour": 23},
"late": {"start_hour": 23, "end_hour": 2}
}
}
This creates three day parts matching directories logos/morning/, logos/prime/, and logos/late/. When end_hour is less than start_hour the period wraps around midnight.
If no day_parts are defined, that level of the hierarchy is skipped.
See the main_config.json reference for full day_parts documentation.
Example Setups
Seasonal logo -- Nickelodeon in October prime time
catalog/NICK/logos/October/prime/nick_pumpkin.png
Tag-driven logo -- special bug during superbowl blocks
catalog/CBS/logos/superbowl/CBSfootball.png
With schedule entries tagged "superbowl".
Friday primetime variant
catalog/ABC/logos/Friday/prime/TGIF.png
December-only logo (or date range)
catalog/NBC/logos/December/holiday_nbc_logo.png
catalog/NBC/logos/December 1 - December 31/holiday_nbc_logo.png
Volume Display
The on-screen volume meter appears for a few seconds whenever the volume is changed (via the remote or the API /player/volume/up and /player/volume/down endpoints). It draws a simple outlined bar with a filled center proportional to the current volume.
A volume meter is shown automatically even if you don't configure one. A default VolumeDisplay is added when none is present in osd.json, and it inherits its color from your first StatusDisplay. Add an explicit VolumeDisplay block only when you want to override the defaults (position, size, color, or timing).
Global Settings (osd.json)
The VolumeDisplay object lives in the same array as the text and logo config:
[
{
"type": "VolumeDisplay",
"halign": "CENTER",
"valign": "BOTTOM",
"width": 0.4,
"height": 0.04,
"x_margin": 0.1,
"y_margin": 0.25,
"color": [0, 255, 0, 200],
"display_time": 5.0,
"border_thickness": 2.0,
"padding": 0.008
}
]
| Field | Type | Description |
|---|---|---|
type |
string | Required. Must be "VolumeDisplay". |
halign |
string | Horizontal alignment: "LEFT", "RIGHT", or "CENTER". Default "CENTER". |
valign |
string | Vertical alignment: "TOP", "BOTTOM", or "CENTER". Default "BOTTOM". |
width |
float | Meter width as a fraction of half the screen width (e.g. 0.4 = 20% of screen). Default 0.4. |
height |
float | Meter height as a fraction of half the screen height. Default 0.04. |
x_margin |
float | Horizontal margin from the aligned edge, as a fraction of half the screen width. Ignored when halign is "CENTER". Default 0.1. |
y_margin |
float | Vertical margin from the aligned edge, as a fraction of half the screen height. Ignored when valign is "CENTER". Default 0.25. |
color |
array | RGBA color of the outline and fill as [R, G, B, A], each value 0-255. Defaults to the color of the first StatusDisplay, or [0, 255, 0, 200] if there isn't one. |
display_time |
float | Seconds the meter stays on screen after a volume change. Default 5.0. |
border_thickness |
float | Line width of the meter's outline, in pixels. Default 2.0. |
padding |
float | Gap in NDC units between the outline and the filled center. Default 0.008. |
Positioning with valign and y_margin
y_margin is the distance from the edge named by valign. With valign: "BOTTOM" a larger y_margin pushes the meter up; with valign: "TOP" a larger y_margin pushes it down. When valign is "CENTER", y_margin is ignored and the meter is centered vertically.
The examples below only change the vertical placement; all other fields keep their defaults.
Near the top of the screen:
{
"type": "VolumeDisplay",
"valign": "TOP",
"y_margin": 0.25
}
Middle of the screen:
{
"type": "VolumeDisplay",
"valign": "CENTER"
}
Default (near the bottom):
{
"type": "VolumeDisplay",
"valign": "BOTTOM",
"y_margin": 0.25
}
Tip: On a real CRT/TV, the outermost edges are lost to overscan. If the meter is clipped at the bottom, increase
y_marginto lift it further into the title-safe area.