Add option to disable seeking on transcodes. (Mitigates #548 & #723)

As per #548, #723, and tsquillario/Jamstash#131, the current method of
estimating `Content-Length` creates various problems.

However, if headers such as `Accept-Ranges` is omitted, clients will only
use the first connection, which is `Transfer-Encoding: chunked`, and no
`Content-Length` is necessary.

Doing this has the side effect that (at least on the web player) seeking
to a specific time is no longer possible, thus this was made an opt-in
option.

Signed-off-by: WillyPillow <wp@nerde.pw>
master
WillyPillow 6 years ago
parent 8ba0bc88f0
commit 84144f287a
No known key found for this signature in database
GPG Key ID: 3839E194B1415A9C
  1. 4
      airsonic-main/src/main/java/org/airsonic/player/controller/StreamController.java
  2. 2
      airsonic-main/src/main/java/org/airsonic/player/controller/TranscodingSettingsController.java
  3. 10
      airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java
  4. 1
      airsonic-main/src/main/resources/org/airsonic/player/i18n/ResourceBundle_en.properties
  5. 1
      airsonic-main/src/main/resources/org/airsonic/player/i18n/ResourceBundle_zh_CN.properties
  6. 1
      airsonic-main/src/main/resources/org/airsonic/player/i18n/ResourceBundle_zh_TW.properties
  7. 5
      airsonic-main/src/main/webapp/WEB-INF/jsp/transcodingSettings.jsp

@ -152,7 +152,7 @@ public class StreamController {
playQueue.addFiles(true, file); playQueue.addFiles(true, file);
player.setPlayQueue(playQueue); player.setPlayQueue(playQueue);
if (!file.isVideo()) { if (settingsService.isEnableSeek() && !file.isVideo()) {
response.setIntHeader("ETag", file.getId()); response.setIntHeader("ETag", file.getId());
response.setHeader("Accept-Ranges", "bytes"); response.setHeader("Accept-Ranges", "bytes");
} }
@ -164,7 +164,7 @@ public class StreamController {
boolean isHls = ServletRequestUtils.getBooleanParameter(request, "hls", false); boolean isHls = ServletRequestUtils.getBooleanParameter(request, "hls", false);
range = getRange(request, file); range = getRange(request, file);
if (range != null && !file.isVideo()) { if (settingsService.isEnableSeek() && range != null && !file.isVideo()) {
LOG.info("Got HTTP range: " + range); LOG.info("Got HTTP range: " + range);
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
Util.setContentLength(response, range.isClosed() ? range.size() : fileLength - range.getFirstBytePos()); Util.setContentLength(response, range.isClosed() ? range.size() : fileLength - range.getFirstBytePos());

@ -56,6 +56,7 @@ public class TranscodingSettingsController {
map.put("transcodings", transcodingService.getAllTranscodings()); map.put("transcodings", transcodingService.getAllTranscodings());
map.put("transcodeDirectory", transcodingService.getTranscodeDirectory()); map.put("transcodeDirectory", transcodingService.getTranscodeDirectory());
map.put("enableSeek", settingsService.isEnableSeek());
map.put("downsampleCommand", settingsService.getDownsamplingCommand()); map.put("downsampleCommand", settingsService.getDownsamplingCommand());
map.put("hlsCommand", settingsService.getHlsCommand()); map.put("hlsCommand", settingsService.getHlsCommand());
map.put("brand", settingsService.getBrand()); map.put("brand", settingsService.getBrand());
@ -131,6 +132,7 @@ public class TranscodingSettingsController {
return error; return error;
} }
} }
settingsService.setEnableSeek(request.getParameter("enableSeek") != null);
settingsService.setDownsamplingCommand(StringUtils.trim(request.getParameter("downsampleCommand"))); settingsService.setDownsamplingCommand(StringUtils.trim(request.getParameter("downsampleCommand")));
settingsService.setHlsCommand(StringUtils.trim(request.getParameter("hlsCommand"))); settingsService.setHlsCommand(StringUtils.trim(request.getParameter("hlsCommand")));
settingsService.save(); settingsService.save();

@ -83,6 +83,7 @@ public class SettingsService {
private static final String KEY_PODCAST_EPISODE_DOWNLOAD_COUNT = "PodcastEpisodeDownloadCount"; private static final String KEY_PODCAST_EPISODE_DOWNLOAD_COUNT = "PodcastEpisodeDownloadCount";
private static final String KEY_DOWNLOAD_BITRATE_LIMIT = "DownloadBitrateLimit"; private static final String KEY_DOWNLOAD_BITRATE_LIMIT = "DownloadBitrateLimit";
private static final String KEY_UPLOAD_BITRATE_LIMIT = "UploadBitrateLimit"; private static final String KEY_UPLOAD_BITRATE_LIMIT = "UploadBitrateLimit";
private static final String KEY_ENABLE_SEEK = "EnableSeek1";
private static final String KEY_DOWNSAMPLING_COMMAND = "DownsamplingCommand4"; private static final String KEY_DOWNSAMPLING_COMMAND = "DownsamplingCommand4";
private static final String KEY_HLS_COMMAND = "HlsCommand3"; private static final String KEY_HLS_COMMAND = "HlsCommand3";
private static final String KEY_JUKEBOX_COMMAND = "JukeboxCommand2"; private static final String KEY_JUKEBOX_COMMAND = "JukeboxCommand2";
@ -165,6 +166,7 @@ public class SettingsService {
private static final int DEFAULT_PODCAST_EPISODE_DOWNLOAD_COUNT = 1; private static final int DEFAULT_PODCAST_EPISODE_DOWNLOAD_COUNT = 1;
private static final long DEFAULT_DOWNLOAD_BITRATE_LIMIT = 0; private static final long DEFAULT_DOWNLOAD_BITRATE_LIMIT = 0;
private static final long DEFAULT_UPLOAD_BITRATE_LIMIT = 0; private static final long DEFAULT_UPLOAD_BITRATE_LIMIT = 0;
private static final boolean DEFAULT_ENABLE_SEEK = true;
private static final String DEFAULT_DOWNSAMPLING_COMMAND = "ffmpeg -i %s -map 0:0 -b:a %bk -v 0 -f mp3 -"; private static final String DEFAULT_DOWNSAMPLING_COMMAND = "ffmpeg -i %s -map 0:0 -b:a %bk -v 0 -f mp3 -";
private static final String DEFAULT_HLS_COMMAND = "ffmpeg -ss %o -t %d -i %s -async 1 -b:v %bk -s %wx%h -ar 44100 -ac 2 -v 0 -f mpegts -c:v libx264 -preset superfast -c:a libmp3lame -threads 0 -"; private static final String DEFAULT_HLS_COMMAND = "ffmpeg -ss %o -t %d -i %s -async 1 -b:v %bk -s %wx%h -ar 44100 -ac 2 -v 0 -f mpegts -c:v libx264 -preset superfast -c:a libmp3lame -threads 0 -";
private static final String DEFAULT_JUKEBOX_COMMAND = "ffmpeg -ss %o -i %s -map 0:0 -v 0 -ar 44100 -ac 2 -f s16be -"; private static final String DEFAULT_JUKEBOX_COMMAND = "ffmpeg -ss %o -i %s -map 0:0 -v 0 -ar 44100 -ac 2 -f s16be -";
@ -621,6 +623,14 @@ public class SettingsService {
setLong(KEY_UPLOAD_BITRATE_LIMIT, limit); setLong(KEY_UPLOAD_BITRATE_LIMIT, limit);
} }
public boolean isEnableSeek() {
return getBoolean(KEY_ENABLE_SEEK, DEFAULT_ENABLE_SEEK);
}
public void setEnableSeek(boolean enableSeek) {
setBoolean(KEY_ENABLE_SEEK, enableSeek);
}
public String getDownsamplingCommand() { public String getDownsamplingCommand() {
return getProperty(KEY_DOWNSAMPLING_COMMAND, DEFAULT_DOWNSAMPLING_COMMAND); return getProperty(KEY_DOWNSAMPLING_COMMAND, DEFAULT_DOWNSAMPLING_COMMAND);
} }

@ -418,6 +418,7 @@ transcodingsettings.step2=Step 2
transcodingsettings.step3=Step 3 transcodingsettings.step3=Step 3
transcodingsettings.add=Add transcoding transcodingsettings.add=Add transcoding
transcodingsettings.defaultactive=Enable transcoding settings for all existing and new players. transcodingsettings.defaultactive=Enable transcoding settings for all existing and new players.
transcodingsettings.enableseek=Enable seeking on transcodes (might not work well with VBR codecs)
transcodingsettings.recommended=Recommended configuration transcodingsettings.recommended=Recommended configuration
transcodingsettings.noname=Please specify a name. transcodingsettings.noname=Please specify a name.
transcodingsettings.nosourceformat=Please specify the format to convert from. transcodingsettings.nosourceformat=Please specify the format to convert from.

@ -385,6 +385,7 @@ transcodingsettings.step2 = \u6B65\u9AA4\u4E8C
transcodingsettings.step3 = \u6B65\u9AA4\u4E09 transcodingsettings.step3 = \u6B65\u9AA4\u4E09
transcodingsettings.add = \u6DFB\u52A0 transcodingsettings.add = \u6DFB\u52A0
transcodingsettings.defaultactive = \u4E3A\u73B0\u6709\u548C\u65B0\u64AD\u653E\u5668\u542F\u7528\u8FD9\u9879\u8F6C\u7801\u8BBE\u7F6E transcodingsettings.defaultactive = \u4E3A\u73B0\u6709\u548C\u65B0\u64AD\u653E\u5668\u542F\u7528\u8FD9\u9879\u8F6C\u7801\u8BBE\u7F6E
transcodingsettings.enableseek = \u542F\u7528\u5FEB\u8FDB\uFF08\u5BF9 VBR \u7F16\u7801\u76F8\u5BB9\u6027\u8F83\u5DEE\uFF09
transcodingsettings.recommended = \u63A8\u8350\u8BBE\u7F6E transcodingsettings.recommended = \u63A8\u8350\u8BBE\u7F6E
transcodingsettings.noname = \u8BF7\u6307\u5B9A\u4E00\u4E2A\u540D\u79F0. transcodingsettings.noname = \u8BF7\u6307\u5B9A\u4E00\u4E2A\u540D\u79F0.
transcodingsettings.nosourceformat = \u8BF7\u6307\u5B9A\u8F6C\u6362\u683C\u5F0F. transcodingsettings.nosourceformat = \u8BF7\u6307\u5B9A\u8F6C\u6362\u683C\u5F0F.

@ -467,6 +467,7 @@ transcodingsettings.step2 = \u6B65\u9A5F\u4E8C
transcodingsettings.step3 = \u6B65\u9A5F\u4E09 transcodingsettings.step3 = \u6B65\u9A5F\u4E09
transcodingsettings.add = \u65B0\u589E\u8F49\u78BC\u5668 transcodingsettings.add = \u65B0\u589E\u8F49\u78BC\u5668
transcodingsettings.defaultactive = \u9810\u8A2D transcodingsettings.defaultactive = \u9810\u8A2D
transcodingsettings.enableseek = \u555F\u7528\u5FEB\u9032\uFF08\u5C0D VBR \u7DE8\u78BC\u76F8\u5BB9\u6027\u8F03\u5DEE\uFF09
transcodingsettings.recommended = \u5EFA\u8B70\u7684\u8A2D\u5B9A transcodingsettings.recommended = \u5EFA\u8B70\u7684\u8A2D\u5B9A
transcodingsettings.noname = \u8ACB\u6307\u5B9A\u4E00\u500B\u540D\u7A31\u3002 transcodingsettings.noname = \u8ACB\u6307\u5B9A\u4E00\u500B\u540D\u7A31\u3002
transcodingsettings.nosourceformat = \u8ACB\u6307\u5B9A\u8F49\u63DB\u7684\u4F86\u6E90\u683C\u5F0F\u3002 transcodingsettings.nosourceformat = \u8ACB\u6307\u5B9A\u8F49\u63DB\u7684\u4F86\u6E90\u683C\u5F0F\u3002

@ -59,6 +59,11 @@
<table style="white-space:nowrap" class="indent"> <table style="white-space:nowrap" class="indent">
<tr>
<td>
<input type="checkbox" id="enableSeek" name="enableSeek" class="checkbox" ${model.enableSeek ? "checked" : ""}/>
<label for="enableSeek"><fmt:message key="transcodingsettings.enableseek"/></label>
</td>
<tr> <tr>
<td style="font-weight: bold;"> <td style="font-weight: bold;">
<fmt:message key="advancedsettings.downsamplecommand"/> <fmt:message key="advancedsettings.downsamplecommand"/>

Loading…
Cancel
Save