دعم الموقع

Hi, I'm trying to get random movies via your API, but I hit a rather annoying wall. I keep getting results from page 1, and only page 1. The call goes out smoothly; when I place the call in my browser I get the desired data, but in the app it reverts back to page 1. Is there something I am missing?

The API call + json decoder

func fetchTotalPages(genres: [Int], providers: [Int], completion: @escaping (Result<Int, MovieError>) -> Void) {
            let genresString = genres.map { String($0) }.joined(separator: ",")
            let providersString = providers.map { String($0) }.joined(separator: ",")

            guard let encodedGenres = genresString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
                  let encodedProviders = providersString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
                completion(.failure(.invalidEndpoint))
                return
            }

            let urlString = "https://api.themoviedb.org/3/discover/movie?api_key=\(apiKey)&include_adult=false&page=1&with_genres=\(encodedGenres)&watch_region=NL&vote_average.ite=1&with_watch_providers=\(encodedProviders)"

            guard let url = URL(string: urlString) else {
                completion(.failure(.invalidEndpoint))
                return
            }

            URLSession.shared.dataTask(with: url) { data, response, error in
                if let data = data {
                    do {
                        let apiResponse = try JSONDecoder().decode(APIResponse.self, from: data)
                        DispatchQueue.main.async {
                            self.totalPages = apiResponse.totalPages
                            completion(.success(apiResponse.totalPages))
                            print("total pages are: \(apiResponse.totalPages)")
                        }
                    } catch {
                        print("Error decoding API response: \(error)")
                        completion(.failure(.serializationError))
                    }
                } else if let error = error {
                    print("Error fetching movies: \(error)")
                    completion(.failure(.invalidResponse))
                }
            }.resume()
            print(urlString)
        }

        func discoverMovies(from endpoint: MovieListEndpoint, page: Int, genres: String, providers: String, completion: @escaping (Result<RandomMovieResponse, MovieError>) -> ()) {
            guard let url = URL(string: "https://api.themoviedb.org/3/movie/popular?api_key=\(apiKey)&include_adult=false&page=\(page)&with_genres=\(genres)&watch_region=NL&vote_average.ite=1&with_watch_providers=\(providers)") else {
                completion(.failure(.invalidEndpoint))
                return
            }
            self.loadURLAndDecode(url: url, completion: completion)
            print(url)
        }

        private func loadURLAndDecode<D: Decodable>(url: URL, params: [String: String]? = nil, completion: @escaping (Result<D, MovieError>) -> ()) {
            guard var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
                completion(.failure(.invalidEndpoint))
                return
            }

            var queryItems = [URLQueryItem(name: "api_key", value: apiKey)]
            if let params = params {
                queryItems.append(contentsOf: params.map { URLQueryItem(name: $0.key, value: $0.value) })
            }

            urlComponents.queryItems = queryItems

            guard let finalURL = urlComponents.url else {
                completion(.failure(.invalidEndpoint))
                return
            }

            urlSession.dataTask(with: finalURL) { [weak self] (data, response, error) in
                guard let self = self else { return }

                if error != nil {
                    self.executeCompletionHandlerInMainThread(with: .failure(.apiError), completion: completion)
                    return
                }

                guard let httpResponse = response as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode else {
                    self.executeCompletionHandlerInMainThread(with: .failure(.invalidResponse), completion: completion)
                    return
                }
                guard let data = data else {
                    self.executeCompletionHandlerInMainThread(with: .failure(.noData), completion: completion)
                    return
                }

                do {
                    let decodedResponse = try self.jsonDecoder.decode(D.self, from: data)
                    self.executeCompletionHandlerInMainThread(with: .success(decodedResponse), completion: completion)
                } catch {
                    self.executeCompletionHandlerInMainThread(with: .failure(.serializationError), completion: completion)
                }
            }.resume()
        }

        private func executeCompletionHandlerInMainThread<D: Decodable>(with result: Result<D, MovieError>, completion: @escaping (Result<D, MovieError>) -> ()) {
            DispatchQueue.main.async {
                completion(result)
            }
        }
    }

The function to generate random pages

