Skip to content

Commit

Permalink
Create a My List Playlist
Browse files Browse the repository at this point in the history
  • Loading branch information
1hitsong committed Dec 21, 2024
1 parent f73b335 commit 1f25c41
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 7 deletions.
8 changes: 8 additions & 0 deletions components/Libraries/VisualLibraryScene.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1473,6 +1473,14 @@ function onKeyEvent(key as string, press as boolean) as boolean
return true
end if

if isStringEqual(key, KeyCode.OPTIONS)
focusedItem = getItemFocused()
if not isValid(focusedItem) then return false

resumeData = [tr("Add To My List")]
m.global.sceneManager.callFunc("optionDialog", "libraryitem", tr("Options"), [], resumeData, focusedItem.LookupCI("id"))
end if

return false
end function

Expand Down
8 changes: 7 additions & 1 deletion components/data/SceneManager.bs
Original file line number Diff line number Diff line change
Expand Up @@ -350,12 +350,14 @@ end sub

'
' Display dialog to user with an OK button
sub optionDialog(title, message, buttons)
sub optionDialog(id, title, message, buttons, itemID)
m.itemID = itemID
m.top.dataReturned = false
m.top.returnData = invalid
m.userselection = false

dialog = createObject("roSGNode", "StandardMessageDialog")
dialog.id = id
dlgPalette = createObject("roSGNode", "RSGPalette")
dlgPalette.colors = {
DialogBackgroundColor: ColorPalette.ELEMENTBACKGROUND,
Expand All @@ -381,6 +383,8 @@ sub optionClosed()
if m.userselection then return

m.top.returnData = {
id: m.scene.dialog.id,
itemID: m.itemID,
indexSelected: -1,
buttonSelected: ""
}
Expand All @@ -392,6 +396,8 @@ end sub
sub optionSelected()
m.userselection = true
m.top.returnData = {
id: m.scene.dialog.id,
itemID: m.itemID,
indexSelected: m.scene.dialog.buttonSelected,
buttonSelected: m.scene.dialog.buttons[m.scene.dialog.buttonSelected]
}
Expand Down
63 changes: 62 additions & 1 deletion components/home/HomeRows.bs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ sub init()

m.LoadFavoritesTask = createObject("roSGNode", "LoadItemsTask")
m.LoadFavoritesTask.itemsToLoad = "favorites"

m.LoadMyListTask = createObject("roSGNode", "LoadItemsTask")
m.LoadMyListTask.itemsToLoad = "mylist"
end sub

sub loadLibraries()
Expand Down Expand Up @@ -123,7 +126,8 @@ sub processUserSections()
end if
end for

' Favorites isn't an option in Web settings, so we manually add it to the end for now
' Favorites and my list aren't an option in Web settings, so we manually add them to the end for now
addHomeSection("mylist")
addHomeSection("favorites")

' Start the timer for creating the content rows before we set the cursor size
Expand Down Expand Up @@ -274,6 +278,12 @@ function addHomeSection(sectionType as string) as boolean
return true
end if

' My List Items
if sectionType = "mylist"
createMyListRow()
return true
end if

' This section type isn't supported.
' Count it as processed since we aren't going to do anything else with it
m.processedRowCount++
Expand Down Expand Up @@ -470,6 +480,14 @@ sub createNextUpRow()
m.LoadNextUpTask.control = "RUN"
end sub

' createMyListRow: Creates a row displaying items from the user's personal list
'
sub createMyListRow()
' Load the My List Data
m.LoadMyListTask.observeField("content", "updateMyListItems")
m.LoadMyListTask.control = "RUN"
end sub

' createFavoritesRow: Creates a row displaying items from the user's favorites list
'
sub createFavoritesRow()
Expand Down Expand Up @@ -529,6 +547,49 @@ sub updateFavoritesItems()
setRowItemSize()
end sub

' updateMyListItems: Processes LoadMyListTask content. Removes, Creates, or Updates My List row as needed
'
sub updateMyListItems()
m.processedRowCount++
itemData = m.LoadMyListTask.content
m.LoadMyListTask.unobserveField("content")
m.LoadMyListTask.content = []

sectionName = tr("My List")

if not isValidAndNotEmpty(itemData)
removeHomeSection(sectionName)
return
end if

' remake row using the new data
row = CreateObject("roSGNode", "HomeRow")
row.title = sectionName
row.imageWidth = homeRowItemSizes.WIDE_POSTER[0]
row.cursorSize = homeRowItemSizes.WIDE_POSTER

for each item in itemData
usePoster = true

if lcase(item.type) = "episode" or lcase(item.type) = "audio" or lcase(item.type) = "musicartist"
usePoster = false
end if

item.usePoster = usePoster
item.imageWidth = row.imageWidth
row.appendChild(item)
end for

if sectionExists(sectionName)
m.top.content.replaceChild(row, getSectionIndex(sectionName))
setRowItemSize()
return
end if

m.top.content.insertChild(row, getSectionIndex(sectionName))
setRowItemSize()
end sub

' updateContinueWatchingItems: Processes LoadContinueWatchingTask content. Removes, Creates, or Updates continue watching row as needed
'
sub updateContinueWatchingItems()
Expand Down
81 changes: 81 additions & 0 deletions components/home/LoadItemsTask.bs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,82 @@ function loadFavorites() as object
return results
end function

function loadMyList() as object
results = []

data = api.GetUserViews({ "userId": m.global.session.user.id })
if not isChainValid(data, "Items") then return results

myListPlaylist = invalid

for each item in data.LookupCI("items")
if isStringEqual(item.LookupCI("CollectionType"), "playlists")
myListPlaylist = api.items.Get({
"userid": m.global.session.user.id,
"includeItemTypes": "Playlist",
"nameStartsWith": "[ROKU] My List",
"parentId": item.LookupCI("id")
})
exit for
end if
end for

if not isValid(myListPlaylist) or not isValidAndNotEmpty(myListPlaylist.items) then return results

playlistID = myListPlaylist.items[0].LookupCI("id")

if not isValid(playlistID) then return results

myListData = api.items.Get({
UserId: m.global.session.user.id,
ImageTypeLimit: 1,
EnableImageTypes: `${ImageType.PRIMARY}, ${ImageType.BACKDROP}, ${ImageType.THUMB}`,
Limit: 50,
EnableTotalRecordCount: false,
ParentId: playlistID
})

if not isChainValid(myListData, "Items") then return results

for each item in myListData.Items
if inArray([ItemType.BOOK, ItemType.AUDIO], item.type) then continue for

tmp = CreateObject("roSGNode", "HomeData")

params = {
Tags: item.PrimaryImageTag,
MaxWidth: 234,
MaxHeight: 330
}
tmp.posterURL = ImageUrl(item.Id, "Primary", params)
tmp.json = {
Id: item.LookupCI("Id"),
name: item.LookupCI("name"),
Type: item.LookupCI("Type"),
SeriesName: item.LookupCI("SeriesName"),
ProductionYear: item.LookupCI("ProductionYear"),
Status: item.LookupCI("Status"),
EndDate: item.LookupCI("EndDate"),
ParentIndexNumber: item.LookupCI("ParentIndexNumber"),
IndexNumberEnd: item.LookupCI("IndexNumberEnd"),
IndexNumber: item.LookupCI("IndexNumber"),
OfficialRating: item.LookupCI("OfficialRating"),
CollectionType: item.LookupCI("CollectionType"),
ImageTags: item.LookupCI("ImageTags"),
UserData: item.LookupCI("UserData"),
ParentThumbItemId: item.LookupCI("ParentThumbItemId"),
ParentThumbImageTag: item.LookupCI("ParentThumbImageTag"),
ParentBackdropImageTags: item.LookupCI("ParentBackdropImageTags"),
ParentBackdropItemId: item.LookupCI("ParentBackdropItemId"),
SeriesPrimaryImageTag: item.LookupCI("SeriesPrimaryImageTag"),
BackdropImageTags: item.LookupCI("BackdropImageTags")
}
results.push(tmp)
end for

return results
end function

function loadItemsByPerson(videoType, dimens = {}) as object
results = []

Expand Down Expand Up @@ -564,6 +640,11 @@ sub loadItems()
return
end if

if isStringEqual(m.top.itemsToLoad, "mylist")
m.top.content = loadMyList()
return
end if

if isStringEqual(m.top.itemsToLoad, "backdropImage")
m.top.content = [BackdropImage(m.top.itemId)]
return
Expand Down
69 changes: 65 additions & 4 deletions source/MainEventHandlers.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,13 +1238,28 @@ sub onDataReturnedEvent(msg)

if not isChainValid(popupNode, "returnData") then return

selectedItem = m.global.queueManager.callFunc("getHold")
m.global.queueManager.callFunc("clearHold")
selectedPopupID = chainLookup(popupNode, "returndata.id")
itemID = chainLookup(popupNode, "returndata.itemID")
selectedPopupAction = chainLookup(popupNode, "returndata.indexselected")

if not isValidAndNotEmpty(selectedItem) or not isValid(selectedItem[0]) then return
if isStringEqual(selectedPopupID, "playback")
selectedItem = m.global.queueManager.callFunc("getHold")
m.global.queueManager.callFunc("clearHold")

selectedPopupAction = chainLookup(popupNode, "returndata.indexselected")
if not isValidAndNotEmpty(selectedItem) or not isValid(selectedItem[0]) then return

processPlaybackPopup(selectedPopupAction, selectedItem)
return
end if

if isStringEqual(selectedPopupID, "libraryitem")
if not isValid(itemID) then return
processLibraryItemPopup(selectedPopupAction, itemID)
return
end if
end sub

sub processPlaybackPopup(selectedPopupAction as integer, selectedItem as object)
'Resume video from resume point
if selectedPopupAction = ResumePopupAction.RESUME
selectedItem[0].startingPoint = chainLookup(selectedItem[0], "json.UserData.PlaybackPositionTicks") ?? 0
Expand Down Expand Up @@ -1285,3 +1300,49 @@ sub onDataReturnedEvent(msg)
return
end if
end sub

sub processLibraryItemPopup(selectedPopupAction as integer, itemID as string)
' Add item to user's list
if selectedPopupAction = 0
data = api.GetUserViews({ "userId": m.global.session.user.id })
if not isChainValid(data, "items") then return

myListPlaylist = invalid

for each item in data.LookupCI("items")
if isStringEqual(item.LookupCI("CollectionType"), "playlists")
myListPlaylist = api.items.Get({
"userid": m.global.session.user.id,
"includeItemTypes": "Playlist",
"nameStartsWith": "[ROKU] My List",
"parentId": item.LookupCI("id")
})
exit for
end if
end for

' My list playlist exists. Add item to it
if isValid(myListPlaylist) and isValidAndNotEmpty(myListPlaylist.items)
api.playlists.Add(myListPlaylist.items[0].LookupCI("id"), {
ids: itemID,
userid: m.global.session.user.id
})
return
end if

' My list playlist does not exist. Create it with this item
api.playlists.Create({
name: "[ROKU] My List",
ids: [itemID],
userid: m.global.session.user.id,
mediatype: "Unknown",
users: [
{
userid: m.global.session.user.id,
canedit: true
}
],
ispublic: false
})
end if
end sub
2 changes: 1 addition & 1 deletion source/ShowScenes.bs
Original file line number Diff line number Diff line change
Expand Up @@ -974,5 +974,5 @@ sub playbackOptionDialog(time as longinteger, meta as object)
end if
end if
stopLoadingSpinner()
m.global.sceneManager.callFunc("optionDialog", tr("Playback Options"), [], resumeData)
m.global.sceneManager.callFunc("optionDialog", "playback", tr("Playback Options"), [], resumeData, string.EMPTY)
end sub

0 comments on commit 1f25c41

Please sign in to comment.