Initial working implementation of HLS proxy

This commit is contained in:
2025-10-01 02:40:12 +05:00
commit 3bc563955f
29 changed files with 1594 additions and 0 deletions

View File

@ -0,0 +1,107 @@
package com.backend.hls.proxy.service;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.backend.hls.proxy.exception.FetchFailException;
import com.backend.hls.proxy.model.SimpleResponse;
@Service
public class FetchService {
private final HttpClient httpClient;
public FetchService(HttpClient httpClient) {
this.httpClient = httpClient;
}
/**
* Fetch text content from URL
*
* @throws FetchFailException
*/
@Cacheable("hlsPlaylistContent")
public String fetchTextContent(String url) throws IOException, InterruptedException, FetchFailException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new FetchFailException("Failed to fetch content from " + url + ", status: " + response.statusCode(),
response);
}
return response.body();
}
/**
* Fetch binary content from URL
*
* @throws FetchFailException
*/
@Cacheable("playlistSegmentContent")
public SimpleResponse<byte[]> fetchBinaryContent(String url)
throws IOException, InterruptedException, FetchFailException {
return fetchBinaryContent(url, null);
}
/**
* Fetch binary content from URL
*
* @throws FetchFailException
*/
@Cacheable("playlistSegmentContent")
public SimpleResponse<byte[]> fetchBinaryContent(String url, String rangeHeader)
throws IOException, InterruptedException, FetchFailException {
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(url));
if (rangeHeader != null && !rangeHeader.isEmpty()) {
builder.header("Range", rangeHeader);
}
HttpResponse<byte[]> response = httpClient.send(builder.build(), HttpResponse.BodyHandlers.ofByteArray());
if (response.statusCode() >= 400) {
throw new FetchFailException("Failed to fetch content from " + url + ", status: " + response.statusCode(),
response);
}
return new SimpleResponse<byte[]>(response.body(), response.headers());
}
/**
* Fetch content length
*
* @throws FetchFailException
*/
public long getContentLength(String url)
throws IOException, InterruptedException, FetchFailException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.method("HEAD", HttpRequest.BodyPublishers.noBody())
.timeout(Duration.ofSeconds(10))
.build();
HttpResponse<Void> response = httpClient.send(request,
HttpResponse.BodyHandlers.discarding());
if (response.statusCode() >= 400) {
throw new FetchFailException("HTTP " + response.statusCode(), response);
}
return response.headers()
.firstValueAsLong("Content-Length")
.orElse(-1L);
}
}