Skip to content

Commit

Permalink
Document metadata integration (#835)
Browse files Browse the repository at this point in the history
  • Loading branch information
defagos authored Apr 20, 2024
1 parent 4140ddf commit 657beed
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 27 deletions.
6 changes: 5 additions & 1 deletion Demo/Pillarbox-demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
6F0B2E8B2A40EE0700B69675 /* ContentList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0B2E8A2A40EE0700B69675 /* ContentList.swift */; };
6F0E5CD32B3394EA0031E313 /* PiPButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0E5CD22B3394EA0031E313 /* PiPButton.swift */; };
6F0E5CD52B33A41F0031E313 /* MonoscopicVideoView~ios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0E5CD42B33A41F0031E313 /* MonoscopicVideoView~ios.swift */; };
6F12A9522BD2B8A300AD6DDB /* IntegratingWithControlCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F12A9512BD2B8A300AD6DDB /* IntegratingWithControlCenter.swift */; };
6F26F35E2B33B73900392ED4 /* SupportingBasicPictureInPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F26F35D2B33B73900392ED4 /* SupportingBasicPictureInPicture.swift */; };
6F59E87929CF31E10093E6FB /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F59E84029CF31E10093E6FB /* SearchView.swift */; };
6F59E87A29CF31E10093E6FB /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F59E84129CF31E10093E6FB /* SearchViewModel.swift */; };
Expand Down Expand Up @@ -116,6 +117,7 @@
6F0B2E8A2A40EE0700B69675 /* ContentList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentList.swift; sourceTree = "<group>"; };
6F0E5CD22B3394EA0031E313 /* PiPButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPButton.swift; sourceTree = "<group>"; };
6F0E5CD42B33A41F0031E313 /* MonoscopicVideoView~ios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MonoscopicVideoView~ios.swift"; sourceTree = "<group>"; };
6F12A9512BD2B8A300AD6DDB /* IntegratingWithControlCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegratingWithControlCenter.swift; sourceTree = "<group>"; };
6F26F35D2B33B73900392ED4 /* SupportingBasicPictureInPicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportingBasicPictureInPicture.swift; sourceTree = "<group>"; };
6F45DB9A2893B773008ACCE6 /* Application.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Application.xcconfig; sourceTree = "<group>"; };
6F45DB9B2893B773008ACCE6 /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = "<group>"; };
Expand Down Expand Up @@ -326,7 +328,6 @@
isa = PBXGroup;
children = (
6FCB9DDD29E024E900961B69 /* BlurredView.swift */,
0E46D3002BD2754400133AE2 /* ChaptersPlayerView.swift */,
6F59E86229CF31E10093E6FB /* LinkView.swift */,
6FAD51102B331A2C0078FE08 /* Multi */,
0E6B995B29D43E4200D0276D /* OptInView.swift */,
Expand Down Expand Up @@ -403,6 +404,7 @@
isa = PBXGroup;
children = (
6F59E86E29CF31E10093E6FB /* BasicPlaybackView.swift */,
0E46D3002BD2754400133AE2 /* ChaptersPlayerView.swift */,
0E4128BC2AFB7F2A00D67759 /* InlineSystemPlayerView.swift */,
6F59E86B29CF31E10093E6FB /* PlaybackView.swift */,
6F59E86A29CF31E10093E6FB /* PlayerConfiguration.swift */,
Expand Down Expand Up @@ -468,6 +470,7 @@
6F26F35D2B33B73900392ED4 /* SupportingBasicPictureInPicture.swift */,
6F7EAA542B17755C00194D03 /* TrackingProgressTutorial~ios.swift */,
6FD407882B189C0600D34BD1 /* TrackingVisibilityTutorial~ios.swift */,
6F12A9512BD2B8A300AD6DDB /* IntegratingWithControlCenter.swift */,
);
path = Tutorials;
sourceTree = "<group>";
Expand Down Expand Up @@ -656,6 +659,7 @@
0E48F3FC2B2DBAD4001982BB /* CustomNavigationLink.swift in Sources */,
6FD407892B189C0600D34BD1 /* TrackingVisibilityTutorial~ios.swift in Sources */,
0ECC5AD52A517A4C0064E701 /* PlaybackSlider~ios.swift in Sources */,
6F12A9522BD2B8A300AD6DDB /* IntegratingWithControlCenter.swift in Sources */,
0EE2A3B02B29F82200BAAD65 /* CustomSection.swift in Sources */,
6F59E89929CF31E20093E6FB /* PlaybackView.swift in Sources */,
6F59E8A029CF31E20093E6FB /* Constant.swift in Sources */,
Expand Down
32 changes: 32 additions & 0 deletions Demo/Tutorials/IntegratingWithControlCenter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Copyright (c) SRG SSR. All rights reserved.
//
// License information is available from the LICENSE file.
//

