mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-28 22:27:10 +01:00
fix(jellyfin): include MediaSources with Size/Bitrate on tracks so clients show download size
This commit is contained in:
parent
da451cf927
commit
200ae482c3
5 changed files with 40 additions and 13 deletions
|
|
@ -188,6 +188,7 @@ type MediaSourceInfo struct {
|
|||
Name string `json:"Name,omitempty"`
|
||||
IsRemote bool `json:"IsRemote"`
|
||||
RunTimeTicks int64 `json:"RunTimeTicks,omitempty"`
|
||||
Bitrate int `json:"Bitrate,omitempty"`
|
||||
SupportsTranscoding bool `json:"SupportsTranscoding"`
|
||||
SupportsDirectStream bool `json:"SupportsDirectStream"`
|
||||
SupportsDirectPlay bool `json:"SupportsDirectPlay"`
|
||||
|
|
|
|||
|
|
@ -8,6 +8,27 @@ import (
|
|||
|
||||
func TicksFromSeconds(sec float32) int64 { return int64(float64(sec) * 1e7) }
|
||||
|
||||
// MediaSourceFromMediaFile builds the MediaSourceInfo describing direct playback of mf's
|
||||
// source file. Shared by SongToBaseItem and getPlaybackInfo so clients see the same Size and
|
||||
// Bitrate whether they read it from a browse response or from /PlaybackInfo -- Finamp's
|
||||
// download dialog reads MediaSources[0].Size from the former.
|
||||
func MediaSourceFromMediaFile(mf model.MediaFile) MediaSourceInfo {
|
||||
return MediaSourceInfo{
|
||||
Id: mf.ID,
|
||||
Protocol: "Http",
|
||||
Container: mf.Suffix,
|
||||
Size: mf.Size,
|
||||
Name: mf.Title,
|
||||
Type: "Default",
|
||||
RunTimeTicks: TicksFromSeconds(mf.Duration),
|
||||
Bitrate: mf.BitRate * 1000, // Navidrome stores kbps; Jellyfin's Bitrate is bps.
|
||||
SupportsDirectPlay: true,
|
||||
SupportsDirectStream: true,
|
||||
SupportsTranscoding: true,
|
||||
IsRemote: false,
|
||||
}
|
||||
}
|
||||
|
||||
func UserData(a model.Annotations, itemID string) *UserItemDataDto {
|
||||
d := &UserItemDataDto{
|
||||
PlayCount: int(a.PlayCount),
|
||||
|
|
@ -44,6 +65,7 @@ func SongToBaseItem(mf model.MediaFile) BaseItemDto {
|
|||
CanDownload: true,
|
||||
BackdropImageTags: []string{},
|
||||
UserData: UserData(mf.Annotations, mf.ID),
|
||||
MediaSources: []MediaSourceInfo{MediaSourceFromMediaFile(mf)},
|
||||
}
|
||||
if mf.Year > 0 {
|
||||
item.ProductionYear = new(mf.Year)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ var _ = Describe("mappers", func() {
|
|||
mf := model.MediaFile{
|
||||
ID: "song-1", Title: "Song", Album: "Alb", AlbumID: "alb-1",
|
||||
Artist: "Art", AlbumArtist: "AA", TrackNumber: 3, DiscNumber: 1,
|
||||
Year: 1999, Duration: 60,
|
||||
Year: 1999, Duration: 60, Size: 2_500_000,
|
||||
}
|
||||
mf.PlayCount = 2
|
||||
mf.Starred = true
|
||||
|
|
@ -28,6 +28,20 @@ var _ = Describe("mappers", func() {
|
|||
Expect(item.UserData.IsFavorite).To(BeTrue())
|
||||
Expect(item.UserData.PlayCount).To(Equal(2))
|
||||
Expect(item.UserData.Played).To(BeTrue())
|
||||
Expect(item.MediaSources).To(HaveLen(1))
|
||||
Expect(item.MediaSources[0].Size).To(Equal(int64(2_500_000)))
|
||||
})
|
||||
|
||||
It("builds a MediaSourceInfo from a media file", func() {
|
||||
mf := model.MediaFile{ID: "s1", Size: 5242880, Suffix: "mp3", BitRate: 320, Duration: 100}
|
||||
src := MediaSourceFromMediaFile(mf)
|
||||
Expect(src.Id).To(Equal("s1"))
|
||||
Expect(src.Size).To(Equal(int64(5242880)))
|
||||
Expect(src.Container).To(Equal("mp3"))
|
||||
Expect(src.Bitrate).To(Equal(320_000))
|
||||
Expect(src.RunTimeTicks).To(Equal(int64(1_000_000_000)))
|
||||
Expect(src.Protocol).To(Equal("Http"))
|
||||
Expect(src.SupportsDirectPlay).To(BeTrue())
|
||||
})
|
||||
|
||||
It("omits IndexNumber and ParentIndexNumber when track/disc numbers are untagged", func() {
|
||||
|
|
|
|||
|
|
@ -40,18 +40,7 @@ func (api *Router) getPlaybackInfo(w http.ResponseWriter, r *http.Request) {
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
src := dto.MediaSourceInfo{
|
||||
Id: mf.ID,
|
||||
Protocol: "Http",
|
||||
Container: mf.Suffix,
|
||||
Size: mf.Size,
|
||||
Name: mf.Title,
|
||||
Type: "Default",
|
||||
RunTimeTicks: dto.TicksFromSeconds(mf.Duration),
|
||||
SupportsDirectPlay: true,
|
||||
SupportsDirectStream: true,
|
||||
SupportsTranscoding: true,
|
||||
}
|
||||
src := dto.MediaSourceFromMediaFile(*mf)
|
||||
api.ok(w, r, dto.PlaybackInfoResponse{MediaSources: []dto.MediaSourceInfo{src}, PlaySessionId: mf.ID})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ var _ = Describe("Stream", func() {
|
|||
Expect(res.MediaSources).To(HaveLen(1))
|
||||
Expect(res.MediaSources[0].Id).To(Equal("s1"))
|
||||
Expect(res.MediaSources[0].Container).To(Equal("mp3"))
|
||||
Expect(res.MediaSources[0].Size).To(Equal(int64(1000)))
|
||||
Expect(res.PlaySessionId).ToNot(BeEmpty())
|
||||
})
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue