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.
This commit is contained in:
Florian Klink 2023-11-24 15:23:14 +02:00 committed by Nick Craig-Wood
parent 182b2a6417
commit 1fad49ee35
2 changed files with 59 additions and 12 deletions

View File

@ -130,6 +130,20 @@ func (cds *contentDirectoryService) readContainer(o object, host string) (ret []
return 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) dirEntries, mediaResources := mediaWithResources(dirEntries)
for _, de := range dirEntries { for _, de := range dirEntries {
child := object{ child := object{

View File

@ -180,8 +180,9 @@ func TestContentDirectoryBrowseDirectChildren(t *testing.T) {
require.Contains(t, string(body), "/r/video.srt") require.Contains(t, string(body), "/r/video.srt")
require.Contains(t, string(body), "/r/video.en.srt") require.Contains(t, string(body), "/r/video.en.srt")
// Then a subdirectory // Then a subdirectory (subdir)
req, err = http.NewRequest("POST", baseURL+serviceControlURL, strings.NewReader(` {
req, err = http.NewRequest("POST", baseURL+serviceControlURL, strings.NewReader(`
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
@ -196,14 +197,46 @@ func TestContentDirectoryBrowseDirectChildren(t *testing.T) {
</u:Browse> </u:Browse>
</s:Body> </s:Body>
</s:Envelope>`)) </s:Envelope>`))
require.NoError(t, err) require.NoError(t, err)
req.Header.Set("SOAPACTION", `"urn:schemas-upnp-org:service:ContentDirectory:1#Browse"`) req.Header.Set("SOAPACTION", `"urn:schemas-upnp-org:service:ContentDirectory:1#Browse"`)
resp, err = http.DefaultClient.Do(req) resp, err = http.DefaultClient.Do(req)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
body, err = io.ReadAll(resp.Body) body, err = io.ReadAll(resp.Body)
require.NoError(t, err) require.NoError(t, err)
// expect video.mp4, video.srt, URLs to be in the DIDL // 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.mp4")
require.Contains(t, string(body), "/r/subdir/video.srt") 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(`
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
<ObjectID>%2Fsubdir2</ObjectID>
<BrowseFlag>BrowseDirectChildren</BrowseFlag>
<Filter>*</Filter>
<StartingIndex>0</StartingIndex>
<RequestedCount>0</RequestedCount>
<SortCriteria></SortCriteria>
</u:Browse>
</s:Body>
</s:Envelope>`))
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")
}
} }