Contents

brightdigit/swifttube

A lightweight async/await Swift client for a focused slice of the YouTube Data API v3.

Requirements

  • Swift 6.4+
  • macOS 13+, iOS 16+, tvOS 16+, watchOS 9+ (also builds for Linux, Windows, Android, and WASI)
  • A YouTube Data API key

Installation

Add SwiftTube as a Swift Package Manager dependency:

dependencies: [
  .package(url: "https://github.com/brightdigit/SwiftTube.git", from: "1.0.0-alpha.1")
],
targets: [
  .target(
    name: "YourTarget",
    dependencies: ["SwiftTube"]
  )
]

Usage

Create a YouTubeClient with your API key and ask for the videos in a playlist:

import SwiftTube

let client = YouTubeClient(apiKey: "YOUR_API_KEY")

let videos = try await client.videos(forPlaylistID: "PLxxxxxxxx")

for video in videos {
  print(video.title ?? "Untitled", video.duration ?? "")
}

videos(forPlaylistID:) transparently follows playlist pagination to collect every video id, then fetches the video details in concurrent batches of 50 (the API's per-request id limit).

Video

Each result is a flat, Sendable/Equatable value mapped from the API response. Every field is optional — presence validation is left to the caller, so the type never throws:

public struct Video: Equatable, Sendable {
  public let id: String?
  public let title: String?
  public let description: String?
  public let publishedAt: Date?          // decoded from the API's ISO 8601 date-time
  public let duration: String?           // ISO 8601 duration, e.g. "PT1H2M3S"
  public let standardThumbnailURL: String?
}

Errors

Any non-200 / undocumented response surfaces as:

public enum ClientError: Error, Equatable, Sendable {
  case invalidResponse
}

Custom transports

The default initializer uses URLSessionTransport. On platforms where URLSession is unavailable (WASI), or when you want to inject a custom ClientTransport, pass one explicitly:

let client = YouTubeClient(apiKey: "YOUR_API_KEY", transport: myTransport)

Regenerating the OpenAPI client

The generated Client.swift / Types.swift under Sources/SwiftTube/Generated are committed ahead of time. The generator runs as a mise-managed CLI tool — not a SwiftPM build/command plugin.

mise install                                      # install pinned tooling
mise run generate-openapi                         # regenerate from the committed spec
Scripts/generate-openapi-swifttube.sh --refresh   # re-fetch + convert the upstream spec first
Scripts/generate-openapi-swifttube.sh --check     # verify the committed output is up to date

The set of generated operations is controlled by the filter: key in openapi/openapi-generator-config.yaml. To expose a new endpoint, add its operation id there and regenerate.

Development

swift build                # build
swift test                 # run the test suite (Swift Testing + a mock transport)
./Scripts/lint.sh          # swift-format, SwiftLint, periphery, build

License

SwiftTube is available under the MIT license. See LICENSE for details.

Package Metadata

Repository: brightdigit/swifttube

Default branch: main

README: README.md