import PillarboxPlayer
import SwiftUI

private struct Metadata: AssetMetadata {
var playerMetadata: PlayerMetadata {
// swiftlint:disable:next object_literal
.init(title: "🍎", subtitle: "🍏", image: UIImage(named: "apple"))
}
}

struct IntegratingWithControlCenter: View {
@StateObject private var player = Player(item: .simple(
url: URL(string: "https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_ts/master.m3u8")!,
metadata: Metadata()
))

var body: some View {
ZStack {
VideoView(player: player)
}
.onAppear {
player.play()
player.becomeActive()
}
}
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Its robust player provides all essential playback features you might expect:
- Integration with the standard system playback user experience, both on iOS and tvOS.
- Playlist management including bidirectional navigation.
- Support for alternative audio tracks, Audio Description, subtitles, CC and SDH, all tightly integrated with standard system accessibility features.
- Metadata and chapter support.
- AirPlay compatibility.
- Control center integration.
- Multiple instance support.
Expand All @@ -40,6 +41,7 @@ From left to right:
- Screenshots 1, 2 and 3: [Rich custom player user interface](Demo/Sources/Players/PlaybackView.swift).
- Screenshot 4: [Player with associated playlist](Demo/Sources/Showcase/Playlist/PlaylistView.swift).
- Screenshot 5: [Stories](Demo/Sources/Showcase/Stories/StoriesView.swift).
- Screenshot 6: [Custom chapter navigation](Demo/Sources/Players/ChaptersPlayerView.swift).

# Code example

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ The main responsibility of a ``PlayerItem`` loaded into a ``Player`` is to deliv
To associate Control Center metadata with a player item:

1. Create a type which represents your asset metadata and have it conform to ``AssetMetadata``.
2. Implement the ``AssetMetadata/nowPlayingMetadata()-5kft8`` method and return the ``NowPlayingMetadata`` which must be displayed in the Control Center when the item is currently being played.
2. Implement the ``AssetMetadata/playerMetadata`` method and return the ``PlayerMetadata`` which must be displayed in the Control Center when the item is currently being played.
3. Implement a custom ``PlayerItem`` with a metadata publisher retrieving all metadata required before delivering an asset. Alternatively, and provided you have all metadata and the URL to be played readily available, you can simply use one of the available ``PlayerItem`` construction helpers, supplying the asset metadata at creation time.

> Tip: Metadata associated with a ``PlayerItem`` is automatically published by a ``Player``. You can retrieve this metadata from the ``Player/metadata`` property and use it when building a custom user interface. The metadata is also automatically displayed by ``SystemVideoView`` in a standard way.
### Make a player instance active

Several ``Player`` instances can coexist in an app but at most one can be integrated with the Control Center at any time.
Expand Down
4 changes: 2 additions & 2 deletions Sources/Player/Player.docc/Extensions/player-item.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

### Initializers

- ``init(publisher:trackerAdapters:)``
- ``init(asset:trackerAdapters:)``
- ``init(publisher:trackerAdapters:)-3bxzd``
- ``init(asset:trackerAdapters:)-6pn9c``

### Methods with metadata

Expand Down
8 changes: 5 additions & 3 deletions Sources/Player/Player.docc/PillarboxPlayer.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,17 @@ The PillarboxPlayer framework fully integrates with SwiftUI, embracing its decla
- ``SeekBehavior``
- ``StreamType``

### Metadata

- ``AssetMetadata``
- ``PlayerMetadata``

### System Integration

- <doc:airplay>
- <doc:control-center>
- <doc:picture-in-picture>

- ``AssetMetadata``
- ``NowPlayingInfo``
- ``NowPlayingMetadata``
- ``PictureInPicture``
- ``PictureInPictureButton``
- ``PictureInPictureDelegate``
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import PillarboxPlayer
import SwiftUI

private struct Metadata {}
private struct Metadata: AssetMetadata {}

struct ContentView: View {
@StateObject private var player = Player(item: .simple(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import PillarboxPlayer
import SwiftUI

private struct Metadata {
func nowPlayingMetadata() -> NowPlayingMetadata {
.init(title: "🍎", subtitle: "🍏", image: .apple)
private struct Metadata: AssetMetadata {
var playerMetadata: PlayerMetadata {
.init(title: "🍎", subtitle: "🍏", image: UIImage(named: "apple"))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
@Tutorial(time: 2) {
@Intro(title: "Integrating with the Control Center") {
Enable control of playback directly from the Control Center.
Control playback directly from the Control Center.

@Image(source: integrating-with-control-center, alt: "An image depicting the Control Center.")
}

@Section(title: "Control Center and Playback") {
@Section(title: "Enable playback steering from the Control Center") {
@ContentAndMedia {
Bind the ``Player`` and the Control Center.
Integrate a ``Player`` with the Control Center.
}

@Steps {
@Step {
Start the playback.

Excellent! The player is now active, but the Control Center is not yet aware.
Create a ``Player`` with an associated ``VideoView``.

@Code(name: "ContentView.swift", file: integrating-with-control-center-1-1.swift) {
@Image(source: integrating-with-control-center-1-1, alt: "A screenshot from an iPhone")
}
}

@Step {
Link the ``Player`` with the Control Center.
Enable Control Center integration for the ``Player``.

Great! Now the player is linked to the Control Center, and we can use the controls.
The Control Center can now be used to steer playback but does not display any metadata yet.

@Code(name: "ContentView.swift", file: integrating-with-control-center-1-2.swift) {
@Image(source: integrating-with-control-center-1-2, alt: "A screenshot from an iPhone")
Expand All @@ -33,25 +31,24 @@
}
}

@Section(title: "Control Center and Metadata") {
@Section(title: "Display metadata in the Control Center") {
@ContentAndMedia {
Provide metadata to the Control Center.
Associate metadata with the content being played so that it can be displayed in the Control Center.
}

@Steps {
@Step {
Add metadata to the ``Player``.

By default the metadata is empty.
To populate the Control Center, additional steps are required.
Add metadata to the ``Player``, conforming to the ``AssetMetadata`` protocol.

@Code(name: "ContentView.swift", file: integrating-with-control-center-2-1.swift) {
@Image(source: integrating-with-control-center-2-1, alt: "A screenshot from an iPhone")
}
}

@Step {
Include a title, a subtitle, and an image.
Implement the protocol to return some ``PlayerMetadata``, including a title, a subtitle and an image.

This code assumes that your application resources provide an image called `apple`.

@Code(name: "ContentView.swift", file: integrating-with-control-center-2-2.swift) {
@Image(source: integrating-with-control-center-2-2, alt: "A screenshot from an iPhone")
Expand Down
2 changes: 2 additions & 0 deletions Sources/Player/Types/Chapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public struct Chapter: Equatable {
public let title: String?

/// The image associated with the chapter.
///
/// The image should usually be reasonable in size (less than 1000px wide / tall is in general sufficient).
public let image: UIImage?

/// The time range covered by the chapter.
Expand Down
9 changes: 8 additions & 1 deletion Sources/Player/Types/PlayerMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,23 @@ public struct PlayerMetadata: Equatable {
/// An identifier for the content.
public let identifier: String?

/// The content title.
/// The content title
///
/// For example the name of the show which the content is associated with, if any, otherwise the name
/// of the episode itself.
public let title: String?

/// A subtitle for the content.
///
/// For example the name of the episode when a show name has been provided as title.
public let subtitle: String?

/// A description of the content.
public let description: String?

/// The image associated with the content.
///
/// The image should usually be reasonable in size (less than 1000px wide / tall is in general sufficient).
public let image: UIImage?

/// Episode information associated with the content.
Expand Down
Binary file modified docs/README-images/showcase.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 657beed

Please sign in to comment.