Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Show when a release was previously grabbed or failed in Radarr's interactive search
- Show when a release was previously grabbed or failed in Sonarr v5's interactive search
- Filter Sonarr v5 releases by multi-season pack
- Show every audio and subtitle track in movie file details (Radarr 7.0.1 and later)

### Fixed
- Open the exact movie on Letterboxd instead of a search
Expand Down
22 changes: 22 additions & 0 deletions Ruddarr/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -2029,6 +2029,17 @@
}
}
},
"Forced" : {
"comment" : "Subtitles shown only for foreign dialogue and on-screen text",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Forced"
}
}
}
},
"Framerate" : {
"comment" : "Video frame rate",
"localizations" : {
Expand Down Expand Up @@ -4680,6 +4691,17 @@
}
}
},
"SDH" : {
"comment" : "Subtitles for the deaf and hard of hearing",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "SDH"
}
}
}
},
"Search" : {
"comment" : "Source of the release",
"localizations" : {
Expand Down
46 changes: 46 additions & 0 deletions Ruddarr/Models/MediaFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ struct FileMediaInfo: Equatable, Codable {

let subtitles: String?

let audioStreams: [MediaInfoAudioStream]?
let subtitleStreams: [MediaInfoSubtitleStream]?

var videoCodecLabel: String? {
guard var label = videoCodec else {
return nil
Expand Down Expand Up @@ -164,3 +167,46 @@ struct FileMediaInfo: Equatable, Codable {
return codes.sorted(by: Languages.codeSort)
}
}

struct MediaInfoAudioStream: Equatable, Codable {
let language: String?
let codec: String?
let bitrate: Int?
let channels: Float?

var label: String {
Languages.name(byCode: language ?? "")
}

var detail: String {
[
codec,
channels.map { "\($0)" },
bitrate.flatMap { formatBitrate($0) }.map { "(\($0))" },
]
.compactMap { $0 }
.joined(separator: " ")
}
}

struct MediaInfoSubtitleStream: Equatable, Codable {
let language: String?
let format: String?
let forced: Bool?
let hearingImpaired: Bool?

var label: String {
Languages.name(byCode: language ?? "")
}

var detail: String {
let flags = [
forced == true ? String(localized: "Forced", comment: "Subtitles shown only for foreign dialogue and on-screen text") : nil,
hearingImpaired == true ? String(localized: "SDH", comment: "Subtitles for the deaf and hard of hearing") : nil,
].compactMap { $0 }

return [format, flags.isEmpty ? nil : "(\(flags.formattedList()))"]
.compactMap { $0 }
.joined(separator: " ")
}
}
30 changes: 28 additions & 2 deletions Ruddarr/Views/Shared/MediaFileSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,14 @@ struct MediaFileSheet: View {

@ViewBuilder
var audioMetadata: some View {
if let media = file.mediaInfo {
if let streams = file.mediaInfo?.audioStreams, !streams.isEmpty {
Section {
tracks(streams.map { ($0.label, $0.detail) })
} header: {
headline("Audio")
.padding(.bottom, 4)
}
} else if let media = file.mediaInfo {
Section {
VStack(spacing: 6) {
row(
Expand Down Expand Up @@ -184,7 +191,14 @@ struct MediaFileSheet: View {

@ViewBuilder
var textMetadata: some View {
if let media = file.mediaInfo, let codes = media.subtitleCodes {
if let media = file.mediaInfo, let streams = media.subtitleStreams, !streams.isEmpty {
Section {
tracks(streams.map { ($0.label, $0.detail) })
} header: {
headline("Subtitles")
.padding(.bottom, 4)
}
} else if let media = file.mediaInfo, let codes = media.subtitleCodes {
Section {
VStack(spacing: 6) {
row(
Expand All @@ -206,6 +220,18 @@ struct MediaFileSheet: View {
}
}

func tracks(_ tracks: [(label: String, detail: String)]) -> some View {
VStack(spacing: 6) {
ForEach(Array(tracks.enumerated()), id: \.offset) { index, track in
if index > 0 {
Divider()
}

row(track.label, track.detail)
}
}
}

func headline(_ title: LocalizedStringKey) -> some View {
Text(title)
.font(.title2.bold())
Expand Down
1 change: 1 addition & 0 deletions TestFlight/WhatToTest.en-US.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Added
- Show when a release was previously grabbed or failed in Radarr's interactive search
- Show when a release was previously grabbed or failed in Sonarr v5's interactive search
- Filter Sonarr v5 releases by multi-season pack
- Show every audio and subtitle track in movie file details (Radarr 7.0.1 and later)

Fixed
- Open the exact movie on Letterboxd instead of a search
Expand Down
Loading