OpenSubsonic: getPodcastEpisode, topSongsByArtistId, transcodeOffset (real ffmpeg seek)

This commit is contained in:
2026-08-23 08:06:12 -05:00
parent e38d31d384
commit e88f4e040c
7 changed files with 219 additions and 15 deletions
+13 -4
View File
@@ -17,6 +17,7 @@ import (
)
func init() {
registerExtension("transcodeOffset", 1)
register("stream", handleStream)
register("download", handleDownload)
register("getCoverArt", handleGetCoverArt)
@@ -75,14 +76,22 @@ func handleStream(rc *Context) *apiError {
rc.Handled = true
// format=raw explicitly forces the original bytes. Otherwise,
// transcode only if the client actually asked for something the
// source doesn't already satisfy: a specific format, or a bitrate
// cap below the source's own bitrate.
// format=raw explicitly forces the original bytes (timeOffset can't
// be honored in that case — a direct byte stream has no way to seek
// by time — so it's silently ignored, matching "raw" meaning
// "disable transcoding"). Otherwise, transcode whenever the client
// asked for something the source can't satisfy by itself: a
// specific format, a bitrate cap below the source's own bitrate, or
// (the transcodeOffset extension) a start offset — direct-serving
// bytes has no notion of "start at N seconds", only real
// transcoding with an ffmpeg seek can do that.
needsTranscode := formatParam != "" && formatParam != "raw"
if maxBitRate > 0 && (mf.BitrateKbps == 0 || maxBitRate < mf.BitrateKbps) {
needsTranscode = true
}
if timeOffset > 0 && formatParam != "raw" {
needsTranscode = true
}
if !needsTranscode {
if err := streaming.ServeFile(rc.W, rc.R, absPath, mf.RelativePath); err != nil {
http.Error(rc.W, "could not read media file", http.StatusInternalServerError)