Jman012 / Wasserflug-tvOS

An unofficial Floatplane client for Apple TV/tvOS
MIT License
31 stars 4 forks source link

Videos no longer working #14

Closed Jman012 closed 2 years ago

Jman012 commented 2 years ago

CDN API endpoint changes.

Simulator Screen Shot - Apple TV 4K (2nd generation) - 2022-09-29 at 15 27 58

Summary of changes:

Jman012 commented 2 years ago

This also affected livestreams.

1.2.3-1 is being pushed to Test Flight soon.

Rua-Yuki commented 2 years ago

Apologies for the surprise change there!

As you've figured, the qualityLevelParams dictionary is meant to hold arbitrary keys which resource URI templates may then reference.

We found requiring clients to perform the necessary parsing and replacement for delivery resource URIs to be a source of unwanted complexity. As such, in an effort to simplify client implementations (along with certain backend concerns), we have revamped the way delivery is managed.

Because of this, the concept of qualityLevelParams no longer exists internally, outside of a single unit which is responsible for downgrading new v3 resources to v2. This involves parsing arbitrary sets of v3 URIs on-the-fly and attempting to produce a valid v2 template given said input.

Any and every v3 resource must be automatically downgrade-able to v2. Unfortunately, it is impossible to guarantee this while constrained to only {token} and {qualityLevels} which it appears a number of 3rd party apps have assumed as the only possible keys during template replacement.


