mirror of https://github.com/FreeTubeApp/FreeTube
Add support for viewing movie trailers with local api (#4391)
* Add support for viewing movie trailers with local api * add support for age restricted trailers * remove unused changes * always show trailer, regardless of video playability status * Improve movie parsing logic Co-authored-by: absidue <48293849+absidue@users.noreply.github.com> * check for null instead of truthy * Exclude unneeded properties Co-authored-by: absidue <48293849+absidue@users.noreply.github.com> --------- Co-authored-by: absidue <48293849+absidue@users.noreply.github.com>
This commit is contained in:
parent
057c9d7729
commit
c983e02011
|
@ -126,7 +126,10 @@
|
|||
>
|
||||
<span>{{ channelName }}</span>
|
||||
</router-link>
|
||||
<template v-if="!isLive && !isUpcoming && !isPremium && !hideViews">
|
||||
<span v-else-if="channelName !== null">
|
||||
{{ channelName }}
|
||||
</span>
|
||||
<template v-if="!isLive && !isUpcoming && !isPremium && !hideViews && viewCount != null">
|
||||
<span class="viewCount">
|
||||
<template v-if="channelId !== null"> • </template>
|
||||
{{ $tc('Global.Counts.View Count', viewCount, {count: parsedViewCount}) }}
|
||||
|
|
|
@ -457,7 +457,7 @@ function handleSearchResponse(response) {
|
|||
|
||||
const results = response.results
|
||||
.filter((item) => {
|
||||
return item.type === 'Video' || item.type === 'Channel' || item.type === 'Playlist' || item.type === 'HashtagTile'
|
||||
return item.type === 'Video' || item.type === 'Channel' || item.type === 'Playlist' || item.type === 'HashtagTile' || item.type === 'Movie'
|
||||
})
|
||||
.map((item) => parseListItem(item))
|
||||
|
||||
|
@ -537,22 +537,41 @@ export function parseLocalPlaylistVideo(video) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {import('youtubei.js').YTNodes.Video} video
|
||||
* @param {import('youtubei.js').YTNodes.Video | import('youtubei.js').YTNodes.Movie} item
|
||||
*/
|
||||
export function parseLocalListVideo(video) {
|
||||
return {
|
||||
type: 'video',
|
||||
videoId: video.id,
|
||||
title: video.title.text,
|
||||
author: video.author.name,
|
||||
authorId: video.author.id,
|
||||
description: video.description,
|
||||
viewCount: extractNumberFromString(video.view_count.text),
|
||||
publishedText: video.published.isEmpty() ? null : video.published.text,
|
||||
lengthSeconds: isNaN(video.duration.seconds) ? '' : video.duration.seconds,
|
||||
liveNow: video.is_live,
|
||||
isUpcoming: video.is_upcoming || video.is_premiere,
|
||||
premiereDate: video.upcoming
|
||||
export function parseLocalListVideo(item) {
|
||||
if (item.type === 'Movie') {
|
||||
/** @type {import('youtubei.js').YTNodes.Movie} */
|
||||
const movie = item
|
||||
|
||||
return {
|
||||
type: 'video',
|
||||
videoId: movie.id,
|
||||
title: movie.title.text,
|
||||
author: movie.author.name,
|
||||
authorId: movie.author.id !== 'N/A' ? movie.author.id : null,
|
||||
description: movie.description_snippet?.text,
|
||||
lengthSeconds: isNaN(movie.duration.seconds) ? '' : movie.duration.seconds,
|
||||
liveNow: false,
|
||||
isUpcoming: false,
|
||||
}
|
||||
} else {
|
||||
/** @type {import('youtubei.js').YTNodes.Video} */
|
||||
const video = item
|
||||
return {
|
||||
type: 'video',
|
||||
videoId: video.id,
|
||||
title: video.title.text,
|
||||
author: video.author.name,
|
||||
authorId: video.author.id,
|
||||
description: video.description,
|
||||
viewCount: video.view_count == null ? null : extractNumberFromString(video.view_count.text),
|
||||
publishedText: (video.published == null || video.published.isEmpty()) ? null : video.published.text,
|
||||
lengthSeconds: isNaN(video.duration.seconds) ? '' : video.duration.seconds,
|
||||
liveNow: video.is_live,
|
||||
isUpcoming: video.is_upcoming || video.is_premiere,
|
||||
premiereDate: video.upcoming
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,6 +580,7 @@ export function parseLocalListVideo(video) {
|
|||
*/
|
||||
function parseListItem(item) {
|
||||
switch (item.type) {
|
||||
case 'Movie':
|
||||
case 'Video':
|
||||
return parseLocalListVideo(item)
|
||||
case 'Channel': {
|
||||
|
@ -627,8 +647,8 @@ export function parseLocalWatchNextVideo(video) {
|
|||
title: video.title.text,
|
||||
author: video.author.name,
|
||||
authorId: video.author.id,
|
||||
viewCount: extractNumberFromString(video.view_count.text),
|
||||
publishedText: video.published.isEmpty() ? null : video.published.text,
|
||||
viewCount: video.view_count == null ? null : extractNumberFromString(video.view_count.text),
|
||||
publishedText: (video.published == null || video.published.isEmpty()) ? null : video.published.text,
|
||||
lengthSeconds: isNaN(video.duration.seconds) ? '' : video.duration.seconds,
|
||||
liveNow: video.is_live,
|
||||
isUpcoming: video.is_premiere
|
||||
|
|
|
@ -318,7 +318,7 @@ export default defineComponent({
|
|||
this.isFamilyFriendly = result.basic_info.is_family_safe
|
||||
|
||||
const recommendedVideos = result.watch_next_feed
|
||||
?.filter((item) => item.type === 'CompactVideo')
|
||||
?.filter((item) => item.type === 'CompactVideo' || item.type === 'CompactMovie')
|
||||
.map(parseLocalWatchNextVideo) ?? []
|
||||
|
||||
// place watched recommended videos last
|
||||
|
@ -335,10 +335,28 @@ export default defineComponent({
|
|||
|
||||
let playabilityStatus = result.playability_status
|
||||
let bypassedResult = null
|
||||
if (playabilityStatus.status === 'LOGIN_REQUIRED') {
|
||||
let streamingVideoId = this.videoId
|
||||
let trailerIsNull = false
|
||||
|
||||
// if widevine support is added then we should check if playabilityStatus.status is UNPLAYABLE too
|
||||
if (result.has_trailer) {
|
||||
bypassedResult = result.getTrailerInfo()
|
||||
/**
|
||||
* @type {import ('youtubei.js').YTNodes.PlayerLegacyDesktopYpcTrailer}
|
||||
*/
|
||||
const trailerScreen = result.playability_status.error_screen
|
||||
streamingVideoId = trailerScreen.video_id
|
||||
// if the trailer is null then it is likely age restricted.
|
||||
trailerIsNull = bypassedResult == null
|
||||
if (!trailerIsNull) {
|
||||
playabilityStatus = bypassedResult.playability_status
|
||||
}
|
||||
}
|
||||
|
||||
if (playabilityStatus.status === 'LOGIN_REQUIRED' || trailerIsNull) {
|
||||
// try to bypass the age restriction
|
||||
bypassedResult = await getLocalVideoInfo(this.videoId, true)
|
||||
playabilityStatus = result.playability_status
|
||||
bypassedResult = await getLocalVideoInfo(streamingVideoId, true)
|
||||
playabilityStatus = bypassedResult.playability_status
|
||||
}
|
||||
|
||||
if (playabilityStatus.status === 'UNPLAYABLE') {
|
||||
|
|
Loading…
Reference in New Issue