{"id":15170593,"url":"https://github.com/sventiigi/youtubeplayerkit","last_synced_at":"2025-05-14T21:09:24.510Z","repository":{"id":37536528,"uuid":"408516560","full_name":"SvenTiigi/YouTubePlayerKit","owner":"SvenTiigi","description":"A Swift Package to easily play YouTube videos 📺","archived":false,"fork":false,"pushed_at":"2025-02-03T21:33:13.000Z","size":1732,"stargazers_count":791,"open_issues_count":0,"forks_count":75,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-04-06T15:04:21.709Z","etag":null,"topics":["ios","macos","swift","swiftui","visionos","youtube","youtube-iframe-player","youtube-player"],"latest_commit_sha":null,"homepage":"https://sventiigi.github.io/YouTubePlayerKit/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SvenTiigi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"SvenTiigi"}},"created_at":"2021-09-20T16:22:49.000Z","updated_at":"2025-04-05T04:36:47.000Z","dependencies_parsed_at":"2023-02-14T00:46:14.194Z","dependency_job_id":"abe1ad2b-3183-44b2-abdb-ae5a86c67a0c","html_url":"https://github.com/SvenTiigi/YouTubePlayerKit","commit_stats":{"total_commits":284,"total_committers":9,"mean_commits":"31.555555555555557","dds":"0.052816901408450745","last_synced_commit":"fe1c1ec340f6d79866131432ecaa190fd6bbc4cb"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenTiigi%2FYouTubePlayerKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenTiigi%2FYouTubePlayerKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenTiigi%2FYouTubePlayerKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenTiigi%2FYouTubePlayerKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SvenTiigi","download_url":"https://codeload.github.com/SvenTiigi/YouTubePlayerKit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248753393,"owners_count":21156270,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","macos","swift","swiftui","visionos","youtube","youtube-iframe-player","youtube-player"],"created_at":"2024-09-27T08:04:11.034Z","updated_at":"2025-04-13T17:37:13.874Z","avatar_url":"https://github.com/SvenTiigi.png","language":"Swift","funding_links":["https://github.com/sponsors/SvenTiigi"],"categories":[],"sub_categories":[],"readme":"\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"Assets/logo.png\" width=\"30%\" alt=\"logo\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003e\n    YouTubePlayerKit\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n    A Swift Package to easily play YouTube videos.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n   \u003ca href=\"https://swiftpackageindex.com/SvenTiigi/YouTubePlayerKit\"\u003e\n    \u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FSvenTiigi%2FYouTubePlayerKit%2Fbadge%3Ftype%3Dswift-versions\" alt=\"Swift Version\"\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://swiftpackageindex.com/SvenTiigi/YouTubePlayerKit\"\u003e\n    \u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FSvenTiigi%2FYouTubePlayerKit%2Fbadge%3Ftype%3Dplatforms\" alt=\"Platforms\"\u003e\n   \u003c/a\u003e\n   \u003cbr/\u003e\n   \u003ca href=\"https://github.com/SvenTiigi/YouTubePlayerKit/actions/workflows/build_and_test.yml\"\u003e\n       \u003cimg src=\"https://github.com/SvenTiigi/YouTubePlayerKit/actions/workflows/build_and_test.yml/badge.svg\" alt=\"Build and Test Status\"\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://sventiigi.github.io/YouTubePlayerKit/documentation/youtubeplayerkit/\"\u003e\n       \u003cimg src=\"https://img.shields.io/badge/Documentation-DocC-blue\" alt=\"Documentation\"\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://twitter.com/SvenTiigi/\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/Twitter-@SvenTiigi-blue.svg?style=flat\" alt=\"Twitter\"\u003e\n   \u003c/a\u003e\n    \u003ca href=\"https://mastodon.world/@SvenTiigi\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/Mastodon-@SvenTiigi-8c8dff.svg?style=flat\" alt=\"Mastodon\"\u003e\n   \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cimg align=\"right\" width=\"307\" src=\"Assets/example-app.png\" alt=\"Example application\"\u003e\n\n```swift\nimport SwiftUI\nimport YouTubePlayerKit\n\nstruct ContentView: View {\n\n    var body: some View {\n        //  WWDC 2019 Keynote\n        YouTubePlayerView(\n            \"https://youtube.com/watch?v=psL_5RIBqnY\"\n        )\n    }\n\n}\n```\n\n## Features\n\n- [x] Play YouTube videos with just one line of code 📺\n- [x] YouTube [Terms of Service](https://developers.google.com/youtube/terms/api-services-terms-of-service) compliant implementation ✅\n- [x] Access to all native YouTube iFrame [APIs](https://developers.google.com/youtube/iframe_api_reference) 👩‍💻👨‍💻\n- [x] Support for SwiftUI, UIKit and AppKit 🧑‍🎨\n- [x] Runs on iOS, macOS and visionOS 📱 🖥 👓\n\n## Example\n\nCheck out the example application to see YouTubePlayerKit in action. Simply open the `Example/Example.xcodeproj` and run the \"Example\" scheme.\n\n## Installation\n\nTo integrate using Apple's [Swift Package Manager](https://swift.org/package-manager/), add the following as a dependency to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/SvenTiigi/YouTubePlayerKit.git\", from: \"2.0.0\")\n]\n```\n\nOr navigate to your Xcode project then select `Swift Packages`, click the “+” icon and search for `YouTubePlayerKit`.\n\n\u003e [!NOTE]\n\u003e When integrating YouTubePlayerKit to a macOS or Mac Catalyst target please ensure to enable \"Outgoing Connections (Client)\" in the \"Signing \u0026 Capabilities\" sections.\n\n## App Store Review\n\nWhen submitting an app to the App Store which includes the `YouTubePlayerKit`, please ensure to add a link to the [YouTube API Terms of Services](https://developers.google.com/youtube/terms/api-services-terms-of-service) in the review notes.\n\n```\nhttps://developers.google.com/youtube/terms/api-services-terms-of-service\n```\n\n## Limitations\n\n- Audio background playback is not supported as it violates the YouTube Terms of Service.\n- Simultaneous playback of multiple YouTube players is not supported.\n- Controlling playback of [360° videos](https://developers.google.com/youtube/iframe_api_reference#Spherical_Video_Controls) is not supported.\n\n## Usage\n\n\u003e [!TIP]\n\u003e Please refer to the [YouTubePlayerKit documentation](https://sventiigi.github.io/YouTubePlayerKit/documentation/youtubeplayerkit/) for a complete overview.\n\nA [`YouTubePlayer`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/YouTubePlayer.swift) can be easily displayed when using `SwiftUI` by declaring a [`YouTubePlayerView`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/UI/View/YouTubePlayerView.swift).\n\n```swift\nimport SwiftUI\nimport YouTubePlayerKit\n\nstruct ContentView: View {\n\n    let youTubePlayer: YouTubePlayer = \"https://youtube.com/watch?v=psL_5RIBqnY\"\n\n    var body: some View {\n        YouTubePlayerView(self.youTubePlayer) { state in\n            // An optional overlay view for the current state of the player\n            switch state {\n            case .idle:\n                ProgressView()\n            case .ready:\n                EmptyView()\n            case .error(let error):\n                ContentUnavailableView(\n                    \"Error\",\n                    systemImage: \"exclamationmark.triangle.fill\",\n                    description: Text(\"YouTube player couldn't be loaded: \\(error)\")\n                )\n            }\n        }\n        // Optionally react to specific updates such as the fullscreen state\n        .onReceive(\n            self.youTubePlayer.fullscreenStatePublisher\n        ) { fullscreenState in\n            if fullscreenState.isFullscreen {\n                // ...\n            }\n        }\n    }\n\n}\n```\n\n\u003e [!TIP]\n\u003e You can optionally mark the YouTubePlayer with `@StateObject` or `@ObservedObject` to automatically update your view whenever the source, parameters, or isLoggingEnabled change.\n\nWhen using `UIKit` or `AppKit` you can make use of the [`YouTubePlayerViewController`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/UI/ViewController/YouTubePlayerViewController.swift) or [`YouTubePlayerHostingView`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/UI/HostingView/YouTubePlayerHostingView.swift).\n\n```swift\nimport UIKit\nimport YouTubePlayerKit\n\nlet youTubePlayerViewController = YouTubePlayerViewController(\n    player: \"https://youtube.com/watch?v=psL_5RIBqnY\"\n)\n\nlet youTubePlayerHostingView = YouTubePlayerHostingView(\n    player: \"https://youtube.com/watch?v=psL_5RIBqnY\"\n)\n\n// Access the player on both instances via the `.player` property\n// Example: youTubePlayerViewController.player\n```\n\n## YouTubePlayer\n\nA [`YouTubePlayer`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/YouTubePlayer.swift) is the central object in order to play a certain YouTube video and interact with the underlying YouTube iFrame API.\n\nAs seen in the previous examples you can initialize a player by using a string literal:\n\n```swift\nlet youTubePlayer: YouTubePlayer = \"https://youtube.com/watch?v=psL_5RIBqnY\"\n```\n\nTo take full control you can initialize a [`YouTubePlayer`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/YouTubePlayer.swift) with a [`YouTubePlayer.Source`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/YouTubePlayer%2BSource.swift), [`YouTubePlayer.Parameters`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/YouTubePlayer%2BParameters.swift) and a [`YouTubePlayer.Configuration`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/YouTubePlayer%2BConfiguration.swift)\n\n```swift\nlet youTubePlayer = YouTubePlayer(\n    // Possible values: .video, .videos, .playlist, .channel\n    source: .video(id: \"psL_5RIBqnY\"),\n    // The parameters of the player\n    parameters: .init(\n        autoPlay: true,\n        showControls: true,\n        loopEnabled: true,\n        startTime: .init(value: 5, unit: .minutes),\n        // ...\n    ),\n    // The configuration of the underlying web view\n    configuration: .init(\n        fullscreenMode: .system,\n        allowsInlineMediaPlayback: true,\n        customUserAgent: \"MyCustomUserAgent\",\n        // ...\n    )\n)\n```\n\nTo differentiate between parameters and configuration, understand that parameters control the behavior and style of the YouTube player, while the configuration is linked to the underlying web view.\nYou cannot modify the configuration after instantiation; however, it is possible to update the parameters, as shown below:\n\n```swift\nyouTubePlayer.parameters.showControls = false\n```\n\n\u003e [!WARNING]\n\u003e Updating the [`YouTubePlayer.Parameters`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/YouTubePlayer%2BParameters.swift) during runtime will cause the player to reload.\n\n### Source\n\nThe [`YouTubePlayer.Source`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/YouTubePlayer%2BSource.swift) is an enum which allows you to specify which YouTube source should be loaded/cued.\n\n```swift\n// A single video\nlet video: YouTubePlayer.Source = .video(id: \"psL_5RIBqnY\")\n\n// Series of videos\nlet videos: YouTubePlayer.Source = .videos(ids: [\"w87fOAG8fjk\", \"RXeOiIDNNek\", \"psL_5RIBqnY\"])\n\n// Playlist\nlet playlist: YouTubePlayer.Source = .playlist(id: \"PLHFlHpPjgk72Si7r1kLGt1_aD3aJDu092\")\n\n// Channel\nlet channel: YouTubePlayer.Source = .channel(name: \"GoogleDevelopers\")\n```\n\nYou can also use a URL to initialize a source.\n\n```swift\nlet source: YouTubePlayer.Source? = .init(urlString: \"https://youtube.com/watch?v=psL_5RIBqnY\")\n```\n\n\u003e [!NOTE]\n\u003e The URL parsing logic is designed to handle most known YouTube URL formats, but there may be some variations that it doesn't cover.\n\n### API\n\nA [`YouTubePlayer`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/YouTubePlayer.swift) lets you access the underlying [YouTube Player iFrame API](https://developers.google.com/youtube/iframe_api_reference) to play, pause, seek, retrieve video information and much more.\n\nThe majority of the APIs are `async` and `throwable` functions.\n\n```swift\n// Pauses the currently playing video\ntry await youTubePlayer.pause()\n```\n\n\u003e [!TIP]\n\u003e Please see the [documentation](https://sventiigi.github.io/YouTubePlayerKit/documentation/youtubeplayerkit/youtubeplayer) for a full overview of the available APIs.\n\nIn case of an error, most functions throw a [`YouTubePlayer.APIError`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/Error/YouTubePlayer%2BAPIError.swift).\nThis allows you to easily examine the reason for the error, any underlying error, and the executed JavaScript along with its response.\n\n```swift\ndo {\n    try await youTubePlayer.setCaptions(fontSize: .small)\n} catch {\n    print(\n        \"Failed to set captions font size\",\n        error.reason,\n        error.underlyingError,\n        error.javaScript,\n        error.javaScriptResponse\n    )\n}\n```\n\nAdditionally, several Publishers are available to react to changes of the player:\n\n```swift\n// Observe playback metadata\nlet cancellable = youTubePlayer\n    .playbackMetadataPublisher\n    .sink { playbackMetadata in\n        // ...\n    }\n```\n\n## Video Thumbnail\n\nYou can load a YouTube video thumbnail via the [`YouTubeVideoThumbnail`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/VideoThumbnail/YouTubeVideoThumbnail.swift) object.\n\n```swift\n// Initialize an instance of YouTubeVideoThumbnail\nlet videoThumbnail = YouTubeVideoThumbnail(\n    videoID: \"psL_5RIBqnY\",\n    // Choose between default, medium, high, standard, maximum\n    resolution: .high\n)\n\n// Retrieve the URL, if available\nlet url: URL? = videoThumbnail.url\n\n// Retrieve the image, if available.\nlet image: YouTubeVideoThumbnail.Image? = try await videoThumbnail.image()\n```\n\nAdditionally, the player allows you to easily retrieve the thumbnail url and image for the currently loaded video.\n\n```swift\n// Returns the video thumbnail URL of the currently loaded video\ntry await youTubePlayer.getVideoThumbnailURL()\n\n/// Returns the video thumbnail of the currently loaded video\ntry await youTubePlayer.getVideoThumbnailImage(resolution: .maximum)\n```\n\n## Logging\n\nIf you wish to gain more insights into the underlying communication of the YouTube Player iFrame JavaScript API, you can enable the logging of a player via the `isLogginEnabled` parameter.\n\nThe [`YouTubePlayer`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/YouTubePlayer.swift) utilizes the [unified logging system (OSLog)](https://developer.apple.com/documentation/os/logging) to log information about the player options, JavaScript events and evaluations.\n\n```swift\n// Enable or disable logging during initialization\nlet youTubePlayer = YouTubePlayer(\n    source: [\n        \"w87fOAG8fjk\",\n        \"RXeOiIDNNek\",\n        \"psL_5RIBqnY\"\n    ],\n    isLoggingEnabled: true\n)\n\n// To update during runtime update the isLoggingEnabled property\nyouTubePlayer.isLoggingEnabled = false\n\n// Additionally, you can retrieve an instance of the logger if logging is enabled.\nlet logger: Logger? = youTubePlayer.logger()\n```\n\n## Advanced\n\nYou can observe the incoming stream of [`YouTubePlayer.Event`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/Event/YouTubePlayer%2BEvent.swift) from the underlying YouTube Player iFrame API through the following publisher.\n\n```swift\nlet cancellable = youTubePlayer\n    .eventPublisher\n    .sink { event in\n        switch event.name {\n        case .playbackQualityChange:\n            break\n        case .autoplayBlocked:\n            break\n        default:\n            break\n        }\n    }\n```\n\n\u003e [!IMPORTANT]\n\u003e The YouTubePlayerKit supports both official as well as unofficial/undocumented events. Please see the [`YouTubePlayer.Event.Name`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/Event/YouTubePlayer%2BEvent%2BName.swift) enumeration for more details.\n\nTo run [custom JavaScript](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/JavaScript/YouTubePlayer%2BJavaScript.swift) on the YouTube player JavaScript instance:\n\n```swift\ntry await youTubePlayer.evaluate(\n    javaScript: \"\\(.youTubePlayer).play()\"\n)\n```\n\n\u003e [!NOTE]\n\u003e The custom string interpolation of [`\\(.youTubePlayer)`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/JavaScript/YouTubePlayer%2BJavaScript.swift) is a placeholder for the YouTube player JavaScript variable.\n\nAlternatively, you can use the following convenience function to directly invoke a function on the YouTube player JavaScript object:\n\n```swift\ntry await youTubePlayer.evaluate(\n    javaScript: .youTubePlayer(\n        functionName: \"setLoop\",\n        parameters: [\n            true\n        ]\n    )\n)\n```\n\nIf you wish to further customize the underlying HTML you can configure the [`YouTubePlayer.HTMLBuilder`](https://github.com/SvenTiigi/YouTubePlayerKit/blob/main/Sources/Models/YouTubePlayer%2BHTMLBuilder.swift) when initializing an instance of the player:\n\n```swift\nlet youTubePlayer = YouTubePlayer(\n    source: .video(id: \"psL_5RIBqnY\"),\n    configuration: .init(\n        htmlBuilder: .init(\n            youTubePlayerJavaScriptVariableName: \"youtubePlayer\",\n            youTubePlayerEventCallbackURLScheme: \"youtubeplayer\",\n            youTubePlayerEventCallbackDataParameterName: \"data\",\n            youTubePlayerIframeAPISourceURL: .init(string: \"https://www.youtube.com/iframe_api\")!,\n            htmlProvider: { htmlBuilder, jsonEncodedYouTubePlayerOptions in\n                // TODO: Return custom HTML string\n            }\n        )\n    )\n)\n```\n\n## Credits\n\n- [youtube/youtube-ios-player-helper](https://github.com/youtube/youtube-ios-player-helper)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsventiigi%2Fyoutubeplayerkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsventiigi%2Fyoutubeplayerkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsventiigi%2Fyoutubeplayerkit/lists"}