Soporte de The Movie Database

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 respuestas (en la página 1 de 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.

¿No encuentras una película o serie? Inicia sesión para crearla:

Global

s centrar la barra de búsqueda
p abrir menú de perfil
esc cierra una ventana abierta
? abrir la ventana de atajos del teclado

En las páginas multimedia

b retrocede (o a padre cuando sea aplicable)
e ir a la página de edición

En las páginas de temporada de televisión

(flecha derecha) ir a la temporada siguiente
(flecha izquierda) ir a la temporada anterior

En las páginas de episodio de televisión

(flecha derecha) ir al episodio siguiente
(flecha izquierda) ir al episodio anterior

En todas las páginas de imágenes

a abrir la ventana de añadir imagen

En todas las páginas de edición

t abrir la sección de traducción
ctrl+ s enviar formulario

En las páginas de debate

n crear nuevo debate
w cambiar el estado de visualización
p cambiar público/privado
c cambiar cerrar/abrir
a abrir actividad
r responder al debate
l ir a la última respuesta
ctrl+ enter enviar tu mensaje
(flecha derecha) página siguiente
(flecha izquierda) página anterior

Configuraciones

¿Quieres puntuar o añadir este elemento a una lista?

Iniciar sesión