diff --git a/NineAnimator.xcodeproj/project.pbxproj b/NineAnimator.xcodeproj/project.pbxproj index 0c76ab46d..c156d784f 100644 --- a/NineAnimator.xcodeproj/project.pbxproj +++ b/NineAnimator.xcodeproj/project.pbxproj @@ -9,6 +9,18 @@ /* Begin PBXBuildFile section */ 2C055AF324A9298900FCAC25 /* SourceRequestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C055AF224A9298900FCAC25 /* SourceRequestManager.swift */; }; 2C055AF524A93E1F00FCAC25 /* RequestManager+QueryEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C055AF424A93E1F00FCAC25 /* RequestManager+QueryEncoding.swift */; }; + 2C055AF624AAAF9300FCAC25 /* WonderfulSubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C85368D2234008A00A5CFB9 /* WonderfulSubs.swift */; }; + 2C055AF724AAAF9300FCAC25 /* WonderfulSubs+Featured.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C85368F2234022400A5CFB9 /* WonderfulSubs+Featured.swift */; }; + 2C055AF824AAAF9300FCAC25 /* WonderfulSubs+LinkConstruction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8536912234041500A5CFB9 /* WonderfulSubs+LinkConstruction.swift */; }; + 2C055AF924AAAF9300FCAC25 /* WonderfulSubs+Anime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8536932234093A00A5CFB9 /* WonderfulSubs+Anime.swift */; }; + 2C055AFA24AAAF9300FCAC25 /* WonderfulSubs+Episode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8536952234745400A5CFB9 /* WonderfulSubs+Episode.swift */; }; + 2C055AFB24AAAF9300FCAC25 /* WonderfulSubs+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8536972234856100A5CFB9 /* WonderfulSubs+Search.swift */; }; + 2C055AFC24AAAF9300FCAC25 /* WonderfulSubs+LinkRetrival.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8536992234889F00A5CFB9 /* WonderfulSubs+LinkRetrival.swift */; }; + 2C055AFD24AAAF9300FCAC25 /* WonderfulSubs+ServerRecommendation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C85369B22348BFF00A5CFB9 /* WonderfulSubs+ServerRecommendation.swift */; }; + 2C055AFE24AAB0E300FCAC25 /* SourceMasterAnime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCC746821C0975A0007502A /* SourceMasterAnime.swift */; }; + 2C055AFF24AAB0E300FCAC25 /* SearchMasterAnime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCC746A21C098860007502A /* SearchMasterAnime.swift */; }; + 2C055B0024AAB0E300FCAC25 /* EpisodeMasterAnime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCC746C21C172330007502A /* EpisodeMasterAnime.swift */; }; + 2C055B0124AAB0E300FCAC25 /* MasterAnimeLinkRetriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA1DD4021E18FC6009241CB /* MasterAnimeLinkRetriver.swift */; }; 2C0BBA6122F8314000C35E33 /* PassthroughParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBA6022F8314000C35E33 /* PassthroughParser.swift */; }; 2C0CFC372263B26900EC793E /* ThisWeekTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0CFC362263B26900EC793E /* ThisWeekTableViewCell.swift */; }; 2C0CFC392263B34300EC793E /* Anilist+Recommendation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0CFC382263B34300EC793E /* Anilist+Recommendation.swift */; }; @@ -2267,6 +2279,7 @@ 2C93BD47221F5E62000411CB /* InformationReferenceCollectionViewCell.swift in Sources */, 2CA1DD6021E2BDCA009241CB /* HomeIntegrationTableViewController.swift in Sources */, 2C3BBAAC2217635000F1C77B /* Dictionary+KeyPathAccess.swift in Sources */, + 2C055AFE24AAB0E300FCAC25 /* SourceMasterAnime.swift in Sources */, 2CE18B122374D69200771A16 /* LibrarySceneController+Tips.swift in Sources */, 2C90C6A0236F8BF900C18620 /* LibraryTrackingCollectionController.swift in Sources */, 2C60EABA2266A22400280637 /* UserNotificationManager+RecommendationSource.swift in Sources */, @@ -2275,6 +2288,7 @@ 2C4ABC8521B74A51009B4D47 /* Featured.swift in Sources */, 2C0E755A2262495200DF3AC4 /* QuickActionsTableViewCell+Cell.swift in Sources */, 2CAD375822261BDE008AD6B4 /* MyAnimeList.swift in Sources */, + 2C055AF724AAAF9300FCAC25 /* WonderfulSubs+Featured.swift in Sources */, 2CCC746021C06D1B0007502A /* NineAnime+Featured.swift in Sources */, 2CE1F84A22EEBA6A005448FF /* BasicPlaybackMedia.swift in Sources */, 2C6984ED227D490900C9EF0E /* Anilist+GQLDate.swift in Sources */, @@ -2286,6 +2300,7 @@ 2C684BCC2290613100E1BA35 /* AnimePahe.swift in Sources */, 2C684BD4229066BB00E1BA35 /* AnimePahe+Episode.swift in Sources */, 2C2EACB22415FBFF007C9BAC /* Anilist+GQLUser.swift in Sources */, + 2C055B0124AAB0E300FCAC25 /* MasterAnimeLinkRetriver.swift in Sources */, 2C1C716F221853AD00760A69 /* Anilist.swift in Sources */, 2C6CF24E221C2E090009D554 /* InformationSceneHeadingTableViewCell.swift in Sources */, 2C0CFC3D2263D9AB00EC793E /* DiscoveryLoadingTableViewCell.swift in Sources */, @@ -2306,6 +2321,7 @@ 2C93BD4A22220B07000411CB /* Kitsu.swift in Sources */, 2CEC218A2207E34E00A30F4F /* Promise+All.swift in Sources */, 2C0CFC4322640B6600EC793E /* DiscoveryStandardCell+Cell.swift in Sources */, + 2C055B0024AAB0E300FCAC25 /* EpisodeMasterAnime.swift in Sources */, 2C8519B122CCA03C00EEF3AC /* Kissanime+Episode.swift in Sources */, 2C8519C022D31F0900EEF3AC /* AnimeKisa+Featured.swift in Sources */, 2CD9B9A421FE4AB100203442 /* AnimeAirDateView.swift in Sources */, @@ -2315,6 +2331,7 @@ 2C9383D821FCF1B9008C0D01 /* UITableViewCell+StyleAttributes.swift in Sources */, 2CDE858823226B2300F1A61A /* NineAnimatorCloud.swift in Sources */, 2C42578723268DFD00FCCCCE /* Simkl+Definitions.swift in Sources */, + 2C055AF624AAAF9300FCAC25 /* WonderfulSubs.swift in Sources */, 2C23AE3E2229CFBD00512150 /* MyAnimeList+User.swift in Sources */, 2C71DEC5226E0610004F3AC3 /* ServerSelectionView.swift in Sources */, 2CA1DD5C21E2B404009241CB /* HomeController.swift in Sources */, @@ -2354,6 +2371,7 @@ 2C480015237061EC00ADB03F /* LibraryRecentsCategoryController.swift in Sources */, 2C6A390423A0179700FC00A9 /* FourAnime+Featured.swift in Sources */, 2C8519A922CC8DD900EEF3AC /* Kissanime+RequestModifier.swift in Sources */, + 2C055AFC24AAAF9300FCAC25 /* WonderfulSubs+LinkRetrival.swift in Sources */, 2C12EDCD21BDD4930064D2BD /* PlaybackMedia.swift in Sources */, 2C6C47362394491F001E723C /* AtomicProperty.swift in Sources */, 2C93BD5022220C41000411CB /* Kitsu+Information.swift in Sources */, @@ -2401,6 +2419,7 @@ 2C66779821BC2213000E5ACC /* SearchViewController.swift in Sources */, 2CEC21A022089CF300A30F4F /* NSRegularExpression+StringMatches.swift in Sources */, 2CB4AF96239AD1B700EE4EDA /* CachableAVAssetLoaderDelegate.swift in Sources */, + 2C055AFA24AAAF9300FCAC25 /* WonderfulSubs+Episode.swift in Sources */, 2C3D7C012210AE640045D648 /* AnimeTwist+Episode.swift in Sources */, 2C9C44FE21CD2B33004C8F0C /* SettingsSceneController.swift in Sources */, 2C93BD45221F5C98000411CB /* InformationSceneRelatedTableViewCell.swift in Sources */, @@ -2414,6 +2433,7 @@ 2CA3E275239C4F5300AAC4D1 /* AUEngineParser.swift in Sources */, 2C8536872231D42C00A5CFB9 /* WeakRef.swift in Sources */, C8E12D01242213CB00B0AF6A /* AnimeUnity+Anime.swift in Sources */, + 2C055AFF24AAB0E300FCAC25 /* SearchMasterAnime.swift in Sources */, 2C433157220B35C100A2E64F /* StringArray+FirstMatchingGroup.swift in Sources */, C8E12D092422143700B0AF6A /* AnimeUnity+Search.swift in Sources */, 2C3D7BFD2210AE3C0045D648 /* AnimeTwist+ContentProvider.swift in Sources */, @@ -2430,6 +2450,7 @@ 52CADD6721BD86F40077BEB1 /* UITableView+DeselectRows.swift in Sources */, 2C12EDDE21BDE6B20064D2BD /* HalfFillTransitionDelegate.swift in Sources */, 2CE18B0C2374839100771A16 /* LibrarySubscriptionCell.swift in Sources */, + 2C055AFB24AAAF9300FCAC25 /* WonderfulSubs+Search.swift in Sources */, 2C6984E7227D465D00C9EF0E /* Anilist+GQLPage.swift in Sources */, 2C7A1D56224C500B00DD83A5 /* AnimeUltima+Provider.swift in Sources */, 2C9383D421FCCC43008C0D01 /* UILabel+StyleAttributes.swift in Sources */, @@ -2451,6 +2472,7 @@ 2CF17D122375D19400B38DDB /* LibraryTipImagedCell.swift in Sources */, 2C0FA3B9226E6A7A00108D27 /* SetupServerSelectionViewController.swift in Sources */, 2C9C450021CD3067004C8F0C /* AboutNineAnimatorTableViewController.swift in Sources */, + 2C055AFD24AAAF9300FCAC25 /* WonderfulSubs+ServerRecommendation.swift in Sources */, 2C6A390223A015A200FC00A9 /* FourAnime.swift in Sources */, 65E1D9BC235FC12300234409 /* VeryStreamParser.swift in Sources */, 2C646F8C21C3245B00957A72 /* TiwiKiwiParser.swift in Sources */, @@ -2467,11 +2489,13 @@ 2C1C717D22190FAD00760A69 /* Anilist+Reference.swift in Sources */, 2C646F8A21C3125A00957A72 /* Mp4UploadParser.swift in Sources */, 2C96DAE02455FC5F007A29B0 /* MyAnimeList+Jikan.swift in Sources */, + 2C055AF924AAAF9300FCAC25 /* WonderfulSubs+Anime.swift in Sources */, 2CEFD96D23A894C00064075E /* Alamofire+Promise.swift in Sources */, 2C3545A521DA84F500321B18 /* UserNotificationManager.swift in Sources */, 2C2C54F92215D51300BAA76E /* User+HomeIntegration.swift in Sources */, 2CD1A647222EB94C00121320 /* AnimatedImageCollectionView.swift in Sources */, 2C74F1D024A4012D00D04DA8 /* RequestManager.swift in Sources */, + 2C055AF824AAAF9300FCAC25 /* WonderfulSubs+LinkConstruction.swift in Sources */, 2C0DA2DE238B09C3002C6447 /* SettingsDownloadsController.swift in Sources */, 2C6677AC21BD5FE0000E5ACC /* User.swift in Sources */, 2C46FC8C232030E500D4206D /* LinkSerialization.swift in Sources */, diff --git a/NineAnimator/Models/Anime Source/masterani.me/MasterAnimeLinkRetriver.swift b/NineAnimator/Models/Anime Source/masterani.me/MasterAnimeLinkRetriver.swift index 67a67f616..a06b1fa23 100644 --- a/NineAnimator/Models/Anime Source/masterani.me/MasterAnimeLinkRetriver.swift +++ b/NineAnimator/Models/Anime Source/masterani.me/MasterAnimeLinkRetriver.swift @@ -24,42 +24,44 @@ extension NASourceMasterAnime { static let animeUrlEpisodeNumberRegex = try! NSRegularExpression(pattern: "\\/anime\\/watch\\/[^\\/]+\\/(\\d+)", options: [.caseInsensitive]) func link(from url: URL, _ handler: @escaping NineAnimatorCallback) -> NineAnimatorAsyncTask? { - let urlString = url.absoluteString - - guard let match = NASourceMasterAnime.animeUrlSlugRegex.matches(in: urlString, options: [], range: urlString.matchingRange).first else { - handler(nil, NineAnimatorError.urlError) - return nil - } - - let slug = urlString[match.range(at: 1)] - let reconstructedAnimeUrl = URL(string: "\(endpoint)/anime/info/\(slug)")! - - return anime(from: reconstructedAnimeUrl) { - [urlString, handler] anime, responseError in - guard let anime = anime else { return handler(nil, responseError) } - - if let match = NASourceMasterAnime.animeUrlEpisodeNumberRegex.matches(in: urlString, options: [], range: urlString.matchingRange).first, - let episodeNumber = Int(urlString[match.range(at: 1)]) { - let episodeLinks = anime.episodes - .flatMap { $0.value } - .filter { - let currentEpisodeNumber = $0.identifier.split(separator: ":")[1] - return currentEpisodeNumber == "\(episodeNumber)" - } - - if episodeLinks.isEmpty { - return handler(nil, NineAnimatorError.responseError("No episode found for this link")) - } - - if let recentServer = NineAnimator.default.user.recentServer, - let episodeLink = episodeLinks.first(where: { $0.server == recentServer }) { - return handler(.episode(episodeLink), nil) - } - - handler(.episode(episodeLinks.first!), nil) - } - - handler(.anime(anime.link), nil) - } + handler(nil, NineAnimatorError.contentUnavailableError("masterani.me is no longer available on NineAnimator")) + return nil +// let urlString = url.absoluteString +// +// guard let match = NASourceMasterAnime.animeUrlSlugRegex.matches(in: urlString, options: [], range: urlString.matchingRange).first else { +// handler(nil, NineAnimatorError.urlError) +// return nil +// } +// +// let slug = urlString[match.range(at: 1)] +// let reconstructedAnimeUrl = URL(string: "\(endpoint)/anime/info/\(slug)")! +// +// return anime(from: reconstructedAnimeUrl) { +// [urlString, handler] anime, responseError in +// guard let anime = anime else { return handler(nil, responseError) } +// +// if let match = NASourceMasterAnime.animeUrlEpisodeNumberRegex.matches(in: urlString, options: [], range: urlString.matchingRange).first, +// let episodeNumber = Int(urlString[match.range(at: 1)]) { +// let episodeLinks = anime.episodes +// .flatMap { $0.value } +// .filter { +// let currentEpisodeNumber = $0.identifier.split(separator: ":")[1] +// return currentEpisodeNumber == "\(episodeNumber)" +// } +// +// if episodeLinks.isEmpty { +// return handler(nil, NineAnimatorError.responseError("No episode found for this link")) +// } +// +// if let recentServer = NineAnimator.default.user.recentServer, +// let episodeLink = episodeLinks.first(where: { $0.server == recentServer }) { +// return handler(.episode(episodeLink), nil) +// } +// +// handler(.episode(episodeLinks.first!), nil) +// } +// +// handler(.anime(anime.link), nil) +// } } } diff --git a/NineAnimator/Models/Anime Source/masterani.me/SearchMasterAnime.swift b/NineAnimator/Models/Anime Source/masterani.me/SearchMasterAnime.swift index 53b9af4de..93b5d15c3 100644 --- a/NineAnimator/Models/Anime Source/masterani.me/SearchMasterAnime.swift +++ b/NineAnimator/Models/Anime Source/masterani.me/SearchMasterAnime.swift @@ -50,47 +50,48 @@ class NASearchMasterAnime: ContentProvider { } func more() { - if _lastRequest == nil && moreAvailable { - let keyword = title.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! - let path = String(format: NASearchMasterAnime.apiPathSearch, keyword, "\(availablePages + 1)") - _lastRequest = _parent.request(ajax: path) { - [weak self] response, _ in - guard let self = self else { return } - - defer { self._lastRequest = nil } - - guard let response = response else { - self.delegate?.onError(NineAnimatorError.searchError("Did not find any results for \"\(self.title)\". This might suggests a bad network condition or a service issue."), from: self) - return - } - - self.totalPages = response["last_page"] as? Int - - guard self.totalPages != 0 else { - self.delegate?.onError(NineAnimatorError.searchError("Results Error"), from: self) - return - } - guard let animes = response["data"] as? [NSDictionary] else { return } - - let pageResult: [AnimeLink] = animes.compactMap { anime in - guard let title = anime["title"] as? String, - let slug = anime["slug"] as? String, - let posterDict = anime["poster"] as? NSDictionary, - let posterName = posterDict["file"] as? String - else { return nil } - - return AnimeLink( - title: title, - link: self._parent.anime(slug: slug), - image: self._parent.poster(file: posterName), - source: self._parent - ) - } - - let newPage = self.availablePages - self._results.append(pageResult) - self.delegate?.pageIncoming(newPage, from: self) - } - } + delegate?.onError(NineAnimatorError.contentUnavailableError("masterani.me is no longer available on NineAnimator"), from: self) +// if _lastRequest == nil && moreAvailable { +// let keyword = title.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! +// let path = String(format: NASearchMasterAnime.apiPathSearch, keyword, "\(availablePages + 1)") +// _lastRequest = _parent.request(ajax: path) { +// [weak self] response, _ in +// guard let self = self else { return } +// +// defer { self._lastRequest = nil } +// +// guard let response = response else { +// self.delegate?.onError(NineAnimatorError.searchError("Did not find any results for \"\(self.title)\". This might suggests a bad network condition or a service issue."), from: self) +// return +// } +// +// self.totalPages = response["last_page"] as? Int +// +// guard self.totalPages != 0 else { +// self.delegate?.onError(NineAnimatorError.searchError("Results Error"), from: self) +// return +// } +// guard let animes = response["data"] as? [NSDictionary] else { return } +// +// let pageResult: [AnimeLink] = animes.compactMap { anime in +// guard let title = anime["title"] as? String, +// let slug = anime["slug"] as? String, +// let posterDict = anime["poster"] as? NSDictionary, +// let posterName = posterDict["file"] as? String +// else { return nil } +// +// return AnimeLink( +// title: title, +// link: self._parent.anime(slug: slug), +// image: self._parent.poster(file: posterName), +// source: self._parent +// ) +// } +// +// let newPage = self.availablePages +// self._results.append(pageResult) +// self.delegate?.pageIncoming(newPage, from: self) +// } +// } } } diff --git a/NineAnimator/Models/Anime Source/masterani.me/SourceMasterAnime.swift b/NineAnimator/Models/Anime Source/masterani.me/SourceMasterAnime.swift index 7639c7c90..8b022a163 100644 --- a/NineAnimator/Models/Anime Source/masterani.me/SourceMasterAnime.swift +++ b/NineAnimator/Models/Anime Source/masterani.me/SourceMasterAnime.swift @@ -26,10 +26,6 @@ import UIKit import AppKit #endif -// ---- TO BE FIXED ---- -// swiftlint:disable type_body_length -// swiftlint:disable cyclomatic_complexity -// swiftlint:disable function_parameter_count class NASourceMasterAnime: BaseSource, Source { var name: String = "masterani.me" @@ -133,274 +129,278 @@ class NASourceMasterAnime: BaseSource, Source { } func anime(from url: URL, _ handler: @escaping NineAnimatorCallback) -> NineAnimatorAsyncTask? { - let animeLinkString = url.absoluteString - let matches = NASourceMasterAnime.animeResourceIdentifierRegex.matches(in: animeLinkString, range: animeLinkString.matchingRange) - guard let match = matches.first else { - handler(nil, NineAnimatorError.urlError) - return nil - } - let identifier = animeLinkString[match.range(at: 1)] - let path = String(format: NASourceMasterAnime.apiPathAnimeDetailed, identifier) - let task = AsyncTaskContainer() - - Log.info("Requesting episodes of anime %@ on masterani.me", identifier) - - task.add(request(ajax: path) { [weak task] response, error in - guard let task = task else { return } - guard let response = response else { - return handler(nil, error) - } - func handleError(_ error: String) { - handler(nil, NineAnimatorError.responseError(error)) - } - guard let animeInfo = response["info"] as? [String: Any] else { - return handleError("no info entry found") - } - guard let animeSynopsis = animeInfo["synopsis"] as? String else { - return handleError("no info.synopsis entry found") - } - guard let animeTitle = animeInfo["title"] as? String else { - return handleError("no info.title entry found") - } - guard let slug = animeInfo["slug"] as? String else { - return handleError("no info.slug entry found") - } - guard let posterFileName = response["poster"] as? String else { - return handleError("no poster entry found") - } - guard let animeEpisodes = response["episodes"] as? [NSDictionary] else { - return handleError("no episodes entry found") - } - - let additionalAttributes: [Anime.AttributeKey: Any] = { - var dict = [Anime.AttributeKey: Any]() - - dict[.airDate] = "\(animeInfo["started_airing_date"] as? String ?? "?") - \(animeInfo["finished_airing_date"] as? String ?? "?")" - - if let score = animeInfo["score"] as? Double { - dict[.rating] = Float(score) - dict[.ratingScale] = Float(5.0) - } - - return dict - }() - - let synonyms = ((response["synonyms"] as? [Any]) ?? []).compactMap { - ($0 as? NSDictionary)?.value(forKey: "title") as? String - }.joined(separator: "; ") - - let parentLink = AnimeLink( - title: animeTitle, - link: self.anime(slug: slug), - image: self.poster(file: posterFileName), - source: self - ) - - let episodes = self.episodes(from: animeEpisodes, with: parentLink) - - guard let firstEpisode = episodes.first else { - return handleError("no episodes found") - } - - Log.debug("Found %@ episodes", episodes.count) - Log.debug("Requesting availble streaming servers") - - task.add(self.assembleAnime( - withFirstEpisodeLink: firstEpisode.parent, - parent: parentLink, - synopsis: animeSynopsis, - synonyms: synonyms, - episodes: episodes, - - attributes: additionalAttributes, - handler - )) - }) - return task - } - - // Parse the episodes available from the response json object - private func episodes(from animeEpisodes: [NSDictionary], with parentLink: AnimeLink) -> [Anime.AdditionalEpisodeLinkInformation] { - animeEpisodes.compactMap { episode in - guard let episodeInfo = episode["info"] as? NSDictionary, - // let episodeIdentifier = episodeInfo["id"] as? Int, - let episodeNumber = episodeInfo["episode"] as? String, - let animeIdentifier = episodeInfo["anime_id"] as? Int - else { return nil } - - var episodeName = "\(episodeNumber)" - // New anime may not always have the title set - if let episodeTitle = episodeInfo["title"] as? String { - episodeName = "\(episodeName) - \(episodeTitle)" - } - let episode = EpisodeLink( - identifier: "\(animeIdentifier):\(episodeNumber)", - name: episodeName, - server: "Masterani.me", - parent: parentLink - ) - return Anime.AdditionalEpisodeLinkInformation( - parent: episode, - synopsis: episodeInfo["description"] as? String, - airDate: episodeInfo["aired"] as? String, - episodeNumber: Int(episodeNumber), - title: episodeInfo["title"] as? String - ) - } - } - - // Assemble Anime object from the first episode link given - private func assembleAnime(withFirstEpisodeLink link: EpisodeLink, - parent parentLink: AnimeLink, - synopsis: String, - synonyms: String, - episodes: [Anime.AdditionalEpisodeLinkInformation], - attributes: [Anime.AttributeKey: Any], - _ handler: @escaping NineAnimatorCallback) -> NineAnimatorAsyncTask? { - self.episodeInfo(from: link) { info, error in - guard let hosts = info?.availableHosts - else { return handler(nil, error) } - handler(Anime( - parentLink, - alias: synonyms, - additionalAttributes: attributes, - description: synopsis, - on: hosts, - episodes: Dictionary(uniqueKeysWithValues: hosts.map { - host in ( - host.key, - episodes.map { EpisodeLink( - identifier: $0.parent.identifier, - name: $0.parent.name, - server: host.key, - parent: $0.parent.parent) - } - ) - }), - episodesAttributes: Dictionary(uniqueKeysWithValues: episodes.map { ($0.parent, $0) }) - ), nil) - } - } - - // Fetch episode mirrors from link - private func episodeInfo(from link: EpisodeLink, _ handler: @escaping NineAnimatorCallback) -> NineAnimatorAsyncTask? { - let episodeUniqueId = link.identifier.split(separator: ":") - guard let episodeNumber = episodeUniqueId.last else { - handler(nil, NineAnimatorError.urlError) - return nil - } - guard let animeIdNumber = episodeUniqueId.first else { - handler(nil, NineAnimatorError.urlError) - return nil - } - let animeLinkString = link.parent.link.absoluteString - let matches = NASourceMasterAnime.animeCompleteIdentifierRegex.matches( - in: animeLinkString, options: [], range: animeLinkString.matchingRange - ) - guard let animeIdentifier = matches.first else { - handler(nil, NineAnimatorError.urlError) - return nil - } - let path = String( - format: NASourceMasterAnime.episodePathWatch, - animeLinkString[animeIdentifier.range(at: 1)], - String(episodeNumber) - ) - return request(browse: path) { - [endpoint] response, error in - guard let response = response else { return handler(nil, error) } - - guard let bowl = try? SwiftSoup.parse(response) else { - return handler(nil, NineAnimatorError.responseError("Response is invalid")) - } - - do { - let mirrors$ = try bowl.select("video-mirrors") - let mirrorsJsonString = try mirrors$.attr(":mirrors") - let mirrorsJsonData = mirrorsJsonString.data(using: .utf8)! - guard let mirrors = try JSONSerialization - .jsonObject(with: mirrorsJsonData) as? [NSDictionary] else { - throw NineAnimatorError.responseError("invalid mirrors") - } - - Log.debug("%@ mirrors found for episode %@", mirrors.count, episodeNumber) - - return handler(NAMasterAnimeEpisodeInfo( - link, - streamingInfo: mirrors, - with: URL(string: "\(endpoint)\(path)")!, - parentId: String(animeIdNumber), - episodeId: String(episodeNumber) - ), nil) - } catch { - Log.debug("It seems like this episode does not have multiple streaming services.") - Log.debug("Trying to find a masterani.me hosted video source.") - } - - do { - let videoSourcesRegex = try NSRegularExpression(pattern: "var\\s*videos\\s*=\\s*(\\[[^\\]]+\\])", options: [.caseInsensitive]) - - guard let sourceMatch = videoSourcesRegex.matches(in: response, options: [], range: response.matchingRange).first else { - throw NineAnimatorError.authenticationRequiredError("Cannot find a video source on masterani.me: This is most likely due to the presence of a CAPTCHA. You may complete the CAPTCHA in the opening link. Tap done when you are finished, after which NineAnimator will attempt to load the resource again.", URL(string: "\(endpoint)\(path)")) - } - - guard let sourceJsonData = response[sourceMatch.range(at: 1)].data(using: .utf8) else { - throw NineAnimatorError.responseError("Response cannot be utf8 encoded.") - } - - guard let sourceArray = try JSONSerialization.jsonObject(with: sourceJsonData, options: []) as? NSArray else { - throw NineAnimatorError.responseError("Matched object is not an valid JSON array.") - } - - let sources = sourceArray.compactMap { source -> (resolution: Int, source: URL, type: String)? in - guard let source = source as? NSDictionary else { - Log.error("One of the source object cannot be cast to NSDictionary") - return nil - } - - guard let res = source["res"] as? Int, - let srcString = source["src"] as? String, - let src = URL(string: srcString), - let type = source["type"] as? String else { - Log.error("Values are incomplete for one of the objects in this episode") - return nil - } - - return (res, src, type) - } - - handler(NAMasterAnimeEpisodeInfo( - link, - locallyHosted: sources.map { ($0.0, $0.1) }, - with: URL(string: "\(endpoint)\(path)")!, - parentId: String(animeIdNumber), - episodeId: String(episodeNumber) - ), nil) - } catch { - Log.error("Did not find a masterani.me hosted video source either (%@). Aborting.", error) - handler(nil, error) - } - } + handler(nil, NineAnimatorError.contentUnavailableError("masterani.me is no longer available on NineAnimator")) + return nil +// let animeLinkString = url.absoluteString +// let matches = NASourceMasterAnime.animeResourceIdentifierRegex.matches(in: animeLinkString, range: animeLinkString.matchingRange) +// guard let match = matches.first else { +// handler(nil, NineAnimatorError.urlError) +// return nil +// } +// let identifier = animeLinkString[match.range(at: 1)] +// let path = String(format: NASourceMasterAnime.apiPathAnimeDetailed, identifier) +// let task = AsyncTaskContainer() +// +// Log.info("Requesting episodes of anime %@ on masterani.me", identifier) +// +// task.add(request(ajax: path) { [weak task] response, error in +// guard let task = task else { return } +// guard let response = response else { +// return handler(nil, error) +// } +// func handleError(_ error: String) { +// handler(nil, NineAnimatorError.responseError(error)) +// } +// guard let animeInfo = response["info"] as? [String: Any] else { +// return handleError("no info entry found") +// } +// guard let animeSynopsis = animeInfo["synopsis"] as? String else { +// return handleError("no info.synopsis entry found") +// } +// guard let animeTitle = animeInfo["title"] as? String else { +// return handleError("no info.title entry found") +// } +// guard let slug = animeInfo["slug"] as? String else { +// return handleError("no info.slug entry found") +// } +// guard let posterFileName = response["poster"] as? String else { +// return handleError("no poster entry found") +// } +// guard let animeEpisodes = response["episodes"] as? [NSDictionary] else { +// return handleError("no episodes entry found") +// } +// +// let additionalAttributes: [Anime.AttributeKey: Any] = { +// var dict = [Anime.AttributeKey: Any]() +// +// dict[.airDate] = "\(animeInfo["started_airing_date"] as? String ?? "?") - \(animeInfo["finished_airing_date"] as? String ?? "?")" +// +// if let score = animeInfo["score"] as? Double { +// dict[.rating] = Float(score) +// dict[.ratingScale] = Float(5.0) +// } +// +// return dict +// }() +// +// let synonyms = ((response["synonyms"] as? [Any]) ?? []).compactMap { +// ($0 as? NSDictionary)?.value(forKey: "title") as? String +// }.joined(separator: "; ") +// +// let parentLink = AnimeLink( +// title: animeTitle, +// link: self.anime(slug: slug), +// image: self.poster(file: posterFileName), +// source: self +// ) +// +// let episodes = self.episodes(from: animeEpisodes, with: parentLink) +// +// guard let firstEpisode = episodes.first else { +// return handleError("no episodes found") +// } +// +// Log.debug("Found %@ episodes", episodes.count) +// Log.debug("Requesting availble streaming servers") +// +// task.add(self.assembleAnime( +// withFirstEpisodeLink: firstEpisode.parent, +// parent: parentLink, +// synopsis: animeSynopsis, +// synonyms: synonyms, +// episodes: episodes, +// +// attributes: additionalAttributes, +// handler +// )) +// }) +// return task } +// +// // Parse the episodes available from the response json object +// private func episodes(from animeEpisodes: [NSDictionary], with parentLink: AnimeLink) -> [Anime.AdditionalEpisodeLinkInformation] { +// animeEpisodes.compactMap { episode in +// guard let episodeInfo = episode["info"] as? NSDictionary, +// // let episodeIdentifier = episodeInfo["id"] as? Int, +// let episodeNumber = episodeInfo["episode"] as? String, +// let animeIdentifier = episodeInfo["anime_id"] as? Int +// else { return nil } +// +// var episodeName = "\(episodeNumber)" +// // New anime may not always have the title set +// if let episodeTitle = episodeInfo["title"] as? String { +// episodeName = "\(episodeName) - \(episodeTitle)" +// } +// let episode = EpisodeLink( +// identifier: "\(animeIdentifier):\(episodeNumber)", +// name: episodeName, +// server: "Masterani.me", +// parent: parentLink +// ) +// return Anime.AdditionalEpisodeLinkInformation( +// parent: episode, +// synopsis: episodeInfo["description"] as? String, +// airDate: episodeInfo["aired"] as? String, +// episodeNumber: Int(episodeNumber), +// title: episodeInfo["title"] as? String +// ) +// } +// } +// +// // Assemble Anime object from the first episode link given +// private func assembleAnime(withFirstEpisodeLink link: EpisodeLink, +// parent parentLink: AnimeLink, +// synopsis: String, +// synonyms: String, +// episodes: [Anime.AdditionalEpisodeLinkInformation], +// attributes: [Anime.AttributeKey: Any], +// _ handler: @escaping NineAnimatorCallback) -> NineAnimatorAsyncTask? { +// self.episodeInfo(from: link) { info, error in +// guard let hosts = info?.availableHosts +// else { return handler(nil, error) } +// handler(Anime( +// parentLink, +// alias: synonyms, +// additionalAttributes: attributes, +// description: synopsis, +// on: hosts, +// episodes: Dictionary(uniqueKeysWithValues: hosts.map { +// host in ( +// host.key, +// episodes.map { EpisodeLink( +// identifier: $0.parent.identifier, +// name: $0.parent.name, +// server: host.key, +// parent: $0.parent.parent) +// } +// ) +// }), +// episodesAttributes: Dictionary(uniqueKeysWithValues: episodes.map { ($0.parent, $0) }) +// ), nil) +// } +// } +// +// // Fetch episode mirrors from link +// private func episodeInfo(from link: EpisodeLink, _ handler: @escaping NineAnimatorCallback) -> NineAnimatorAsyncTask? { +// let episodeUniqueId = link.identifier.split(separator: ":") +// guard let episodeNumber = episodeUniqueId.last else { +// handler(nil, NineAnimatorError.urlError) +// return nil +// } +// guard let animeIdNumber = episodeUniqueId.first else { +// handler(nil, NineAnimatorError.urlError) +// return nil +// } +// let animeLinkString = link.parent.link.absoluteString +// let matches = NASourceMasterAnime.animeCompleteIdentifierRegex.matches( +// in: animeLinkString, options: [], range: animeLinkString.matchingRange +// ) +// guard let animeIdentifier = matches.first else { +// handler(nil, NineAnimatorError.urlError) +// return nil +// } +// let path = String( +// format: NASourceMasterAnime.episodePathWatch, +// animeLinkString[animeIdentifier.range(at: 1)], +// String(episodeNumber) +// ) +// return request(browse: path) { +// [endpoint] response, error in +// guard let response = response else { return handler(nil, error) } +// +// guard let bowl = try? SwiftSoup.parse(response) else { +// return handler(nil, NineAnimatorError.responseError("Response is invalid")) +// } +// +// do { +// let mirrors$ = try bowl.select("video-mirrors") +// let mirrorsJsonString = try mirrors$.attr(":mirrors") +// let mirrorsJsonData = mirrorsJsonString.data(using: .utf8)! +// guard let mirrors = try JSONSerialization +// .jsonObject(with: mirrorsJsonData) as? [NSDictionary] else { +// throw NineAnimatorError.responseError("invalid mirrors") +// } +// +// Log.debug("%@ mirrors found for episode %@", mirrors.count, episodeNumber) +// +// return handler(NAMasterAnimeEpisodeInfo( +// link, +// streamingInfo: mirrors, +// with: URL(string: "\(endpoint)\(path)")!, +// parentId: String(animeIdNumber), +// episodeId: String(episodeNumber) +// ), nil) +// } catch { +// Log.debug("It seems like this episode does not have multiple streaming services.") +// Log.debug("Trying to find a masterani.me hosted video source.") +// } +// +// do { +// let videoSourcesRegex = try NSRegularExpression(pattern: "var\\s*videos\\s*=\\s*(\\[[^\\]]+\\])", options: [.caseInsensitive]) +// +// guard let sourceMatch = videoSourcesRegex.matches(in: response, options: [], range: response.matchingRange).first else { +// throw NineAnimatorError.authenticationRequiredError("Cannot find a video source on masterani.me: This is most likely due to the presence of a CAPTCHA. You may complete the CAPTCHA in the opening link. Tap done when you are finished, after which NineAnimator will attempt to load the resource again.", URL(string: "\(endpoint)\(path)")) +// } +// +// guard let sourceJsonData = response[sourceMatch.range(at: 1)].data(using: .utf8) else { +// throw NineAnimatorError.responseError("Response cannot be utf8 encoded.") +// } +// +// guard let sourceArray = try JSONSerialization.jsonObject(with: sourceJsonData, options: []) as? NSArray else { +// throw NineAnimatorError.responseError("Matched object is not an valid JSON array.") +// } +// +// let sources = sourceArray.compactMap { source -> (resolution: Int, source: URL, type: String)? in +// guard let source = source as? NSDictionary else { +// Log.error("One of the source object cannot be cast to NSDictionary") +// return nil +// } +// +// guard let res = source["res"] as? Int, +// let srcString = source["src"] as? String, +// let src = URL(string: srcString), +// let type = source["type"] as? String else { +// Log.error("Values are incomplete for one of the objects in this episode") +// return nil +// } +// +// return (res, src, type) +// } +// +// handler(NAMasterAnimeEpisodeInfo( +// link, +// locallyHosted: sources.map { ($0.0, $0.1) }, +// with: URL(string: "\(endpoint)\(path)")!, +// parentId: String(animeIdNumber), +// episodeId: String(episodeNumber) +// ), nil) +// } catch { +// Log.error("Did not find a masterani.me hosted video source either (%@). Aborting.", error) +// handler(nil, error) +// } +// } +// } func episode(from link: EpisodeLink, with anime: Anime, _ handler: @escaping NineAnimatorCallback) -> NineAnimatorAsyncTask? { - let task = AsyncTaskContainer() - task.add(episodeInfo(from: link) { - info, error in - guard let info = info else { return handler(nil, error) } - guard let stream = info.select(server: link.server, option: .bestQuality) else { - return handler(nil, NineAnimatorError.providerError( - "This episode is not availble on the selected server" - )) - } - - guard let streamTarget = stream.target else { - return handler(nil, NineAnimatorError.urlError) - } - let episode = Episode(link, target: streamTarget, parent: anime, referer: info.url.absoluteString) - handler(episode, nil) - }) - return task + handler(nil, NineAnimatorError.contentUnavailableError("masterani.me is no longer available on NineAnimator")) + return nil +// let task = AsyncTaskContainer() +// task.add(episodeInfo(from: link) { +// info, error in +// guard let info = info else { return handler(nil, error) } +// guard let stream = info.select(server: link.server, option: .bestQuality) else { +// return handler(nil, NineAnimatorError.providerError( +// "This episode is not availble on the selected server" +// )) +// } +// +// guard let streamTarget = stream.target else { +// return handler(nil, NineAnimatorError.urlError) +// } +// let episode = Episode(link, target: streamTarget, parent: anime, referer: info.url.absoluteString) +// handler(episode, nil) +// }) +// return task } func search(keyword: String) -> ContentProvider { diff --git a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Anime.swift b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Anime.swift index 82ce9b23d..6cf587d78 100644 --- a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Anime.swift +++ b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Anime.swift @@ -21,45 +21,46 @@ import Foundation extension NASourceWonderfulSubs { func anime(from link: AnimeLink) -> NineAnimatorPromise { - if !isEnabled { - return NineAnimatorPromise.fail( - NineAnimatorError.contentUnavailableError( - "WonderfulSubs is no longer available on NineAnimator. Please consider using other sources." - ) - ) - } - - return request( - ajaxPathDictionary: "/api/media/series", - query: [ "series": link.link.lastPathComponent ], - headers: [ "Referer": link.link.absoluteString ] - ) .then { - response in - let detailedSeriesEntry = try response.value(at: "json", type: NSDictionary.self) - let reassembledLink = try self.constructAnimeLink(from: detailedSeriesEntry, withParent: link) - let aliases = detailedSeriesEntry.valueIfPresent(at: "aliases", type: [String].self) ?? [] - let description = try detailedSeriesEntry.value(at: "description", type: String.self) - - // Construct child anime - let seasons = try detailedSeriesEntry.value(at: "seasons", type: NSDictionary.self) - let medias = try seasons - .compactMap { _, season in season as? NSDictionary } - .flatMap { try $0.value(at: "media", type: [NSDictionary].self) } - let children = medias.compactMap { try? self.anime(fromMediaEntry: $0, withParent: reassembledLink) } - - // Handle empty children list - guard !children.isEmpty else { - throw NineAnimatorError.responseError("No seasons found for this anime") - } - - // Construct the parent Anime object - return Anime( - reassembledLink, - alias: aliases.joined(separator: "; "), - description: description, - children: children - ) - } + .fail(.contentUnavailableError("WonderfulSubs is no longer available on NineAnimator")) +// if !isEnabled { +// return NineAnimatorPromise.fail( +// NineAnimatorError.contentUnavailableError( +// "WonderfulSubs is no longer available on NineAnimator. Please consider using other sources." +// ) +// ) +// } +// +// return request( +// ajaxPathDictionary: "/api/media/series", +// query: [ "series": link.link.lastPathComponent ], +// headers: [ "Referer": link.link.absoluteString ] +// ) .then { +// response in +// let detailedSeriesEntry = try response.value(at: "json", type: NSDictionary.self) +// let reassembledLink = try self.constructAnimeLink(from: detailedSeriesEntry, withParent: link) +// let aliases = detailedSeriesEntry.valueIfPresent(at: "aliases", type: [String].self) ?? [] +// let description = try detailedSeriesEntry.value(at: "description", type: String.self) +// +// // Construct child anime +// let seasons = try detailedSeriesEntry.value(at: "seasons", type: NSDictionary.self) +// let medias = try seasons +// .compactMap { _, season in season as? NSDictionary } +// .flatMap { try $0.value(at: "media", type: [NSDictionary].self) } +// let children = medias.compactMap { try? self.anime(fromMediaEntry: $0, withParent: reassembledLink) } +// +// // Handle empty children list +// guard !children.isEmpty else { +// throw NineAnimatorError.responseError("No seasons found for this anime") +// } +// +// // Construct the parent Anime object +// return Anime( +// reassembledLink, +// alias: aliases.joined(separator: "; "), +// description: description, +// children: children +// ) +// } } /// For WonderfulSubs, this is a rather tedius and computational intensive task diff --git a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Episode.swift b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Episode.swift index dc4bcd5e3..a73455485 100644 --- a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Episode.swift +++ b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Episode.swift @@ -46,32 +46,33 @@ extension NASourceWonderfulSubs { } func episode(from link: EpisodeLink, with anime: Anime) -> NineAnimatorPromise { - request( - ajaxPathDictionary: "/api/media/stream", - query: [ "code": link.identifier ], - headers: [ "Referer": link.parent.link.absoluteString ] - ) .then { - [weak self] response in - guard let self = self else { return nil } - - // A common error for WonderfulSubs - if response["status"] as? Int == 404 { - throw NineAnimatorError.responseError("This episode is not available on this server") - } - - do { - return try self.tryDecodeOrdinary(link, anime: anime, response: response) - } catch { - Log.info("[NASourceWonderfulSubs] Unable to decode as ordinary stream response: %@. Trying alternative format.", error) - } - - do { - return try self.tryDecodeEmbed(link, anime: anime, response: response) - } catch { - Log.info("[NASourceWonderfulSubs] Unable to decode as embed stream response: %@.", error) - throw NineAnimatorError.responseError("This episode cannot be parsed under the current server") - } - } + .fail(.contentUnavailableError("WonderfulSubs is no longer available on NineAnimator")) +// request( +// ajaxPathDictionary: "/api/media/stream", +// query: [ "code": link.identifier ], +// headers: [ "Referer": link.parent.link.absoluteString ] +// ) .then { +// [weak self] response in +// guard let self = self else { return nil } +// +// // A common error for WonderfulSubs +// if response["status"] as? Int == 404 { +// throw NineAnimatorError.responseError("This episode is not available on this server") +// } +// +// do { +// return try self.tryDecodeOrdinary(link, anime: anime, response: response) +// } catch { +// Log.info("[NASourceWonderfulSubs] Unable to decode as ordinary stream response: %@. Trying alternative format.", error) +// } +// +// do { +// return try self.tryDecodeEmbed(link, anime: anime, response: response) +// } catch { +// Log.info("[NASourceWonderfulSubs] Unable to decode as embed stream response: %@.", error) +// throw NineAnimatorError.responseError("This episode cannot be parsed under the current server") +// } +// } } private func tryDecodeEmbed(_ link: EpisodeLink, anime: Anime, response: NSDictionary) throws -> Episode { diff --git a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Featured.swift b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Featured.swift index 9106d6864..df8ba9260 100644 --- a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Featured.swift +++ b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Featured.swift @@ -21,30 +21,31 @@ import Foundation extension NASourceWonderfulSubs { func featured() -> NineAnimatorPromise { - NineAnimatorPromise<[AnimeLink]> - .queue(listOfPromises: [ retrieveFeaturedAnimePromise, retrieveLatestAnimePromise ]) - .then { results in BasicFeaturedContainer(featured: results[0], latest: results[1]) } - } - - private var retrieveFeaturedAnimePromise: NineAnimatorPromise<[AnimeLink]> { - request( - ajaxPathDictionary: "/api/media/popular?count=12", - headers: [ "Referer": endpoint ] - ) .then { - response in - let series = try response.value(at: "json.series", type: [NSDictionary].self) - return try series.map { try self.constructAnimeLink(from: $0, useWidePoster: true) } - } - } - - private var retrieveLatestAnimePromise: NineAnimatorPromise<[AnimeLink]> { - request( - ajaxPathDictionary: "/api/media/latest?count=12", - headers: [ "Referer": endpoint ] - ) .then { - response in - let series = try response.value(at: "json.series", type: [NSDictionary].self) - return try series.map { try self.constructAnimeLink(from: $0) } - } + .fail(.contentUnavailableError("WonderfulSubs is no longer available on NineAnimator")) +// NineAnimatorPromise<[AnimeLink]> +// .queue(listOfPromises: [ retrieveFeaturedAnimePromise, retrieveLatestAnimePromise ]) +// .then { results in BasicFeaturedContainer(featured: results[0], latest: results[1]) } } +// +// private var retrieveFeaturedAnimePromise: NineAnimatorPromise<[AnimeLink]> { +// request( +// ajaxPathDictionary: "/api/media/popular?count=12", +// headers: [ "Referer": endpoint ] +// ) .then { +// response in +// let series = try response.value(at: "json.series", type: [NSDictionary].self) +// return try series.map { try self.constructAnimeLink(from: $0, useWidePoster: true) } +// } +// } +// +// private var retrieveLatestAnimePromise: NineAnimatorPromise<[AnimeLink]> { +// request( +// ajaxPathDictionary: "/api/media/latest?count=12", +// headers: [ "Referer": endpoint ] +// ) .then { +// response in +// let series = try response.value(at: "json.series", type: [NSDictionary].self) +// return try series.map { try self.constructAnimeLink(from: $0) } +// } +// } } diff --git a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+LinkRetrival.swift b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+LinkRetrival.swift index 0026ef0a0..b575b40f1 100644 --- a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+LinkRetrival.swift +++ b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+LinkRetrival.swift @@ -21,29 +21,6 @@ import Foundation extension NASourceWonderfulSubs { func link(from url: URL) -> NineAnimatorPromise { - NineAnimatorPromise.firstly { - () -> String in - let components = url.pathComponents - // Make sure this is an url pointing to an anime - guard components.count > 2, components[1] == "watch" else { - throw NineAnimatorError.urlError - } - return components[2] - } .thenPromise { - [endpointURL] series -> NineAnimatorPromise<(NSDictionary, URL)> in - let reconstructedLink = endpointURL - .appendingPathComponent("watch") - .appendingPathComponent(series) - return self.request( - ajaxPathDictionary: "/api/media/series", - query: [ "series": series ], - headers: [ "Referer": url.absoluteString ] - ) .then { ($0, reconstructedLink) } - } .then { - [endpointURL] response, link in - let seriesEntry = try response.value(at: "json", type: NSDictionary.self) - let dummyLink = AnimeLink(title: "", link: link, image: endpointURL, source: self) - return .anime(try self.constructAnimeLink(from: seriesEntry, withParent: dummyLink)) - } + .fail(.contentUnavailableError("WonderfulSubs is no longer available on NineAnimator")) } } diff --git a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Search.swift b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Search.swift index 91335a106..65dfe09b4 100644 --- a/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Search.swift +++ b/NineAnimator/Models/Anime Source/wonderfulsubs.com/WonderfulSubs+Search.swift @@ -40,33 +40,10 @@ extension NASourceWonderfulSubs { func more() { guard _queryTask == nil, moreAvailable else { return } - _queryTask = parent - .request( - ajaxPathDictionary: "/api/media/search", - query: [ "q": query ], - headers: [ "Referer": parent.endpoint ] - ) - .then { - [unowned parent] response -> [AnimeLink] in - let seriesObjects = try response.value(at: "json.series", type: [NSDictionary].self) - let objects = try seriesObjects.map { try parent.constructAnimeLink(from: $0) } - guard !objects.isEmpty else { - throw NineAnimatorError.searchError("No results found") - } - return objects - } .error { - [weak self] error in - guard let self = self else { return } - self.results = [] - self.delegate?.onError(error, from: self) - self._queryTask = nil - } .finally { - [weak self] results in - guard let self = self else { return } - self.results = results - self.delegate?.pageIncoming(0, from: self) - self._queryTask = nil - } + delegate?.onError( + NineAnimatorError.contentUnavailableError("WonderfulSubs is no longer available on NineAnimator"), + from: self + ) } init(_ query: String, parent: NASourceWonderfulSubs) { diff --git a/NineAnimator/Models/NineAnimator.swift b/NineAnimator/Models/NineAnimator.swift index 5ebcba3d4..fcfcd04ea 100644 --- a/NineAnimator/Models/NineAnimator.swift +++ b/NineAnimator/Models/NineAnimator.swift @@ -155,8 +155,8 @@ extension NineAnimator { register(source: NASourceAnimeUnity(with: self)) // Disabled sources -// register(source: NASourceWonderfulSubs(with: self)) -// register(source: NASourceMasterAnime(with: self)) + register(source: NASourceWonderfulSubs(with: self)) + register(source: NASourceMasterAnime(with: self)) } } diff --git a/NineAnimator/Utilities/Networking/RequestManager.swift b/NineAnimator/Utilities/Networking/RequestManager.swift index f6ccc17a5..1e73320a6 100644 --- a/NineAnimator/Utilities/Networking/RequestManager.swift +++ b/NineAnimator/Utilities/Networking/RequestManager.swift @@ -44,10 +44,7 @@ class NARequestManager: NSObject { private(set) var currentIdentity = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15" @AtomicProperty private var _internalTaskReferences = [ObjectIdentifier: NineAnimatorAsyncTask]() - @AtomicProperty fileprivate var _requestCustomRedirectionHandlers = [( - WeakRef, - RequestBuilding.RedirectionHandler - )]() + @AtomicProperty fileprivate var _requestCustomRedirectionHandlers = [(WeakRef, RequestBuilding.RedirectionHandler)]() fileprivate var _internalAdapterChain = [WeakRef]() fileprivate var _internalRetrierChain = [WeakRef]() fileprivate var _internalRetryPolicy = Alamofire.RetryPolicy(retryLimit: 3)