diff --git a/AnimeGen.xcodeproj/project.pbxproj b/AnimeGen.xcodeproj/project.pbxproj index 5ea05d79..ba0ac3ab 100644 --- a/AnimeGen.xcodeproj/project.pbxproj +++ b/AnimeGen.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 13910EC92B80D5C2009BF17E /* nekos-best.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13910EC82B80D5C2009BF17E /* nekos-best.swift */; }; 13910ECB2B80D5C8009BF17E /* waifu-pics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13910ECA2B80D5C8009BF17E /* waifu-pics.swift */; }; 13910ECF2B80D90D009BF17E /* SDWebImage in Frameworks */ = {isa = PBXBuildFile; productRef = 13910ECE2B80D90D009BF17E /* SDWebImage */; }; + 13BE98C02B828B8000379AB7 /* nekosmoe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13BE98BF2B828B8000379AB7 /* nekosmoe.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -47,6 +48,7 @@ 13910EC62B80D5B9009BF17E /* waifu-im.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "waifu-im.swift"; sourceTree = ""; }; 13910EC82B80D5C2009BF17E /* nekos-best.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "nekos-best.swift"; sourceTree = ""; }; 13910ECA2B80D5C8009BF17E /* waifu-pics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "waifu-pics.swift"; sourceTree = ""; }; + 13BE98BF2B828B8000379AB7 /* nekosmoe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = nekosmoe.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -113,6 +115,7 @@ 13910EC82B80D5C2009BF17E /* nekos-best.swift */, 138661222B81216D0062AC91 /* Hmtai.swift */, 138661242B8136DC0062AC91 /* nekosapi.swift */, + 13BE98BF2B828B8000379AB7 /* nekosmoe.swift */, ); path = APIs; sourceTree = ""; @@ -205,6 +208,7 @@ files = ( 13910EC72B80D5B9009BF17E /* waifu-im.swift in Sources */, 13877B192B82001800251A60 /* SettingsPage.swift in Sources */, + 13BE98C02B828B8000379AB7 /* nekosmoe.swift in Sources */, 130A80572B78C02E0028985F /* ViewController.swift in Sources */, 130A80532B78C02E0028985F /* AppDelegate.swift in Sources */, 130A80552B78C02E0028985F /* SceneDelegate.swift in Sources */, diff --git a/AnimeGen.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate b/AnimeGen.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate index f0b00e6a..0b526ad1 100644 Binary files a/AnimeGen.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate and b/AnimeGen.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/AnimeGen/APIs/Hmtai.swift b/AnimeGen/APIs/Hmtai.swift index 5f8aba61..1959c710 100644 --- a/AnimeGen/APIs/Hmtai.swift +++ b/AnimeGen/APIs/Hmtai.swift @@ -16,7 +16,6 @@ extension ViewController { let endpointPrefix: String if UserDefaults.standard.bool(forKey: "enableExplictiCont") { - // If explicit content is enabled, include NSFW categories categories3 = ["ass","anal","bdsm","classic","cum","creampie","manga","femdom","hentai","incest","masturbation","public","ero","orgy","elves","yuri","pantsu","pussy","glasses","cuckold","blowjob","boobjob","handjob","footjob","boobs","thighs","ahegao","uniform","gangbang","tentacles","gif","nsfwNeko","nsfwMobileWallpaper","zettaiRyouiki"] endpointPrefix = "https://hmtai.hatsunia.cfd/nsfw/" } else { @@ -69,6 +68,8 @@ extension ViewController { let category3 = randomCategory3 + self.tagsLabel.isHidden = false + self.currentImageURL = imageUrlString self.updateUIWithTags([category3]) diff --git a/AnimeGen/APIs/nekos-best.swift b/AnimeGen/APIs/nekos-best.swift index 127b0c87..bb5c86aa 100644 --- a/AnimeGen/APIs/nekos-best.swift +++ b/AnimeGen/APIs/nekos-best.swift @@ -61,6 +61,7 @@ extension ViewController { if let data = try? Data(contentsOf: imageUrl), let newImage = UIImage(data: data) { self.imageView.image = newImage + self.tagsLabel.isHidden = false self.animateImageChange(with: newImage) self.updateUIWithTags([], author: author, category: category) self.stopLoadingIndicator() diff --git a/AnimeGen/APIs/nekosapi.swift b/AnimeGen/APIs/nekosapi.swift index e5cbd6a3..53a24494 100644 --- a/AnimeGen/APIs/nekosapi.swift +++ b/AnimeGen/APIs/nekosapi.swift @@ -73,7 +73,9 @@ extension ViewController { if let data = try? Data(contentsOf: imageUrl), let newImage = UIImage(data: data) { self.imageView.image = newImage self.animateImageChange(with: newImage) - + + self.tagsLabel.isHidden = false + self.updateUIWithTags(tags) self.stopLoadingIndicator() diff --git a/AnimeGen/APIs/nekosmoe.swift b/AnimeGen/APIs/nekosmoe.swift new file mode 100644 index 00000000..0806ada2 --- /dev/null +++ b/AnimeGen/APIs/nekosmoe.swift @@ -0,0 +1,163 @@ +// +// nekosmoe.swift +// AnimeGen +// +// Created by cranci on 18/02/24. +// + +import UIKit + +extension ViewController { + + func loadImageAndTagsFromNekosMoe() { + startLoadingIndicator() + + let isNSFW = UserDefaults.standard.bool(forKey: "enableExplictiCont") + let moetags = UserDefaults.standard.bool(forKey: "enableMoeTags") + + let apiEndpoint = "https://nekos.moe/api/v1/random/image" + + var components = URLComponents(string: apiEndpoint) + components?.queryItems = [ + URLQueryItem(name: "nsfw", value: isNSFW.description.lowercased()) + ] + + guard let url = components?.url else { + print("Invalid URL") + stopLoadingIndicator() + return + } + + var request = URLRequest(url: url) + request.httpMethod = "GET" + + let task = URLSession.shared.dataTask(with: request) { (data, response, error) in + DispatchQueue.main.async { + if let error = error { + print("Error: \(error)") + self.stopLoadingIndicator() + return + } + + guard let httpResponse = response as? HTTPURLResponse else { + print("Invalid HTTP response") + self.stopLoadingIndicator() + return + } + + guard httpResponse.statusCode == 200 else { + print("Invalid status code: \(httpResponse.statusCode)") + self.stopLoadingIndicator() + return + } + + do { + if let jsonData = data, + let jsonResponse = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any], + let images = jsonResponse["images"] as? [[String: Any]], + let firstImage = images.first { + + let imageId = firstImage["id"] as? String + + if moetags { + if let tagsArray = firstImage["tags"] as? [String] { + // Print tags for debugging + print("Tags: \(tagsArray)") + + // Update UI with tags + self.updateUIWithTags(tagsArray) + + var newComponents = URLComponents(string: "https://nekos.moe/thumbnail/\(imageId ?? "")") + newComponents?.queryItems = [ + URLQueryItem(name: "tags", value: tagsArray.joined(separator: ",")) + // Add more query parameters as needed + ] + + guard let newUrl = newComponents?.url else { + print("Invalid URL with tags") + self.stopLoadingIndicator() + return + } + + let imageRequest = URLRequest(url: newUrl) + let imageTask = URLSession.shared.dataTask(with: imageRequest) { (imageData, _, imageError) in + DispatchQueue.main.async { + if let imageError = imageError { + print("Image loading error: \(imageError)") + self.stopLoadingIndicator() + return + } + + if let imageData = imageData, let newImage = UIImage(data: imageData) { + self.imageView.image = newImage + self.animateImageChange(with: newImage) + + // Continue with the rest of your code here + // Add any additional logic or UI updates you need + + // Temporarily hide the tag label when using nekos.moe API + self.tagsLabel.isHidden = true + + self.stopLoadingIndicator() + } else { + print("Failed to load image data with tags.") + self.stopLoadingIndicator() + } + } + } + + imageTask.resume() + } else { + print("Tags data not available.") + self.stopLoadingIndicator() + } + } else { + // Load the image without tags + var newComponents = URLComponents(string: "https://nekos.moe/thumbnail/\(imageId ?? "")") + + guard let newUrl = newComponents?.url else { + print("Invalid URL without tags") + self.stopLoadingIndicator() + return + } + + let imageRequest = URLRequest(url: newUrl) + let imageTask = URLSession.shared.dataTask(with: imageRequest) { (imageData, _, imageError) in + DispatchQueue.main.async { + if let imageError = imageError { + print("Image loading error: \(imageError)") + self.stopLoadingIndicator() + return + } + + if let imageData = imageData, let newImage = UIImage(data: imageData) { + self.imageView.image = newImage + self.animateImageChange(with: newImage) + + // Continue with the rest of your code here + // Add any additional logic or UI updates you need + + // Temporarily hide the tag label when using nekos.moe API + self.tagsLabel.isHidden = true + + self.stopLoadingIndicator() + } else { + print("Failed to load image data without tags.") + self.stopLoadingIndicator() + } + } + } + + imageTask.resume() + } + } else { + print("Failed to parse JSON response or missing necessary data.") + self.stopLoadingIndicator() + } + } + } + } + + task.resume() + } +} diff --git a/AnimeGen/APIs/pic-re.swift b/AnimeGen/APIs/pic-re.swift index 402eb332..44b34a38 100644 --- a/AnimeGen/APIs/pic-re.swift +++ b/AnimeGen/APIs/pic-re.swift @@ -64,6 +64,7 @@ extension ViewController { } DispatchQueue.main.async { + self.tagsLabel.isHidden = false self.imageView.image = newImage self.animateImageChange(with: newImage) self.stopLoadingIndicator() diff --git a/AnimeGen/APIs/waifu-im.swift b/AnimeGen/APIs/waifu-im.swift index 0b1f78fc..cc367787 100644 --- a/AnimeGen/APIs/waifu-im.swift +++ b/AnimeGen/APIs/waifu-im.swift @@ -19,7 +19,6 @@ extension ViewController { var components = URLComponents(string: apiEndpoint) components?.queryItems = [ URLQueryItem(name: "is_nsfw", value: isNSFW ? "true" : "false") - // Add more query parameters as needed ] guard let url = components?.url else { @@ -67,6 +66,8 @@ extension ViewController { if let data = try? Data(contentsOf: imageUrl), let newImage = UIImage(data: data) { self.imageView.image = newImage self.animateImageChange(with: newImage) + + self.tagsLabel.isHidden = false self.updateUIWithTags(tags) diff --git a/AnimeGen/APIs/waifu-pics.swift b/AnimeGen/APIs/waifu-pics.swift index 80a386f8..59e5d563 100644 --- a/AnimeGen/APIs/waifu-pics.swift +++ b/AnimeGen/APIs/waifu-pics.swift @@ -68,6 +68,8 @@ extension ViewController { self.currentImageURL = imageUrlString + self.tagsLabel.isHidden = false + self.updateUIWithTags([randomCategory]) self.stopLoadingIndicator() diff --git a/AnimeGen/Settings/SettingsPage.swift b/AnimeGen/Settings/SettingsPage.swift index c02372ab..78ebb6c0 100644 --- a/AnimeGen/Settings/SettingsPage.swift +++ b/AnimeGen/Settings/SettingsPage.swift @@ -12,6 +12,7 @@ struct SettingsPage: View { // Features @State private var animations = UserDefaults.standard.bool(forKey: "enableAnimations") @State private var tags = UserDefaults.standard.bool(forKey: "enableTags") + @State private var moetags = UserDefaults.standard.bool(forKey: "enableMoeTags") // Content @State private var suggestiveCont = UserDefaults.standard.bool(forKey: "enablesuggestiveCont") @@ -37,6 +38,13 @@ struct SettingsPage: View { UserDefaults.standard.set(newValue, forKey: "enableTags") } )) + Toggle("Display nekos.moe Tags", isOn: Binding( + get: { self.moetags }, + set: { newValue in + self.moetags = newValue + UserDefaults.standard.set(newValue, forKey: "enableMoeTags") + } + )) } Section(header: Text("Content"), footer: Text("Caution: This content is on the borderline of explicit material and includes adult content. Viewer discretion is advised.")) { diff --git a/AnimeGen/ViewController.swift b/AnimeGen/ViewController.swift index f7960f02..b302d394 100644 --- a/AnimeGen/ViewController.swift +++ b/AnimeGen/ViewController.swift @@ -37,6 +37,8 @@ class ViewController: UIViewController { var enableAnimations = UserDefaults.standard.bool(forKey: "enableAnimations") + var moetags = UserDefaults.standard.bool(forKey: "enableMoeTags") + override func viewDidLoad() { super.viewDidLoad() @@ -227,6 +229,8 @@ class ViewController: UIViewController { loadImagesFromHmtai() case "Nekos api": loadImageAndTagsFromNekosapi() + case "nekos.moe": + loadImageAndTagsFromNekosMoe() default: break } @@ -271,6 +275,9 @@ class ViewController: UIViewController { case "Nekos api": lastImage = imageView.image loadImageAndTagsFromNekosapi() + case "nekos.moe": + lastImage = imageView.image + loadImageAndTagsFromNekosMoe() default: break } @@ -280,7 +287,7 @@ class ViewController: UIViewController { @objc func apiButtonTapped() { let alertController = UIAlertController(title: "Select API", message: nil, preferredStyle: .actionSheet) - let apiOptions = ["Nekos api", "Hmtai", "waifu.pics", "nekos.best", "waifu.im", "pic.re"] + let apiOptions = ["nekos.moe", "Nekos api", "Hmtai", "waifu.pics", "nekos.best", "waifu.im", "pic.re"] for option in apiOptions { let action = UIAlertAction(title: option, style: .default) { _ in self.apiButton.setTitle(option, for: .normal) diff --git a/README.md b/README.md index dece6689..6d47f753 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,27 @@ Its Made to support any iOS/iPadOS device running iOS 13+ - [waifu.pics api](https://waifu.pics/docs) SFW/NSFW - [Hmtai api](https://hmtai.hatsunia.cfd/endpoints) SFW/NSFW - [Nekos api](https://nekosapi.com/docs) SFW/NSFW +- [Nekos.moe](https://docs.nekos.moe) SFW/NSFW + + + + + + +
Working APIsType
+ +| APIs | Type | Working | +| ------------------- | ----- | :--------: | +| Pic.re | SFW | :white_check_mark: | +| Waifu.im | SFW/NSFW | :white_check_mark: | +| Nekos.best | SFW | :white_check_mark: | +| Waifu.pics | SFW/NSFW | :white_check_mark: | +| Hmtai | SFW/NSFW | :white_check_mark: | +| Nekos api | SFW/NSFW | :white_check_mark: | +| Nekos.mod | SFW/NSFW | :white_check_mark: | + +
+ ## Third Party Softwares