@@ -32,13 +32,11 @@ final class YTMusicClient: YTMusicClientProtocol {
3232
3333 // MARK: - Public API Methods
3434
35- /// Maximum number of continuations to fetch initially for faster perceived load.
36- private static let maxInitialContinuations = 3
37-
3835 /// Maximum total continuations to prevent infinite loops.
39- private static let maxTotalContinuations = 10
36+ private static let maxTotalContinuations = 5
4037
41- /// Fetches the home page content with all sections (including continuations).
38+ /// Fetches the home page content (initial sections only for fast display).
39+ /// Call `getHomeContinuation` to load additional sections progressively.
4240 func getHome( ) async throws -> HomeResponse {
4341 logger. info ( " Fetching home page " )
4442
@@ -47,90 +45,50 @@ final class YTMusicClient: YTMusicClientProtocol {
4745 ]
4846
4947 let data = try await request ( " browse " , body: body, ttl: APICache . TTL. home)
50- var response = HomeResponseParser . parse ( data)
51-
52- // Fetch limited continuations for faster initial load
53- var continuationToken = HomeResponseParser . extractContinuationToken ( from: data)
54- var continuationCount = 0
55-
56- while let token = continuationToken, continuationCount < Self . maxInitialContinuations {
57- continuationCount += 1
58- logger. info ( " Fetching home continuation \( continuationCount) " )
59-
60- do {
61- let continuationData = try await requestContinuation ( token)
62- let additionalSections = HomeResponseParser . parseContinuation ( continuationData)
63- response = HomeResponse ( sections: response. sections + additionalSections)
64- continuationToken = HomeResponseParser . extractContinuationTokenFromContinuation ( continuationData)
65- } catch {
66- logger. warning ( " Failed to fetch continuation: \( error. localizedDescription) " )
67- break
68- }
69- }
48+ let response = HomeResponseParser . parse ( data)
49+
50+ // Store continuation token for progressive loading
51+ let token = HomeResponseParser . extractContinuationToken ( from: data)
52+ _homeContinuationToken = token
7053
71- logger. info ( " Total home sections after initial continuations : \( response. sections. count) " )
54+ logger. info ( " Home page loaded : \( response. sections. count) initial sections, hasMore: \( token != nil ) " )
7255 return response
7356 }
7457
75- /// Fetches additional home sections via continuation.
76- /// Call this to progressively load more content after initial load.
77- /// - Parameter currentSections: The current sections to append to
78- /// - Returns: Updated HomeResponse with additional sections, or nil if no more available
79- func getHomeMore( after currentSections: [ HomeSection ] ) async throws -> HomeResponse ? {
80- logger. info ( " Fetching more home sections " )
81-
82- // We need to refetch and skip to the continuation point
83- // This is a simplified approach - in production, you'd cache the continuation token
84- let body : [ String : Any ] = [
85- " browseId " : " FEmusic_home " ,
86- ]
58+ /// Internal storage for continuation token (reset on each getHome call).
59+ private var _homeContinuationToken : String ?
8760
88- let data = try await request ( " browse " , body: body, ttl: APICache . TTL. home)
89- var token = HomeResponseParser . extractContinuationToken ( from: data)
90-
91- // Skip the continuations we already have (approximation based on section count)
92- var skipped = 0
93- let skipCount = max ( 0 , Self . maxInitialContinuations)
94-
95- while let currentToken = token, skipped < skipCount {
96- let continuationData = try await requestContinuation ( currentToken)
97- token = HomeResponseParser . extractContinuationTokenFromContinuation ( continuationData)
98- skipped += 1
99- }
100-
101- // Now fetch additional sections
102- guard let nextToken = token else {
103- logger. info ( " No more home continuations available " )
61+ /// Fetches the next batch of home sections via continuation.
62+ /// Returns nil if no more sections are available.
63+ func getHomeContinuation( ) async throws -> [ HomeSection ] ? {
64+ guard let token = _homeContinuationToken else {
65+ logger. debug ( " No home continuation token available " )
10466 return nil
10567 }
10668
107- var additionalSections : [ HomeSection ] = [ ]
108- var continuationToken : String ? = nextToken
109- var continuationCount = 0
110- let maxAdditional = Self . maxTotalContinuations - Self. maxInitialContinuations
69+ logger. info ( " Fetching home continuation " )
11170
112- while let currentToken = continuationToken, continuationCount < maxAdditional {
113- continuationCount += 1
114- logger. info ( " Fetching additional home continuation \( continuationCount) " )
71+ do {
72+ let continuationData = try await requestContinuation ( token)
73+ let additionalSections = HomeResponseParser . parseContinuation ( continuationData)
74+ _homeContinuationToken = HomeResponseParser . extractContinuationTokenFromContinuation ( continuationData)
75+ let hasMore = _homeContinuationToken != nil
11576
116- do {
117- let continuationData = try await requestContinuation ( currentToken)
118- let sections = HomeResponseParser . parseContinuation ( continuationData)
119- additionalSections. append ( contentsOf: sections)
120- continuationToken = HomeResponseParser . extractContinuationTokenFromContinuation ( continuationData)
121- } catch {
122- logger. warning ( " Failed to fetch additional continuation: \( error. localizedDescription) " )
123- break
124- }
77+ logger. info ( " Home continuation loaded: \( additionalSections. count) sections, hasMore: \( hasMore) " )
78+ return additionalSections
79+ } catch {
80+ logger. warning ( " Failed to fetch home continuation: \( error. localizedDescription) " )
81+ _homeContinuationToken = nil
82+ throw error
12583 }
84+ }
12685
127- guard !additionalSections. isEmpty else { return nil }
128-
129- logger. info ( " Fetched \( additionalSections. count) additional home sections " )
130- return HomeResponse ( sections: currentSections + additionalSections)
86+ /// Whether more home sections are available to load.
87+ var hasMoreHomeSections : Bool {
88+ _homeContinuationToken != nil
13189 }
13290
133- /// Fetches the explore page content with all sections.
91+ /// Fetches the explore page content (initial sections only for fast display) .
13492 func getExplore( ) async throws -> HomeResponse {
13593 logger. info ( " Fetching explore page " )
13694
@@ -139,31 +97,48 @@ final class YTMusicClient: YTMusicClientProtocol {
13997 ]
14098
14199 let data = try await request ( " browse " , body: body, ttl: APICache . TTL. home)
142- var response = HomeResponseParser . parse ( data)
143-
144- // Fetch limited continuations for faster initial load
145- var continuationToken = HomeResponseParser . extractContinuationToken ( from: data)
146- var continuationCount = 0
147-
148- while let token = continuationToken, continuationCount < Self . maxInitialContinuations {
149- continuationCount += 1
150- logger. info ( " Fetching explore continuation \( continuationCount) " )
151-
152- do {
153- let continuationData = try await requestContinuation ( token)
154- let additionalSections = HomeResponseParser . parseContinuation ( continuationData)
155- response = HomeResponse ( sections: response. sections + additionalSections)
156- continuationToken = HomeResponseParser . extractContinuationTokenFromContinuation ( continuationData)
157- } catch {
158- logger. warning ( " Failed to fetch continuation: \( error. localizedDescription) " )
159- break
160- }
161- }
100+ let response = HomeResponseParser . parse ( data)
101+
102+ // Store continuation token for progressive loading
103+ let token = HomeResponseParser . extractContinuationToken ( from: data)
104+ _exploreContinuationToken = token
162105
163- logger. info ( " Total explore sections after initial continuations : \( response. sections. count) " )
106+ logger. info ( " Explore page loaded : \( response. sections. count) initial sections, hasMore: \( token != nil ) " )
164107 return response
165108 }
166109
110+ /// Internal storage for explore continuation token.
111+ private var _exploreContinuationToken : String ?
112+
113+ /// Fetches the next batch of explore sections via continuation.
114+ func getExploreContinuation( ) async throws -> [ HomeSection ] ? {
115+ guard let token = _exploreContinuationToken else {
116+ logger. debug ( " No explore continuation token available " )
117+ return nil
118+ }
119+
120+ logger. info ( " Fetching explore continuation " )
121+
122+ do {
123+ let continuationData = try await requestContinuation ( token)
124+ let additionalSections = HomeResponseParser . parseContinuation ( continuationData)
125+ _exploreContinuationToken = HomeResponseParser . extractContinuationTokenFromContinuation ( continuationData)
126+ let hasMore = _exploreContinuationToken != nil
127+
128+ logger. info ( " Explore continuation loaded: \( additionalSections. count) sections, hasMore: \( hasMore) " )
129+ return additionalSections
130+ } catch {
131+ logger. warning ( " Failed to fetch explore continuation: \( error. localizedDescription) " )
132+ _exploreContinuationToken = nil
133+ throw error
134+ }
135+ }
136+
137+ /// Whether more explore sections are available to load.
138+ var hasMoreExploreSections : Bool {
139+ _exploreContinuationToken != nil
140+ }
141+
167142 /// Makes a continuation request.
168143 private func requestContinuation( _ token: String , ttl: TimeInterval ? = APICache . TTL. home) async throws -> [ String : Any ] {
169144 let body : [ String : Any ] = [
0 commit comments