Skip to content
Merged
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
12 changes: 0 additions & 12 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,10 @@ function createWindow() {
const metadata = await window.overlayApi.metadata();
const settings = await window.overlayApi.loadSettings();
const radios = await window.overlayApi.discoverRadios();
const csvPath = ${JSON.stringify(process.env.MT12_SMOKE_CSV || "")};
let preview = null;
if (csvPath) {
const summary = await window.overlayApi.loadCsvSummary({ csv_path: csvPath, offset_ms: 0 });
preview = await window.overlayApi.previewState({
csv_path: csvPath,
time_ms: Math.min(1000, summary.duration_ms),
layout: settings.layout,
calibration: settings.calibration,
});
}
return {
sourceCount: metadata.sources.length,
layoutCount: Object.keys(settings.layout || {}).length,
radioCount: radios.sources.length,
previewOk: preview ? Boolean(preview.state) : null,
};
})();
`);
Expand Down
52 changes: 9 additions & 43 deletions src/main/nativeApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,14 @@ import { execSync, spawn } from "node:child_process";
import { app } from "electron";
import { makeCanvas, renderFrameToCanvas, getRawFrame } from "./frameRenderer";
import { buildRunningStatsArray, getRunningStatsAt } from "../shared/widgetDraw";
import { BAR_APPEARANCE_DEFAULTS as BAR_DEFAULTS, clamp, interpolateState } from "../shared/util";
import type { CsvSample } from "../shared/types";
import https from "node:https";
import os from "node:os";
import path from "node:path";

type Sample = {
time_ms: number;
values: Record<string, number>;
};

type FrameState = Record<string, number>;

type LoadedCsv = {
samples: Sample[];
samples: CsvSample[];
sources: string[];
};

Expand All @@ -30,26 +25,16 @@ const TIME_WIDGET_TYPES = ["text"];
const LEGACY_VERTICAL_BAR_TO_BAR_SCALE_X = 330 / 220;
const LEGACY_VERTICAL_BAR_TO_BAR_SCALE_Y = 130 / 48;
const BAR_APPEARANCE_DEFAULTS = {
bar_track_fill_thickness: 68,
bar_track_outline_thickness: 3,
bar_center_mark_thickness: 2,
bar_corner_radius: 100,
bar_track_fill_thickness: BAR_DEFAULTS.trackFillThickness,
bar_track_outline_thickness: BAR_DEFAULTS.trackOutlineThickness,
bar_center_mark_thickness: BAR_DEFAULTS.centerMarkThickness,
bar_corner_radius: BAR_DEFAULTS.cornerRadius,
};

function clamp(value: number, low: number, high: number) {
if (!Number.isFinite(value)) return low;
return Math.max(low, Math.min(high, value));
}


function widgetTypesForSource(source: string) {
return source === TIME_SOURCE ? TIME_WIDGET_TYPES : CHANNEL_WIDGET_TYPES;
}

function sourceDisplayName(source: string) {
return source;
}

function defaultItemName(source: string, itemId: string) {
const prefix = `item_${source}_`;
if (itemId.startsWith(prefix)) {
Expand Down Expand Up @@ -170,7 +155,7 @@ function defaultItemForSource(source: string, itemId: string) {
const base = {
source,
name: defaultItemName(source, itemId),
label: sourceDisplayName(source),
label: source,
widget: widgetTypesForSource(source)[0],
x: 0.5,
y: 0.5,
Expand Down Expand Up @@ -377,7 +362,7 @@ function loadSamples(csvPath: string, offsetMs = 0): LoadedCsv {
const index = Object.fromEntries(headers.map((header, idx) => [header, idx]));
let firstTick: number | null = null;

const samples: Sample[] = [];
const samples: CsvSample[] = [];
for (const line of lines.slice(1)) {
const row = parseCsvLine(line);
const tick = Number(row[index.timestamp]);
Expand All @@ -397,25 +382,6 @@ function loadSamples(csvPath: string, offsetMs = 0): LoadedCsv {
return { samples, sources };
}

function interpolateState(samples: Sample[], timeMs: number): FrameState {
if (timeMs <= samples[0].time_ms) return { ...samples[0].values };
const last = samples[samples.length - 1];
if (timeMs >= last.time_ms) return { ...last.values };
let index = 0;
while (index < samples.length - 2 && samples[index + 1].time_ms < timeMs) index += 1;
const left = samples[index];
const right = samples[index + 1];
const segment = right.time_ms - left.time_ms;
const t = segment <= 0 ? 0 : (timeMs - left.time_ms) / segment;
const lerp = (a: number, b: number) => a + (b - a) * t;
const state: FrameState = {};
const sources = new Set([...Object.keys(left.values), ...Object.keys(right.values)]);
for (const source of sources) {
state[source] = lerp(left.values[source] ?? 0, right.values[source] ?? 0);
}
return state;
}

function loadCsvSummary(payload: Record<string, unknown>) {
const csvPath = String(payload.csv_path || "");
const { samples, sources } = loadSamples(csvPath, Number(payload.offset_ms || 0));
Expand Down
14 changes: 8 additions & 6 deletions src/renderer/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,18 @@ import "./styles.css";
import "./i18n";
import {
api,
clamp,
defaultSettings,
fallbackMetadata,
interpolateLocalState,
} from "./utils";
import type { HandleId, ResizePreview, ResizingState } from "./utils";
import {
clamp,
interpolateState,
itemBounds,
numeric,
widgetSize,
widgetTypesForSource,
} from "./utils";
import type { HandleId, ResizePreview, ResizingState } from "./utils";
} from "../shared/util";
import { buildRunningStatsArray, getRunningStatsAt, type RunningStats } from "../shared/widgetDraw";
import { CaptureRenderer } from "./components/CaptureRenderer";
import { LangDropdown } from "./components/LangDropdown";
Expand Down Expand Up @@ -219,7 +221,7 @@ function App() {
async function refreshPreview(path = settings.csv_path, timeMs = previewTime, sourceSettings = settings) {
if (!path) return;
if (previewSamples.length) {
setPreviewState(interpolateLocalState(previewSamples, timeMs));
setPreviewState(interpolateState(previewSamples, timeMs));
return;
}
const requestId = previewRequestRef.current + 1;
Expand Down Expand Up @@ -251,7 +253,7 @@ function App() {
void refreshPreview(settings.csv_path, timeMs, latestSettingsRef.current);
return;
}
setPreviewState(interpolateLocalState(samples, timeMs));
setPreviewState(interpolateState(samples, timeMs));
}

async function autoDetectFfmpeg() {
Expand Down
53 changes: 53 additions & 0 deletions src/renderer/components/SupportCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useTranslation } from "react-i18next";
import QRCode from "react-qr-code";
import topercLogo from "../assets/toperc-logo.png";

export function SupportCard() {
const { t } = useTranslation();

return (
<div className="support-card">
<div className="support-section support-yt">
<img src={topercLogo} alt="TopeRC" className="support-yt-logo" />
<div className="support-yt-text">
<span className="support-label">TopeRC</span>
<span className="support-sub">{t("support.channelSub")}</span>
</div>
<a
className="support-yt-btn"
href="https://www.youtube.com/@TopeRC-es"
target="_blank"
rel="noreferrer"
>
{t("support.subscribe")}
</a>
</div>

<div className="support-divider" />

<div className="support-section support-donate">
<div className="support-qr">
<QRCode
value="https://paypal.me/dgarana"
size={96}
bgColor="transparent"
fgColor="#edf3f8"
level="M"
/>
</div>
<div className="support-donate-text">
<span className="support-label">{t("support.donateTitle")}</span>
<span className="support-sub">{t("support.donateSub")}</span>
<a
className="support-donate-link"
href="https://paypal.me/dgarana"
target="_blank"
rel="noreferrer"
>
paypal.me/dgarana
</a>
</div>
</div>
</div>
);
}
3 changes: 0 additions & 3 deletions src/renderer/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@
"controlColor": "Farbe",
"controlThickness": "Stärke",
"controlThicknessPercent": "Stärke (%)",
"barTrackFillThickness": "Spur (%)",
"barTrackOutlineThickness": "Kontur",
"barCenterMarkThickness": "Mitte",
"barCornerRadius": "Radius (%)",
"selectOrAdd": "Widget auswählen oder hinzufügen",
"zoomOut": "Herauszoomen",
Expand Down
3 changes: 0 additions & 3 deletions src/renderer/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@
"controlColor": "Color",
"controlThickness": "Thickness",
"controlThicknessPercent": "Thickness (%)",
"barTrackFillThickness": "Track (%)",
"barTrackOutlineThickness": "Outline",
"barCenterMarkThickness": "Center mark",
"barCornerRadius": "Radius (%)",
"selectOrAdd": "Select or add a widget",
"zoomOut": "Zoom out",
Expand Down
3 changes: 0 additions & 3 deletions src/renderer/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@
"controlColor": "Color",
"controlThickness": "Grosor",
"controlThicknessPercent": "Grosor (%)",
"barTrackFillThickness": "Pista (%)",
"barTrackOutlineThickness": "Contorno",
"barCenterMarkThickness": "Marca central",
"barCornerRadius": "Redondeado (%)",
"selectOrAdd": "Selecciona o añade un widget",
"zoomOut": "Alejar",
Expand Down
3 changes: 0 additions & 3 deletions src/renderer/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@
"controlColor": "Couleur",
"controlThickness": "Epaisseur",
"controlThicknessPercent": "Epaisseur (%)",
"barTrackFillThickness": "Piste (%)",
"barTrackOutlineThickness": "Contour",
"barCenterMarkThickness": "Repère central",
"barCornerRadius": "Arrondi (%)",
"selectOrAdd": "Sélectionner ou ajouter un widget",
"zoomOut": "Dézoomer",
Expand Down
Loading
Loading