Skip to content

Commit

Permalink
Allow to fetch streams by date to access content more than 7 days int…
Browse files Browse the repository at this point in the history
…o the past
  • Loading branch information
centic9 committed Feb 22, 2024
1 parent c7b8b69 commit 62f1686
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 15 deletions.
75 changes: 60 additions & 15 deletions src/main/java/org/dstadler/audio/fm4/FM4.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,46 @@ public class FM4 {

private static final ObjectMapper objectMapper = new ObjectMapper();

/**
* Fetch default list of previous streams, usually returns data for the last 7 days
* @return A list of {@link FM4Stream}
* @throws IOException If fetching data via the FM4 REST API fails
*/
public List<FM4Stream> fetchStreams() throws IOException {
return fetchStreams(FM4_API_URL, FM4_STREAM_URL_BASE);
}

public List<FM4Stream> fetchStreams(String apiUrl, String streamUrlBase) throws IOException {
final String json;
try {
// fetch stream
json = HttpClientWrapper.retrieveData(apiUrl);
} catch (IOException e) {
throw new IOException("While reading from: " + apiUrl, e);
}
/**
* Fetch a list of previous streams for a given day.
*
* @param date A date in the form of yyyyMMdd, usually data is available for the last 30 days
* @return A list of {@link FM4Stream}
* @throws IOException If fetching data via the FM4 REST API fails
*/
public List<FM4Stream> fetchStreams(String date) throws IOException {
// https://audioapi.orf.at/fm4/api/json/5.0/broadcasts/20240131?_o=sound.orf.at
String apiUrl = FM4_API_URL.replace("/broadcasts?", "/broadcasts/" + date + "?");

JsonNode jsonNode = objectMapper.readTree(json).get("payload");
JsonNode jsonNode = parsAPI(apiUrl);

/*{
"dateOffset" : -3600000,
"broadcasts" : [
{
...
List<FM4Stream> streams = new ArrayList<>();
for (JsonNode node : jsonNode) {
streams.add(new FM4Stream(node, FM4_STREAM_URL_BASE));
}
return streams;
}

*/
/**
* Fetch default list of previous streams via the given REST API URLs.
* This usually returns data for the last 7 days
*
* @param apiUrl The REST API URL to use
* @param streamUrlBase The URL to use for downloading streams
* @return A list of {@link FM4Stream}
* @throws IOException If fetching data via the FM4 REST API fails
*/
public List<FM4Stream> fetchStreams(String apiUrl, String streamUrlBase) throws IOException {
JsonNode jsonNode = parsAPI(apiUrl);

List<FM4Stream> streams = new ArrayList<>();
for (JsonNode node : jsonNode) {
Expand All @@ -64,6 +82,26 @@ public List<FM4Stream> fetchStreams(String apiUrl, String streamUrlBase) throws
return streams;
}

private static JsonNode parsAPI(String apiUrl) throws IOException {
final String json;
try {
// fetch stream
json = HttpClientWrapper.retrieveData(apiUrl);
} catch (IOException e) {
throw new IOException("While reading from: " + apiUrl, e);
}

return objectMapper.readTree(json).get("payload");
}

/**
* Fetch streams and filter them by the given programKey and also remove
* future instances of streams.
*
* @param programKey The FM4 program-key, e.g. "4MG"
* @return A list of {@link FM4Stream}
* @throws IOException If fetching data via the FM4 REST API fails
*/
public List<FM4Stream> filterStreams(String programKey) throws IOException {
List<FM4Stream> streams = fetchStreams();

Expand All @@ -87,6 +125,13 @@ public List<FM4Stream> filterStreams(String programKey) throws IOException {
collect(Collectors.toList());
}

/**
* Download the given stream to a MP3 file.
*
* @param stream The FM4 stream to download
* @param downloadDir Where to store the resulting file. It will be named after the title of the stream.
* @throws IOException If fetching data via the FM4 REST API fails
*/
public void downloadStream(FM4Stream stream, File downloadDir) throws IOException {
int count = 0;
for (String url : stream.getStreams()) {
Expand Down
22 changes: 22 additions & 0 deletions src/test/java/org/dstadler/audio/fm4/FM4Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.apache.commons.io.HexDump;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
Expand All @@ -25,6 +27,7 @@
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

Expand Down Expand Up @@ -60,6 +63,25 @@ public void testFetch() throws IOException, ParseException {
}
}

@Test
public void testFetchForDate() throws IOException, ParseException {
String date = FastDateFormat.getInstance("yyyyMMdd").format(DateUtils.addDays(new Date(), -3));
List<FM4Stream> fm4Streams = fm4.fetchStreams(date);

assertNotNull(fm4Streams);
assertFalse(fm4Streams.isEmpty());

// check resulting streams are sane
for (FM4Stream stream : fm4Streams) {
assertTrue(stream.getDuration() > 60_000);
assertTrue(stream.getStart() > System.currentTimeMillis() - (35L*24*60*60*1000));
assertNotNull(stream.getProgramKey());
assertNotNull(stream.getTitle());
assertNotNull(stream.getShortTime());
assertNotNull(DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.parse(stream.getShortTime()));
}
}

@Ignore("Fetches streams for all programs, this runs for some time, so disable for CI")
@Test
public void testFetchAllStreams() throws IOException {
Expand Down

0 comments on commit 62f1686

Please sign in to comment.