Skip to content

Commit

Permalink
Merge pull request #701 from podverse/develop
Browse files Browse the repository at this point in the history
Release v4.15.6
  • Loading branch information
mitchdowney committed Nov 18, 2023
2 parents b15af5e + 6e45e6e commit b89eca7
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 37 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "podverse-api",
"version": "4.15.5",
"version": "4.15.6",
"description": "Data API, database migration scripts, and backend services for all Podverse models.",
"contributors": [
"Mitch Downey"
Expand Down
80 changes: 48 additions & 32 deletions src/controllers/playlist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { validateClassOrThrow } from '~/lib/errors'
import { getUserSubscribedPlaylistIds } from './user'
import { getMediaRef } from './mediaRef'
import { getEpisode } from './episode'
import { combineAndSortPlaylistItems } from 'podverse-shared'
const createError = require('http-errors')

// medium = podcast are always be put in the general "mixed" category for playlists
Expand Down Expand Up @@ -250,57 +251,72 @@ const addOrRemovePlaylistItem = async (playlistId, mediaRefId, episodeId, logged
throw new createError.Unauthorized('Log in to delete this playlist')
}

const itemsOrder = playlist.itemsOrder
let actionTaken = 'removed'
const { episodes, itemsOrder: previousItemsOrder, mediaRefs } = playlist

/*
Prior to 4.15.6, the itemsOrder property was not getting set properly.
As a result the itemsOrder may have fallen out-of-sync with the saved
episodes and mediaRefs. Whenever the itemsOrder.length does not match
the combinedItems length, then fully update the itemsOrder.
*/

let newItemsOrder = previousItemsOrder
const combinedItemsTotal = episodes.length + mediaRefs.length
if (combinedItemsTotal !== previousItemsOrder.length) {
const combinedAndSortedItems = combineAndSortPlaylistItems(
episodes as any,
mediaRefs as any,
previousItemsOrder as any
)
newItemsOrder = combinedAndSortedItems.map((item: any) => item.id)
}

if (mediaRefId) {
// If no mediaRefs match filter, add the playlist item.
// Else, remove the playlist item.
const filteredMediaRefs = playlist.mediaRefs.filter((x) => x.id !== mediaRefId)
let actionTaken = ''

if (filteredMediaRefs.length === playlist.mediaRefs.length) {
if (mediaRefId) {
// If no mediaRefs match filter, add the playlist item. Else, remove the playlist item.
const filteredMediaRefs = mediaRefs.filter((x) => x.id !== mediaRefId)
const mediaRefWasRemoved = filteredMediaRefs.length === mediaRefs.length
if (mediaRefWasRemoved) {
actionTaken = 'removed'
playlist.mediaRefs = filteredMediaRefs
playlist.itemsOrder = newItemsOrder.filter((x) => x !== mediaRefId)
} else {
const mediaRef = await getMediaRef(mediaRefId)

if (mediaRef) {
if (!mediaRef) {
throw new createError.NotFound('MediaRef not found')
} else {
actionTaken = 'added'
const filteredMedium = getPlaylistMedium(mediaRef.episode.podcast.medium)
if (playlist.medium !== 'mixed' && playlist.medium !== filteredMedium) {
throw new createError.NotFound('Item can not be added to this type of playlist')
}

playlist.mediaRefs.push(mediaRef)
actionTaken = 'added'
} else {
throw new createError.NotFound('MediaRef not found')
playlist.itemsOrder.push(mediaRef.id)
}
} else {
playlist.mediaRefs = filteredMediaRefs
}

playlist.itemsOrder = itemsOrder.filter((x) => x !== mediaRefId)
} else if (episodeId) {
// If no episodes match filter, add the playlist item.
// Else, remove the playlist item.
const filteredEpisodes = playlist.episodes.filter((x) => x.id !== episodeId)

if (filteredEpisodes.length === playlist.episodes.length) {
// If no episodes match filter, add the playlist item. Else, remove the playlist item.
const filteredEpisodes = episodes.filter((x) => x.id !== episodeId)
const episodeWasRemoved = filteredEpisodes.length === episodes.length
if (episodeWasRemoved) {
actionTaken = 'removed'
playlist.episodes = filteredEpisodes
playlist.itemsOrder = newItemsOrder.filter((x) => x !== episodeId)
} else {
const episode = await getEpisode(episodeId)

if (episode) {
if (!episode) {
throw new createError.NotFound('Episode not found')
} else {
actionTaken = 'added'
const filteredMedium = getPlaylistMedium(episode.podcast.medium)
if (playlist.medium !== 'mixed' && playlist.medium !== filteredMedium) {
throw new createError.NotFound('Item can not be added to this type of playlist')
}

playlist.episodes.push(episode)
actionTaken = 'added'
} else {
throw new createError.NotFound('Episode not found')
playlist.itemsOrder.push(episode.id)
}
} else {
playlist.episodes = filteredEpisodes
}

playlist.itemsOrder = itemsOrder.filter((x) => x !== episodeId)
} else {
throw new createError.NotFound('Must provide a MediaRef or Episode id')
}
Expand Down
49 changes: 47 additions & 2 deletions src/controllers/secondaryQueue.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { LessThan, MoreThan, getRepository } from 'typeorm'
import { Episode, Podcast } from '~/entities'
import { getPlaylist } from './playlist'
import { combineAndSortPlaylistItems } from 'podverse-shared'
const createError = require('http-errors')

const relations = ['liveItem', 'podcast']

type SecondaryQueueResponseData = {
type SecondaryQueueEpisodesForPodcastIdResponseData = {
previousEpisodes: Episode[]
nextEpisodes: Episode[]
inheritedPodcast: Podcast
Expand All @@ -13,7 +15,7 @@ type SecondaryQueueResponseData = {
export const getSecondaryQueueEpisodesForPodcastId = async (
episodeId: string,
podcastId: string
): Promise<SecondaryQueueResponseData> => {
): Promise<SecondaryQueueEpisodesForPodcastIdResponseData> => {
const repository = getRepository(Episode)
const currentEpisode = await repository.findOne(
{
Expand Down Expand Up @@ -72,3 +74,46 @@ export const getSecondaryQueueEpisodesForPodcastId = async (

return { previousEpisodes, nextEpisodes, inheritedPodcast }
}

type SecondaryQueueEpisodesForPlaylistIdResponseData = {
previousEpisodesAndMediaRefs: Episode[]
nextEpisodesAndMediaRefs: Episode[]
}

export const getSecondaryQueueEpisodesForPlaylist = async (
playlistId: string,
episodeOrMediaRefId: string,
audioOnly: boolean
): Promise<SecondaryQueueEpisodesForPlaylistIdResponseData> => {
const currentPlaylist = await getPlaylist(playlistId)

if (!currentPlaylist) {
throw new createError.NotFound('Playlist not found')
}

const { episodes, itemsOrder, mediaRefs } = currentPlaylist

const combinedPlaylistItems = combineAndSortPlaylistItems(episodes as any, mediaRefs as any, itemsOrder as any)
let filteredPlaylistItems = combinedPlaylistItems
if (audioOnly) {
filteredPlaylistItems = filteredPlaylistItems.filter((item: any) => {
if (item?.startTime) {
const mediaRef = item
return !mediaRef?.episode?.podcast?.hasVideo
} else {
const episode = item
return !episode?.podcast?.hasVideo
}
})
}

const currentItemIndex = filteredPlaylistItems.findIndex((item: any) => {
return item.id === episodeOrMediaRefId
})

// limit to the nearest 50 ids
const previousEpisodesAndMediaRefs = filteredPlaylistItems.slice(currentItemIndex - 50, currentItemIndex)
const nextEpisodesAndMediaRefs = filteredPlaylistItems.slice(currentItemIndex + 1, currentItemIndex + 1 + 50)

return { previousEpisodesAndMediaRefs, nextEpisodesAndMediaRefs }
}
32 changes: 30 additions & 2 deletions src/routes/secondaryQueue.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import * as Router from 'koa-router'
import { config } from '~/config'
import { getSecondaryQueueEpisodesForPodcastId } from '~/controllers/secondaryQueue'
import {
getSecondaryQueueEpisodesForPodcastId,
getSecondaryQueueEpisodesForPlaylist
} from '~/controllers/secondaryQueue'
import { emitRouterError } from '~/lib/errors'
import { parseNSFWHeader } from '~/middleware/parseNSFWHeader'

const router = new Router({ prefix: `${config.apiPrefix}${config.apiVersion}/secondary-queue` })

// Get episodes that are adjacent to a podcast
/* TODO: REMOVE THIS AFTER NEXT BETA RELEASE */
// Get episodes that are adjacent within a podcast
router.get('/episode/:episodeId/podcast/:podcastId', parseNSFWHeader, async (ctx) => {
try {
const data = await getSecondaryQueueEpisodesForPodcastId(ctx.params.episodeId, ctx.params.podcastId)
Expand All @@ -16,4 +20,28 @@ router.get('/episode/:episodeId/podcast/:podcastId', parseNSFWHeader, async (ctx
}
})

// Get episodes that are adjacent within a podcast
router.get('/podcast/:podcastId/episode/:episodeId', parseNSFWHeader, async (ctx) => {
try {
const data = await getSecondaryQueueEpisodesForPodcastId(ctx.params.episodeId, ctx.params.podcastId)
ctx.body = data
} catch (error) {
emitRouterError(error, ctx)
}
})

// Get episodes that are adjacent within a playlist
router.get('/playlist/:playlistId/episode-or-media-ref/:episodeOrMediaRef', parseNSFWHeader, async (ctx) => {
try {
const data = await getSecondaryQueueEpisodesForPlaylist(
ctx.params.playlistId,
ctx.params.episodeOrMediaRef,
!!ctx.query.audioOnly
)
ctx.body = data
} catch (error) {
emitRouterError(error, ctx)
}
})

export const secondaryQueueRouter = router

0 comments on commit b89eca7

Please sign in to comment.