diff --git a/CHANGELOG.md b/CHANGELOG.md index fb4857167e..6329006a3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 7.85 ----- - Revert episode detail screen dismiss action when archiving [#2802](https://github.com/Automattic/pocket-casts-ios/pull/2802) +- Filter out non-toc chapters [#2807](https://github.com/Automattic/pocket-casts-ios/pull/2807) 7.84 ----- diff --git a/Modules/Utils/Sources/PocketCastsUtils/Feature Flags/FeatureFlag.swift b/Modules/Utils/Sources/PocketCastsUtils/Feature Flags/FeatureFlag.swift index 4f39da262f..5304006470 100644 --- a/Modules/Utils/Sources/PocketCastsUtils/Feature Flags/FeatureFlag.swift +++ b/Modules/Utils/Sources/PocketCastsUtils/Feature Flags/FeatureFlag.swift @@ -144,6 +144,9 @@ public enum FeatureFlag: String, CaseIterable { /// Enable Disable the use of suggested folders case suggestedFolders + /// Parse toc value in chapters + case parseChaptersToc + /// Enable the generated transcript case generatedTranscripts @@ -243,6 +246,8 @@ public enum FeatureFlag: String, CaseIterable { true case .suggestedFolders: false + case .parseChaptersToc: + true case .generatedTranscripts: false } diff --git a/podcasts/ChapterInfo.swift b/podcasts/ChapterInfo.swift index cf2abf2c36..ce92be4ba9 100644 --- a/podcasts/ChapterInfo.swift +++ b/podcasts/ChapterInfo.swift @@ -15,8 +15,10 @@ class ChapterInfo: Equatable { var isFirst = false var isLast = false var index = 0 + var originalIndex = 0 var duration: TimeInterval = 0 var isHidden = false + var toc = true /// Should only be used for sync purposes, if reading for playback /// use `isPlayable()` instead diff --git a/podcasts/ChapterManager.swift b/podcasts/ChapterManager.swift index b87b8e7374..0e0ff92fcd 100644 --- a/podcasts/ChapterManager.swift +++ b/podcasts/ChapterManager.swift @@ -187,10 +187,21 @@ class ChapterManager { private func handleChaptersLoaded(_ chapters: [ChapterInfo], for episode: BaseEpisode) { self.chapters = chapters - episode.deselectedChapters? - .split(separator: ",") - .compactMap { Int($0) } - .forEach { self.chapters[safe: $0]?.shouldPlay = false } + if FeatureFlag.parseChaptersToc.enabled { + let map = chapters.reduce(into: [Int: ChapterInfo]()) { + $0[$1.originalIndex] = $1 + } + + episode.deselectedChapters? + .split(separator: ",") + .compactMap { Int($0) } + .forEach { map[$0]?.shouldPlay = false } + } else { + episode.deselectedChapters? + .split(separator: ",") + .compactMap { Int($0) } + .forEach { self.chapters[safe: $0]?.shouldPlay = false } + } updateCurrentChapter(time: PlaybackManager.shared.currentTime()) diff --git a/podcasts/Chapters.swift b/podcasts/Chapters.swift index ffb07f91a2..6a7db65e87 100644 --- a/podcasts/Chapters.swift +++ b/podcasts/Chapters.swift @@ -20,6 +20,10 @@ class Chapters: Equatable { visibleChapter?.index ?? -1 } + var originalIndex: Int { + visibleChapter?.originalIndex ?? -1 + } + var url: String? { chapters.last(where: { $0.url != nil })?.url } diff --git a/podcasts/PlayerChapterCell.swift b/podcasts/PlayerChapterCell.swift index 09159f3e28..a6cdcec2f4 100644 --- a/podcasts/PlayerChapterCell.swift +++ b/podcasts/PlayerChapterCell.swift @@ -120,7 +120,9 @@ class PlayerChapterCell: UITableViewCell { setColors(dim: chapter?.isPlayable() == false) - if let currentEpisode = PlaybackManager.shared.currentEpisode(), let index = chapter?.index { + let chapterIndex = FeatureFlag.parseChaptersToc.enabled ? chapter?.originalIndex : chapter?.index + + if let currentEpisode = PlaybackManager.shared.currentEpisode(), let index = chapterIndex { if chapter?.shouldPlay == true { currentEpisode.select(chapterIndex: index) track(.deselectChaptersChapterSelected) diff --git a/podcasts/PodcastChapterParser.swift b/podcasts/PodcastChapterParser.swift index 153ad62929..35a2bf311f 100644 --- a/podcasts/PodcastChapterParser.swift +++ b/podcasts/PodcastChapterParser.swift @@ -41,6 +41,9 @@ class PodcastChapterParser { let chapterInfo = ChapterInfo() chapterInfo.title = chapter.title ?? "" chapterInfo.index = index + if FeatureFlag.parseChaptersToc.enabled { + chapterInfo.originalIndex = index + } chapterInfo.startTime = CMTime(seconds: chapter.startTime, preferredTimescale: 1000000) // Calculate chapter duration based on the info we have @@ -57,20 +60,34 @@ class PodcastChapterParser { } func parsePodcastIndexChapters(_ podcastIndexChapters: [PodcastIndexChapter], episodeDuration: TimeInterval) -> [ChapterInfo] { - podcastIndexChapters.enumerated().map { index, chapter in + var index = 0 + let chapters = podcastIndexChapters.enumerated().map { originalIndex, chapter in let chapterInfo = ChapterInfo() chapterInfo.title = chapter.title ?? "" - chapterInfo.index = chapter.number ?? index + if FeatureFlag.parseChaptersToc.enabled { + chapterInfo.originalIndex = chapter.number ?? originalIndex + chapterInfo.toc = chapter.toc ?? true + if chapterInfo.toc { + chapterInfo.index = index + index += 1 + } + } else { + chapterInfo.index = chapter.number ?? originalIndex + } chapterInfo.startTime = CMTime(seconds: chapter.startTime, preferredTimescale: 1000000) if let endTime = chapter.endTime { chapterInfo.duration = endTime - chapter.startTime - } else if let nextChapterStartTime = podcastIndexChapters[safe: index + 1]?.startTime { + } else if let nextChapterStartTime = podcastIndexChapters[safe: originalIndex + 1]?.startTime { chapterInfo.duration = nextChapterStartTime - chapter.startTime } else { chapterInfo.duration = episodeDuration - chapter.startTime } return chapterInfo } + if FeatureFlag.parseChaptersToc.enabled { + return chapters.filter { $0.toc == true } + } + return chapters } private func parseChapters(url: URL, episodeDuration: TimeInterval, completion: @escaping (([ChapterInfo]) -> Void)) { @@ -108,6 +125,9 @@ class PodcastChapterParser { convertedChapter.isHidden = chapter.hidden if !convertedChapter.isHidden { convertedChapter.index = index + if FeatureFlag.parseChaptersToc.enabled { + convertedChapter.originalIndex = index + } index += 1 } if strongSelf.isValidUrl(chapter.url) { diff --git a/podcasts/PodcastIndexChapterDataRetriever.swift b/podcasts/PodcastIndexChapterDataRetriever.swift index 4d741c6780..bb3b56d526 100644 --- a/podcasts/PodcastIndexChapterDataRetriever.swift +++ b/podcasts/PodcastIndexChapterDataRetriever.swift @@ -10,6 +10,7 @@ struct PodcastIndexChapter: Decodable { let number: Int? let endTime: TimeInterval? let startTime: TimeInterval + let toc: Bool? } /// Request information about an episode using the show notes endpoint