From 1fad49ee35f1600bf00d7d8edfa4b9274fcb7a3e Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Fri, 24 Nov 2023 15:23:14 +0200 Subject: [PATCH] dlna: also look at "Subs" subdirectory Apparently it seems pretty common for subtitles to be put in a subdirectory called "Subs", rather than in the same directory as the media file itself. This covers that usecase, by checking the returned listing for a directory called "Subs" to exist. If it does, its child nodes are added to the list before they're being passed to mediaWithResources, allowing these subtitles to be discovered automatically. --- cmd/serve/dlna/cds.go | 14 +++++++++ cmd/serve/dlna/dlna_test.go | 57 +++++++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/cmd/serve/dlna/cds.go b/cmd/serve/dlna/cds.go index 98ad42799..8678ad5cb 100644 --- a/cmd/serve/dlna/cds.go +++ b/cmd/serve/dlna/cds.go @@ -130,6 +130,20 @@ func (cds *contentDirectoryService) readContainer(o object, host string) (ret [] return } + // if there's a "Subs" child directory, add its children to the list as well, + // so mediaWithResources is able to find them. + for _, node := range dirEntries { + if strings.EqualFold(node.Name(), "Subs") && node.IsDir() { + subtitleDir := node.(*vfs.Dir) + subtitleEntries, err := subtitleDir.ReadDirAll() + if err != nil { + err = errors.New("failed to list subtitle directory") + return nil, err + } + dirEntries = append(dirEntries, subtitleEntries...) + } + } + dirEntries, mediaResources := mediaWithResources(dirEntries) for _, de := range dirEntries { child := object{ diff --git a/cmd/serve/dlna/dlna_test.go b/cmd/serve/dlna/dlna_test.go index 0270f27ba..5b090acd3 100644 --- a/cmd/serve/dlna/dlna_test.go +++ b/cmd/serve/dlna/dlna_test.go @@ -180,8 +180,9 @@ func TestContentDirectoryBrowseDirectChildren(t *testing.T) { require.Contains(t, string(body), "/r/video.srt") require.Contains(t, string(body), "/r/video.en.srt") - // Then a subdirectory - req, err = http.NewRequest("POST", baseURL+serviceControlURL, strings.NewReader(` + // Then a subdirectory (subdir) + { + req, err = http.NewRequest("POST", baseURL+serviceControlURL, strings.NewReader(` @@ -196,14 +197,46 @@ func TestContentDirectoryBrowseDirectChildren(t *testing.T) { `)) - require.NoError(t, err) - req.Header.Set("SOAPACTION", `"urn:schemas-upnp-org:service:ContentDirectory:1#Browse"`) - resp, err = http.DefaultClient.Do(req) - require.NoError(t, err) - assert.Equal(t, http.StatusOK, resp.StatusCode) - body, err = io.ReadAll(resp.Body) - require.NoError(t, err) - // expect video.mp4, video.srt, URLs to be in the DIDL - require.Contains(t, string(body), "/r/subdir/video.mp4") - require.Contains(t, string(body), "/r/subdir/video.srt") + require.NoError(t, err) + req.Header.Set("SOAPACTION", `"urn:schemas-upnp-org:service:ContentDirectory:1#Browse"`) + resp, err = http.DefaultClient.Do(req) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + body, err = io.ReadAll(resp.Body) + require.NoError(t, err) + // expect video.mp4, video.srt, URLs to be in the DIDL + require.Contains(t, string(body), "/r/subdir/video.mp4") + require.Contains(t, string(body), "/r/subdir/video.srt") + + } + + // Then a subdirectory with subtitles separately (subdir2) + { + req, err = http.NewRequest("POST", baseURL+serviceControlURL, strings.NewReader(` + + + + + %2Fsubdir2 + BrowseDirectChildren + * + 0 + 0 + + + +`)) + require.NoError(t, err) + req.Header.Set("SOAPACTION", `"urn:schemas-upnp-org:service:ContentDirectory:1#Browse"`) + resp, err = http.DefaultClient.Do(req) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + body, err = io.ReadAll(resp.Body) + require.NoError(t, err) + // expect video.mp4, Subs/video.srt, URLs to be in the DIDL + require.Contains(t, string(body), "/r/subdir2/video.mp4") + require.Contains(t, string(body), "/r/subdir2/Subs/video.srt") + + } }