Subtitle file charset on the fly conversion
I have all SK/CZ subtitles in windows-1250 encoding on my DLNA server and I'm using serviio with 2 TVs. Samsung TV supports only windows-1250 and Panasonic Viera supports only Latin2 (ISO-8859-2) character set for central European characters.
So I cannot convert subtitle files directly on the server, because they still will be not working correctly on the both TVs.
Currently I'm using the following ugly hardcoded patch for on the fly conversion for Panasonic TV. But I think better way would be to add new parameter for that in the TV profile.
For example:
<SubtitlesCharsetConversion sourceCharset="windows-1250" destinationCharset="ISO-8859-2" />
If the element will be defined then serviio automatically convert charset from sourceCharset to destionationCharset on the fly.
If it won't be defined for TV then the subtitles are not converted.
- Code:
package org.serviio.delivery;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import org.serviio.dlna.MediaFormatProfile;
import org.serviio.dlna.UnsupportedDLNAMediaFileFormatException;
import org.serviio.library.service.SubtitlesService;
import org.serviio.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SubtitlesRetrievalStrategy
implements ResourceRetrievalStrategy
{
private static final Logger log = LoggerFactory.getLogger(SubtitlesRetrievalStrategy.class);
public DeliveryContainer retrieveResource(Long mediaItemId, MediaFormatProfile selectedVersion, Client client, boolean markAsRead)
throws FileNotFoundException, IOException
{
File subtitleFile = SubtitlesService.findSubtitleFile(mediaItemId);
if (subtitleFile == null) {
throw new FileNotFoundException(String.format("Subtitle file for media item %s cannot be found", new Object[] { mediaItemId }));
}
log.debug(String.format("Retrieving Subtitles for media item with id %s", new Object[] { mediaItemId }));
ResourceInfo resourceInfo = retrieveResourceInfo(mediaItemId, subtitleFile, client);
DeliveryContainer container;
if (client.getRendererProfile().getId().equals("12")) {
InputStreamReader sr = null;
OutputStreamWriter sw = null;
try {
sr = new InputStreamReader(new ByteArrayInputStream(FileUtils.readFileBytes(subtitleFile)), "windows-1250");
StringBuffer sb = new StringBuffer();
char[] chars = new char[2048];
int numRead = 0;
while ((numRead = sr.read(chars)) > 0) {
sb.append(chars, 0, numRead);
}
sr.close();
String s = sb.toString();
s = s.replace("<b>", "");
s = s.replace("<i>", "");
s = s.replace("<u>", "");
s = s.replace("</b>", "");
s = s.replace("</i>", "");
s = s.replace("</u>", "");
ByteArrayOutputStream os = new ByteArrayOutputStream();
sw = new OutputStreamWriter(os, "ISO-8859-2");
sw.write(s);
container = new StreamDeliveryContainer(new ByteArrayInputStream(os.toByteArray()), resourceInfo);
}
catch (Exception e) {
throw new IOException(String.format("Subtitle file for media item %s cannot be converted", new Object[] { mediaItemId }));
}
finally {
if (sr != null) {
sr.close();
}
if (sw != null) {
sw.close();
}
}
}
else {
container = new StreamDeliveryContainer(new ByteArrayInputStream(FileUtils.readFileBytes(subtitleFile)), resourceInfo);
}
return container;
}
public ResourceInfo retrieveResourceInfo(Long mediaItemId, MediaFormatProfile selectedVersion, Client client)
throws FileNotFoundException, UnsupportedDLNAMediaFileFormatException
{
File subtitleFile = SubtitlesService.findSubtitleFile(mediaItemId);
if (subtitleFile == null) {
throw new FileNotFoundException(String.format("Subtitle file for media item %s cannot be found", new Object[] { mediaItemId }));
}
log.debug(String.format("Retrieving info of Subtitles for media item with id %s", new Object[] { mediaItemId }));
return retrieveResourceInfo(mediaItemId, subtitleFile, client);
}
private ResourceInfo retrieveResourceInfo(Long mediaItemId, File subtitleFile, Client client)
throws FileNotFoundException
{
ResourceInfo resourceInfo = new SubtitlesInfo(mediaItemId, Long.valueOf(subtitleFile.length()), client.getRendererProfile().getSubtitlesMimeType());
return resourceInfo;
}
}