According to Google's YouTube v3 API reference documentation for the properties of a video resource, there is a JSON object called liveStreamingDetails which should have the following fields:
actualStartTimeactualEndTimescheduledStartTimescheduledEndTimeconcurrentViewersactiveLiveChatId
I have prepared my objects based on this structure, but I'm getting the following exceptions thrown when I try to deserialize actual JSON snippet responses from the API for videos:
JsonSerializationException: Error converting value "none" to type 'A1ITF.API+YouTube+LiveStreamDetails'. Path 'items[0].snippet.liveBroadcastContent', line 46, position 38.ArgumentException: Could not cast or convert from System.String to A1ITF.API+YouTube+LiveStreamDetails.
Looking at the JSON response from the API, I completely understand the error. Here's the JSON response I'm getting (redacted for the sake of brevity):
{
"kind": "youtube#videoListResponse",
"etag": "MR2hZ6pif1LwlWdiOvdZ_4m7vDI",
"items": [
{
"kind": "youtube#video",
"etag": "hfbATXrQ1iQB2yrckDCv-dn0iiI",
"id": "skSK9lUvqjY",
"snippet": {
"publishedAt": "2020-08-14T19:00:15Z",
"channelId": "UCZGYJFUizSax-yElQaFDp5Q",
"title": "Leia, Princess of Alderaan | The Star Wars Show Book Club",
"description": <LONG DESCRIPTION TEXT>,
"thumbnails": {<THUMBNAIL OBJECTS>},
"channelTitle": "Star Wars",
"tags": [<SEVERAL TAGS>],
"categoryId": "24",
"liveBroadcastContent": "none",
"localized": {
"title": "Leia, Princess of Alderaan | The Star Wars Show Book Club",
"description": <LONG DESCRIPTION TEXT>
},
"defaultAudioLanguage": "en-US"
}
}
],
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
}
}
The reason for the exception is clear: the value for the liveBroadcastContent field is a single string ("none"). It is NOT the object as defined in the documentation above. Based on the documentation, what I'm expecting
"liveBroadcastContent":
{
"actualStartTime": <ISO 8601 datetime VALUE>,
"actualEndTime": <ISO 8601 datetime VALUE>,
"scheduledStartTime": <ISO 8601 datetime VALUE>,
"scheduledEndTime": <ISO 8601 datetime VALUE>,
"concurrentViewers": <unsigned long VALUE>,
"activeLiveChatId": <string VALUE>
},
or, if there isn't any information to populate the liveBroadcastContent fields
"liveBroadcastContent":
{
"actualStartTime": null,
"actualEndTime": null,
"scheduledStartTime": null,
"scheduledEndTime": null,
"concurrentViewers": null,
"activeLiveChatId": ""
},
or even
"liveBroadcastContent": {},
or just omitting that property entirely doesn't match what I'm actually receiving
"liveBroadcastContent": "none",
I've actually been struggling to find an effective way to conditionally deserialize this element for a bit now, but can't seem to get it to simply return Nothing for what the API is returning (that's another question for another time, but I'm still researching ways to hopefully accomplish that).
My initial test was for a "regular" video, though (not an actual live stream), so I figured I'd check a known live stream video. I went into my YouTube notifications and found a couple of professional/semi-pro YouTube channels that had recent live streams and picked one to test. However, the JSON for this video was also missing a structured liveStreamingDetails object (only a value of "none"). Thinking this might be a "fluke", I checked a few other videos that were designated in my YouTube notifications as being live streams and all of them showed the exact same results.
If I change the definition of this field in my object to a simple String, everything deserializes without exception and I get a (mostly) fully populated object. However, I'd actually like to have some of this information available for my application - at least to know whether or not a video is/was a live broadcast - but "none" obviously isn't going to tell me much. So, while I work on a way to make my object correctly and conditionally deserialize this field's value (I came up with some ideas while typing this), I'm wondering if anyone knows whether or not this field is actually even implemented? Am I basically spinning my wheels trying to make something work that's already been deprecated, is this something intended as being implemented in the future, or am I just being totally dense and missing something obvious (a definite and distinct possibility)?
EDIT (RESOLVED BY ACCEPTED ANSWER)
Based on the accepted answer, I was being totally dense. I had mistakenly guessed that the liveBroadcastContent field (in the snippet object) was the same as the liveStreamingDetails object (a part of the items collection). If I had thoroughly and accurately read the documentation, I would have seen that the former is defined as (emphasis mine):
stringIndicates if the video is an upcoming/active live broadcast. Or it's "none" if the video is not an upcoming/active live broadcast.
Valid values for this property are:
livenoneupcoming
(The reason this was showing as "none" in all of my tests is that the live broadcasts had already ended)
The latter is defined as (included in the accepted answer):
objectThe
liveStreamingDetailsobject contains metadata about a live video broadcast. The object will only be present in avideoresource if the video is an upcoming, live, or completed live broadcast.
Additionally, my API request was flawed. While I was calling the correct endpoint, I wasn't actually requesting the information needed to populate the liveStreamingDetails object. I was only requesting part=snippet when I should have been requesting part=snippet,liveStreamingDetails.
EXAMPLE API REQUEST: Prepared (not live) video
https://www.googleapis.com/youtube/v3/videos?id=skSK9lUvqjY&part=snippet,liveStreamingDetails&key={API_KEY}
RETURNS (redacted for the sake of brevity)
{
"kind": "youtube#videoListResponse",
"etag": "MR2hZ6pif1LwlWdiOvdZ_4m7vDI",
"items": [
{
"kind": "youtube#video",
"etag": "hfbATXrQ1iQB2yrckDCv-dn0iiI",
"id": "skSK9lUvqjY",
"snippet": {
"publishedAt": "2020-08-14T19:00:15Z",
"channelId": "UCZGYJFUizSax-yElQaFDp5Q",
"title": "Leia, Princess of Alderaan | The Star Wars Show Book Club",
"description": <LONG DESCRIPTION TEXT>,
"thumbnails": {<THUMBNAIL OBJECTS>},
"channelTitle": "Star Wars",
"tags": [<TAGS>],
"categoryId": "24",
"liveBroadcastContent": "none",
"localized": {
"title": "Leia, Princess of Alderaan | The Star Wars Show Book Club",
"description": <LONG DESCRIPTION TEXT>
},
"defaultAudioLanguage": "en-US"
}
}
],
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
}
}
EXAMPLE API REQUEST: Live Stream Broadcast
https://www.googleapis.com/youtube/v3/videos?id=RX4vy_M-NS8&part=snippet,liveStreamingDetails&key={API_KEY}
RETURNS (redacted for the sake of brevity)
{
"kind": "youtube#videoListResponse",
"etag": "Aq44bdQmbZxoLEp0SOJh4xW0PSE",
"items": [
{
"kind": "youtube#video",
"etag": "9TVc3oB01vQME2QsvEJcaRueEqc",
"id": "RX4vy_M-NS8",
"snippet": {
"publishedAt": "2020-08-20T18:50:20Z",
"channelId": "UCRTQL0CmZjHlvPy5nLZ1Gfg",
"title": "Starting a new character in Star Wars: The Old Republic [Live Stream Recorded on August 20, 2020]",
"description": <LONG DESCRIPTION TEXT>,
"thumbnails": {<THUMBNAIL OBJECTS>},
"channelTitle": "HelloGreedo",
"tags": [<TAGS>],
"categoryId": "1",
"liveBroadcastContent": "none",
"localized": {
"title": "Starting a new character in Star Wars: The Old Republic [Live Stream Recorded on August 20, 2020]",
"description": <LONG DESCRIPTION TEXT>
}
},
"liveStreamingDetails": {
"actualStartTime": "2020-08-20T17:04:45Z",
"actualEndTime": "2020-08-20T18:41:23Z"
}
}
],
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
}
}
After correcting my API request and adding the appropriate property to my prepared object in code, everything I wanted is coming through exactly as expected/desired.