Compare commits
2 Commits
500db0bbe3
...
4c9c10b013
Author | SHA1 | Date | |
---|---|---|---|
|
4c9c10b013 | ||
|
91a53ec119 |
24
Build.bat
Normal file
24
Build.bat
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
@echo off
|
||||||
|
echo === Building RadioDJ-TunaBridge ===
|
||||||
|
|
||||||
|
REM Clean previous build
|
||||||
|
mvn clean
|
||||||
|
|
||||||
|
REM Compile and package the JAR
|
||||||
|
mvn package
|
||||||
|
|
||||||
|
IF %ERRORLEVEL% NEQ 0 (
|
||||||
|
echo ❌ Build failed.
|
||||||
|
pause
|
||||||
|
exit /b %ERRORLEVEL%
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Copy final JAR to top-level folder (optional)
|
||||||
|
IF EXIST target\radiodj-tuna-bridge-1.0-SNAPSHOT.jar (
|
||||||
|
copy target\radiodj-tuna-bridge-1.0-SNAPSHOT.jar radiodj-tuna-bridge.jar >nul
|
||||||
|
echo ✅ Build complete. Output: radiodj-tuna-bridge.jar
|
||||||
|
) ELSE (
|
||||||
|
echo ❌ JAR not found!
|
||||||
|
)
|
||||||
|
|
||||||
|
pause
|
40
README.md
40
README.md
@@ -1,2 +1,40 @@
|
|||||||
# RadioDJ-Tuna
|
# 🎧 RadioDJ Tuna Bridge
|
||||||
|
|
||||||
|
A lightweight Java utility that pulls "Now Playing" info from RadioDJ's REST XML API, and outputs it as `.txt` files and album art for tools like Tuna (OBS plugin).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Features
|
||||||
|
|
||||||
|
- ✅ Pulls title / artist / album / album art via REST
|
||||||
|
- 🛑 Only updates files if the song actually changed
|
||||||
|
- 🖼️ Copies matching album art, or uses fallback image
|
||||||
|
- 💾 Creates & reads from `config.yml` and `last-played.xml`
|
||||||
|
- 🪄 Fully customizable update interval
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Usage
|
||||||
|
|
||||||
|
1. **First Run:**
|
||||||
|
- Launch the app with `java -jar radiodj-tuna-bridge.jar`
|
||||||
|
- You'll be prompted to enter your API URL, art folder, fallback filename, and polling interval
|
||||||
|
|
||||||
|
2. **Outputs:**
|
||||||
|
- Stored in `tuna-output/` folder:
|
||||||
|
- `track-title.txt`
|
||||||
|
- `track-artist.txt`
|
||||||
|
- `track-album.txt`
|
||||||
|
- `album-art.jpg` (copied from your RadioDJ art folder)
|
||||||
|
|
||||||
|
3. **Reconfigure:**
|
||||||
|
- Edit the `config.yml` file to change settings at any time
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Build Instructions
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/you/radiodj-tuna-bridge.git
|
||||||
|
cd radiodj-tuna-bridge
|
||||||
|
build.bat
|
42
pom.xml
Normal file
42
pom.xml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>radiodj-tuna-bridge</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- Jackson for XML & JSON processing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||||
|
<artifactId>jackson-dataformat-xml</artifactId>
|
||||||
|
<version>2.17.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SnakeYAML for config.yml parsing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.yaml</groupId>
|
||||||
|
<artifactId>snakeyaml</artifactId>
|
||||||
|
<version>2.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Dorkbox SystemTray for Windows notifications -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.dorkbox</groupId>
|
||||||
|
<artifactId>SystemTray</artifactId>
|
||||||
|
<version>3.17</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
7
run.bat
Normal file
7
run.bat
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
@echo off
|
||||||
|
echo === Running RadioDJ Tuna Bridge ===
|
||||||
|
|
||||||
|
REM Run the JAR (assumes you built it already)
|
||||||
|
java -jar radiodj-tuna-bridge.jar
|
||||||
|
|
||||||
|
pause
|
40
src/main/java/com/minster586/radiodjtuna/Config.java
Normal file
40
src/main/java/com/minster586/radiodjtuna/Config.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package com.minster586.radiodjtuna;
|
||||||
|
|
||||||
|
public class Config {
|
||||||
|
private String radioDjApiUrl;
|
||||||
|
private String albumArtDirectory;
|
||||||
|
private int updateIntervalSeconds;
|
||||||
|
private String fallbackArtFilename;
|
||||||
|
|
||||||
|
public String getRadioDjApiUrl() {
|
||||||
|
return radioDjApiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRadioDjApiUrl(String radioDjApiUrl) {
|
||||||
|
this.radioDjApiUrl = radioDjApiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlbumArtDirectory() {
|
||||||
|
return albumArtDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlbumArtDirectory(String albumArtDirectory) {
|
||||||
|
this.albumArtDirectory = albumArtDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUpdateIntervalSeconds() {
|
||||||
|
return updateIntervalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateIntervalSeconds(int updateIntervalSeconds) {
|
||||||
|
this.updateIntervalSeconds = updateIntervalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFallbackArtFilename() {
|
||||||
|
return fallbackArtFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFallbackArtFilename(String fallbackArtFilename) {
|
||||||
|
this.fallbackArtFilename = fallbackArtFilename;
|
||||||
|
}
|
||||||
|
}
|
74
src/main/java/com/minster586/radiodjtuna/ConfigManager.java
Normal file
74
src/main/java/com/minster586/radiodjtuna/ConfigManager.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package com.minster586.radiodjtuna;
|
||||||
|
|
||||||
|
import org.yaml.snakeyaml.DumperOptions;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
import org.yaml.snakeyaml.constructor.Constructor;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
public class ConfigManager {
|
||||||
|
|
||||||
|
private final Path configPath;
|
||||||
|
|
||||||
|
public ConfigManager(Path configPath) {
|
||||||
|
this.configPath = configPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config loadOrCreateConfig() {
|
||||||
|
File configFile = configPath.toFile();
|
||||||
|
if (!configFile.exists()) {
|
||||||
|
System.out.println("⚙️ Creating new config.yml...");
|
||||||
|
Config newConfig = promptForConfig();
|
||||||
|
saveConfig(newConfig);
|
||||||
|
return newConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream input = java.nio.file.Files.newInputStream(configPath)) {
|
||||||
|
Yaml yaml = new Yaml(new Constructor(Config.class));
|
||||||
|
Config loaded = yaml.load(input);
|
||||||
|
System.out.println("✅ Config loaded successfully.");
|
||||||
|
return loaded;
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("❌ Failed to load config: " + e.getMessage());
|
||||||
|
System.exit(1);
|
||||||
|
return null; // unreachable, but satisfies compiler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Config promptForConfig() {
|
||||||
|
Scanner scanner = new Scanner(System.in);
|
||||||
|
Config config = new Config();
|
||||||
|
|
||||||
|
System.out.print("🔗 Enter RadioDJ API URL (e.g. http://localhost:1234/playing): ");
|
||||||
|
config.setRadioDjApiUrl(scanner.nextLine().trim());
|
||||||
|
|
||||||
|
System.out.print("📁 Enter full path to RadioDJ album art folder: ");
|
||||||
|
config.setAlbumArtDirectory(scanner.nextLine().trim());
|
||||||
|
|
||||||
|
System.out.print("⏱️ Enter update interval (seconds): ");
|
||||||
|
config.setUpdateIntervalSeconds(Integer.parseInt(scanner.nextLine().trim()));
|
||||||
|
|
||||||
|
System.out.print("🖼️ Enter fallback album art filename (e.g. fallback-art.jpg): ");
|
||||||
|
config.setFallbackArtFilename(scanner.nextLine().trim());
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveConfig(Config config) {
|
||||||
|
try (FileWriter writer = new FileWriter(configPath.toFile())) {
|
||||||
|
DumperOptions options = new DumperOptions();
|
||||||
|
options.setIndent(2);
|
||||||
|
options.setPrettyFlow(true);
|
||||||
|
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||||
|
Yaml yaml = new Yaml(options);
|
||||||
|
yaml.dump(config, writer);
|
||||||
|
System.out.println("💾 Config saved to " + configPath);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("❌ Failed to save config: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
src/main/java/com/minster586/radiodjtuna/MainApp.java
Normal file
68
src/main/java/com/minster586/radiodjtuna/MainApp.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package com.minster586.radiodjtuna;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
public class MainApp {
|
||||||
|
|
||||||
|
// Base paths determined at runtime
|
||||||
|
private static Path jarDir;
|
||||||
|
private static Path outputDir;
|
||||||
|
private static Path configFile;
|
||||||
|
private static Path cacheFile;
|
||||||
|
|
||||||
|
// Core components
|
||||||
|
private static Config config;
|
||||||
|
private static MetadataCacheManager cacheManager;
|
||||||
|
private static TrackInfo lastPlayed;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("🔊 RadioDJ Tuna Bridge starting up...");
|
||||||
|
|
||||||
|
initializePaths();
|
||||||
|
ensureOutputFolder();
|
||||||
|
|
||||||
|
// Load or create config
|
||||||
|
ConfigManager configManager = new ConfigManager(configFile);
|
||||||
|
config = configManager.loadOrCreateConfig();
|
||||||
|
|
||||||
|
// Set up metadata cache manager
|
||||||
|
cacheManager = new MetadataCacheManager(cacheFile);
|
||||||
|
lastPlayed = cacheManager.loadCache();
|
||||||
|
|
||||||
|
if (lastPlayed != null) {
|
||||||
|
System.out.println("🗃️ Loaded cached track: " + lastPlayed.getTitle());
|
||||||
|
} else {
|
||||||
|
System.out.println("📁 No metadata cache found yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Poll RadioDJ API using config.getRadioDjApiUrl()
|
||||||
|
// TODO: Compare result to lastPlayed using lastPlayed.equals()
|
||||||
|
// TODO: If different, write new metadata to output folder
|
||||||
|
// TODO: Save new metadata to last-played.xml
|
||||||
|
// TODO: Handle album art copy or fallback
|
||||||
|
// TODO: Show toast if API is unreachable
|
||||||
|
|
||||||
|
System.out.println("✅ System initialized. Ready for polling phase.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initializePaths() {
|
||||||
|
jarDir = Paths.get("").toAbsolutePath();
|
||||||
|
outputDir = jarDir.resolve("tuna-output");
|
||||||
|
configFile = jarDir.resolve("config.yml");
|
||||||
|
cacheFile = jarDir.resolve("last-played.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureOutputFolder() {
|
||||||
|
File outFolder = outputDir.toFile();
|
||||||
|
if (!outFolder.exists()) {
|
||||||
|
boolean created = outFolder.mkdirs();
|
||||||
|
if (created) {
|
||||||
|
System.out.println("📁 Created output folder: " + outputDir);
|
||||||
|
} else {
|
||||||
|
System.err.println("❌ Failed to create output folder. Check permissions.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,82 @@
|
|||||||
|
package com.minster586.radiodjtuna;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.transform.*;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
|
||||||
|
import org.w3c.dom.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class MetadataCacheManager {
|
||||||
|
private final Path cachePath;
|
||||||
|
|
||||||
|
public MetadataCacheManager(Path cachePath) {
|
||||||
|
this.cachePath = cachePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrackInfo loadCache() {
|
||||||
|
File file = cachePath.toFile();
|
||||||
|
if (!file.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
Document doc = builder.parse(file);
|
||||||
|
|
||||||
|
Element root = doc.getDocumentElement();
|
||||||
|
|
||||||
|
String title = getText(root, "Title");
|
||||||
|
String artist = getText(root, "Artist");
|
||||||
|
String album = getText(root, "Album");
|
||||||
|
String albumArt = getText(root, "AlbumArt");
|
||||||
|
|
||||||
|
return new TrackInfo(title, artist, album, albumArt);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("⚠️ Failed to load last-played.xml: " + e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveCache(TrackInfo track) {
|
||||||
|
try {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
Document doc = builder.newDocument();
|
||||||
|
|
||||||
|
Element root = doc.createElement("LastPlayed");
|
||||||
|
doc.appendChild(root);
|
||||||
|
|
||||||
|
addText(doc, root, "Title", track.getTitle());
|
||||||
|
addText(doc, root, "Artist", track.getArtist());
|
||||||
|
addText(doc, root, "Album", track.getAlbum());
|
||||||
|
addText(doc, root, "AlbumArt", track.getAlbumArt());
|
||||||
|
|
||||||
|
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||||
|
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||||
|
Result output = new StreamResult(cachePath.toFile());
|
||||||
|
Source input = new DOMSource(doc);
|
||||||
|
transformer.transform(input, output);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("❌ Failed to save last-played.xml: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getText(Element root, String tag) {
|
||||||
|
NodeList list = root.getElementsByTagName(tag);
|
||||||
|
return (list.getLength() > 0) ? list.item(0).getTextContent() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addText(Document doc, Element parent, String tag, String value) {
|
||||||
|
Element node = doc.createElement(tag);
|
||||||
|
node.appendChild(doc.createTextNode(value != null ? value : ""));
|
||||||
|
parent.appendChild(node);
|
||||||
|
}
|
||||||
|
}
|
75
src/main/java/com/minster586/radiodjtuna/OutputManager.java
Normal file
75
src/main/java/com/minster586/radiodjtuna/OutputManager.java
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package com.minster586.radiodjtuna;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.*;
|
||||||
|
|
||||||
|
public class OutputManager {
|
||||||
|
|
||||||
|
private final Path outputDir;
|
||||||
|
private final Path albumArtSourceFolder;
|
||||||
|
private final String fallbackArtFilename;
|
||||||
|
|
||||||
|
public OutputManager(Path outputDir, String albumArtSourceDir, String fallbackArtFilename) {
|
||||||
|
this.outputDir = outputDir;
|
||||||
|
this.albumArtSourceFolder = Paths.get(albumArtSourceDir);
|
||||||
|
this.fallbackArtFilename = fallbackArtFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeOutputFiles(TrackInfo track) {
|
||||||
|
try {
|
||||||
|
writeTextFile("track-title.txt", track.getTitle());
|
||||||
|
writeTextFile("track-artist.txt", track.getArtist());
|
||||||
|
writeTextFile("track-album.txt", track.getAlbum());
|
||||||
|
copyAlbumArt(track.getAlbumArt());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("❌ Failed writing output files: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeTextFile(String fileName, String content) throws IOException {
|
||||||
|
Path file = outputDir.resolve(fileName);
|
||||||
|
Files.writeString(file, content != null ? content : "", StandardCharsets.UTF_8,
|
||||||
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyAlbumArt(String albumArtFileName) {
|
||||||
|
Path destination = outputDir.resolve("album-art.jpg");
|
||||||
|
|
||||||
|
if (albumArtFileName == null || albumArtFileName.isBlank()) {
|
||||||
|
System.out.println("ℹ️ No album art in tag, using fallback.");
|
||||||
|
copyFallback(destination);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path sourceFile = albumArtSourceFolder.resolve(albumArtFileName);
|
||||||
|
|
||||||
|
if (!Files.exists(sourceFile)) {
|
||||||
|
System.out.println("⚠️ Album art not found: " + sourceFile.getFileName() + ", using fallback.");
|
||||||
|
copyFallback(destination);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.copy(sourceFile, destination, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
System.out.println("🎨 Album art updated: " + albumArtFileName);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("❌ Failed copying album art: " + e.getMessage());
|
||||||
|
copyFallback(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyFallback(Path destination) {
|
||||||
|
Path fallbackSource = outputDir.resolve(fallbackArtFilename);
|
||||||
|
if (Files.exists(fallbackSource)) {
|
||||||
|
try {
|
||||||
|
Files.copy(fallbackSource, destination, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
System.out.println("🖼️ Fallback album art used.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("❌ Failed to copy fallback art: " + e.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("❌ Fallback art file is missing: " + fallbackSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,46 @@
|
|||||||
|
package com.minster586.radiodjtuna;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class RadioDjApiClient {
|
||||||
|
private final String apiUrl;
|
||||||
|
|
||||||
|
public RadioDjApiClient(String apiUrl) {
|
||||||
|
this.apiUrl = apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrackInfo fetchNowPlaying() throws Exception {
|
||||||
|
URL url = new URL(apiUrl);
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setConnectTimeout(3000); // 3s timeout
|
||||||
|
connection.setReadTimeout(3000);
|
||||||
|
|
||||||
|
try (InputStream in = connection.getInputStream()) {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
Document doc = builder.parse(in);
|
||||||
|
Element root = doc.getDocumentElement();
|
||||||
|
|
||||||
|
String title = getText(root, "Title");
|
||||||
|
String artist = getText(root, "Artist");
|
||||||
|
String album = getText(root, "Album");
|
||||||
|
String albumArt = getText(root, "AlbumArt");
|
||||||
|
|
||||||
|
return new TrackInfo(title, artist, album, albumArt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getText(Element root, String tag) {
|
||||||
|
return root.getElementsByTagName(tag).getLength() > 0
|
||||||
|
? root.getElementsByTagName(tag).item(0).getTextContent()
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
}
|
63
src/main/java/com/minster586/radiodjtuna/TrackInfo.java
Normal file
63
src/main/java/com/minster586/radiodjtuna/TrackInfo.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package com.minster586.radiodjtuna;
|
||||||
|
|
||||||
|
public class TrackInfo {
|
||||||
|
private String title;
|
||||||
|
private String artist;
|
||||||
|
private String album;
|
||||||
|
private String albumArt;
|
||||||
|
|
||||||
|
public TrackInfo() {
|
||||||
|
// Default constructor for XML deserialization
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrackInfo(String title, String artist, String album, String albumArt) {
|
||||||
|
this.title = title;
|
||||||
|
this.artist = artist;
|
||||||
|
this.album = album;
|
||||||
|
this.albumArt = albumArt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getArtist() {
|
||||||
|
return artist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArtist(String artist) {
|
||||||
|
this.artist = artist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlbum() {
|
||||||
|
return album;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlbum(String album) {
|
||||||
|
this.album = album;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlbumArt() {
|
||||||
|
return albumArt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlbumArt(String albumArt) {
|
||||||
|
this.albumArt = albumArt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(TrackInfo other) {
|
||||||
|
if (other == null) return false;
|
||||||
|
return safeEquals(this.title, other.title)
|
||||||
|
&& safeEquals(this.artist, other.artist)
|
||||||
|
&& safeEquals(this.album, other.album)
|
||||||
|
&& safeEquals(this.albumArt, other.albumArt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean safeEquals(String a, String b) {
|
||||||
|
return (a == null && b == null) || (a != null && a.equals(b));
|
||||||
|
}
|
||||||
|
}
|
BIN
target/classes/com/minster586/radiodjtuna/Config.class
Normal file
BIN
target/classes/com/minster586/radiodjtuna/Config.class
Normal file
Binary file not shown.
BIN
target/classes/com/minster586/radiodjtuna/ConfigManager.class
Normal file
BIN
target/classes/com/minster586/radiodjtuna/ConfigManager.class
Normal file
Binary file not shown.
BIN
target/classes/com/minster586/radiodjtuna/MainApp.class
Normal file
BIN
target/classes/com/minster586/radiodjtuna/MainApp.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
target/classes/com/minster586/radiodjtuna/OutputManager.class
Normal file
BIN
target/classes/com/minster586/radiodjtuna/OutputManager.class
Normal file
Binary file not shown.
BIN
target/classes/com/minster586/radiodjtuna/RadioDjApiClient.class
Normal file
BIN
target/classes/com/minster586/radiodjtuna/RadioDjApiClient.class
Normal file
Binary file not shown.
BIN
target/classes/com/minster586/radiodjtuna/TrackInfo.class
Normal file
BIN
target/classes/com/minster586/radiodjtuna/TrackInfo.class
Normal file
Binary file not shown.
Reference in New Issue
Block a user