iTunes TV Show Seasons Release Finder Swift Script

This Swift script lets you search for a TV show by title from the macOS Terminal, displaying its initial release date and a chronological list of seasons with their release dates, all pulled from the iTunes Store API. Perfect for TV enthusiasts wanting quick access to show timelines!

Click to view script…
#!/usr/bin/env swift

import Foundation

// Define structs to match the iTunes Search API response for TV seasons
struct SearchResponse: Codable {
    let resultCount: Int
    let results: [TVSeason]
}

struct TVSeason: Codable {
    let artistName: String      // The TV show's name
    let collectionName: String  // The season's name
    let releaseDate: Date       // The season's release date
}

// Check for command-line arguments
if CommandLine.arguments.count < 2 {
    print("Usage: \(CommandLine.arguments[0]) <tv show title>")
    exit(1)
}

// Combine all arguments after the script name into a single TV show title
let tvShowTitle = CommandLine.arguments[1...].joined(separator: " ")

// Construct the API URL for searching TV seasons
let baseURL = "https://itunes.apple.com/search"
let queryItems = [
    URLQueryItem(name: "term", value: tvShowTitle),
    URLQueryItem(name: "media", value: "tvShow"),
    URLQueryItem(name: "entity", value: "tvSeason"),
    URLQueryItem(name: "country", value: "us")
]
var urlComponents = URLComponents(string: baseURL)!
urlComponents.queryItems = queryItems
guard let url = urlComponents.url else {
    print("Invalid URL.")
    exit(1)
}

// Set up semaphore to handle asynchronous URLSession task
let semaphore = DispatchSemaphore(value: 0)
var exitCode: Int32 = 0  // Exit code for the script

// Perform the network request
let session = URLSession.shared
let task = session.dataTask(with: url) { data, response, error in
    if let error = error {
        print("Error: \(error.localizedDescription)")
        exitCode = 1
    } else if let data = data {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601 // Handle ISO 8601 date format
        do {
            let searchResponse = try decoder.decode(SearchResponse.self, from: data)
            if searchResponse.resultCount > 0 {
                let seasons = searchResponse.results
                let showName = seasons[0].artistName
                // Sort seasons by release date
                let sortedSeasons = seasons.sorted { $0.releaseDate < $1.releaseDate }
                // Display show info and initial release date
                if let firstReleaseDate = sortedSeasons.first?.releaseDate {
                    let dateFormatter = DateFormatter()
                    dateFormatter.dateStyle = .long
                    let formattedDate = dateFormatter.string(from: firstReleaseDate)
                    print("TV Show: \(showName)")
                    print("Initial Release Date: \(formattedDate)")
                } else {
                    print("TV Show: \(showName)")
                    print("Release date not available.")
                }
                // List all seasons
                print("Seasons:")
                for season in sortedSeasons {
                    let seasonDateFormatter = DateFormatter()
                    seasonDateFormatter.dateStyle = .long
                    let seasonFormattedDate = seasonDateFormatter.string(from: season.releaseDate)
                    print("- \(season.collectionName): \(seasonFormattedDate)")
                }
                exitCode = 0
            } else {
                print("No TV show found for \"\(tvShowTitle)\".")
                exitCode = 1
            }
        } catch {
            print("Error decoding JSON: \(error)")
            exitCode = 1
        }
    } else {
        print("No data received.")
        exitCode = 1
    }
    semaphore.signal() // Signal completion
}

// Start the task and wait for it to complete
task.resume()
semaphore.wait()
exit(exitCode)