diff --git a/cmd/serve/dlna/cds.go b/cmd/serve/dlna/cds.go index 0b3cb7063..102879b18 100644 --- a/cmd/serve/dlna/cds.go +++ b/cmd/serve/dlna/cds.go @@ -80,7 +80,9 @@ func (cds *contentDirectoryService) cdsObjectToUpnpavObject(cdsObject object, fi } obj.Class = "object.item." + mediaType[1] + "Item" - obj.Title = fileInfo.Name() + // Remove file extension from title to prevent Samsung TVs from duplicating it + // File type is already provided via MIME type in protocolInfo + obj.Title = strings.TrimSuffix(fileInfo.Name(), filepath.Ext(fileInfo.Name())) obj.Date = upnpav.Timestamp{Time: fileInfo.ModTime()} item := upnpav.Item{ diff --git a/cmd/serve/dlna/cds_test.go b/cmd/serve/dlna/cds_test.go index cef1804d4..a0d6a9023 100644 --- a/cmd/serve/dlna/cds_test.go +++ b/cmd/serve/dlna/cds_test.go @@ -3,7 +3,9 @@ package dlna import ( "context" "encoding/xml" + "path/filepath" "sort" + "strings" "testing" "github.com/anacrolix/dms/soap" @@ -176,6 +178,49 @@ func TestSOAPResponseQuoteEscaping(t *testing.T) { assert.Contains(t, resultStr, """, "SOAP arguments should contain " entities") } +func TestTitleExtensionRemoval(t *testing.T) { + // Test that file extensions are removed from titles to prevent Samsung TV duplication + tests := []struct { + name string + filename string + expected string + }{ + { + name: "image file", + filename: "photo.jpg", + expected: "photo", + }, + { + name: "video file", + filename: "movie.mp4", + expected: "movie", + }, + { + name: "multiple dots", + filename: "file.name.with.dots.mkv", + expected: "file.name.with.dots", + }, + { + name: "no extension", + filename: "filename_no_ext", + expected: "filename_no_ext", + }, + { + name: "hidden file", + filename: ".hidden.txt", + expected: ".hidden", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Simulate the title processing logic + title := strings.TrimSuffix(tt.filename, filepath.Ext(tt.filename)) + assert.Equal(t, tt.expected, title) + }) + } +} + func TestAdjustXMLApostrophes(t *testing.T) { tests := []struct { name string