I'd highly recommend switching over to delivery-info v3 if possible. I'm not able to provide in-depth details at the moment (it's quite a lot to prepare public docs for), though I can nudge you towards the right path a bit:

You may safely assume:

Given the constraints of v3, any deviation from the above will be considered a bug, so please do let us know if you encounter anything bizarre.

We're aware and would like to make 3rd party interactions with the API more pleasant. This is however pending other tasks in the pipeline. Many thanks for your patience!

Jman012 commented 2 years ago

I appreciate this very, very much Rua-Yuki! This is quite detailed and will do us well when implementing it. Such details about optional fields can be quite important for consumption. I don't happen to see a common field under meta in any examples currently, but it's nice to know that may exist. I'll be sure to include those details.

I will formalize all of this into https://github.com/Jman012/FloatplaneAPI/ in the coming days.

We all appreciate this a lot!

Cc @bmlzootown, @Inrixia.

Rua-Yuki commented 2 years ago

I don't happen to see a common field under meta in any examples currently, but it's nice to know that may exist. I'll be sure to include those details.

Sorry, the example links posted above only go as far as 1080p. The relevant fields should appear if you try, e.g., a 4K video given a 1080p-subbed user.


Consider meta to look something like so:

// Related types referenced by metadata.
// ═══════════════════════════════════════════════════════

enum DeliveryResourceAccessDenialReason {
    /**
     * Indicates that the requester is lacking a required plan or other form of permission
     * entitling on to access the corresponding resource.
     */
    IsMissingPermission = 'isMissingPermission',
    /**
     * Indicates that the corresponding resource is processing. Clients may choose to
     * periodically refetch an asset's info when it has reported this state.
     */
    IsProcessing = 'isProcessing',
    /**
     * Indicates that the corresponding resource is defective in some manner which has
     * rendered it currently inaccessible. It is possible that the asset will be repaired
     * at some later point in time. Clients may choose to periodically refetch an asset's
     * info when it has reported this state.
     */
    IsBroken = 'isBroken',
}

enum DeliveryResourceLowLatencyLiveExtension {
    /**
     * 🍎-backed low-latency HLS extension.
     */
    LLHls = 'llhls',
    /**
     * Community-backed low-latency HLS extension.
     */
    CLHls = 'clhls',
    /**
     * IVS custom low-latency HLS extension.
     */
    IvsHls = 'ivshls',
    /**
     * DASH-IF-backed low-Latency DASH extension.
     */
    LLDash = 'lldash',
}

// Common characteristics shared by metadata components.
// ═══════════════════════════════════════════════════════

interface MediaBitrateInfo {
    /**
     * Maximum bitrate observed for the data stream.
     */
    maximum: number;
    /**
     * Average bitrate observed for the data stream.
     */
    average: number;
}

interface MediaIdentityCharacteristics {
    /**
     * RFC 6381 codec string indicating stream data chunk format.
     */
    codec?: string;
    /**
     * RFC 6381 codec string indicating stream format on the most basic level, without the
     * addition of profile/level/etc. information.
     */
    codecSimple?: string;
    /**
     * MIME-type for individual stream data chunks (as opposed to a containing playlist).
     */
    mimeType?: string;
}

interface ImagePresentationCharacteristics {
    /**
     * Count of horizontal pixels presented.
     */
    width?: number;
    /**
     * Count of vertical pixels presented.
     */
    height?: number;
    /**
     * Whether or not this data stream carries HDR content.
     */
    isHdr?: boolean;
}

// Components of metadata.
// ═══════════════════════════════════════════════════════

/**
 * Basic information which generally applies to most resource types.
 */
interface MetadataCommonInfo {
    /**
     *  Size of the corresponding media file, measured in bytes.
     */
    size?: number;
    /**
     * Contains clarifying information regarding resource access rules.
     * 
     * This is often (but not always) set when a variant is not enabled.
     */
    access?: {
        /**
         * Indicator describing the reason access has been witheld for a resource.
         */
        deniedReason?: DeliveryResourceAccessDenialReason;
        /**
         * Message describing in human-readable terms why access has been witheld for a
         * resource.
         */
        deniedMessage?: string;
    }
}

/**
 * Metadata specific to still-image streams carried by resources. This generally applies
 * only to pure picture content but may see use for embedded thumbnails/etc. in video/audio
 * files.
 */
type MetadataImageInfo = MediaIdentityCharacteristics & ImagePresentationCharacteristics;

/**
 * Metadata specific to audio streams carried by resources.
 */
interface MetadataAudioInfo extends MediaIdentityCharacteristics {
    /**
     * Count of channels carried by the audio stream.
     */
    channelCount?: number;
    /**
     * Count of samples recorded per second.
     */
    samplerate?: number;
    /**
     * Bitrate information for the carried media data stream.
     * @todo (this is partial only temporarily; average bitrate isn't held for all media)
     */
    bitrate?: Partial<MediaBitrateInfo>;
}

/**
 * Metadata specific to video streams carried by resources.
 */
interface MetadataVideoInfo extends MediaIdentityCharacteristics, ImagePresentationCharacteristics {
    /**
     * Maximum count of frames presented per second for the video.
     */
    fps?: number;
    /**
     * Bitrate information for the carried media data stream.
     * @todo (this is partial only temporarily; average bitrate isn't held for all media)
     */
    bitrate?: Partial<MediaBitrateInfo>;
}

/**
 * Metadata specific to livestream resources.
 */
interface MetadataLiveInfo {
    /**
     * Indicates the low-latency extension, if any, which the resource leverages.
     */
    lowLatencyExtension?: DeliveryResourceLowLatencyLiveExtension;
}

// Combined resource metadata as served.
// ═══════════════════════════════════════════════════════

interface DeliveryResourceMetadata {
    common?: MetadataCommonInfo;
    video?: MetadataVideoInfo;
    audio?: MetadataAudioInfo;
    image?: MetadataImageInfo;
    live?: MetadataLiveInfo;
}
Jman012 commented 2 years ago

Thank you so much for the TS types! That helped create a full meta object. I've implemented this in the unofficial API spec at https://github.com/Jman012/FloatplaneAPI/commit/f8aba6842526e7aee6ec986da1769975b2c24bac. I'll integrate this into Wasserflug soon to make sure it works well.

Jman012 commented 2 years ago

Using the new Delivery API will be included in 1.3.0-1.