func performTask(numOption: Int, selectedEndpoint: MovieListEndpoint, selectedGenresViewModel: SelectedGenresViewModel, selectedProviderViewModel: SelectedProviderViewModel, completion: @escaping ([Int], Int?) -> Void) {
    let genreIDs = selectedGenresViewModel.selectedGenres.map { $0.id }
    let providerIDs = Array(selectedProviderViewModel.selectedProvider.map { $0.provider_id }.shuffled().prefix(1))

    RandomMovieStore.shared.fetchTotalPages(genres: genreIDs, providers: providerIDs) { result in
        switch result {
        case .success(let totalPages):
            let pageNumbers = getRandomPageNumbers(numOption: numOption, totalPages: totalPages)
            applyFiltersAndFindMovieIDs(selectedEndpoint: selectedEndpoint, pages: pageNumbers, genres: genreIDs, providers: providerIDs) { ids in
                completion(ids, totalPages)
            }
        case .failure(let error):
            print("Failed to fetch total pages: \(error)")
            completion([], nil)
        }
    }

    // kiest een random pagina nummer tussen 1 en de totaal pagina's
    func getRandomPageNumbers(numOption: Int, totalPages: Int) -> [Int] {
        let limitedTotalPages = min(totalPages, 50)  // Limiet van 50 pagina's
        let randomNumbers = Array(1...limitedTotalPages).shuffled().prefix(numOption)
        print("number of options: \(numOption)")
        print(randomNumbers)
        return Array(randomNumbers)
    }

    // Voegt filters toe aan de API call (mocht die er zijn), voegt de pagina in de api call. Bij succes kiest die 1 random film van de resultaten en pakt de film id.
    func applyFiltersAndFindMovieIDs(selectedEndpoint: MovieListEndpoint, pages: [Int], genres: [Int], providers: [Int], completion: @escaping ([Int]) -> Void) {
        var movieIDs = [Int]()
        let group = DispatchGroup()

        for page in pages {
            group.enter()

            let genreIDs = genres.map(String.init).joined(separator: ",")
            let providerIDs = Array(providers.shuffled().prefix(1)) // Limiet van 1 provider id per api call.

            RandomMovieStore.shared.discoverMovies(from: selectedEndpoint, page: page, genres: genreIDs, providers: providerIDs.map(String.init).joined()) { result in
                switch result {
                case .success(let response):
                    print("this is page", page)
                    if !response.results.isEmpty {
                        print("API response:", response)
                        let randomIndex = Int.random(in: 1..<response.results.count)
                        print("this is randomIndex", randomIndex)
                        let randomMovie = response.results[randomIndex]
                        let randomMovieID = randomMovie.id
                        print("Random movie ID:", randomMovieID)
                        movieIDs.append(randomMovieID)
                    }
                case .failure(let error):
                    print("API call failed with error: \(error)")
                }

                group.leave()
            }
        }

        group.notify(queue: .main) {
            print("All API calls completed")
            completion(movieIDs)
        }
    }
}

Then the button that activates it

Button(action: {
                    Task {
                        performTask(
                            numOption: numOption, selectedEndpoint: selectedEndpoint,
                            selectedGenresViewModel: selectedGenresViewModel,
                            selectedProviderViewModel: selectedProviderViewModel
                        ) { movieIDs,arg  in
                            var fetchedMovies = [Movie]()
                            let dispatchGroup = DispatchGroup()

                            // plaatst de id van de films om de infromatie eruit te halen
                            for id in movieIDs {
                                dispatchGroup.enter()
                                print("Fetching movie with ID: \(id)")
                                MovieStore.shared.fetchMovie(id: id) { result in
                                    switch result {
                                    case .success(let movie):
                                        fetchedMovies.append(movie)
                                    case .failure(let error):
                                        print(error.localizedDescription)
                                    }
                                    dispatchGroup.leave()
                                }
                            }

                            dispatchGroup.notify(queue: .main) {
                                self.filteredMovies = fetchedMovies
                                self.movieTitles = fetchedMovies.map({ $0.title })
                                print(self.movieTitles)
                            }
                        }
                    }

It then fetches the movie via ID.

Is my code wrong or is there a reason I only get page 1?

2 ردود (على هذه الصفحة 1 من 1)

Jump to last post

I'm not a code programmer.
I can't even identify which programming language/tool you are using.
My advice is that you add the name of the language/tool in the title of this talk.
Perhaps that way it will more easily attract the attention of other users.
For example, if you are using JavaScript, leave the title like this:
JavaScript - not going past page 1

Ah my bad. It is in swiftUI.

لم تجد الفلم أو المسلسل ؟ سجل دخولك و انشئها

عام

s ركز شريط البحث
p افتح قائمة الملف الشخصي
esc اغلق النافذة المفتوحة
? افتح نافذة اختصارات لوحة المفاتيح

على كافة صفحات الوسائط

b ارجع للخلف (او للصفحة الام عند التطبيق)
e انتقل لصفحة التعديل

على كافة صفحات موسم المسلسل

(السهم الايمن) انتقل للموسم التالي
(السهم الايسر) انتقل للموسم السابق

على كافة صفحات حلقة المسلسل

(السهم الايمن) انتقل للحلقة التالية
(السهم الايسر) انتقل للحلقة السابقة

على كافة صفحات الصور

a افتح صفحة اضافة الصورة

على كافة صفحات التعديل

t افتح محدد الترجمة
ctrl+ s ارسال النموذج

على صفحات المناقشة

n انشى نقاش جديد
w تبديل حالة المتابعة
p تبديل عام / خاص
c تبديل اغلاق / فتح
a افتح الانشطة
r رد على النقاش
l انتقل لأخر رد
ctrl+ enter أرسل رسالتك
(السهم الايمن) الصفحة التالية
(السهم الايسر) الصفحة السابقة

الاعدادات

هل تريد تقييم او اضافة هذا العنصر للقائمة؟

تسجيل الدخول