mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
added TMDB
This commit is contained in:
parent
eb65912998
commit
9af4984cc6
8 changed files with 342 additions and 7 deletions
57
Sora/Tracking Services/TMDB/HomePage/TMDB-Seasonal.swift
Normal file
57
Sora/Tracking Services/TMDB/HomePage/TMDB-Seasonal.swift
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// TMDB-Seasonal.swift
|
||||
// Sulfur
|
||||
//
|
||||
// Created by Francesco on 05/03/25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class TMDBSeasonal {
|
||||
static func fetchTMDBSeasonal(completion: @escaping ([AniListItem]?) -> Void) {
|
||||
Task {
|
||||
do {
|
||||
let url = URL(string: "https://api.themoviedb.org/3/movie/upcoming")!
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true)!
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "language", value: "en-US"),
|
||||
URLQueryItem(name: "page", value: "1"),
|
||||
]
|
||||
|
||||
var request = URLRequest(url: components.url!)
|
||||
request.httpMethod = "GET"
|
||||
request.timeoutInterval = 10
|
||||
request.allHTTPHeaderFields = [
|
||||
"accept": "application/json",
|
||||
"Authorization": "Bearer \(TMBDRequest.decryptToken())"
|
||||
]
|
||||
|
||||
let (data, _) = try await URLSession.custom.data(for: request)
|
||||
let response = try JSONDecoder().decode(TMDBResponse.self, from: data)
|
||||
|
||||
let anilistItems = response.results.map { item in
|
||||
AniListItem(
|
||||
id: item.id,
|
||||
title: AniListTitle(
|
||||
romaji: item.displayTitle,
|
||||
english: item.originalTitle ?? item.originalName ?? item.displayTitle,
|
||||
native: ""
|
||||
),
|
||||
coverImage: AniListCoverImage(
|
||||
large: item.posterURL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completion(anilistItems)
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
Logger.shared.log("Error fetching TMDB seasonal: \(error.localizedDescription)")
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Sora/Tracking Services/TMDB/HomePage/TMDB-Trending.swift
Normal file
62
Sora/Tracking Services/TMDB/HomePage/TMDB-Trending.swift
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// TMDB-Trending.swift
|
||||
// Sulfur
|
||||
//
|
||||
// Created by Francesco on 05/03/25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class TMBDTrending {
|
||||
static func fetchTMDBTrending(completion: @escaping ([AniListItem]?) -> Void) {
|
||||
Task {
|
||||
do {
|
||||
let items = try await fetchTrendingItems()
|
||||
|
||||
let anilistItems = items.map { item in
|
||||
AniListItem(
|
||||
id: item.id,
|
||||
title: AniListTitle(
|
||||
romaji: item.displayTitle,
|
||||
english: item.originalTitle ?? item.originalName ?? item.displayTitle,
|
||||
native: ""
|
||||
),
|
||||
coverImage: AniListCoverImage(
|
||||
large: item.posterURL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completion(anilistItems)
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
Logger.shared.log("Error fetching TMDB trending: \(error.localizedDescription)")
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static func fetchTrendingItems() async throws -> [TMDBItem] {
|
||||
let url = URL(string: "https://api.themoviedb.org/3/trending/all/day")!
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true)!
|
||||
let queryItems: [URLQueryItem] = [
|
||||
URLQueryItem(name: "language", value: "en-US")
|
||||
]
|
||||
components.queryItems = queryItems
|
||||
|
||||
var request = URLRequest(url: components.url!)
|
||||
request.httpMethod = "GET"
|
||||
request.timeoutInterval = 10
|
||||
request.allHTTPHeaderFields = [
|
||||
"accept": "application/json",
|
||||
"Authorization": "Bearer \(TMBDRequest.decryptToken())"
|
||||
]
|
||||
|
||||
let (data, _) = try await URLSession.custom.data(for: request)
|
||||
let response = try JSONDecoder().decode(TMDBResponse.self, from: data)
|
||||
return response.results
|
||||
}
|
||||
}
|
||||
61
Sora/Tracking Services/TMDB/Struct/TMDBItem.swift
Normal file
61
Sora/Tracking Services/TMDB/Struct/TMDBItem.swift
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// TMDBItem.swift
|
||||
// Sulfur
|
||||
//
|
||||
// Created by Francesco on 05/03/25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct TMDBItem: Codable {
|
||||
let id: Int
|
||||
let mediaType: String?
|
||||
|
||||
let title: String?
|
||||
let originalTitle: String?
|
||||
let releaseDate: String?
|
||||
|
||||
let name: String?
|
||||
let originalName: String?
|
||||
let firstAirDate: String?
|
||||
|
||||
let posterPath: String?
|
||||
let backdropPath: String?
|
||||
let overview: String
|
||||
let voteAverage: Double?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id, overview
|
||||
case mediaType = "media_type"
|
||||
case title, name
|
||||
case originalTitle = "original_title"
|
||||
case originalName = "original_name"
|
||||
case posterPath = "poster_path"
|
||||
case backdropPath = "backdrop_path"
|
||||
case releaseDate = "release_date"
|
||||
case firstAirDate = "first_air_date"
|
||||
case voteAverage = "vote_average"
|
||||
}
|
||||
|
||||
var displayTitle: String {
|
||||
return title ?? name ?? "Unknown Title"
|
||||
}
|
||||
|
||||
var posterURL: String {
|
||||
if let path = posterPath {
|
||||
return "https://image.tmdb.org/t/p/w500\(path)"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var backdropURL: String {
|
||||
if let path = backdropPath {
|
||||
return "https://image.tmdb.org/t/p/original\(path)"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var displayDate: String {
|
||||
return releaseDate ?? firstAirDate ?? ""
|
||||
}
|
||||
}
|
||||
41
Sora/Tracking Services/TMDB/Struct/TMDBRequest.swift
Normal file
41
Sora/Tracking Services/TMDB/Struct/TMDBRequest.swift
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// TMDBRequest.swift
|
||||
// Sulfur
|
||||
//
|
||||
// Created by Francesco on 05/03/25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct TMDBResponse: Codable {
|
||||
let results: [TMDBItem]
|
||||
let page: Int
|
||||
let totalPages: Int
|
||||
let totalResults: Int
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case results, page
|
||||
case totalPages = "total_pages"
|
||||
case totalResults = "total_results"
|
||||
}
|
||||
}
|
||||
|
||||
class TMBDRequest {
|
||||
static let encodedTokenParts = [
|
||||
"XZXlKaGJHY2lPaUpJVXpJMU5pSjk=",
|
||||
"XZXlKaGRXUWlPaUkzTXpoaU5HVmtaREJoTVRVMlkyTXhNalprWXpSaE5HSTRZV1ZoTkdGallTSXNJbTVpWmlJNk1UYzBNVEUzTXpjd01pNDNPRGN3TURJc0luTjFZaUk2SWpZM1l6Z3pNMk0yWkRjME1UbGpaR1prT0RabE1tUmtaaUlzSW5OamIzQmxjeUk2V3lKaGNHbGZjbVZoWkNKZExDSjJaWEp6YVc5dUlqb3hmUT09",
|
||||
"XR2ZlN0YtOENXSlhnT052MzRtZzNqSFhmTDZCeGJqLWhBWWY5ZllpOUNrRQ=="
|
||||
]
|
||||
|
||||
static func decryptToken() -> String {
|
||||
let decodedParts = encodedTokenParts.map { part -> String in
|
||||
let cleanPart = String(part.dropFirst(1))
|
||||
guard let data = Data(base64Encoded: cleanPart) else {
|
||||
return ""
|
||||
}
|
||||
return String(data: data, encoding: .utf8) ?? ""
|
||||
}
|
||||
|
||||
return decodedParts.joined()
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import SwiftUI
|
|||
import Kingfisher
|
||||
|
||||
struct HomeView: View {
|
||||
@AppStorage("trackingService") private var tracingService: String = "AniList"
|
||||
@State private var aniListItems: [AniListItem] = []
|
||||
@State private var trendingItems: [AniListItem] = []
|
||||
@State private var continueWatchingItems: [ContinueWatchingItem] = []
|
||||
|
|
@ -257,14 +258,28 @@ struct HomeView: View {
|
|||
}
|
||||
.onAppear {
|
||||
continueWatchingItems = ContinueWatchingManager.shared.fetchItems()
|
||||
AnilistServiceSeasonalAnime().fetchSeasonalAnime { items in
|
||||
if let items = items {
|
||||
aniListItems = items
|
||||
if tracingService == "TMDB" {
|
||||
TMDBSeasonal.fetchTMDBSeasonal { items in
|
||||
if let items = items {
|
||||
aniListItems = items
|
||||
}
|
||||
}
|
||||
}
|
||||
AnilistServiceTrendingAnime().fetchTrendingAnime { items in
|
||||
if let items = items {
|
||||
trendingItems = items
|
||||
|
||||
TMBDTrending.fetchTMDBTrending { items in
|
||||
if let items = items {
|
||||
trendingItems = items
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AnilistServiceSeasonalAnime().fetchSeasonalAnime { items in
|
||||
if let items = items {
|
||||
aniListItems = items
|
||||
}
|
||||
}
|
||||
AnilistServiceTrendingAnime().fetchTrendingAnime { items in
|
||||
if let items = items {
|
||||
trendingItems = items
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// SettingsViewTrackingServices.swift
|
||||
// Sulfur
|
||||
//
|
||||
// Created by Francesco on 05/03/25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Kingfisher
|
||||
|
||||
struct SettingsViewTrackingServices: View {
|
||||
@AppStorage("trackingService") private var trackingService: String = "AniList"
|
||||
@EnvironmentObject var settings: Settings
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Tracking Service")) {
|
||||
HStack {
|
||||
Text("Service")
|
||||
Spacer()
|
||||
Menu {
|
||||
Button(action: { trackingService = "AniList" }) {
|
||||
HStack {
|
||||
KFImage(URL(string: "https://avatars.githubusercontent.com/u/18018524?s=280&v=4"))
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)
|
||||
Text("AniList")
|
||||
}
|
||||
}
|
||||
Button(action: { trackingService = "TMDB" }) {
|
||||
HStack {
|
||||
KFImage(URL(string: "https://pbs.twimg.com/profile_images/1243623122089041920/gVZIvphd_400x400.jpg"))
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)
|
||||
Text("TMDB")
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
KFImage(URL(string: trackingService == "TMDB" ? "https://pbs.twimg.com/profile_images/1243623122089041920/gVZIvphd_400x400.jpg" : "https://avatars.githubusercontent.com/u/18018524?s=280&v=4"))
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)
|
||||
Text(trackingService)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Tracking Service")
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,9 @@ struct SettingsView: View {
|
|||
NavigationLink(destination: SettingsViewModule()) {
|
||||
Text("Modules")
|
||||
}
|
||||
NavigationLink(destination: SettingsViewTrackingServices()) {
|
||||
Text("Tracking Services")
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Info")) {
|
||||
|
|
@ -73,6 +76,7 @@ struct SettingsView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
Section(footer: Text("Running Sora 0.2.1")) {}
|
||||
}
|
||||
.navigationTitle("Settings")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@
|
|||
131845F92D47C62D00CA7A54 /* SettingsViewGeneral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 131845F82D47C62D00CA7A54 /* SettingsViewGeneral.swift */; };
|
||||
1327FBA72D758CEA00FC6689 /* Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1327FBA62D758CEA00FC6689 /* Analytics.swift */; };
|
||||
1327FBA92D758DEA00FC6689 /* UIDevice+Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1327FBA82D758DEA00FC6689 /* UIDevice+Model.swift */; };
|
||||
1334FF4D2D786C93007E289F /* TMDB-Seasonal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1334FF4C2D786C93007E289F /* TMDB-Seasonal.swift */; };
|
||||
1334FF4F2D786C9E007E289F /* TMDB-Trending.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1334FF4E2D786C9E007E289F /* TMDB-Trending.swift */; };
|
||||
1334FF522D7871B7007E289F /* TMDBItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1334FF512D7871B7007E289F /* TMDBItem.swift */; };
|
||||
1334FF542D787217007E289F /* TMDBRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1334FF532D787217007E289F /* TMDBRequest.swift */; };
|
||||
1334FF562D7872E9007E289F /* SettingsViewTrackingServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1334FF552D7872E9007E289F /* SettingsViewTrackingServices.swift */; };
|
||||
133D7C6E2D2BE2500075467E /* SoraApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6D2D2BE2500075467E /* SoraApp.swift */; };
|
||||
133D7C702D2BE2500075467E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6F2D2BE2500075467E /* ContentView.swift */; };
|
||||
133D7C722D2BE2520075467E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 133D7C712D2BE2520075467E /* Assets.xcassets */; };
|
||||
|
|
@ -67,6 +72,11 @@
|
|||
131845F82D47C62D00CA7A54 /* SettingsViewGeneral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewGeneral.swift; sourceTree = "<group>"; };
|
||||
1327FBA62D758CEA00FC6689 /* Analytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Analytics.swift; sourceTree = "<group>"; };
|
||||
1327FBA82D758DEA00FC6689 /* UIDevice+Model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIDevice+Model.swift"; sourceTree = "<group>"; };
|
||||
1334FF4C2D786C93007E289F /* TMDB-Seasonal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TMDB-Seasonal.swift"; sourceTree = "<group>"; };
|
||||
1334FF4E2D786C9E007E289F /* TMDB-Trending.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TMDB-Trending.swift"; sourceTree = "<group>"; };
|
||||
1334FF512D7871B7007E289F /* TMDBItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TMDBItem.swift; sourceTree = "<group>"; };
|
||||
1334FF532D787217007E289F /* TMDBRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TMDBRequest.swift; sourceTree = "<group>"; };
|
||||
1334FF552D7872E9007E289F /* SettingsViewTrackingServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewTrackingServices.swift; sourceTree = "<group>"; };
|
||||
133D7C6A2D2BE2500075467E /* Sulfur.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sulfur.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
133D7C6D2D2BE2500075467E /* SoraApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoraApp.swift; sourceTree = "<group>"; };
|
||||
133D7C6F2D2BE2500075467E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -123,6 +133,7 @@
|
|||
13103E802D589D6C000F0673 /* Tracking Services */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1334FF4A2D786C6D007E289F /* TMDB */,
|
||||
13103E812D589D77000F0673 /* AniList */,
|
||||
);
|
||||
path = "Tracking Services";
|
||||
|
|
@ -173,6 +184,33 @@
|
|||
path = Analytics;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1334FF4A2D786C6D007E289F /* TMDB */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1334FF502D7871A4007E289F /* Struct */,
|
||||
1334FF4B2D786C81007E289F /* HomePage */,
|
||||
);
|
||||
path = TMDB;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1334FF4B2D786C81007E289F /* HomePage */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1334FF4C2D786C93007E289F /* TMDB-Seasonal.swift */,
|
||||
1334FF4E2D786C9E007E289F /* TMDB-Trending.swift */,
|
||||
);
|
||||
path = HomePage;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1334FF502D7871A4007E289F /* Struct */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1334FF512D7871B7007E289F /* TMDBItem.swift */,
|
||||
1334FF532D787217007E289F /* TMDBRequest.swift */,
|
||||
);
|
||||
path = Struct;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
133D7C612D2BE2500075467E = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -243,6 +281,7 @@
|
|||
131845F82D47C62D00CA7A54 /* SettingsViewGeneral.swift */,
|
||||
135CCBE12D4D1138008B9C0E /* SettingsViewPlayer.swift */,
|
||||
130C6BF92D53AB1F00DC1432 /* SettingsViewData.swift */,
|
||||
1334FF552D7872E9007E289F /* SettingsViewTrackingServices.swift */,
|
||||
);
|
||||
path = SettingsSubViews;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -475,14 +514,18 @@
|
|||
13B7F4C12D58FFDD0045714A /* Shimmer.swift in Sources */,
|
||||
139935662D468C450065CEFF /* ModuleManager.swift in Sources */,
|
||||
133D7C902D2BE2640075467E /* SettingsView.swift in Sources */,
|
||||
1334FF4F2D786C9E007E289F /* TMDB-Trending.swift in Sources */,
|
||||
13CBEFDA2D5F7D1200D011EE /* String.swift in Sources */,
|
||||
130C6BFA2D53AB1F00DC1432 /* SettingsViewData.swift in Sources */,
|
||||
13EA2BD72D32D97400C1EBD7 /* MusicProgressSlider.swift in Sources */,
|
||||
1334FF542D787217007E289F /* TMDBRequest.swift in Sources */,
|
||||
1E9FF1D32D403E49008AC100 /* SettingsViewLoggerFilter.swift in Sources */,
|
||||
13EA2BD92D32D98400C1EBD7 /* NormalPlayer.swift in Sources */,
|
||||
133D7C932D2BE2640075467E /* Modules.swift in Sources */,
|
||||
1334FF562D7872E9007E289F /* SettingsViewTrackingServices.swift in Sources */,
|
||||
136F21B92D5B8DD8006409AC /* AniList-MediaInfo.swift in Sources */,
|
||||
133D7C702D2BE2500075467E /* ContentView.swift in Sources */,
|
||||
1334FF522D7871B7007E289F /* TMDBItem.swift in Sources */,
|
||||
13D99CF72D4E73C300250A86 /* ModuleAdditionSettingsView.swift in Sources */,
|
||||
13C0E5EC2D5F85F800E7F619 /* ContinueWatchingItem.swift in Sources */,
|
||||
13CBA0882D60F19C00EFE70A /* VTTSubtitlesLoader.swift in Sources */,
|
||||
|
|
@ -507,6 +550,7 @@
|
|||
133D7C8E2D2BE2640075467E /* LibraryView.swift in Sources */,
|
||||
133D7C6E2D2BE2500075467E /* SoraApp.swift in Sources */,
|
||||
138AA1B92D2D66FD0021F9DF /* CircularProgressBar.swift in Sources */,
|
||||
1334FF4D2D786C93007E289F /* TMDB-Seasonal.swift in Sources */,
|
||||
13EA2BD52D32D97400C1EBD7 /* CustomPlayer.swift in Sources */,
|
||||
1399FAD42D3AB38C00E97C31 /* SettingsViewLogger.swift in Sources */,
|
||||
13C0E5EA2D5F85EA00E7F619 /* ContinueWatchingManager.swift in Sources */,
|
||||
|
|
|
|||
Loading…
Reference in a new issue