From aad971db9cc3af37e59161237dde893b7f2055f9 Mon Sep 17 00:00:00 2001 From: Thinline Dynamic Solutions <124536445+Thinline-Dynamic-Solutions@users.noreply.github.com> Date: Fri, 13 Nov 2026 04:54:08 -0500 Subject: [PATCH] Add Thinline Radio completed-call upload stream type (#2626) Same /api/call-upload flow as Rdio Scanner, with its own configuration and playlist editor. Reuses RdioScannerBroadcaster. Co-authored-by: Michael Chambers Co-authored-by: Cursor --- .../broadcast/BroadcastConfiguration.java | 2 + .../audio/broadcast/BroadcastFactory.java | 4 + .../audio/broadcast/BroadcastServerType.java | 1 + .../rdioscanner/RdioScannerBroadcaster.java | 14 ++-- .../rdioscanner/RdioScannerConfiguration.java | 10 +++ .../thinline/ThinlineRadioConfiguration.java | 75 +++++++++++++++++++ .../playlist/streaming/RdioScannerEditor.java | 20 ++++- .../streaming/StreamEditorFactory.java | 2 + .../streaming/ThinlineRadioEditor.java | 52 +++++++++++++ 9 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 src/main/java/io/github/dsheirer/audio/broadcast/thinline/ThinlineRadioConfiguration.java create mode 100644 src/main/java/io/github/dsheirer/gui/playlist/streaming/ThinlineRadioEditor.java diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastConfiguration.java b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastConfiguration.java index 8391c492..e6069897 100644 --- a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastConfiguration.java +++ b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastConfiguration.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyCallConfiguration; import io.github.dsheirer.audio.broadcast.rdioscanner.RdioScannerConfiguration; +import io.github.dsheirer.audio.broadcast.thinline.ThinlineRadioConfiguration; import io.github.dsheirer.audio.broadcast.openmhz.OpenMHzConfiguration; import io.github.dsheirer.audio.broadcast.icecast.IcecastConfiguration; import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1Configuration; @@ -49,6 +50,7 @@ import java.net.SocketAddress; @JsonSubTypes({ @JsonSubTypes.Type(value = BroadcastifyCallConfiguration.class, name="broadcastifyCallConfiguration"), @JsonSubTypes.Type(value = RdioScannerConfiguration.class, name="RdioScannerConfiguration"), + @JsonSubTypes.Type(value = ThinlineRadioConfiguration.class, name="ThinlineRadioConfiguration"), @JsonSubTypes.Type(value = OpenMHzConfiguration.class, name="OpenMHzConfiguration"), @JsonSubTypes.Type(value = IcecastConfiguration.class, name="icecastConfiguration"), @JsonSubTypes.Type(value = ShoutcastV1Configuration.class, name="shoutcastV1Configuration"), diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastFactory.java b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastFactory.java index f513938d..43a2a8e0 100644 --- a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastFactory.java +++ b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastFactory.java @@ -24,6 +24,7 @@ import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyCallConfigura import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyFeedConfiguration; import io.github.dsheirer.audio.broadcast.rdioscanner.RdioScannerBroadcaster; import io.github.dsheirer.audio.broadcast.rdioscanner.RdioScannerConfiguration; +import io.github.dsheirer.audio.broadcast.thinline.ThinlineRadioConfiguration; import io.github.dsheirer.audio.broadcast.rdioscanner.RdioScannerFeedConfiguration; import io.github.dsheirer.audio.broadcast.openmhz.OpenMHzBroadcaster; import io.github.dsheirer.audio.broadcast.openmhz.OpenMHzConfiguration; @@ -68,6 +69,7 @@ public class BroadcastFactory return new BroadcastifyCallBroadcaster((BroadcastifyCallConfiguration)configuration, inputAudioFormat, mp3Setting, aliasModel); case RDIOSCANNER_CALL: + case THINLINE_RADIO: return new RdioScannerBroadcaster((RdioScannerConfiguration)configuration, inputAudioFormat, mp3Setting, aliasModel); case OPENMHZ: @@ -113,6 +115,8 @@ public class BroadcastFactory return new BroadcastifyCallConfiguration(format); case RDIOSCANNER_CALL: return new RdioScannerConfiguration(format); + case THINLINE_RADIO: + return new ThinlineRadioConfiguration(format); case BROADCASTIFY: return new BroadcastifyFeedConfiguration(format); case OPENMHZ: diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastServerType.java b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastServerType.java index b33e88c8..07c09799 100644 --- a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastServerType.java +++ b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastServerType.java @@ -32,6 +32,7 @@ public enum BroadcastServerType ICECAST_HTTP("Icecast 2 (v2.4+)", "images/icecast.png"), RDIOSCANNER_CALL("Rdio Scanner", "images/rdioscanner.png"), + THINLINE_RADIO("Thinline Radio", "images/rdioscanner.png"), OPENMHZ("OpenMHz", "images/openmhz.png"), ICECAST_TCP("Icecast (v2.3)", "images/icecast.png"), SHOUTCAST_V1("Shoutcast v1.x", "images/shoutcast.png"), diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/rdioscanner/RdioScannerBroadcaster.java b/src/main/java/io/github/dsheirer/audio/broadcast/rdioscanner/RdioScannerBroadcaster.java index 468a42dd..2cb9ffdd 100644 --- a/src/main/java/io/github/dsheirer/audio/broadcast/rdioscanner/RdioScannerBroadcaster.java +++ b/src/main/java/io/github/dsheirer/audio/broadcast/rdioscanner/RdioScannerBroadcaster.java @@ -113,7 +113,8 @@ public class RdioScannerBroadcaster extends AbstractAudioBroadcaster + * **************************************************************************** + */ + +package io.github.dsheirer.audio.broadcast.thinline; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import io.github.dsheirer.audio.broadcast.BroadcastConfiguration; +import io.github.dsheirer.audio.broadcast.BroadcastFormat; +import io.github.dsheirer.audio.broadcast.BroadcastServerType; +import io.github.dsheirer.audio.broadcast.rdioscanner.RdioScannerConfiguration; + +/** + * Call upload configuration for Thinline Radio. + * + * Thinline Radio accepts the same completed-call upload used by Rdio Scanner, including the system id, API key, + * and /api/call-upload path. + */ +public class ThinlineRadioConfiguration extends RdioScannerConfiguration +{ + /** + * Constructor for Jackson + */ + public ThinlineRadioConfiguration() + { + this(BroadcastFormat.MP3); + } + + /** + * Public constructor. + * @param format to use for audio recording (MP3) + */ + public ThinlineRadioConfiguration(BroadcastFormat format) + { + super(format); + } + + @JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance") + @Override + public BroadcastServerType getBroadcastServerType() + { + return BroadcastServerType.THINLINE_RADIO; + } + + @JsonIgnore + @Override + public String getServiceName() + { + return "Thinline Radio"; + } + + @Override + public BroadcastConfiguration copyOf() + { + ThinlineRadioConfiguration copy = new ThinlineRadioConfiguration(); + copy.setSystemID(getSystemID()); + return copy; + } +} diff --git a/src/main/java/io/github/dsheirer/gui/playlist/streaming/RdioScannerEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/streaming/RdioScannerEditor.java index 485b5ffe..03699700 100644 --- a/src/main/java/io/github/dsheirer/gui/playlist/streaming/RdioScannerEditor.java +++ b/src/main/java/io/github/dsheirer/gui/playlist/streaming/RdioScannerEditor.java @@ -119,6 +119,22 @@ public class RdioScannerEditor extends AbstractBroadcastEditor + * **************************************************************************** + */ + +package io.github.dsheirer.gui.playlist.streaming; + +import io.github.dsheirer.audio.broadcast.BroadcastServerType; +import io.github.dsheirer.playlist.PlaylistManager; + +/** + * Thinline Radio call upload configuration editor. + * + * The form and upload path match the Rdio Scanner editor. + */ +public class ThinlineRadioEditor extends RdioScannerEditor +{ + /** + * Constructs an instance + * @param playlistManager for accessing the broadcast model + */ + public ThinlineRadioEditor(PlaylistManager playlistManager) + { + super(playlistManager); + } + + @Override + public BroadcastServerType getBroadcastServerType() + { + return BroadcastServerType.THINLINE_RADIO; + } + + @Override + protected String getHostLabel() + { + return "Thinline Radio URL"; + } +}