mirror of
https://github.com/mas-cli/mas
synced 2024-11-22 03:23:08 +00:00
♻️ Refactor lookupURL, searchURL
Resolves unused protocol method lint warnings by moving updated implementations back to StoreSearch. Added `country` to MasStoreSearch, set to fixed fvalue for tests.
This commit is contained in:
parent
5aafd4c0aa
commit
521df64b51
3 changed files with 38 additions and 71 deletions
|
@ -13,58 +13,25 @@ import Version
|
|||
|
||||
/// Manages searching the MAS catalog through the iTunes Search and Lookup APIs.
|
||||
class MasStoreSearch: StoreSearch {
|
||||
private let networkManager: NetworkManager
|
||||
private static let appVersionExpression = Regex(#"\"versionDisplay\"\:\"([^\"]+)\""#)
|
||||
|
||||
enum Entity: String {
|
||||
case macSoftware
|
||||
case iPadSoftware
|
||||
case iPhoneSoftware = "software"
|
||||
}
|
||||
// CommerceKit and StoreFoundation don't seem to expose the region of the Apple ID signed
|
||||
// into the App Store. Instead, we'll make an educated guess that it matches the currently
|
||||
// selected locale in macOS. This obviously isn't always going to match, but it's probably
|
||||
// better than passing no "country" at all to the iTunes Search API.
|
||||
// https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/
|
||||
private let country: String?
|
||||
private let networkManager: NetworkManager
|
||||
|
||||
/// Designated initializer.
|
||||
init(networkManager: NetworkManager = NetworkManager()) {
|
||||
init(
|
||||
country: String? = Locale.autoupdatingCurrent.regionCode,
|
||||
networkManager: NetworkManager = NetworkManager()
|
||||
) {
|
||||
self.country = country
|
||||
self.networkManager = networkManager
|
||||
}
|
||||
|
||||
/// Builds the search URL for an app.
|
||||
///
|
||||
/// - Parameter appName: MAS app identifier.
|
||||
/// - Returns: URL for the search service or nil if appName can't be encoded.
|
||||
static func searchURL(for appName: String, ofEntity entity: Entity = .macSoftware) -> URL {
|
||||
guard var components = URLComponents(string: "https://itunes.apple.com/search") else {
|
||||
fatalError("URLComponents failed to parse URL.")
|
||||
}
|
||||
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "media", value: "software"),
|
||||
URLQueryItem(name: "entity", value: entity.rawValue),
|
||||
URLQueryItem(name: "term", value: appName),
|
||||
]
|
||||
guard let url = components.url else {
|
||||
fatalError("URLComponents failed to generate URL.")
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
/// Builds the lookup URL for an app.
|
||||
///
|
||||
/// - Parameter appId: MAS app identifier.
|
||||
/// - Returns: URL for the lookup service or nil if appId can't be encoded.
|
||||
static func lookupURL(forApp appId: Int) -> URL {
|
||||
guard var components = URLComponents(string: "https://itunes.apple.com/lookup") else {
|
||||
fatalError("URLComponents failed to parse URL.")
|
||||
}
|
||||
|
||||
components.queryItems = [URLQueryItem(name: "id", value: "\(appId)")]
|
||||
guard let url = components.url else {
|
||||
fatalError("URLComponents failed to generate URL.")
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
/// Searches for an app.
|
||||
///
|
||||
/// - Parameter appName: MAS ID of app
|
||||
|
@ -79,7 +46,9 @@ class MasStoreSearch: StoreSearch {
|
|||
}
|
||||
|
||||
let results = entities.map { entity -> Promise<[SearchResult]> in
|
||||
let url = MasStoreSearch.searchURL(for: appName, ofEntity: entity)
|
||||
guard let url = searchURL(for: appName, inCountry: country, ofEntity: entity) else {
|
||||
fatalError("Failed to build URL for \(appName)")
|
||||
}
|
||||
return loadSearchResults(url)
|
||||
}
|
||||
|
||||
|
@ -96,7 +65,9 @@ class MasStoreSearch: StoreSearch {
|
|||
/// - Returns: A Promise for the search result record of app, or nil if no apps match the ID,
|
||||
/// or an Error if there is a problem with the network request.
|
||||
func lookup(app appId: Int) -> Promise<SearchResult?> {
|
||||
let url = MasStoreSearch.lookupURL(forApp: appId)
|
||||
guard let url = lookupURL(forApp: appId, inCountry: country) else {
|
||||
fatalError("Failed to build URL for \(appId)")
|
||||
}
|
||||
return firstly {
|
||||
loadSearchResults(url)
|
||||
}.then { results -> Guarantee<SearchResult?> in
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// Copyright © 2018 mas-cli. All rights reserved.
|
||||
//
|
||||
|
||||
import PromiseKit
|
||||
import Foundation
|
||||
import PromiseKit
|
||||
|
||||
/// Protocol for searching the MAS catalog.
|
||||
protocol StoreSearch {
|
||||
|
@ -15,25 +15,31 @@ protocol StoreSearch {
|
|||
func search(for appName: String) -> Promise<[SearchResult]>
|
||||
}
|
||||
|
||||
enum Entity: String {
|
||||
case macSoftware
|
||||
case iPadSoftware
|
||||
case iPhoneSoftware = "software"
|
||||
}
|
||||
|
||||
// MARK: - Common methods
|
||||
extension StoreSearch {
|
||||
/// Builds the search URL for an app.
|
||||
///
|
||||
/// - Parameter appName: MAS app identifier.
|
||||
/// - Returns: URL for the search service or nil if appName can't be encoded.
|
||||
func searchURL(for appName: String) -> URL? {
|
||||
func searchURL(for appName: String, inCountry country: String?, ofEntity entity: Entity = .macSoftware) -> URL? {
|
||||
guard var components = URLComponents(string: "https://itunes.apple.com/search") else {
|
||||
return nil
|
||||
}
|
||||
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "media", value: "software"),
|
||||
URLQueryItem(name: "entity", value: "macSoftware"),
|
||||
URLQueryItem(name: "entity", value: entity.rawValue),
|
||||
URLQueryItem(name: "term", value: appName),
|
||||
]
|
||||
|
||||
if let country {
|
||||
components.queryItems!.append(country)
|
||||
components.queryItems!.append(URLQueryItem(name: "country", value: country))
|
||||
}
|
||||
|
||||
return components.url
|
||||
|
@ -43,7 +49,7 @@ extension StoreSearch {
|
|||
///
|
||||
/// - Parameter appId: MAS app identifier.
|
||||
/// - Returns: URL for the lookup service or nil if appId can't be encoded.
|
||||
func lookupURL(forApp appId: Int) -> URL? {
|
||||
func lookupURL(forApp appId: Int, inCountry country: String?) -> URL? {
|
||||
guard var components = URLComponents(string: "https://itunes.apple.com/lookup") else {
|
||||
return nil
|
||||
}
|
||||
|
@ -54,22 +60,9 @@ extension StoreSearch {
|
|||
]
|
||||
|
||||
if let country {
|
||||
components.queryItems!.append(country)
|
||||
components.queryItems!.append(URLQueryItem(name: "country", value: country))
|
||||
}
|
||||
|
||||
return components.url
|
||||
}
|
||||
|
||||
private var country: URLQueryItem? {
|
||||
// CommerceKit and StoreFoundation don't seem to expose the region of the Apple ID signed
|
||||
// into the App Store. Instead, we'll make an educated guess that it matches the currently
|
||||
// selected locale in macOS. This obviously isn't always going to match, but it's probably
|
||||
// better than passing no "country" at all to the iTunes Search API.
|
||||
// https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/
|
||||
guard let region = Locale.autoupdatingCurrent.regionCode else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return URLQueryItem(name: "country", value: region)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,15 +19,18 @@ public class MasStoreSearchSpec: QuickSpec {
|
|||
describe("url string") {
|
||||
it("contains the app name") {
|
||||
let appName = "myapp"
|
||||
let urlString = MasStoreSearch.searchURL(for: appName).absoluteString
|
||||
expect(urlString) == "https://itunes.apple.com/search?media=software&entity=macSoftware&term=\(appName)"
|
||||
let urlString = MasStoreSearch().searchURL(for: appName, inCountry: "US")?.absoluteString
|
||||
expect(urlString) == """
|
||||
https://itunes.apple.com/search?media=software&entity=macSoftware&term=\(appName)&country=US
|
||||
"""
|
||||
}
|
||||
it("contains the encoded app name") {
|
||||
let appName = "My App"
|
||||
let appNameEncoded = "My%20App"
|
||||
let urlString = MasStoreSearch.searchURL(for: appName).absoluteString
|
||||
expect(urlString)
|
||||
== "https://itunes.apple.com/search?media=software&entity=macSoftware&term=\(appNameEncoded)"
|
||||
let urlString = MasStoreSearch().searchURL(for: appName, inCountry: "US")?.absoluteString
|
||||
expect(urlString) == """
|
||||
https://itunes.apple.com/search?media=software&entity=macSoftware&term=\(appNameEncoded)&country=US
|
||||
"""
|
||||
}
|
||||
}
|
||||
describe("store") {
|
||||
|
|
Loading…
Reference in a new issue