Merge branch 'master' into expand-homerows

This commit is contained in:
Charles Ewert 2024-11-08 11:29:49 -05:00 committed by GitHub
commit aa5210f758
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
372 changed files with 5551 additions and 1630 deletions

View File

@ -10,8 +10,8 @@ jobs:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4 - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
with: with:
node-version: "lts/*" node-version: "lts/*"
cache: "npm" cache: "npm"
@ -21,7 +21,7 @@ jobs:
run: npm run ropm run: npm run ropm
- name: Build app - name: Build app
run: npm run build run: npm run build
- uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # v4 - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
with: with:
name: Jellyfin-Roku-dev-${{ github.sha }} name: Jellyfin-Roku-dev-${{ github.sha }}
path: ${{ github.workspace }}/build/staging path: ${{ github.workspace }}/build/staging

View File

@ -13,7 +13,7 @@ jobs:
# Give the default GITHUB_TOKEN write permission to commit and push the changed files back to the repository. # Give the default GITHUB_TOKEN write permission to commit and push the changed files back to the repository.
contents: write contents: write
steps: steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
ref: ${{ github.head_ref }} ref: ${{ github.head_ref }}
token: ${{ secrets.JF_BOT_TOKEN }} token: ${{ secrets.JF_BOT_TOKEN }}

View File

@ -12,8 +12,8 @@ jobs:
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'release-prep') }} if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'release-prep') }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4 - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
with: with:
node-version: "lts/*" node-version: "lts/*"
cache: "npm" cache: "npm"
@ -23,7 +23,7 @@ jobs:
run: npm run ropm run: npm run ropm
- name: Build app for production - name: Build app for production
run: npm run build-prod run: npm run build-prod
- uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # v4 - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
with: with:
name: Jellyfin-Roku-v${{ env.newManVersion }}-${{ github.sha }} name: Jellyfin-Roku-v${{ env.newManVersion }}-${{ github.sha }}
path: ${{ github.workspace }}/build/staging path: ${{ github.workspace }}/build/staging

View File

@ -26,7 +26,7 @@ jobs:
steps: steps:
# Setup # Setup
- name: Checkout code - name: Checkout code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Install required packages - name: Install required packages
uses: awalsh128/cache-apt-pkgs-action@latest uses: awalsh128/cache-apt-pkgs-action@latest
with: with:
@ -50,7 +50,7 @@ jobs:
run: echo "targetBranch=${{ env.bugfixBranch }}" >> $GITHUB_ENV run: echo "targetBranch=${{ env.bugfixBranch }}" >> $GITHUB_ENV
- name: Checkout bugfix branch - name: Checkout bugfix branch
if: github.event.inputs.targetBranch == 'bugfix' if: github.event.inputs.targetBranch == 'bugfix'
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
ref: ${{ env.targetBranch }} ref: ${{ env.targetBranch }}
# Save old version again if needed # Save old version again if needed
@ -101,7 +101,7 @@ jobs:
steps: steps:
# Setup # Setup
- name: Checkout code - name: Checkout code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Install jq to update json - name: Install jq to update json
uses: awalsh128/cache-apt-pkgs-action@latest uses: awalsh128/cache-apt-pkgs-action@latest
with: with:
@ -125,7 +125,7 @@ jobs:
run: echo "targetBranch=${{ env.bugfixBranch }}" >> $GITHUB_ENV run: echo "targetBranch=${{ env.bugfixBranch }}" >> $GITHUB_ENV
- name: Checkout bugfix branch - name: Checkout bugfix branch
if: github.event.inputs.targetBranch == 'bugfix' if: github.event.inputs.targetBranch == 'bugfix'
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
ref: ${{ env.targetBranch }} ref: ${{ env.targetBranch }}
# Calculate new version # Calculate new version
@ -169,7 +169,7 @@ jobs:
steps: steps:
# Setup # Setup
- name: Checkout code - name: Checkout code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Install jq to update json - name: Install jq to update json
uses: awalsh128/cache-apt-pkgs-action@latest uses: awalsh128/cache-apt-pkgs-action@latest
with: with:
@ -193,7 +193,7 @@ jobs:
run: echo "targetBranch=${{ env.bugfixBranch }}" >> $GITHUB_ENV run: echo "targetBranch=${{ env.bugfixBranch }}" >> $GITHUB_ENV
- name: Checkout bugfix branch - name: Checkout bugfix branch
if: github.event.inputs.targetBranch == 'bugfix' if: github.event.inputs.targetBranch == 'bugfix'
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
ref: ${{ env.targetBranch }} ref: ${{ env.targetBranch }}
# Calculate new version # Calculate new version

View File

@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Pages - name: Setup Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
- name: Upload artifact - name: Upload artifact

View File

@ -12,8 +12,8 @@ jobs:
if: github.repository == 'jellyfin/jellyfin-roku' && github.event_name != 'pull_request' || github.repository == 'jellyfin/jellyfin-roku' && github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name if: github.repository == 'jellyfin/jellyfin-roku' && github.event_name != 'pull_request' || github.repository == 'jellyfin/jellyfin-roku' && github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4 - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
with: with:
node-version: "lts/*" node-version: "lts/*"
cache: "npm" cache: "npm"
@ -28,7 +28,7 @@ jobs:
if: env.BRANCH_NAME == 'master' if: env.BRANCH_NAME == 'master'
run: npm run build-prod run: npm run build-prod
- name: Setup Java - name: Setup Java
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4 uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4
with: with:
distribution: "temurin" distribution: "temurin"
java-version: "21" java-version: "21"

18
.vscode/launch.json vendored
View File

@ -2,9 +2,9 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Build and Deploy",
"type": "brightscript", "type": "brightscript",
"request": "launch", "request": "launch",
"name": "Jellyfin Debug",
"rootDir": "${workspaceFolder}/build/staging", "rootDir": "${workspaceFolder}/build/staging",
"preLaunchTask": "build-dev", "preLaunchTask": "build-dev",
"stopOnEntry": false, "stopOnEntry": false,
@ -18,6 +18,22 @@
//WARNING: don't edit this value. Instead, set "brightscript.debug.password": "YOUR_PASSWORD_HERE" in your vscode user settings //WARNING: don't edit this value. Instead, set "brightscript.debug.password": "YOUR_PASSWORD_HERE" in your vscode user settings
//"password": "${promptForPassword}", //"password": "${promptForPassword}",
}, },
{
"name": "Deploy",
"type": "brightscript",
"request": "launch",
"rootDir": "${workspaceFolder}/build/staging",
"stopOnEntry": false,
// To enable RALE:
// set "brightscript.debug.raleTrackerTaskFileLocation": "/absolute/path/to/rale/TrackerTask.xml" in your vscode user settings
// set the below field to true
"injectRaleTrackerTask": false,
"injectRdbOnDeviceComponent": true,
//WARNING: don't edit this value. Instead, set "brightscript.debug.host": "YOUR_HOST_HERE" in your vscode user settings
//"host": "${promptForHost}",
//WARNING: don't edit this value. Instead, set "brightscript.debug.password": "YOUR_PASSWORD_HERE" in your vscode user settings
//"password": "${promptForPassword}",
},
{ {
"name": "Run tests", "name": "Run tests",
"type": "brightscript", "type": "brightscript",

View File

@ -3,7 +3,7 @@
# If you want to get_images, you'll also need convert from ImageMagick # If you want to get_images, you'll also need convert from ImageMagick
########################################################################## ##########################################################################
VERSION := 2.1.4 VERSION := 2.2.2
## usage ## usage

View File

@ -20,9 +20,6 @@ sub init()
m.checkmark.width = 90 m.checkmark.width = 90
m.checkmark.height = 60 m.checkmark.height = 60
m.itemText.translation = [0, m.itemPoster.height + 7]
m.itemText.visible = m.gridTitles = "showalways"
' Add some padding space when Item Titles are always showing ' Add some padding space when Item Titles are always showing
if m.itemText.visible then m.itemText.maxWidth = 250 if m.itemText.visible then m.itemText.maxWidth = 250
@ -38,14 +35,17 @@ sub init()
end if end if
end if end if
m.itemText.translation = [0, m.itemPoster.height + 7]
m.itemText.visible = m.gridTitles = "showalways"
end sub end sub
sub itemContentChanged() sub itemContentChanged()
m.backdrop.blendColor = "#00a4db" ' set default in case global var is invalid m.backdrop.blendColor = "#00a4db" ' set default in case global var is invalid
localGlobal = m.global myGlobal = m.global
if isValid(localGlobal) and isValid(localGlobal.constants) and isValid(localGlobal.constants.poster_bg_pallet) if isValid(myGlobal) and isValid(myGlobal.constants) and isValid(myGlobal.constants.poster_bg_pallet)
posterBackgrounds = localGlobal.constants.poster_bg_pallet posterBackgrounds = myGlobal.constants.poster_bg_pallet
m.backdrop.blendColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1] m.backdrop.blendColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1]
end if end if
@ -62,8 +62,8 @@ sub itemContentChanged()
m.itemIcon.uri = itemData.iconUrl m.itemIcon.uri = itemData.iconUrl
m.itemText.text = itemData.Title m.itemText.text = itemData.Title
else if itemData.type = "Series" else if itemData.type = "Series"
if isValid(localGlobal) and isValid(localGlobal.session) and isValid(localGlobal.session.user) and isValid(localGlobal.session.user.settings) if isValid(myGlobal) and isValid(myGlobal.session) and isValid(myGlobal.session.user) and isValid(myGlobal.session.user.settings)
if localGlobal.session.user.settings["ui.tvshows.disableUnwatchedEpisodeCount"] = false if myGlobal.session.user.settings["ui.tvshows.disableUnwatchedEpisodeCount"] = false
if isValid(itemData.json) and isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount) if isValid(itemData.json) and isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount)
if itemData.json.UserData.UnplayedItemCount > 0 if itemData.json.UserData.UnplayedItemCount > 0
m.unplayedCount.visible = true m.unplayedCount.visible = true
@ -116,7 +116,7 @@ sub itemContentChanged()
m.itemText.text = itemData.Title m.itemText.text = itemData.Title
end if end if
' Adjust to wide posters for "View All Next Up" ' Adjust to wide posters for "View All Next Up"
if m.topParent.overhangTitle = tr("View All Next Up") if m.itemGrid.overhangTitle = tr("View All Next Up")
m.posterMask.maskUri = "" m.posterMask.maskUri = ""
m.itemPoster.height = 300 m.itemPoster.height = 300

View File

@ -4,7 +4,7 @@ import "pkg:/source/utils/config.bs"
sub init() sub init()
m.itemPoster = m.top.findNode("itemPoster") m.itemPoster = m.top.findNode("itemPoster")
m.posterText = m.top.findNode("posterText") m.posterText = m.top.findNode("posterText")
m.title = m.top.findNode("title") initTitle()
m.posterText.font.size = 30 m.posterText.font.size = 30
m.title.font.size = 25 m.title.font.size = 25
m.backdrop = m.top.findNode("backdrop") m.backdrop = m.top.findNode("backdrop")
@ -23,6 +23,10 @@ sub init()
end if end if
end sub end sub
sub initTitle()
m.title = m.top.findNode("title")
end sub
sub itemContentChanged() sub itemContentChanged()
m.backdrop.blendColor = "#101010" m.backdrop.blendColor = "#101010"
@ -54,6 +58,8 @@ sub itemContentChanged()
end sub end sub
sub focusChanged() sub focusChanged()
if not isValid(m.title) then initTitle()
if m.top.itemHasFocus = true if m.top.itemHasFocus = true
m.title.repeatCount = -1 m.title.repeatCount = -1
else else

View File

@ -6,9 +6,12 @@ import "pkg:/source/roku_modules/log/LogMixin.brs"
sub init() sub init()
m.log = log.Logger("ItemGrid") m.log = log.Logger("ItemGrid")
m.log.debug("start init()")
userSettings = m.global.session.user.settings
m.options = m.top.findNode("options") m.options = m.top.findNode("options")
m.showItemCount = m.global.session.user.settings["itemgrid.showItemCount"] m.showItemCount = userSettings["itemgrid.showItemCount"]
m.tvGuide = invalid m.tvGuide = invalid
m.channelFocused = invalid m.channelFocused = invalid
@ -67,9 +70,10 @@ sub init()
m.alphaMenu = m.alpha.findNode("alphaMenu") m.alphaMenu = m.alpha.findNode("alphaMenu")
'Get reset folder setting 'Get reset folder setting
m.resetGrid = m.global.session.user.settings["itemgrid.reset"] m.resetGrid = userSettings["itemgrid.reset"]
m.top.gridTitles = m.global.session.user.settings["itemgrid.gridTitles"] m.top.gridTitles = userSettings["itemgrid.gridTitles"]
m.log.debug("end init()")
end sub end sub
'Genre Item Selected 'Genre Item Selected
@ -79,8 +83,10 @@ end sub
'Load initial set of Data 'Load initial set of Data
sub loadInitialItems() sub loadInitialItems()
m.log.debug("start loadInitialItems()")
m.loadItemsTask.control = "stop" m.loadItemsTask.control = "stop"
startLoadingSpinner() startLoadingSpinner()
userSettings = m.global.session.user.settings
if m.top.parentItem.json.Type = "CollectionFolder" 'or m.top.parentItem.json.Type = "Folder" if m.top.parentItem.json.Type = "CollectionFolder" 'or m.top.parentItem.json.Type = "Folder"
m.top.HomeLibraryItem = m.top.parentItem.Id m.top.HomeLibraryItem = m.top.parentItem.Id
@ -93,25 +99,25 @@ sub loadInitialItems()
' Read view/sort/filter settings ' Read view/sort/filter settings
if m.top.parentItem.collectionType = "livetv" if m.top.parentItem.collectionType = "livetv"
' Translate between app and server nomenclature ' Translate between app and server nomenclature
viewSetting = m.global.session.user.settings["display.livetv.landing"] viewSetting = userSettings["display.livetv.landing"]
if viewSetting = "guide" if viewSetting = "guide"
m.view = "tvGuide" m.view = "tvGuide"
else else
m.view = "livetv" m.view = "livetv"
end if end if
m.sortField = m.global.session.user.settings["display.livetv.sortField"] m.sortField = userSettings["display.livetv.sortField"]
sortAscendingStr = m.global.session.user.settings["display.livetv.sortAscending"] sortAscendingStr = userSettings["display.livetv.sortAscending"]
m.filter = m.global.session.user.settings["display.livetv.filter"] m.filter = userSettings["display.livetv.filter"]
else if m.top.parentItem.collectionType = "music" else if m.top.parentItem.collectionType = "music"
m.view = m.global.session.user.settings["display.music.view"] m.view = userSettings["display.music.view"]
m.sortField = m.global.session.user.settings["display." + m.top.parentItem.Id + ".sortField"] m.sortField = userSettings["display." + m.top.parentItem.Id + ".sortField"]
sortAscendingStr = m.global.session.user.settings["display." + m.top.parentItem.Id + ".sortAscending"] sortAscendingStr = userSettings["display." + m.top.parentItem.Id + ".sortAscending"]
m.filter = m.global.session.user.settings["display." + m.top.parentItem.Id + ".filter"] m.filter = userSettings["display." + m.top.parentItem.Id + ".filter"]
else else
m.sortField = m.global.session.user.settings["display." + m.top.parentItem.Id + ".sortField"] m.sortField = userSettings["display." + m.top.parentItem.Id + ".sortField"]
sortAscendingStr = m.global.session.user.settings["display." + m.top.parentItem.Id + ".sortAscending"] sortAscendingStr = userSettings["display." + m.top.parentItem.Id + ".sortAscending"]
m.filter = m.global.session.user.settings["display." + m.top.parentItem.Id + ".filter"] m.filter = userSettings["display." + m.top.parentItem.Id + ".filter"]
m.view = m.global.session.user.settings["display." + m.top.parentItem.Id + ".landing"] m.view = userSettings["display." + m.top.parentItem.Id + ".landing"]
end if end if
if m.sortField = invalid if m.sortField = invalid
@ -177,7 +183,7 @@ sub loadInitialItems()
m.loadItemsTask.itemType = "MusicArtist" m.loadItemsTask.itemType = "MusicArtist"
m.loadItemsTask.itemId = m.top.parentItem.Id m.loadItemsTask.itemId = m.top.parentItem.Id
m.view = m.global.session.user.settings["display.music.view"] m.view = userSettings["display.music.view"]
if m.view = "music-album" if m.view = "music-album"
m.loadItemsTask.itemType = "MusicAlbum" m.loadItemsTask.itemType = "MusicAlbum"
@ -188,7 +194,7 @@ sub loadInitialItems()
' For LiveTV, we want to "Fit" the item images, not zoom ' For LiveTV, we want to "Fit" the item images, not zoom
m.top.imageDisplayMode = "scaleToFit" m.top.imageDisplayMode = "scaleToFit"
if m.global.session.user.settings["display.livetv.landing"] = "guide" and m.options.view <> "livetv" if userSettings["display.livetv.landing"] = "guide" and m.options.view <> "livetv"
showTvGuide() showTvGuide()
end if end if
else if m.top.parentItem.collectionType = "CollectionFolder" or m.top.parentItem.type = "CollectionFolder" or m.top.parentItem.collectionType = "boxsets" or m.top.parentItem.Type = "Boxset" or m.top.parentItem.Type = "Boxsets" or m.top.parentItem.Type = "Folder" or m.top.parentItem.Type = "Channel" else if m.top.parentItem.collectionType = "CollectionFolder" or m.top.parentItem.type = "CollectionFolder" or m.top.parentItem.collectionType = "boxsets" or m.top.parentItem.Type = "Boxset" or m.top.parentItem.Type = "Boxsets" or m.top.parentItem.Type = "Folder" or m.top.parentItem.Type = "Channel"
@ -235,6 +241,7 @@ sub loadInitialItems()
startLoadingSpinner(false) startLoadingSpinner(false)
m.loadItemsTask.control = "RUN" m.loadItemsTask.control = "RUN"
SetUpOptions() SetUpOptions()
m.log.debug("end loadInitialItems()")
end sub end sub
' Set Movies view, sort, and filter options ' Set Movies view, sort, and filter options
@ -295,7 +302,7 @@ sub setTvShowsOptions(options)
{ "Title": tr("TITLE"), "Name": "SortName" }, { "Title": tr("TITLE"), "Name": "SortName" },
{ "Title": tr("IMDB_RATING"), "Name": "CommunityRating" }, { "Title": tr("IMDB_RATING"), "Name": "CommunityRating" },
{ "Title": tr("DATE_ADDED"), "Name": "DateCreated" }, { "Title": tr("DATE_ADDED"), "Name": "DateCreated" },
{ "Title": tr("DATE_PLAYED"), "Name": "DatePlayed" }, { "Title": tr("DATE_PLAYED"), "Name": "SeriesDatePlayed" },
{ "Title": tr("OFFICIAL_RATING"), "Name": "OfficialRating" }, { "Title": tr("OFFICIAL_RATING"), "Name": "OfficialRating" },
{ "Title": tr("RELEASE_DATE"), "Name": "PremiereDate" }, { "Title": tr("RELEASE_DATE"), "Name": "PremiereDate" },
{ "Title": tr("Random"), "Name": "Random" }, { "Title": tr("Random"), "Name": "Random" },
@ -445,6 +452,7 @@ end sub
'Handle loaded data, and add to Grid 'Handle loaded data, and add to Grid
sub ItemDataLoaded(msg) sub ItemDataLoaded(msg)
m.log.debug("start ItemDataLoaded()")
itemData = msg.GetData() itemData = msg.GetData()
m.loadItemsTask.unobserveField("content") m.loadItemsTask.unobserveField("content")
m.loadItemsTask.content = [] m.loadItemsTask.content = []
@ -501,22 +509,28 @@ sub ItemDataLoaded(msg)
end if end if
stopLoadingSpinner() stopLoadingSpinner()
m.log.debug("end ItemDataLoaded()")
end sub end sub
'Set Background Image 'Set Background Image
sub SetBackground(backgroundUri as string) sub SetBackground(backgroundUri as string)
m.log.debug("start SetBackground()", backgroundUri, m.swapAnimation.state, m.newBackdrop.loadStatus)
'If a new image is being loaded, or transitioned to, store URL to load next 'If a new image is being loaded, or transitioned to, store URL to load next
if m.swapAnimation.state <> "stopped" or m.newBackdrop.loadStatus = "loading" if not m.top.alphaActive
m.queuedBGUri = backgroundUri if m.swapAnimation.state <> "stopped" or m.newBackdrop.loadStatus = "loading"
return m.log.debug("caching new background URI")
m.queuedBGUri = backgroundUri
return
end if
end if end if
m.newBackdrop.uri = backgroundUri m.newBackdrop.uri = backgroundUri
m.log.debug("end SetBackground()")
end sub end sub
'Handle new item being focused 'Handle new item being focused
sub onItemFocused() sub onItemFocused()
m.log.debug("start onItemFocused()", m.itemGrid.currFocusRow, m.itemGrid.itemFocused)
focusedRow = m.itemGrid.currFocusRow focusedRow = m.itemGrid.currFocusRow
@ -525,7 +539,7 @@ sub onItemFocused()
updateTitle() updateTitle()
' If no selected item, set background to parent backdrop ' If no selected item, set background to parent backdrop
if itemInt = -1 if itemInt = -1 or focusedRow = -1
return return
end if end if
@ -538,6 +552,7 @@ sub onItemFocused()
if focusedRow >= m.loadedRows - 5 and m.loadeditems < m.loadItemsTask.totalRecordCount if focusedRow >= m.loadedRows - 5 and m.loadeditems < m.loadItemsTask.totalRecordCount
loadMoreData() loadMoreData()
end if end if
m.log.debug("end onItemFocused()")
end sub end sub
'When Image Loading Status changes 'When Image Loading Status changes
@ -558,6 +573,7 @@ sub swapDone()
'If there is another one to load 'If there is another one to load
if m.newBackdrop.uri <> m.queuedBGUri and m.queuedBGUri <> "" if m.newBackdrop.uri <> m.queuedBGUri and m.queuedBGUri <> ""
m.log.debug("Loading queued backdrop image", m.queuedBGUri)
SetBackground(m.queuedBGUri) SetBackground(m.queuedBGUri)
m.queuedBGUri = "" m.queuedBGUri = ""
end if end if
@ -566,6 +582,7 @@ end sub
'Load next set of items 'Load next set of items
sub loadMoreData() sub loadMoreData()
m.log.debug("start loadMoreData()")
if m.Loading = true then return if m.Loading = true then return
startLoadingSpinner(false) startLoadingSpinner(false)
@ -573,6 +590,7 @@ sub loadMoreData()
m.loadItemsTask.startIndex = m.loadedItems m.loadItemsTask.startIndex = m.loadedItems
m.loadItemsTask.observeField("content", "ItemDataLoaded") m.loadItemsTask.observeField("content", "ItemDataLoaded")
m.loadItemsTask.control = "RUN" m.loadItemsTask.control = "RUN"
m.log.debug("end loadMoreData()")
end sub end sub
'Item Selected 'Item Selected
@ -767,6 +785,20 @@ function getItemFocused()
return invalid return invalid
end function end function
sub alphaActiveChanged()
m.log.debug("start alphaActiveChanged()", m.top.alphaActive)
if m.top.alphaActive
' fade into an empty backdrop
m.swapAnimation.state = "stop"
m.queuedBGUri = ""
' use a 1px image because we can't use the animation to fade into a blank uri string
SetBackground("pkg:/images/1px-262626.png")
end if
m.log.debug("end alphaActiveChanged()")
end sub
function onKeyEvent(key as string, press as boolean) as boolean function onKeyEvent(key as string, press as boolean) as boolean
if not press then return false if not press then return false
@ -833,11 +865,14 @@ function onKeyEvent(key as string, press as boolean) as boolean
return true return true
end if end if
else if key = "left" and topGrp.isinFocusChain() and m.alpha.visible else if key = "left" and topGrp.isinFocusChain() and m.alpha.visible
m.log.debug("Now entering alpha menu")
m.top.alphaActive = true m.top.alphaActive = true
topGrp.setFocus(false) topGrp.setFocus(false)
m.alphaMenu.setFocus(true) m.alphaMenu.setFocus(true)
return true return true
else if key = "right" and m.alpha.isinFocusChain() else if key = "right" and m.alpha.isinFocusChain()
m.log.debug("Now leaving alpha menu")
m.top.alphaActive = false m.top.alphaActive = false
m.alphaMenu.setFocus(false) m.alphaMenu.setFocus(false)
topGrp.setFocus(true) topGrp.setFocus(true)

View File

@ -33,7 +33,7 @@
<field id="quickPlayNode" type="node" alwaysNotify="true" /> <field id="quickPlayNode" type="node" alwaysNotify="true" />
<field id="imageDisplayMode" type="string" value="scaleToZoom" /> <field id="imageDisplayMode" type="string" value="scaleToZoom" />
<field id="alphaSelected" type="string" alias="alpha.letterSelected" alwaysNotify="true" onChange="alphaSelectedChanged" /> <field id="alphaSelected" type="string" alias="alpha.letterSelected" alwaysNotify="true" onChange="alphaSelectedChanged" />
<field id="alphaActive" type="boolean" value="false" /> <field id="alphaActive" type="boolean" value="false" onChange="alphaActiveChanged" />
<field id="jumpToItem" type="integer" value="" /> <field id="jumpToItem" type="integer" value="" />
<field id="gridTitles" type="string" /> <field id="gridTitles" type="string" />
</interface> </interface>

View File

@ -6,6 +6,7 @@ import "pkg:/source/utils/config.bs"
import "pkg:/source/api/Image.bs" import "pkg:/source/api/Image.bs"
import "pkg:/source/api/userauth.bs" import "pkg:/source/api/userauth.bs"
import "pkg:/source/utils/deviceCapabilities.bs" import "pkg:/source/utils/deviceCapabilities.bs"
import "pkg:/source/utils/session.bs"
enum SubtitleSelection enum SubtitleSelection
notset = -2 notset = -2
@ -17,21 +18,23 @@ sub init()
end sub end sub
sub loadItems() sub loadItems()
queueManager = m.global.queueManager
' Reset intro tracker in case task gets reused ' Reset intro tracker in case task gets reused
m.top.isIntro = false m.top.isIntro = false
' Only show preroll once per queue ' Only show preroll once per queue
if m.global.queueManager.callFunc("isPrerollActive") if queueManager.callFunc("isPrerollActive")
' Prerolls not allowed if we're resuming video ' Prerolls not allowed if we're resuming video
if m.global.queueManager.callFunc("getCurrentItem").startingPoint = 0 if queueManager.callFunc("getCurrentItem").startingPoint = 0
preRoll = GetIntroVideos(m.top.itemId) preRoll = GetIntroVideos(m.top.itemId)
if isValid(preRoll) and preRoll.TotalRecordCount > 0 and isValid(preRoll.items[0]) if isValid(preRoll) and preRoll.TotalRecordCount > 0 and isValid(preRoll.items[0])
' If an error is thrown in the Intros plugin, instead of passing the error they pass the entire rick roll music video. ' If an error is thrown in the Intros plugin, instead of passing the error they pass the entire rick roll music video.
' Bypass the music video and treat it as an error message ' Bypass the music video and treat it as an error message
if lcase(preRoll.items[0].name) <> "rick roll'd" if lcase(preRoll.items[0].name) <> "rick roll'd"
m.global.queueManager.callFunc("push", m.global.queueManager.callFunc("getCurrentItem")) queueManager.callFunc("push", queueManager.callFunc("getCurrentItem"))
m.top.itemId = preRoll.items[0].id m.top.itemId = preRoll.items[0].id
m.global.queueManager.callFunc("setPrerollStatus", false) queueManager.callFunc("setPrerollStatus", false)
m.top.isIntro = true m.top.isIntro = true
end if end if
end if end if
@ -39,7 +42,7 @@ sub loadItems()
end if end if
if m.top.selectedAudioStreamIndex = 0 if m.top.selectedAudioStreamIndex = 0
currentItem = m.global.queueManager.callFunc("getCurrentItem") currentItem = queueManager.callFunc("getCurrentItem")
if isValid(currentItem) and isValid(currentItem.json) if isValid(currentItem) and isValid(currentItem.json)
m.top.selectedAudioStreamIndex = FindPreferredAudioStream(currentItem.json.MediaStreams) m.top.selectedAudioStreamIndex = FindPreferredAudioStream(currentItem.json.MediaStreams)
end if end if
@ -71,14 +74,30 @@ end function
sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean) sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean)
meta = ItemMetaData(video.id) meta = ItemMetaData(video.id)
subtitle_idx = m.top.selectedSubtitleIndex
if not isValid(meta) if not isValid(meta)
video.errorMsg = "Error loading metadata" video.errorMsg = "Error loading metadata"
video.content = invalid video.content = invalid
return return
end if end if
queueManager = m.global.queueManager
userSession = m.global.session.user
userSettings = userSession.settings
session.video.Update(meta)
if isValid(meta.json.MediaSources[0].RunTimeTicks)
if meta.json.MediaSources[0].RunTimeTicks = 0
video.length = 0
else
video.length = meta.json.MediaSources[0].RunTimeTicks / 10000000
end if
end if
if isValid(meta.json.MediaSources[0]) and isValid(meta.json.MediaSources[0].MediaStreams[0])
video.MaxVideoDecodeResolution = [meta.json.MediaSources[0].MediaStreams[0].Width, meta.json.MediaSources[0].MediaStreams[0].Height]
end if
subtitle_idx = m.top.selectedSubtitleIndex
videotype = LCase(meta.type) videotype = LCase(meta.type)
' Check for any Live TV streams or Recordings coming from other places other than the TV Guide ' Check for any Live TV streams or Recordings coming from other places other than the TV Guide
@ -118,15 +137,15 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
video.logoImage = api.items.GetImageURL(logoLookupID, "logo", 0, { "maxHeight": 65, "maxWidth": 300, "quality": "90" }) video.logoImage = api.items.GetImageURL(logoLookupID, "logo", 0, { "maxHeight": 65, "maxWidth": 300, "quality": "90" })
end if end if
if m.global.session.user.Configuration.EnableNextEpisodeAutoPlay if LCase(m.top.itemType) = "episode"
if LCase(m.top.itemType) = "episode" if userSettings["playback.playnextepisode"] = "enabled" or userSettings["playback.playnextepisode"] = "webclient" and userSession.Configuration.EnableNextEpisodeAutoPlay
addNextEpisodesToQueue(video.showID) addNextEpisodesToQueue(video.showID)
end if end if
end if end if
playbackPosition = 0! playbackPosition = 0!
currentItem = m.global.queueManager.callFunc("getCurrentItem") currentItem = queueManager.callFunc("getCurrentItem")
if isValid(currentItem) and isValid(currentItem.startingPoint) if isValid(currentItem) and isValid(currentItem.startingPoint)
playbackPosition = currentItem.startingPoint playbackPosition = currentItem.startingPoint
@ -196,20 +215,18 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
} }
end if end if
' 'TODO: allow user selection of subtitle track before playback initiated, for now set to no subtitles ' 'TODO: allow user selection of subtitle track before playback initiated, for now set to no subtitles
video.directPlaySupported = m.playbackInfo.MediaSources[0].SupportsDirectPlay video.directPlaySupported = m.playbackInfo.MediaSources[0].SupportsDirectPlay
fully_external = false fully_external = false
' For h264/hevc video, Roku spec states that it supports specfic encoding levels ' For h264/hevc video, Roku spec states that it supports specfic encoding levels
' The device can decode content with a Higher Encoding level but may play it back with certain ' The device can decode content with a Higher Encoding level but may play it back with certain
' artifacts. If the user preference is set, and the only reason the server says we need to ' artifacts. If the user preference is set, and the only reason the server says we need to
' transcode is that the Encoding Level is not supported, then try to direct play but silently ' transcode is that the Encoding Level is not supported, then try to direct play but silently
' fall back to the transcode if that fails. ' fall back to the transcode if that fails.
if m.playbackInfo.MediaSources[0].MediaStreams.Count() > 0 and meta.live = false if m.playbackInfo.MediaSources[0].MediaStreams.Count() > 0 and meta.live = false
tryDirectPlay = m.global.session.user.settings["playback.tryDirect.h264ProfileLevel"] and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = "h264" tryDirectPlay = userSettings["playback.tryDirect.h264ProfileLevel"] and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = "h264"
tryDirectPlay = tryDirectPlay or (m.global.session.user.settings["playback.tryDirect.hevcProfileLevel"] and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = "hevc") tryDirectPlay = tryDirectPlay or (userSettings["playback.tryDirect.hevcProfileLevel"] and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = "hevc")
if tryDirectPlay and isValid(m.playbackInfo.MediaSources[0].TranscodingUrl) and forceTranscoding = false if tryDirectPlay and isValid(m.playbackInfo.MediaSources[0].TranscodingUrl) and forceTranscoding = false
transcodingReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl) transcodingReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl)
if transcodingReasons.Count() = 1 and transcodingReasons[0] = "VideoLevelNotSupported" if transcodingReasons.Count() = 1 and transcodingReasons[0] = "VideoLevelNotSupported"
@ -249,7 +266,8 @@ end sub
' @param {dynamic} videoID - id of video user is playing ' @param {dynamic} videoID - id of video user is playing
' @return {integer} indicating the default track's server-side index. Defaults to {SubtitleSelection.none} is one is not found ' @return {integer} indicating the default track's server-side index. Defaults to {SubtitleSelection.none} is one is not found
function defaultSubtitleTrackFromVid(videoID) as integer function defaultSubtitleTrackFromVid(videoID) as integer
if m.global.session.user.configuration.SubtitleMode = "None" userSession = m.global.session.user
if userSession.configuration.SubtitleMode = "None"
return SubtitleSelection.none ' No subtitles desired: return none return SubtitleSelection.none ' No subtitles desired: return none
end if end if
@ -275,7 +293,7 @@ function defaultSubtitleTrackFromVid(videoID) as integer
return defaultTextSubs return defaultTextSubs
end if end if
if not m.global.session.user.settings["playback.subs.onlytext"] if not userSession.settings["playback.subs.onlytext"]
return defaultSubtitleTrack(subtitles["all"], selectedAudioLanguage) ' if no appropriate text subs exist, allow non-text return defaultSubtitleTrack(subtitles["all"], selectedAudioLanguage) ' if no appropriate text subs exist, allow non-text
end if end if
@ -350,11 +368,15 @@ sub addVideoContentURL(video, mediaSourceId, audio_stream_idx, fully_external)
protocol = LCase(m.playbackInfo.MediaSources[0].Protocol) protocol = LCase(m.playbackInfo.MediaSources[0].Protocol)
if protocol <> "file" if protocol <> "file"
uri = parseUrl(m.playbackInfo.MediaSources[0].Path) uri = parseUrl(m.playbackInfo.MediaSources[0].Path)
if isLocalhost(uri[2]) if not isValidAndNotEmpty(uri) then return
if isValid(uri[2]) and isLocalhost(uri[2])
' if the domain of the URI is local to the server, ' if the domain of the URI is local to the server,
' create a new URI by appending the received path to the server URL ' create a new URI by appending the received path to the server URL
' later we will substitute the users provided URL for this case ' later we will substitute the users provided URL for this case
video.content.url = buildURL(uri[4]) if isValid(uri[4])
video.content.url = buildURL(uri[4])
end if
else else
fully_external = true fully_external = true
video.content.url = m.playbackInfo.MediaSources[0].Path video.content.url = m.playbackInfo.MediaSources[0].Path
@ -475,6 +497,8 @@ end function
' Add next episodes to the playback queue ' Add next episodes to the playback queue
sub addNextEpisodesToQueue(showID) sub addNextEpisodesToQueue(showID)
queueManager = m.global.queueManager
' Don't queue next episodes if we already have a playback queue ' Don't queue next episodes if we already have a playback queue
maxQueueCount = 1 maxQueueCount = 1
@ -482,13 +506,13 @@ sub addNextEpisodesToQueue(showID)
maxQueueCount = 2 maxQueueCount = 2
end if end if
if m.global.queueManager.callFunc("getCount") > maxQueueCount then return if queueManager.callFunc("getCount") > maxQueueCount then return
videoID = m.top.itemId videoID = m.top.itemId
' If first item is an intro video, use the next item in the queue ' If first item is an intro video, use the next item in the queue
if m.top.isIntro if m.top.isIntro
currentVideo = m.global.queueManager.callFunc("getItemByIndex", 1) currentVideo = queueManager.callFunc("getItemByIndex", 1)
if isValid(currentVideo) and isValid(currentVideo.id) if isValid(currentVideo) and isValid(currentVideo.id)
videoID = currentVideo.id videoID = currentVideo.id
@ -510,7 +534,7 @@ sub addNextEpisodesToQueue(showID)
if isValid(data) and data.Items.Count() > 1 if isValid(data) and data.Items.Count() > 1
for i = 1 to data.Items.Count() - 1 for i = 1 to data.Items.Count() - 1
m.global.queueManager.callFunc("push", data.Items[i]) queueManager.callFunc("push", data.Items[i])
end for end for
end if end if
end sub end sub
@ -569,8 +593,9 @@ function sortSubtitles(id as string, MediaStreams)
end function end function
function FindPreferredAudioStream(streams as dynamic) as integer function FindPreferredAudioStream(streams as dynamic) as integer
preferredLanguage = m.global.session.user.Configuration.AudioLanguagePreference userConfig = m.global.session.user.configuration
playDefault = m.global.session.user.Configuration.PlayDefaultAudioTrack preferredLanguage = userConfig.AudioLanguagePreference
playDefault = userConfig.PlayDefaultAudioTrack
if playDefault <> invalid and playDefault = true if playDefault <> invalid and playDefault = true
return 1 return 1

View File

@ -30,6 +30,7 @@ end sub
sub init() sub init()
setupNodes() setupNodes()
userSettings = m.global.session.user.settings
m.overhang.isVisible = false m.overhang.isVisible = false
@ -39,7 +40,7 @@ sub init()
alphaMicText = m.alpha.findNode("alphaMicText") alphaMicText = m.alpha.findNode("alphaMicText")
alphaMicText.visible = false alphaMicText.visible = false
m.showItemCount = m.global.session.user.settings["itemgrid.showItemCount"] m.showItemCount = userSettings["itemgrid.showItemCount"]
m.swapAnimation.observeField("state", "swapDone") m.swapAnimation.observeField("state", "swapDone")
@ -86,7 +87,7 @@ sub init()
m.loadItemsTask.totalRecordCount = 0 m.loadItemsTask.totalRecordCount = 0
'Get reset folder setting 'Get reset folder setting
m.resetGrid = m.global.session.user.settings["itemgrid.reset"] m.resetGrid = userSettings["itemgrid.reset"]
end sub end sub
sub OnScreenHidden() sub OnScreenHidden()
@ -112,6 +113,7 @@ end sub
sub loadInitialItems() sub loadInitialItems()
m.loadItemsTask.control = "stop" m.loadItemsTask.control = "stop"
startLoadingSpinner(false) startLoadingSpinner(false)
userSettings = m.global.session.user.settings
if m.top.parentItem.json.Type = "CollectionFolder" if m.top.parentItem.json.Type = "CollectionFolder"
m.top.HomeLibraryItem = m.top.parentItem.Id m.top.HomeLibraryItem = m.top.parentItem.Id
@ -123,15 +125,15 @@ sub loadInitialItems()
SetBackground("") SetBackground("")
end if end if
m.sortField = m.global.session.user.settings["display." + m.top.parentItem.Id + ".sortField"] m.sortField = userSettings["display." + m.top.parentItem.Id + ".sortField"]
m.filter = m.global.session.user.settings["display." + m.top.parentItem.Id + ".filter"] m.filter = userSettings["display." + m.top.parentItem.Id + ".filter"]
m.filterOptions = m.global.session.user.settings["display." + m.top.parentItem.Id + ".filterOptions"] m.filterOptions = userSettings["display." + m.top.parentItem.Id + ".filterOptions"]
m.view = m.global.session.user.settings["display." + m.top.parentItem.Id + ".landing"] m.view = userSettings["display." + m.top.parentItem.Id + ".landing"]
m.sortAscending = m.global.session.user.settings["display." + m.top.parentItem.Id + ".sortAscending"] m.sortAscending = userSettings["display." + m.top.parentItem.Id + ".sortAscending"]
' If user has not set a preferred view for this folder, check if they've set a default view ' If user has not set a preferred view for this folder, check if they've set a default view
if not isValid(m.view) if not isValid(m.view)
m.view = m.global.session.user.settings["itemgrid.movieDefaultView"] m.view = userSettings["itemgrid.movieDefaultView"]
end if end if
if not isValid(m.sortField) then m.sortField = "SortName" if not isValid(m.sortField) then m.sortField = "SortName"
@ -200,7 +202,7 @@ sub loadInitialItems()
m.itemGrid.numRows = "3" m.itemGrid.numRows = "3"
m.selectedMovieOverview.visible = false m.selectedMovieOverview.visible = false
m.infoGroup.visible = false m.infoGroup.visible = false
m.top.showItemTitles = m.global.session.user.settings["itemgrid.gridTitles"] m.top.showItemTitles = userSettings["itemgrid.gridTitles"]
if LCase(m.top.showItemTitles) = "hidealways" if LCase(m.top.showItemTitles) = "hidealways"
m.itemGrid.itemSize = "[230, 315]" m.itemGrid.itemSize = "[230, 315]"
m.itemGrid.rowHeights = "[315]" m.itemGrid.rowHeights = "[315]"

View File

@ -18,10 +18,8 @@ sub init()
m.itemPoster.loadDisplayMode = m.topParent.imageDisplayMode m.itemPoster.loadDisplayMode = m.topParent.imageDisplayMode
end if end if
m.gridTitles = m.global.session.user.settings["itemgrid.gridTitles"]
m.posterText.visible = false m.posterText.visible = false
m.postTextBackground.visible = false m.postTextBackground.visible = false
end sub end sub
sub itemContentChanged() sub itemContentChanged()

View File

@ -25,6 +25,7 @@ end sub
sub init() sub init()
setupNodes() setupNodes()
userSettings = m.global.session.user.settings
m.overhang.isVisible = false m.overhang.isVisible = false
@ -34,7 +35,7 @@ sub init()
alphaMicText = m.alpha.findNode("alphaMicText") alphaMicText = m.alpha.findNode("alphaMicText")
alphaMicText.visible = false alphaMicText.visible = false
m.showItemCount = m.global.session.user.settings["itemgrid.showItemCount"] m.showItemCount = userSettings["itemgrid.showItemCount"]
m.swapAnimation.observeField("state", "swapDone") m.swapAnimation.observeField("state", "swapDone")
@ -80,7 +81,7 @@ sub init()
m.loadItemsTask.totalRecordCount = 0 m.loadItemsTask.totalRecordCount = 0
'Get reset folder setting 'Get reset folder setting
m.resetGrid = m.global.session.user.settings["itemgrid.reset"] m.resetGrid = userSettings["itemgrid.reset"]
end sub end sub
sub OnScreenHidden() sub OnScreenHidden()
@ -106,6 +107,7 @@ end sub
sub loadInitialItems() sub loadInitialItems()
m.loadItemsTask.control = "stop" m.loadItemsTask.control = "stop"
startLoadingSpinner(false) startLoadingSpinner(false)
userSettings = m.global.session.user.settings
if LCase(m.top.parentItem.json.Type) = "collectionfolder" if LCase(m.top.parentItem.json.Type) = "collectionfolder"
m.top.HomeLibraryItem = m.top.parentItem.Id m.top.HomeLibraryItem = m.top.parentItem.Id
@ -117,17 +119,17 @@ sub loadInitialItems()
SetBackground("") SetBackground("")
end if end if
m.sortField = m.global.session.user.settings["display." + m.top.parentItem.Id + ".sortField"] m.sortField = userSettings["display." + m.top.parentItem.Id + ".sortField"]
m.sortAscending = m.global.session.user.settings["display." + m.top.parentItem.Id + ".sortAscending"] m.sortAscending = userSettings["display." + m.top.parentItem.Id + ".sortAscending"]
m.filter = m.global.session.user.settings["display." + m.top.parentItem.Id + ".filter"] m.filter = userSettings["display." + m.top.parentItem.Id + ".filter"]
m.view = m.global.session.user.settings["display." + m.top.parentItem.Id + ".landing"] m.view = userSettings["display." + m.top.parentItem.Id + ".landing"]
if not isValid(m.sortField) then m.sortField = "SortName" if not isValid(m.sortField) then m.sortField = "SortName"
if not isValid(m.filter) then m.filter = "All" if not isValid(m.filter) then m.filter = "All"
if not isValid(m.view) then m.view = "ArtistsPresentation" if not isValid(m.view) then m.view = "ArtistsPresentation"
if not isValid(m.sortAscending) then m.sortAscending = true if not isValid(m.sortAscending) then m.sortAscending = true
m.top.showItemTitles = m.global.session.user.settings["itemgrid.gridTitles"] m.top.showItemTitles = userSettings["itemgrid.gridTitles"]
if LCase(m.top.parentItem.json.type) = "musicgenre" if LCase(m.top.parentItem.json.type) = "musicgenre"
m.itemGrid.translation = "[96, 60]" m.itemGrid.translation = "[96, 60]"

View File

@ -13,7 +13,8 @@ sub init()
m.top.transcodeReasons = [] m.top.transcodeReasons = []
m.bufferCheckTimer.duration = 30 m.bufferCheckTimer.duration = 30
if m.global.session.user.settings["ui.design.hideclock"] = true userSettings = m.global.session.user.settings
if userSettings["ui.design.hideclock"]
clockNode = findNodeBySubtype(m.top, "clock") clockNode = findNodeBySubtype(m.top, "clock")
if clockNode[0] <> invalid then clockNode[0].parent.removeChild(clockNode[0].node) if clockNode[0] <> invalid then clockNode[0].parent.removeChild(clockNode[0].node)
end if end if
@ -22,7 +23,7 @@ sub init()
m.nextEpisodeButton = m.top.findNode("nextEpisode") m.nextEpisodeButton = m.top.findNode("nextEpisode")
m.nextEpisodeButton.text = tr("Next Episode") m.nextEpisodeButton.text = tr("Next Episode")
m.nextEpisodeButton.setFocus(false) m.nextEpisodeButton.setFocus(false)
m.nextupbuttonseconds = m.global.session.user.settings["playback.nextupbuttonseconds"].ToInt() m.nextupbuttonseconds = userSettings["playback.nextupbuttonseconds"].ToInt()
m.showNextEpisodeButtonAnimation = m.top.findNode("showNextEpisodeButton") m.showNextEpisodeButtonAnimation = m.top.findNode("showNextEpisodeButton")
m.hideNextEpisodeButtonAnimation = m.top.findNode("hideNextEpisodeButton") m.hideNextEpisodeButtonAnimation = m.top.findNode("hideNextEpisodeButton")
@ -92,12 +93,14 @@ end sub
sub showNextEpisodeButton() sub showNextEpisodeButton()
if m.top.content.contenttype <> 4 then return ' only display when content is type "Episode" if m.top.content.contenttype <> 4 then return ' only display when content is type "Episode"
if m.nextupbuttonseconds = 0 then return ' is the button disabled? if m.nextupbuttonseconds = 0 then return ' is the button disabled?
if m.nextEpisodeButton.opacity <> 0 then return
userSession = m.global.session.user
if userSession.settings["playback.playnextepisode"] = "disabled" then return
if userSession.settings["playback.playnextepisode"] = "webclient" and not userSession.Configuration.EnableNextEpisodeAutoPlay then return
if m.nextEpisodeButton.opacity = 0 and m.global.session.user.configuration.EnableNextEpisodeAutoPlay m.nextEpisodeButton.visible = true
m.nextEpisodeButton.visible = true m.showNextEpisodeButtonAnimation.control = "start"
m.showNextEpisodeButtonAnimation.control = "start" m.nextEpisodeButton.setFocus(true)
m.nextEpisodeButton.setFocus(true)
end if
end sub end sub
' '

View File

@ -17,10 +17,10 @@ sub init()
' Randomize the background colors ' Randomize the background colors
backdropColor = "#00a4db" ' set default in case global var is invalid backdropColor = "#00a4db" ' set default in case global var is invalid
localGlobal = m.global myGlobal = m.global
if isValid(localGlobal) and isValid(localGlobal.constants) and isValid(localGlobal.constants.poster_bg_pallet) if isValid(myGlobal) and isValid(myGlobal.constants) and isValid(myGlobal.constants.poster_bg_pallet)
posterBackgrounds = localGlobal.constants.poster_bg_pallet posterBackgrounds = myGlobal.constants.poster_bg_pallet
backdropColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1] backdropColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1]
end if end if
@ -65,8 +65,9 @@ sub itemContentChanged() as void
m.poster = m.top.findNode("poster") m.poster = m.top.findNode("poster")
itemData = m.top.itemContent itemData = m.top.itemContent
m.title.text = itemData.title m.title.text = itemData.title
userSettings = m.global.session.user.settings
if m.global.session.user.settings["ui.tvshows.disableUnwatchedEpisodeCount"] = false if not userSettings["ui.tvshows.disableUnwatchedEpisodeCount"]
if isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount) if isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount)
if itemData.json.UserData.UnplayedItemCount > 0 if itemData.json.UserData.UnplayedItemCount > 0
m.unplayedCount.visible = true m.unplayedCount.visible = true
@ -94,7 +95,7 @@ sub itemContentChanged() as void
imageUrl = itemData.posterURL imageUrl = itemData.posterURL
if m.global.session.user.settings["ui.tvshows.blurunwatched"] = true if userSettings["ui.tvshows.blurunwatched"]
if itemData.json.lookup("Type") = "Episode" and isValid(itemData.json.userdata) if itemData.json.lookup("Type") = "Episode" and isValid(itemData.json.userdata)
if not itemData.json.userdata.played if not itemData.json.userdata.played
imageUrl = imageUrl + "&blur=15" imageUrl = imageUrl + "&blur=15"
@ -116,7 +117,7 @@ sub focusChanged()
m.staticTitle.visible = false m.staticTitle.visible = false
m.title.visible = true m.title.visible = true
' text to speech for accessibility ' text to speech for accessibility
if m.global.device.isAudioGuideEnabled = true if m.global.device.isAudioGuideEnabled
txt2Speech = CreateObject("roTextToSpeech") txt2Speech = CreateObject("roTextToSpeech")
txt2Speech.Flush() txt2Speech.Flush()
txt2Speech.Say(m.title.text) txt2Speech.Say(m.title.text)

View File

@ -8,7 +8,7 @@ end sub
sub PlaystateUpdate() sub PlaystateUpdate()
if m.top.status = "start" if m.top.status = "start"
url = "Sessions/Playing" url = "Sessions/Playing"
else if m.top.status = "stop" else if m.top.status = "stop" or m.top.status = "finished"
url = "Sessions/Playing/Stopped" url = "Sessions/Playing/Stopped"
else if m.top.status = "update" else if m.top.status = "update"
url = "Sessions/Playing/Progress" url = "Sessions/Playing/Progress"

View File

@ -1,11 +1,12 @@
sub init() sub init()
m.content = m.top.findNode("content") m.content = m.top.findNode("content")
appVersion = m.global.app.version
setPalette() setPalette()
m.top.id = "OKDialog" m.top.id = "OKDialog"
m.top.height = 900 m.top.height = 900
m.top.title = tr("Welcome to version") + " " + m.global.app.version m.top.title = tr("Welcome to version") + " " + appVersion
m.top.buttons = [tr("OK")] m.top.buttons = [tr("OK")]
dialogStyles = { dialogStyles = {
@ -27,7 +28,7 @@ sub init()
textLine = m.content.CreateChild("StdDlgMultiStyleTextItem") textLine = m.content.CreateChild("StdDlgMultiStyleTextItem")
textLine.drawingStyles = dialogStyles textLine.drawingStyles = dialogStyles
textLine.text = tr("To view a complete list of changes visit") + " <url>https://github.com/jellyfin/jellyfin-roku/releases/tag/v" + m.global.app.version + "</url>" textLine.text = tr("To view a complete list of changes visit") + " <url>https://github.com/jellyfin/jellyfin-roku/releases/tag/v" + appVersion + "</url>"
end sub end sub
sub setPalette() sub setPalette()

View File

@ -1,7 +1,9 @@
import "pkg:/source/utils/config.bs" import "pkg:/source/utils/config.bs"
import "pkg:/source/api/baserequest.bs" import "pkg:/source/api/baserequest.bs"
import "pkg:/source/roku_modules/log/LogMixin.brs"
sub init() sub init()
m.log = log.Logger("captionTask")
m.top.observeField("url", "fetchCaption") m.top.observeField("url", "fetchCaption")
m.top.currentCaption = [] m.top.currentCaption = []
m.top.currentPos = 0 m.top.currentPos = 0
@ -41,17 +43,26 @@ sub setFont()
end sub end sub
sub fetchCaption() sub fetchCaption()
m.log.debug("start fetchCaption()")
m.captionTimer.control = "stop" m.captionTimer.control = "stop"
re = CreateObject("roRegex", "(http.*?\.vtt)", "s") re = CreateObject("roRegex", "(http.*?\.vtt)", "s")
url = re.match(m.top.url)[0] url = re.match(m.top.url)[0]
if url <> invalid if url <> invalid
port = createObject("roMessagePort")
m.reader.setUrl(url) m.reader.setUrl(url)
text = m.reader.GetToString() m.reader.setMessagePort(port)
m.captionList = parseVTT(text) if m.reader.AsyncGetToString()
m.captionTimer.control = "start" msg = port.waitMessage(0)
if type(msg) = "roUrlEvent"
m.captionList = parseVTT(msg.GetString())
m.captionTimer.control = "start"
end if
end if
else else
m.captionTimer.control = "stop" m.captionTimer.control = "stop"
end if end if
m.log.debug("end fetchCaption()", url)
end sub end sub
function newlabel(txt) function newlabel(txt)

View File

@ -5,7 +5,11 @@ import "pkg:/source/utils/config.bs"
sub setFields() sub setFields()
json = m.top.json json = m.top.json
m.top.id = json.id m.top.id = json.id
m.top.title = json.name if isValid(json.number)
m.top.title = `${tr("CH")} ${json.number} ${json.name}`
else
m.top.title = json.name
end if
m.top.live = true m.top.live = true
m.top.Type = "TvChannel" m.top.Type = "TvChannel"
setPoster() setPoster()

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<component name="ChannelData" extends="JFContentItem"> <component name="ChannelData" extends="JFContentItem">
<interface> <interface>
<field id="image" type="node" onChange="setPoster" />
<field id="channelID" type="string" /> <field id="channelID" type="string" />
<field id="selectedAudioStreamIndex" type="integer" value="0" /> <field id="selectedAudioStreamIndex" type="integer" value="0" />
</interface> </interface>

View File

@ -60,6 +60,7 @@ sub setData()
end if end if
else if datum.type = "Series" else if datum.type = "Series"
m.top.isWatched = datum.UserData.Played
imgParams = { "maxHeight": 261 } imgParams = { "maxHeight": 261 }
imgParams.Append({ "maxWidth": 464 }) imgParams.Append({ "maxWidth": 464 })

View File

@ -4,9 +4,12 @@ import "pkg:/source/utils/config.bs"
sub setFields() sub setFields()
json = m.top.json json = m.top.json
m.top.Type = "Person"
if json = invalid then return
m.top.id = json.id m.top.id = json.id
m.top.favorite = json.UserData.isFavorite m.top.favorite = json.UserData.isFavorite
m.top.Type = "Person"
setPoster() setPoster()
end sub end sub

View File

@ -35,6 +35,7 @@ sub updateSize()
end sub end sub
sub loadParts(data as object) sub loadParts(data as object)
m.extrasGrp = m.top.getParent().findNode("extrasGrp")
m.top.parentId = data.id m.top.parentId = data.id
m.people = data.People m.people = data.People
m.LoadAdditionalPartsTask.itemId = m.top.parentId m.LoadAdditionalPartsTask.itemId = m.top.parentId
@ -42,6 +43,7 @@ sub loadParts(data as object)
end sub end sub
sub loadPersonVideos(personId) sub loadPersonVideos(personId)
m.extrasGrp = m.top.getParent().findNode("extrasGrp")
m.personId = personId m.personId = personId
m.LoadMoviesTask.itemId = m.personId m.LoadMoviesTask.itemId = m.personId
m.LoadMoviesTask.observeField("content", "onMoviesLoaded") m.LoadMoviesTask.observeField("content", "onMoviesLoaded")
@ -114,7 +116,7 @@ sub onLikeThisLoaded()
m.SpecialFeaturesTask.control = "RUN" m.SpecialFeaturesTask.control = "RUN"
end sub end sub
function onSpecialFeaturesLoaded() sub onSpecialFeaturesLoaded()
data = m.SpecialFeaturesTask.content data = m.SpecialFeaturesTask.content
m.SpecialFeaturesTask.unobserveField("content") m.SpecialFeaturesTask.unobserveField("content")
if data <> invalid and data.count() > 0 if data <> invalid and data.count() > 0
@ -132,8 +134,8 @@ function onSpecialFeaturesLoaded()
addRowSize([462, 372]) addRowSize([462, 372])
end if end if
return m.top.content showOrHideMe()
end function end sub
sub onMoviesLoaded() sub onMoviesLoaded()
data = m.LoadMoviesTask.content data = m.LoadMoviesTask.content
@ -179,6 +181,8 @@ sub onSeriesLoaded()
m.top.content.appendChild(row) m.top.content.appendChild(row)
end if end if
m.top.visible = true m.top.visible = true
showOrHideMe()
end sub end sub
function buildRow(rowTitle as string, items, imgWdth = 0) function buildRow(rowTitle as string, items, imgWdth = 0)
@ -218,6 +222,17 @@ sub addRowSize(newRow)
m.top.rowItemSize = newSizeArray m.top.rowItemSize = newSizeArray
end sub end sub
' don't show popup panel if there is nothing to show
sub showOrHideMe()
if isValid(m.top.content)
if m.top.content.getChildCount() = 0
m.extrasGrp.visible = false
else
m.extrasGrp.visible = true
end if
end if
end sub
sub onRowItemSelected() sub onRowItemSelected()
m.top.selectedItem = m.top.content.getChild(m.top.rowItemSelected[0]).getChild(m.top.rowItemSelected[1]) m.top.selectedItem = m.top.content.getChild(m.top.rowItemSelected[0]).getChild(m.top.rowItemSelected[1])
end sub end sub

View File

@ -10,22 +10,22 @@ sub init()
initItemPoster() initItemPoster()
m.itemProgress = m.top.findNode("progress") m.itemProgress = m.top.findNode("progress")
m.itemProgressBackground = m.top.findNode("progressBackground") m.itemProgressBackground = m.top.findNode("progressBackground")
m.itemIcon = m.top.findNode("itemIcon") initItemIcon()
initItemTextExtra() initItemTextExtra()
m.itemPoster.observeField("loadStatus", "onPosterLoadStatusChanged") m.itemPoster.observeField("loadStatus", "onPosterLoadStatusChanged")
m.unplayedCount = m.top.findNode("unplayedCount") m.unplayedCount = m.top.findNode("unplayedCount")
m.unplayedEpisodeCount = m.top.findNode("unplayedEpisodeCount") m.unplayedEpisodeCount = m.top.findNode("unplayedEpisodeCount")
m.playedIndicator = m.top.findNode("playedIndicator") initPlayedIndicator()
m.showProgressBarAnimation = m.top.findNode("showProgressBar") m.showProgressBarAnimation = m.top.findNode("showProgressBar")
m.showProgressBarField = m.top.findNode("showProgressBarField") m.showProgressBarField = m.top.findNode("showProgressBarField")
' Randomize the background colors ' Randomize the background colors
backdropColor = "#00a4db" ' set default in case global var is invalid backdropColor = "#00a4db" ' set default in case global var is invalid
localGlobal = m.global myGlobal = m.global
if isValid(localGlobal) and isValid(localGlobal.constants) and isValid(localGlobal.constants.poster_bg_pallet) if isValid(myGlobal) and isValid(myGlobal.constants) and isValid(myGlobal.constants.poster_bg_pallet)
posterBackgrounds = localGlobal.constants.poster_bg_pallet posterBackgrounds = myGlobal.constants.poster_bg_pallet
backdropColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1] backdropColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1]
end if end if
@ -50,11 +50,19 @@ sub initBackdrop()
m.backdrop = m.top.findNode("backdrop") m.backdrop = m.top.findNode("backdrop")
end sub end sub
sub initItemIcon()
m.itemIcon = m.top.findNode("itemIcon")
end sub
sub initPlayedIndicator()
m.playedIndicator = m.top.findNode("playedIndicator")
end sub
sub itemContentChanged() sub itemContentChanged()
if isValid(m.unplayedCount) then m.unplayedCount.visible = false if isValid(m.unplayedCount) then m.unplayedCount.visible = false
itemData = m.top.itemContent itemData = m.top.itemContent
if itemData = invalid then return if itemData = invalid then return
localGlobal = m.global userSettings = m.global.session.user.settings
itemData.Title = itemData.name ' Temporarily required while we move from "HomeItem" to "JFContentItem" itemData.Title = itemData.name ' Temporarily required while we move from "HomeItem" to "JFContentItem"
@ -63,15 +71,17 @@ sub itemContentChanged()
if not isValid(m.itemText) then initItemText() if not isValid(m.itemText) then initItemText()
if not isValid(m.itemTextExtra) then initItemTextExtra() if not isValid(m.itemTextExtra) then initItemTextExtra()
if not isValid(m.backdrop) then initBackdrop() if not isValid(m.backdrop) then initBackdrop()
if not isValid(m.itemIcon) then initItemIcon()
if not isValid(m.playedIndicator) then initPlayedIndicator()
m.itemPoster.width = itemData.imageWidth m.itemPoster.width = itemData.imageWidth
m.itemText.maxWidth = itemData.imageWidth m.itemText.maxWidth = itemData.imageWidth
m.itemTextExtra.width = itemData.imageWidth m.itemTextExtra.width = itemData.imageWidth
m.itemTextExtra.visible = true m.itemTextExtra.visible = true
m.itemTextExtra.text = "" m.itemTextExtra.text = ""
m.backdrop.width = itemData.imageWidth m.backdrop.width = itemData.imageWidth
if isValid(itemData.iconUrl) if isValid(itemData.iconUrl)
m.itemIcon.uri = itemData.iconUrl m.itemIcon.uri = itemData.iconUrl
end if end if
@ -82,12 +92,15 @@ sub itemContentChanged()
m.playedIndicator.visible = false m.playedIndicator.visible = false
if LCase(itemData.type) = "series" if LCase(itemData.type) = "series"
if isValid(localGlobal) and isValid(localGlobal.session) and isValid(localGlobal.session.user) and isValid(localGlobal.session.user.settings) if isValid(userSettings)
if not localGlobal.session.user.settings["ui.tvshows.disableUnwatchedEpisodeCount"] unwatchedEpisodeCountSetting = userSettings["ui.tvshows.disableUnwatchedEpisodeCount"]
if isValid(unwatchedEpisodeCountSetting) and not unwatchedEpisodeCountSetting
if isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount) if isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount)
if itemData.json.UserData.UnplayedItemCount > 0 if itemData.json.UserData.UnplayedItemCount > 0
if isValid(m.unplayedCount) then m.unplayedCount.visible = true if isValid(m.unplayedCount) then m.unplayedCount.visible = true
m.unplayedEpisodeCount.text = itemData.json.UserData.UnplayedItemCount if isValid(m.unplayedEpisodeCount)
m.unplayedEpisodeCount.text = itemData.json.UserData.UnplayedItemCount
end if
end if end if
end if end if
end if end if
@ -151,16 +164,16 @@ sub itemContentChanged()
drawProgressBar(itemData) drawProgressBar(itemData)
end if end if
if localGlobal.session.user.settings["ui.general.episodeimagesnextup"] = "webclient" if userSettings["ui.general.episodeimagesnextup"] = "webclient"
tmpSetting = localGlobal.session.user.Configuration.useEpisodeImagesInNextUpAndResume tmpSetting = m.global.session.user.Configuration.useEpisodeImagesInNextUpAndResume
if isValid(tmpSetting) and tmpSetting if isValid(tmpSetting) and tmpSetting
m.itemPoster.uri = itemData.thumbnailURL m.itemPoster.uri = itemData.thumbnailURL
else else
m.itemPoster.uri = itemData.widePosterURL m.itemPoster.uri = itemData.widePosterURL
end if end if
else if localGlobal.session.user.settings["ui.general.episodeimagesnextup"] = "show" else if userSettings["ui.general.episodeimagesnextup"] = "show"
m.itemPoster.uri = itemData.widePosterURL m.itemPoster.uri = itemData.widePosterURL
else if localGlobal.session.user.settings["ui.general.episodeimagesnextup"] = "episode" else if userSettings["ui.general.episodeimagesnextup"] = "episode"
m.itemPoster.uri = itemData.thumbnailURL m.itemPoster.uri = itemData.thumbnailURL
end if end if

View File

@ -82,10 +82,11 @@ sub processUserSections()
m.processedRowCount = 0 m.processedRowCount = 0
sessionUser = m.global.session.user sessionUser = m.global.session.user
userSettings = sessionUser.settings
' calculate expected row count by processing homesections ' calculate expected row count by processing homesections
for i = 0 to 6 for i = 0 to 6
userSection = sessionUser.settings["homesection" + i.toStr()] userSection = userSettings["homesection" + i.toStr()]
sectionName = userSection ?? "none" sectionName = userSection ?? "none"
sectionName = LCase(sectionName) sectionName = LCase(sectionName)
@ -105,7 +106,7 @@ sub processUserSections()
' Add home sections in order based on user settings ' Add home sections in order based on user settings
loadedSections = 0 loadedSections = 0
for i = 0 to 6 for i = 0 to 6
userSection = sessionUser.settings["homesection" + i.toStr()] userSection = userSettings["homesection" + i.toStr()]
sectionName = userSection ?? "none" sectionName = userSection ?? "none"
sectionName = LCase(sectionName) sectionName = LCase(sectionName)
@ -155,10 +156,10 @@ function getOriginalSectionIndex(sectionName as string) as integer
sectionIndex = 0 sectionIndex = 0
indexLatestMediaSection = 0 indexLatestMediaSection = 0
sessionUser = m.global.session.user userSettings = m.global.session.user.settings
for i = 0 to 6 for i = 0 to 6
userSection = sessionUser.settings["homesection" + i.toStr()] userSection = userSettings["homesection" + i.toStr()]
settingSectionName = userSection ?? "none" settingSectionName = userSection ?? "none"
settingSectionName = LCase(settingSectionName) settingSectionName = LCase(settingSectionName)
@ -692,6 +693,7 @@ end sub
sub itemSelected() sub itemSelected()
m.selectedRowItem = m.top.rowItemSelected m.selectedRowItem = m.top.rowItemSelected
m.global.launchSource = "home"
m.top.selectedItem = m.top.content.getChild(m.top.rowItemSelected[0]).getChild(m.top.rowItemSelected[1]) m.top.selectedItem = m.top.content.getChild(m.top.rowItemSelected[0]).getChild(m.top.rowItemSelected[1])
'Prevent the selected item event from double firing 'Prevent the selected item event from double firing

View File

@ -60,6 +60,7 @@ sub loadItems()
' Load Next Up ' Load Next Up
else if m.top.itemsToLoad = "nextUp" else if m.top.itemsToLoad = "nextUp"
userSettings = m.global.session.user.settings
url = "Shows/NextUp" url = "Shows/NextUp"
params = {} params = {}
@ -68,12 +69,13 @@ sub loadItems()
params["SortOrder"] = "Descending" params["SortOrder"] = "Descending"
params["ImageTypeLimit"] = 1 params["ImageTypeLimit"] = 1
params["UserId"] = m.global.session.user.id params["UserId"] = m.global.session.user.id
params["EnableRewatching"] = m.global.session.user.settings["ui.details.enablerewatchingnextup"] params["EnableRewatching"] = userSettings["ui.details.enablerewatchingnextup"]
params["DisableFirstEpisode"] = false params["DisableFirstEpisode"] = false
params["limit"] = 24 params["limit"] = 24
params["EnableTotalRecordCount"] = false params["EnableTotalRecordCount"] = false
params["EnableResumable"] = false
maxDaysInNextUp = m.global.session.user.settings["ui.details.maxdaysnextup"].ToInt() maxDaysInNextUp = userSettings["ui.details.maxdaysnextup"].ToInt()
if isValid(maxDaysInNextUp) if isValid(maxDaysInNextUp)
if maxDaysInNextUp > 0 if maxDaysInNextUp > 0
dateToday = CreateObject("roDateTime") dateToday = CreateObject("roDateTime")

View File

@ -58,9 +58,9 @@ sub onSelectAudioPressed()
audioData.data.push(audioStreamItem) audioData.data.push(audioStreamItem)
end for end for
sceneManager = m.global.sceneManager
m.global.sceneManager.callFunc("radioDialog", tr("Select Audio"), audioData) sceneManager.callFunc("radioDialog", tr("Select Audio"), audioData)
m.global.sceneManager.observeField("returnData", "onSelectionMade") sceneManager.observeField("returnData", "onSelectionMade")
end sub end sub
' User requested subtitle selection popup ' User requested subtitle selection popup
@ -110,23 +110,25 @@ sub onSelectSubtitlePressed()
"Type": "subtitleselection" "Type": "subtitleselection"
}) })
m.global.sceneManager.callFunc("radioDialog", tr("Select Subtitles"), subtitleData) sceneManager = m.global.sceneManager
m.global.sceneManager.observeField("returnData", "onSelectionMade") sceneManager.callFunc("radioDialog", tr("Select Subtitles"), subtitleData)
sceneManager.observeField("returnData", "onSelectionMade")
end sub end sub
' User has selected something from the radioDialog popup ' User has selected something from the radioDialog popup
sub onSelectionMade() sub onSelectionMade()
m.global.sceneManager.unobserveField("returnData") sceneManager = m.global.sceneManager
sceneManager.unobserveField("returnData")
if not isValid(m.global.sceneManager.returnData) then return if not isValid(sceneManager.returnData) then return
if not isValid(m.global.sceneManager.returnData.type) then return if not isValid(sceneManager.returnData.type) then return
if LCase(m.global.sceneManager.returnData.type) = "subtitleselection" if LCase(sceneManager.returnData.type) = "subtitleselection"
processSubtitleSelection() processSubtitleSelection()
return return
end if end if
if LCase(m.global.sceneManager.returnData.type) = "audioselection" if LCase(sceneManager.returnData.type) = "audioselection"
processAudioSelection() processAudioSelection()
return return
end if end if
@ -216,21 +218,24 @@ end sub
' Playback state change event handlers ' Playback state change event handlers
sub onStateChange() sub onStateChange()
if LCase(m.view.state) = "finished" if LCase(m.view.state) = "finished"
sceneManager = m.global.sceneManager
queueManager = m.global.queueManager
' Close any open dialogs ' Close any open dialogs
if m.global.sceneManager.callFunc("isDialogOpen") if sceneManager.callFunc("isDialogOpen")
m.global.sceneManager.callFunc("dismissDialog") sceneManager.callFunc("dismissDialog")
end if end if
' If there is something next in the queue, play it ' If there is something next in the queue, play it
if m.global.queueManager.callFunc("getPosition") < m.global.queueManager.callFunc("getCount") - 1 if queueManager.callFunc("getPosition") < queueManager.callFunc("getCount") - 1
m.global.sceneManager.callFunc("clearPreviousScene") sceneManager.callFunc("clearPreviousScene")
m.global.queueManager.callFunc("moveForward") queueManager.callFunc("moveForward")
m.global.queueManager.callFunc("playQueue") queueManager.callFunc("playQueue")
return return
end if end if
' Playback completed, return user to previous screen ' Playback completed, return user to previous screen
m.global.sceneManager.callFunc("popScene") sceneManager.callFunc("popScene")
m.global.audioPlayer.loopMode = "" m.global.audioPlayer.loopMode = ""
end if end if
end sub end sub

View File

@ -97,6 +97,7 @@ sub itemContentChanged()
' Updates video metadata ' Updates video metadata
item = m.top.itemContent item = m.top.itemContent
if isValid(item) and isValid(item.json) if isValid(item) and isValid(item.json)
userSettings = m.global.session.user.settings
itemData = item.json itemData = item.json
m.top.id = itemData.id m.top.id = itemData.id
m.top.findNode("moviePoster").uri = m.top.itemContent.posterURL m.top.findNode("moviePoster").uri = m.top.itemContent.posterURL
@ -120,7 +121,7 @@ sub itemContentChanged()
m.infoGroup.removeChild(m.top.findNode("officialRating")) m.infoGroup.removeChild(m.top.findNode("officialRating"))
end if end if
if m.global.session.user.settings["ui.movies.showRatings"] if userSettings["ui.movies.showRatings"]
if isValid(itemData.communityRating) if isValid(itemData.communityRating)
setFieldText("communityRating", int(itemData.communityRating * 10) / 10) setFieldText("communityRating", int(itemData.communityRating * 10) / 10)
else else
@ -145,7 +146,7 @@ sub itemContentChanged()
if type(itemData.RunTimeTicks) = "LongInteger" if type(itemData.RunTimeTicks) = "LongInteger"
setFieldText("runtime", stri(getRuntime()) + " mins") setFieldText("runtime", stri(getRuntime()) + " mins")
if m.global.session.user.settings["ui.design.hideclock"] <> true if userSettings["ui.design.hideclock"] <> true
setFieldText("ends-at", tr("Ends at %1").Replace("%1", getEndTime())) setFieldText("ends-at", tr("Ends at %1").Replace("%1", getEndTime()))
end if end if
end if end if
@ -173,7 +174,7 @@ sub itemContentChanged()
m.top.findNode("details").removeChild(m.top.findNode("director")) m.top.findNode("details").removeChild(m.top.findNode("director"))
end if end if
if m.global.session.user.settings["ui.details.hidetagline"] = false if userSettings["ui.details.hidetagline"] = false
if itemData.taglines.count() > 0 if itemData.taglines.count() > 0
setFieldText("tagline", itemData.taglines[0]) setFieldText("tagline", itemData.taglines[0])
end if end if
@ -402,7 +403,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
m.options.setFocus(true) m.options.setFocus(true)
end if end if
if key = "down" and m.buttonGrp.isInFocusChain() if key = "down" and m.buttonGrp.isInFocusChain() and m.extrasGrp.visible = true
m.top.lastFocus = m.extrasGrid m.top.lastFocus = m.extrasGrid
m.extrasGrid.setFocus(true) m.extrasGrid.setFocus(true)
m.top.findNode("VertSlider").reverse = false m.top.findNode("VertSlider").reverse = false

View File

@ -136,7 +136,7 @@ sub createFullDscrDlg()
dlg.Title = tr("Press 'Back' to Close") dlg.Title = tr("Press 'Back' to Close")
dlg.width = 1290 dlg.width = 1290
dlg.palette = m.dlgPalette dlg.palette = m.dlgPalette
dlg.overview = [m.dscr.text] dlg.overview = m.dscr.text
m.fullDscrDlg = dlg m.fullDscrDlg = dlg
m.top.getScene().dialog = dlg m.top.getScene().dialog = dlg
border = createObject("roSGNode", "Poster") border = createObject("roSGNode", "Poster")

View File

@ -223,7 +223,7 @@ sub createFullDscrDlg()
dlg.Title = tr("Press 'Back' to Close") dlg.Title = tr("Press 'Back' to Close")
dlg.width = 1290 dlg.width = 1290
dlg.palette = m.dlgPalette dlg.palette = m.dlgPalette
dlg.overview = [m.dscr.text] dlg.overview = m.dscr.text
m.fullDscrDlg = dlg m.fullDscrDlg = dlg
m.top.getScene().dialog = dlg m.top.getScene().dialog = dlg
border = createObject("roSGNode", "Poster") border = createObject("roSGNode", "Poster")

View File

@ -9,9 +9,14 @@ sub init()
m.lastRecordedPositionTimestamp = 0 m.lastRecordedPositionTimestamp = 0
m.scrubTimestamp = -1 m.scrubTimestamp = -1
m.playlistTypeCount = m.global.queueManager.callFunc("getQueueUniqueTypes").count() m.queueManager = m.global.queueManager
m.playlistTypeCount = m.queueManager.callFunc("getQueueUniqueTypes").count()
m.audioPlayer = m.global.audioPlayer
m.audioPlayer.observeField("state", "audioStateChanged")
m.audioPlayer.observeField("position", "audioPositionChanged")
m.audioPlayer.observeField("bufferingStatus", "bufferPositionChanged")
setupAudioNode()
setupAnimationTasks() setupAnimationTasks()
setupButtons() setupButtons()
setupInfoNodes() setupInfoNodes()
@ -91,13 +96,6 @@ sub setupDataTasks()
m.LoadScreenSaverTimeoutTask = CreateObject("roSGNode", "LoadScreenSaverTimeoutTask") m.LoadScreenSaverTimeoutTask = CreateObject("roSGNode", "LoadScreenSaverTimeoutTask")
end sub end sub
' Creates audio node used to play song(s)
sub setupAudioNode()
m.global.audioPlayer.observeField("state", "audioStateChanged")
m.global.audioPlayer.observeField("position", "audioPositionChanged")
m.global.audioPlayer.observeField("bufferingStatus", "bufferPositionChanged")
end sub
' Setup playback buttons, default to Play button selected ' Setup playback buttons, default to Play button selected
sub setupButtons() sub setupButtons()
m.buttons = m.top.findNode("buttons") m.buttons = m.top.findNode("buttons")
@ -149,10 +147,10 @@ end sub
sub bufferPositionChanged() sub bufferPositionChanged()
if m.inScrubMode then return if m.inScrubMode then return
if not isValid(m.global.audioPlayer.bufferingStatus) if not isValid(m.audioPlayer.bufferingStatus)
bufferPositionBarWidth = m.seekBar.width bufferPositionBarWidth = m.seekBar.width
else else
bufferPositionBarWidth = m.seekBar.width * m.global.audioPlayer.bufferingStatus.percentage bufferPositionBarWidth = m.seekBar.width * m.audioPlayer.bufferingStatus.percentage
end if end if
' Ensure position bar is never wider than the seek bar ' Ensure position bar is never wider than the seek bar
@ -168,16 +166,16 @@ end sub
sub audioPositionChanged() sub audioPositionChanged()
stopLoadingSpinner() stopLoadingSpinner()
if m.global.audioPlayer.position = 0 if m.audioPlayer.position = 0
m.playPosition.width = 0 m.playPosition.width = 0
end if end if
if not isValid(m.global.audioPlayer.position) if not isValid(m.audioPlayer.position)
playPositionBarWidth = 0 playPositionBarWidth = 0
else if not isValid(m.songDuration) else if not isValid(m.songDuration)
playPositionBarWidth = 0 playPositionBarWidth = 0
else else
songPercentComplete = m.global.audioPlayer.position / m.songDuration songPercentComplete = m.audioPlayer.position / m.songDuration
playPositionBarWidth = m.seekBar.width * songPercentComplete playPositionBarWidth = m.seekBar.width * songPercentComplete
end if end if
@ -189,7 +187,7 @@ sub audioPositionChanged()
if not m.inScrubMode if not m.inScrubMode
moveSeekbarThumb(playPositionBarWidth) moveSeekbarThumb(playPositionBarWidth)
' Change the seek position timestamp ' Change the seek position timestamp
m.seekTimestamp.text = secondsToHuman(m.global.audioPlayer.position, false) m.seekTimestamp.text = secondsToHuman(m.audioPlayer.position, false)
end if end if
' Use animation to make the display smooth ' Use animation to make the display smooth
@ -197,9 +195,9 @@ sub audioPositionChanged()
m.playPositionAnimation.control = "start" m.playPositionAnimation.control = "start"
' Update displayed position timestamp ' Update displayed position timestamp
if isValid(m.global.audioPlayer.position) if isValid(m.audioPlayer.position)
m.lastRecordedPositionTimestamp = m.global.audioPlayer.position m.lastRecordedPositionTimestamp = m.audioPlayer.position
m.positionTimestamp.text = secondsToHuman(m.global.audioPlayer.position, false) m.positionTimestamp.text = secondsToHuman(m.audioPlayer.position, false)
else else
m.lastRecordedPositionTimestamp = 0 m.lastRecordedPositionTimestamp = 0
m.positionTimestamp.text = "0:00" m.positionTimestamp.text = "0:00"
@ -247,25 +245,24 @@ sub endScreenSaver()
end sub end sub
sub audioStateChanged() sub audioStateChanged()
' Song Finished, attempt to move to next song ' Song Finished, attempt to move to next song
if m.global.audioPlayer.state = "finished" if m.audioPlayer.state = "finished"
' User has enabled single song loop, play current song again ' User has enabled single song loop, play current song again
if m.global.audioPlayer.loopMode = "one" if m.audioPlayer.loopMode = "one"
m.scrubTimestamp = -1 m.scrubTimestamp = -1
playAction() playAction()
exitScrubMode() exitScrubMode()
return return
end if end if
if m.global.queueManager.callFunc("getPosition") < m.global.queueManager.callFunc("getCount") - 1 if m.queueManager.callFunc("getPosition") < m.queueManager.callFunc("getCount") - 1
m.top.state = "finished" m.top.state = "finished"
else else
' We are at the end of the song queue ' We are at the end of the song queue
' User has enabled loop for entire song queue, move back to first song ' User has enabled loop for entire song queue, move back to first song
if m.global.audioPlayer.loopMode = "all" if m.audioPlayer.loopMode = "all"
m.global.queueManager.callFunc("setPosition", -1) m.queueManager.callFunc("setPosition", -1)
LoadNextSong() LoadNextSong()
return return
end if end if
@ -277,18 +274,19 @@ sub audioStateChanged()
end sub end sub
function playAction() as boolean function playAction() as boolean
if m.global.audioPlayer.state = "playing"
m.global.audioPlayer.control = "pause" if m.audioPlayer.state = "playing"
m.audioPlayer.control = "pause"
' Allow screen to go to real screensaver ' Allow screen to go to real screensaver
WriteAsciiFile("tmp:/scene.temp", "nowplaying-paused") WriteAsciiFile("tmp:/scene.temp", "nowplaying-paused")
MoveFile("tmp:/scene.temp", "tmp:/scene") MoveFile("tmp:/scene.temp", "tmp:/scene")
else if m.global.audioPlayer.state = "paused" else if m.audioPlayer.state = "paused"
m.global.audioPlayer.control = "resume" m.audioPlayer.control = "resume"
' Write screen tracker for screensaver ' Write screen tracker for screensaver
WriteAsciiFile("tmp:/scene.temp", "nowplaying") WriteAsciiFile("tmp:/scene.temp", "nowplaying")
MoveFile("tmp:/scene.temp", "tmp:/scene") MoveFile("tmp:/scene.temp", "tmp:/scene")
else if m.global.audioPlayer.state = "finished" else if m.audioPlayer.state = "finished"
m.global.audioPlayer.control = "play" m.audioPlayer.control = "play"
' Write screen tracker for screensaver ' Write screen tracker for screensaver
WriteAsciiFile("tmp:/scene.temp", "nowplaying") WriteAsciiFile("tmp:/scene.temp", "nowplaying")
MoveFile("tmp:/scene.temp", "tmp:/scene") MoveFile("tmp:/scene.temp", "tmp:/scene")
@ -298,20 +296,19 @@ function playAction() as boolean
end function end function
function previousClicked() as boolean function previousClicked() as boolean
currentQueuePosition = m.global.queueManager.callFunc("getPosition") currentQueuePosition = m.queueManager.callFunc("getPosition")
if currentQueuePosition = 0 then return false if currentQueuePosition = 0 then return false
if m.playlistTypeCount > 1 if m.playlistTypeCount > 1
previousItem = m.global.queueManager.callFunc("getItemByIndex", currentQueuePosition - 1) previousItem = m.queueManager.callFunc("getItemByIndex", currentQueuePosition - 1)
previousItemType = m.global.queueManager.callFunc("getItemType", previousItem) previousItemType = m.queueManager.callFunc("getItemType", previousItem)
if previousItemType <> "audio" if previousItemType <> "audio"
m.global.audioPlayer.control = "stop" m.audioPlayer.control = "stop"
m.global.sceneManager.callFunc("clearPreviousScene") m.global.sceneManager.callFunc("clearPreviousScene")
m.global.queueManager.callFunc("moveBack") m.queueManager.callFunc("moveBack")
m.global.queueManager.callFunc("playQueue") m.queueManager.callFunc("playQueue")
return true return true
end if end if
end if end if
@ -321,34 +318,33 @@ function previousClicked() as boolean
m.lastRecordedPositionTimestamp = 0 m.lastRecordedPositionTimestamp = 0
m.positionTimestamp.text = "0:00" m.positionTimestamp.text = "0:00"
if m.global.audioPlayer.state = "playing" if m.audioPlayer.state = "playing"
m.global.audioPlayer.control = "stop" m.audioPlayer.control = "stop"
end if end if
' Reset loop mode due to manual user interaction ' Reset loop mode due to manual user interaction
if m.global.audioPlayer.loopMode = "one" if m.audioPlayer.loopMode = "one"
resetLoopModeToDefault() resetLoopModeToDefault()
end if end if
m.global.queueManager.callFunc("moveBack") m.queueManager.callFunc("moveBack")
pageContentChanged() pageContentChanged()
return true return true
end function end function
sub resetLoopModeToDefault() sub resetLoopModeToDefault()
m.global.audioPlayer.loopMode = "" m.audioPlayer.loopMode = ""
setLoopButtonImage() setLoopButtonImage()
end sub end sub
function loopClicked() as boolean function loopClicked() as boolean
if m.audioPlayer.loopMode = ""
if m.global.audioPlayer.loopMode = "" m.audioPlayer.loopMode = "all"
m.global.audioPlayer.loopMode = "all" else if m.audioPlayer.loopMode = "all"
else if m.global.audioPlayer.loopMode = "all" m.audioPlayer.loopMode = "one"
m.global.audioPlayer.loopMode = "one"
else else
m.global.audioPlayer.loopMode = "" m.audioPlayer.loopMode = ""
end if end if
setLoopButtonImage() setLoopButtonImage()
@ -357,10 +353,10 @@ function loopClicked() as boolean
end function end function
sub setLoopButtonImage() sub setLoopButtonImage()
if m.global.audioPlayer.loopMode = "all" if m.audioPlayer.loopMode = "all"
m.loopIndicator.opacity = "1" m.loopIndicator.opacity = "1"
m.loopIndicator.uri = m.loopIndicator.uri.Replace("-off", "-on") m.loopIndicator.uri = m.loopIndicator.uri.Replace("-off", "-on")
else if m.global.audioPlayer.loopMode = "one" else if m.audioPlayer.loopMode = "one"
m.loopIndicator.uri = m.loopIndicator.uri.Replace("-on", "1-on") m.loopIndicator.uri = m.loopIndicator.uri.Replace("-on", "1-on")
else else
m.loopIndicator.uri = m.loopIndicator.uri.Replace("1-on", "-off") m.loopIndicator.uri = m.loopIndicator.uri.Replace("1-on", "-off")
@ -368,19 +364,20 @@ sub setLoopButtonImage()
end sub end sub
function nextClicked() as boolean function nextClicked() as boolean
if m.playlistTypeCount > 1
currentQueuePosition = m.global.queueManager.callFunc("getPosition")
if currentQueuePosition < m.global.queueManager.callFunc("getCount") - 1
nextItem = m.global.queueManager.callFunc("getItemByIndex", currentQueuePosition + 1) if m.playlistTypeCount > 1
nextItemType = m.global.queueManager.callFunc("getItemType", nextItem) currentQueuePosition = m.queueManager.callFunc("getPosition")
if currentQueuePosition < m.queueManager.callFunc("getCount") - 1
nextItem = m.queueManager.callFunc("getItemByIndex", currentQueuePosition + 1)
nextItemType = m.queueManager.callFunc("getItemType", nextItem)
if nextItemType <> "audio" if nextItemType <> "audio"
m.global.audioPlayer.control = "stop" m.audioPlayer.control = "stop"
m.global.sceneManager.callFunc("clearPreviousScene") m.global.sceneManager.callFunc("clearPreviousScene")
m.global.queueManager.callFunc("moveForward") m.queueManager.callFunc("moveForward")
m.global.queueManager.callFunc("playQueue") m.queueManager.callFunc("playQueue")
return true return true
end if end if
end if end if
@ -392,11 +389,11 @@ function nextClicked() as boolean
m.positionTimestamp.text = "0:00" m.positionTimestamp.text = "0:00"
' Reset loop mode due to manual user interaction ' Reset loop mode due to manual user interaction
if m.global.audioPlayer.loopMode = "one" if m.audioPlayer.loopMode = "one"
resetLoopModeToDefault() resetLoopModeToDefault()
end if end if
if m.global.queueManager.callFunc("getPosition") < m.global.queueManager.callFunc("getCount") - 1 if m.queueManager.callFunc("getPosition") < m.queueManager.callFunc("getCount") - 1
LoadNextSong() LoadNextSong()
end if end if
@ -404,14 +401,14 @@ function nextClicked() as boolean
end function end function
sub toggleShuffleEnabled() sub toggleShuffleEnabled()
m.global.queueManager.callFunc("toggleShuffle") m.queueManager.callFunc("toggleShuffle")
end sub end sub
function findCurrentSongIndex(songList) as integer function findCurrentSongIndex(songList) as integer
if not isValidAndNotEmpty(songList) then return 0 if not isValidAndNotEmpty(songList) then return 0
for i = 0 to songList.count() - 1 for i = 0 to songList.count() - 1
if songList[i].id = m.global.queueManager.callFunc("getCurrentItem").id if songList[i].id = m.queueManager.callFunc("getCurrentItem").id
return i return i
end if end if
end for end for
@ -420,15 +417,14 @@ function findCurrentSongIndex(songList) as integer
end function end function
function shuffleClicked() as boolean function shuffleClicked() as boolean
currentSongIndex = findCurrentSongIndex(m.queueManager.callFunc("getUnshuffledQueue"))
currentSongIndex = findCurrentSongIndex(m.global.queueManager.callFunc("getUnshuffledQueue"))
toggleShuffleEnabled() toggleShuffleEnabled()
if not m.global.queueManager.callFunc("getIsShuffled") if not m.queueManager.callFunc("getIsShuffled")
m.shuffleIndicator.opacity = ".4" m.shuffleIndicator.opacity = ".4"
m.shuffleIndicator.uri = m.shuffleIndicator.uri.Replace("-on", "-off") m.shuffleIndicator.uri = m.shuffleIndicator.uri.Replace("-on", "-off")
m.global.queueManager.callFunc("setPosition", currentSongIndex) m.queueManager.callFunc("setPosition", currentSongIndex)
setTrackNumberDisplay() setTrackNumberDisplay()
return true return true
end if end if
@ -441,26 +437,26 @@ function shuffleClicked() as boolean
end function end function
sub setShuffleIconState() sub setShuffleIconState()
if m.global.queueManager.callFunc("getIsShuffled") if m.queueManager.callFunc("getIsShuffled")
m.shuffleIndicator.opacity = "1" m.shuffleIndicator.opacity = "1"
m.shuffleIndicator.uri = m.shuffleIndicator.uri.Replace("-off", "-on") m.shuffleIndicator.uri = m.shuffleIndicator.uri.Replace("-off", "-on")
end if end if
end sub end sub
sub setTrackNumberDisplay() sub setTrackNumberDisplay()
setFieldTextValue("numberofsongs", "Track " + stri(m.global.queueManager.callFunc("getPosition") + 1) + "/" + stri(m.global.queueManager.callFunc("getCount"))) setFieldTextValue("numberofsongs", "Track " + stri(m.queueManager.callFunc("getPosition") + 1) + "/" + stri(m.queueManager.callFunc("getCount")))
end sub end sub
sub LoadNextSong() sub LoadNextSong()
if m.global.audioPlayer.state = "playing" if m.audioPlayer.state = "playing"
m.global.audioPlayer.control = "stop" m.audioPlayer.control = "stop"
end if end if
exitScrubMode() exitScrubMode()
' Reset playPosition bar without animation ' Reset playPosition bar without animation
m.playPosition.width = 0 m.playPosition.width = 0
m.global.queueManager.callFunc("moveForward") m.queueManager.callFunc("moveForward")
pageContentChanged() pageContentChanged()
end sub end sub
@ -469,7 +465,7 @@ sub pageContentChanged()
m.LoadAudioStreamTask.control = "STOP" m.LoadAudioStreamTask.control = "STOP"
currentItem = m.global.queueManager.callFunc("getCurrentItem") currentItem = m.queueManager.callFunc("getCurrentItem")
m.LoadAudioStreamTask.itemId = currentItem.id m.LoadAudioStreamTask.itemId = currentItem.id
m.LoadAudioStreamTask.observeField("content", "onAudioStreamLoaded") m.LoadAudioStreamTask.observeField("content", "onAudioStreamLoaded")
@ -478,7 +474,7 @@ end sub
' If we have more and 1 song to play, fade in the next and previous controls ' If we have more and 1 song to play, fade in the next and previous controls
sub loadButtons() sub loadButtons()
if m.global.queueManager.callFunc("getCount") > 1 if m.queueManager.callFunc("getCount") > 1
m.shuffleIndicator.opacity = ".4" m.shuffleIndicator.opacity = ".4"
m.loopIndicator.opacity = ".4" m.loopIndicator.opacity = ".4"
m.displayButtonsAnimation.control = "start" m.displayButtonsAnimation.control = "start"
@ -495,7 +491,7 @@ sub onAudioStreamLoaded()
m.bufferPosition.width = 0 m.bufferPosition.width = 0
useMetaTask = false useMetaTask = false
currentItem = m.global.queueManager.callFunc("getCurrentItem") currentItem = m.queueManager.callFunc("getCurrentItem")
if not isValid(currentItem.RunTimeTicks) if not isValid(currentItem.RunTimeTicks)
useMetaTask = true useMetaTask = true
@ -531,9 +527,9 @@ sub onAudioStreamLoaded()
m.totalLengthTimestamp.text = ticksToHuman(currentItem.RunTimeTicks) m.totalLengthTimestamp.text = ticksToHuman(currentItem.RunTimeTicks)
end if end if
m.global.audioPlayer.content = data m.audioPlayer.content = data
m.global.audioPlayer.control = "none" m.audioPlayer.control = "none"
m.global.audioPlayer.control = "play" m.audioPlayer.control = "play"
end if end if
end sub end sub
@ -739,7 +735,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
if m.inScrubMode if m.inScrubMode
startLoadingSpinner() startLoadingSpinner()
m.inScrubMode = false m.inScrubMode = false
m.global.audioPlayer.seek = m.scrubTimestamp m.audioPlayer.seek = m.scrubTimestamp
return true return true
end if end if
@ -773,15 +769,15 @@ function onKeyEvent(key as string, press as boolean) as boolean
end if end if
if key = "back" if key = "back"
m.global.audioPlayer.control = "stop" m.audioPlayer.control = "stop"
m.global.audioPlayer.loopMode = "" m.audioPlayer.loopMode = ""
else if key = "rewind" else if key = "rewind"
return previousClicked() return previousClicked()
else if key = "fastforward" else if key = "fastforward"
return nextClicked() return nextClicked()
else if key = "left" else if key = "left"
if m.buttons.hasFocus() if m.buttons.hasFocus()
if m.global.queueManager.callFunc("getCount") = 1 then return false if m.queueManager.callFunc("getCount") = 1 then return false
if m.top.selectedButtonIndex > 0 if m.top.selectedButtonIndex > 0
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
@ -791,7 +787,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
end if end if
else if key = "right" else if key = "right"
if m.buttons.hasFocus() if m.buttons.hasFocus()
if m.global.queueManager.callFunc("getCount") = 1 then return false if m.queueManager.callFunc("getCount") = 1 then return false
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
if m.top.selectedButtonIndex < m.buttonCount - 1 then m.top.selectedButtonIndex = m.top.selectedButtonIndex + 1 if m.top.selectedButtonIndex < m.buttonCount - 1 then m.top.selectedButtonIndex = m.top.selectedButtonIndex + 1

View File

@ -127,7 +127,7 @@ sub createFullDscrDlg()
dlg.Title = tr("Press 'Back' to Close") dlg.Title = tr("Press 'Back' to Close")
dlg.width = 1290 dlg.width = 1290
dlg.palette = m.dlgPalette dlg.palette = m.dlgPalette
dlg.overview = [m.dscr.text] dlg.overview = m.dscr.text
m.fullDscrDlg = dlg m.fullDscrDlg = dlg
m.top.getScene().dialog = dlg m.top.getScene().dialog = dlg
border = createObject("roSGNode", "Poster") border = createObject("roSGNode", "Poster")

View File

@ -10,8 +10,9 @@ sub init()
m.textBackground = m.top.findNode("background") m.textBackground = m.top.findNode("background")
m.statusTimer = m.top.findNode("statusTimer") m.statusTimer = m.top.findNode("statusTimer")
m.statusTimer.observeField("fire", "statusUpdate") m.statusTimer.observeField("fire", "statusUpdate")
m.slideshow = m.global.session.user.settings["photos.slideshow"] userSettings = m.global.session.user.settings
m.random = m.global.session.user.settings["photos.random"] m.slideshow = userSettings["photos.slideshow"]
m.random = userSettings["photos.random"]
m.showStatusAnimation = m.top.findNode("showStatusAnimation") m.showStatusAnimation = m.top.findNode("showStatusAnimation")
m.hideStatusAnimation = m.top.findNode("hideStatusAnimation") m.hideStatusAnimation = m.top.findNode("hideStatusAnimation")

View File

@ -91,26 +91,28 @@ sub settingFocused()
m.integerSetting.visible = false m.integerSetting.visible = false
m.radioSetting.visible = false m.radioSetting.visible = false
userSettings = m.global.session.user.settings
if selectedSetting.type = invalid if selectedSetting.type = invalid
return return
else if selectedSetting.type = "bool" else if selectedSetting.type = "bool"
m.boolSetting.visible = true m.boolSetting.visible = true
if m.global.session.user.settings[selectedSetting.settingName] = true if userSettings[selectedSetting.settingName] = true
m.boolSetting.checkedItem = 1 m.boolSetting.checkedItem = 1
else else
m.boolSetting.checkedItem = 0 m.boolSetting.checkedItem = 0
end if end if
else if selectedSetting.type = "integer" else if selectedSetting.type = "integer"
integerValue = m.global.session.user.settings[selectedSetting.settingName].ToStr() integerValue = userSettings[selectedSetting.settingName].ToStr()
if isValid(integerValue) if isValid(integerValue)
m.integerSetting.text = integerValue m.integerSetting.text = integerValue
end if end if
m.integerSetting.visible = true m.integerSetting.visible = true
else if LCase(selectedSetting.type) = "radio" else if LCase(selectedSetting.type) = "radio"
selectedValue = m.global.session.user.settings[selectedSetting.settingName] selectedValue = userSettings[selectedSetting.settingName]
radioContent = CreateObject("roSGNode", "ContentNode") radioContent = CreateObject("roSGNode", "ContentNode")
@ -173,7 +175,6 @@ sub boolSettingChanged()
set_setting(selectedSetting.settingName, "true") set_setting(selectedSetting.settingName, "true")
' setting specific triggers ' setting specific triggers
if selectedSetting.settingName = "global.rememberme" if selectedSetting.settingName = "global.rememberme"
print "m.global.session.user.id=", m.global.session.user.id
set_setting("active_user", m.global.session.user.id) set_setting("active_user", m.global.session.user.id)
end if end if
else else

View File

@ -6,11 +6,28 @@ sub init()
m.top.showRowLabel = [false] m.top.showRowLabel = [false]
m.top.observeField("selectItemId", "onItemSelected")
updateSize() updateSize()
m.top.setFocus(true) m.top.setFocus(true)
end sub end sub
sub onItemSelected()
Id = m.top.selectItemId
if Id <> invalid and Id <> "" and m.top.objects <> invalid
for i = 0 to m.top.objects.items.count() - 1
item = m.top.objects.items[i]
if item.id = Id
m.top.jumpToItem = i
return
end if
end for
end if
end sub
sub updateSize() sub updateSize()
m.top.translation = [450, 180] m.top.translation = [450, 180]

View File

@ -4,5 +4,8 @@
<field id="objects" type="assocarray" onChange="setupRows" /> <field id="objects" type="assocarray" onChange="setupRows" />
<field id="escapeButton" type="string" alwaysNotify="true" /> <field id="escapeButton" type="string" alwaysNotify="true" />
<field id="doneLoading" type="boolean" /> <field id="doneLoading" type="boolean" />
<field id="selectItemId" type="string" />
<function name="onItemSelected" />
</interface> </interface>
</component> </component>

View File

@ -4,9 +4,15 @@ sub init()
m.rows = m.top.findNode("tvEpisodeRow") m.rows = m.top.findNode("tvEpisodeRow")
m.tvListOptions = m.top.findNode("tvListOptions") m.tvListOptions = m.top.findNode("tvListOptions")
m.top.observeField("selectItemId", "onItemSelected")
m.rows.observeField("doneLoading", "rowsDoneLoading") m.rows.observeField("doneLoading", "rowsDoneLoading")
end sub end sub
sub onItemSelected()
Id = m.top.selectItemId
m.rows.selectItemId = Id
end sub
sub setupRows() sub setupRows()
objects = m.top.objects objects = m.top.objects
m.rows.objects = objects m.rows.objects = objects

View File

@ -8,5 +8,8 @@
<field id="objects" type="assocarray" onChange="setupRows" /> <field id="objects" type="assocarray" onChange="setupRows" />
<field id="itemSelected" type="integer" /> <field id="itemSelected" type="integer" />
<field id="doneLoading" type="boolean" /> <field id="doneLoading" type="boolean" />
<field id="selectItemId" type="string" />
<function name="onItemSelected" />
</interface> </interface>
</component> </component>

View File

@ -6,6 +6,7 @@ import "pkg:/source/api/sdk.bs"
sub init() sub init()
m.top.optionsAvailable = false m.top.optionsAvailable = false
m.top.observeField("selectItemId", "onItemSelected")
m.rows = m.top.findNode("picker") m.rows = m.top.findNode("picker")
m.poster = m.top.findNode("seasonPoster") m.poster = m.top.findNode("seasonPoster")
@ -25,6 +26,11 @@ sub setSeasonLoading()
m.top.overhangTitle = tr("Loading...") m.top.overhangTitle = tr("Loading...")
end sub end sub
sub onItemSelected()
Id = m.top.selectItemId
m.rows.selectItemId = Id
end sub
' Updates the visibility of the Extras button based on if this season has any extra features ' Updates the visibility of the Extras button based on if this season has any extra features
sub setExtraButtonVisibility() sub setExtraButtonVisibility()
if isValid(m.top.extrasObjects) and isValidAndNotEmpty(m.top.extrasObjects.items) if isValid(m.top.extrasObjects) and isValidAndNotEmpty(m.top.extrasObjects.items)
@ -73,6 +79,7 @@ end function
' OnScreenShown: Callback function when view is presented on screen ' OnScreenShown: Callback function when view is presented on screen
' '
sub OnScreenShown() sub OnScreenShown()
if m.isFirstRun if m.isFirstRun
m.isFirstRun = false m.isFirstRun = false
return return
@ -80,6 +87,7 @@ sub OnScreenShown()
m.tvEpisodeRow.setFocus(true) m.tvEpisodeRow.setFocus(true)
m.top.refreshSeasonDetailsData = not m.top.refreshSeasonDetailsData m.top.refreshSeasonDetailsData = not m.top.refreshSeasonDetailsData
end sub end sub
' Handle navigation input from the remote and act on it ' Handle navigation input from the remote and act on it

View File

@ -19,6 +19,9 @@
<field id="objects" alias="picker.objects" /> <field id="objects" alias="picker.objects" />
<field id="episodeObjects" type="assocarray" /> <field id="episodeObjects" type="assocarray" />
<field id="extrasObjects" type="assocarray" onChange="setExtraButtonVisibility" /> <field id="extrasObjects" type="assocarray" onChange="setExtraButtonVisibility" />
<field id="selectItemId" type="string" />
<function name="updateSeason" /> <function name="updateSeason" />
<function name="onItemSelected" />
</interface> </interface>
</component> </component>

View File

@ -21,13 +21,16 @@ end sub
sub itemContentChanged() sub itemContentChanged()
item = m.top.itemContent item = m.top.itemContent
itemData = item.json itemData = item.json
userSettings = m.global.session.user.settings
' Set default video source if user hasn't selected one yet ' Set default video source if user hasn't selected one yet
if item.selectedVideoStreamId = "" and isValid(itemData.MediaSources) if item.selectedVideoStreamId = "" and isValid(itemData.MediaSources)
item.selectedVideoStreamId = itemData.MediaSources[0].id item.selectedVideoStreamId = itemData.MediaSources[0].id
end if end if
if isValid(itemData.indexNumber) if isValid(itemData.parentIndexNumber) and itemData.parentIndexNumber = 0
indexNumber = `${tr("Special")} - `
else if isValid(itemData.indexNumber)
indexNumber = `${itemData.indexNumber}. ` indexNumber = `${itemData.indexNumber}. `
if isValid(itemData.indexNumberEnd) if isValid(itemData.indexNumberEnd)
indexNumber = `${itemData.indexNumber}-${itemData.indexNumberEnd}. ` indexNumber = `${itemData.indexNumber}-${itemData.indexNumberEnd}. `
@ -46,7 +49,7 @@ sub itemContentChanged()
imageUrl = item.posterURL imageUrl = item.posterURL
if m.global.session.user.settings["ui.tvshows.blurunwatched"] = true if userSettings["ui.tvshows.blurunwatched"] = true
if itemData.lookup("Type") = "Episode" if itemData.lookup("Type") = "Episode"
if not itemData.userdata.played if not itemData.userdata.played
imageUrl = imageUrl + "&blur=15" imageUrl = imageUrl + "&blur=15"
@ -64,12 +67,12 @@ sub itemContentChanged()
m.top.findNode("runtime").text = stri(runTime).trim() + " mins" m.top.findNode("runtime").text = stri(runTime).trim() + " mins"
end if end if
if m.global.session.user.settings["ui.design.hideclock"] <> true if userSettings["ui.design.hideclock"] <> true
m.top.findNode("endtime").text = tr("Ends at %1").Replace("%1", getEndTime()) m.top.findNode("endtime").text = tr("Ends at %1").Replace("%1", getEndTime())
end if end if
end if end if
if m.global.session.user.settings["ui.tvshows.disableCommunityRating"] = false if userSettings["ui.tvshows.disableCommunityRating"] = false
if isValid(itemData.communityRating) if isValid(itemData.communityRating)
m.top.findNode("star").visible = true m.top.findNode("star").visible = true
m.top.findNode("communityRating").text = str(int(itemData.communityRating * 10) / 10) m.top.findNode("communityRating").text = str(int(itemData.communityRating * 10) / 10)

View File

@ -181,8 +181,12 @@ end function
sub onShuffleEpisodeDataLoaded() sub onShuffleEpisodeDataLoaded()
m.getShuffleEpisodesTask.unobserveField("data") m.getShuffleEpisodesTask.unobserveField("data")
m.global.queueManager.callFunc("set", m.getShuffleEpisodesTask.data.items)
m.global.queueManager.callFunc("playQueue") if isValid(m.getShuffleEpisodesTask.data)
queueManager = m.global.queueManager
queueManager.callFunc("set", m.getShuffleEpisodesTask.data.items)
queueManager.callFunc("playQueue")
end if
end sub end sub
function onKeyEvent(key as string, press as boolean) as boolean function onKeyEvent(key as string, press as boolean) as boolean

View File

@ -35,14 +35,27 @@ sub init()
m.optionControls.buttonFocused = m.optionControls.getChildCount() - 1 m.optionControls.buttonFocused = m.optionControls.getChildCount() - 1
m.videoControls.getChild(m.defaultButtonIndex).focus = true m.videoControls.getChild(m.defaultButtonIndex).focus = true
m.deviceInfo = CreateObject("roDeviceInfo")
end sub end sub
' onProgressPercentageChanged: Handler for changes to m.top.progressPercentage param ' onProgressPercentageChanged: Handler for changes to m.top.progressPercentage param
' '
sub onProgressPercentageChanged() sub onProgressPercentageChanged()
m.videoPositionTime.text = secondsToHuman(m.top.positionTime, true) m.videoPositionTime.text = secondsToHuman(m.top.positionTime, true)
m.videoRemainingTime.text = secondsToHuman(m.top.remainingPositionTime, true)
osdmode = m.global.session.user.settings["ui.general.osdremainingtime"]
if m.global.session.user.settings["ui.design.hideclock"]
' in order to honor the hide clocks setting
osdmode = "remaining"
end if
if osdmode = "remaining"
m.videoRemainingTime.text = secondsToHuman(m.top.remainingPositionTime, true)
else if osdmode = "timeofday"
m.videoRemainingTime.text = secondsToEndTime(m.top.remainingPositionTime)
else if osdmode = "both"
m.videoRemainingTime.text = secondsToHuman(m.top.remainingPositionTime, true) + " | " + secondsToEndTime(m.top.remainingPositionTime)
end if
m.progressBar.width = m.progressBarBackground.width * m.top.progressPercentage m.progressBar.width = m.progressBarBackground.width * m.top.progressPercentage
end sub end sub
@ -211,7 +224,8 @@ sub inactiveCheck()
return return
end if end if
if m.deviceInfo.timeSinceLastKeypress() >= m.top.inactiveTimeout deviceInfo = CreateObject("roDeviceInfo")
if deviceInfo.timeSinceLastKeypress() >= m.top.inactiveTimeout
m.top.action = "hide" m.top.action = "hide"
end if end if
end sub end sub

View File

@ -34,7 +34,7 @@
</Rectangle> </Rectangle>
<Label id="videoPositionTime" font="font:MediumSystemFont" color="0xffffffFF" translation="[103,985]" /> <Label id="videoPositionTime" font="font:MediumSystemFont" color="0xffffffFF" translation="[103,985]" />
<Label id="videoRemainingTime" font="font:MediumSystemFont" color="0xffffffFF" horizAlign="right" width="200" translation="[1617,985]" /> <Label id="videoRemainingTime" font="font:MediumSystemFont" color="0xffffffFF" horizAlign="right" width="400" translation="[1450,985]" />
<Timer id="inactivityTimer" duration="1" repeat="true" /> <Timer id="inactivityTimer" duration="1" repeat="true" />
</children> </children>

View File

@ -1,10 +1,15 @@
import "pkg:/source/utils/misc.bs" import "pkg:/source/utils/misc.bs"
import "pkg:/source/utils/config.bs" import "pkg:/source/utils/config.bs"
import "pkg:/source/utils/session.bs"
import "pkg:/source/roku_modules/log/LogMixin.brs"
sub init() sub init()
m.log = log.Logger("VideoPlayerView")
' Hide the overhang on init to prevent showing 2 clocks ' Hide the overhang on init to prevent showing 2 clocks
m.top.getScene().findNode("overhang").visible = false m.top.getScene().findNode("overhang").visible = false
userSettings = m.global.session.user.settings
m.currentItem = m.global.queueManager.callFunc("getCurrentItem") m.currentItem = m.global.queueManager.callFunc("getCurrentItem")
m.originalClosedCaptionState = invalid
m.top.id = m.currentItem.id m.top.id = m.currentItem.id
m.top.seekMode = "accurate" m.top.seekMode = "accurate"
@ -43,7 +48,7 @@ sub init()
m.top.transcodeReasons = [] m.top.transcodeReasons = []
m.bufferCheckTimer.duration = 30 m.bufferCheckTimer.duration = 30
if m.global.session.user.settings["ui.design.hideclock"] = true if userSettings["ui.design.hideclock"] = true
clockNode = findNodeBySubtype(m.top, "clock") clockNode = findNodeBySubtype(m.top, "clock")
if clockNode[0] <> invalid then clockNode[0].parent.removeChild(clockNode[0].node) if clockNode[0] <> invalid then clockNode[0].parent.removeChild(clockNode[0].node)
end if end if
@ -52,7 +57,7 @@ sub init()
m.nextEpisodeButton = m.top.findNode("nextEpisode") m.nextEpisodeButton = m.top.findNode("nextEpisode")
m.nextEpisodeButton.text = tr("Next Episode") m.nextEpisodeButton.text = tr("Next Episode")
m.nextEpisodeButton.setFocus(false) m.nextEpisodeButton.setFocus(false)
m.nextupbuttonseconds = m.global.session.user.settings["playback.nextupbuttonseconds"].ToInt() m.nextupbuttonseconds = userSettings["playback.nextupbuttonseconds"].ToInt()
m.showNextEpisodeButtonAnimation = m.top.findNode("showNextEpisodeButton") m.showNextEpisodeButtonAnimation = m.top.findNode("showNextEpisodeButton")
m.hideNextEpisodeButtonAnimation = m.top.findNode("hideNextEpisodeButton") m.hideNextEpisodeButtonAnimation = m.top.findNode("hideNextEpisodeButton")
@ -97,24 +102,30 @@ end sub
' @param {string} action - skip action to take ' @param {string} action - skip action to take
sub handleItemSkipAction(action as string) sub handleItemSkipAction(action as string)
if action = "itemnext" if action = "itemnext"
queueManager = m.global.queueManager
' If there is something next in the queue, play it ' If there is something next in the queue, play it
if m.global.queueManager.callFunc("getPosition") < m.global.queueManager.callFunc("getCount") - 1 if queueManager.callFunc("getPosition") < queueManager.callFunc("getCount") - 1
m.top.control = "stop" m.top.control = "stop"
session.video.Delete()
m.global.sceneManager.callFunc("clearPreviousScene") m.global.sceneManager.callFunc("clearPreviousScene")
m.global.queueManager.callFunc("moveForward") queueManager.callFunc("moveForward")
m.global.queueManager.callFunc("playQueue") queueManager.callFunc("playQueue")
end if end if
return return
end if end if
if action = "itemback" if action = "itemback"
queueManager = m.global.queueManager
' If there is something previous in the queue, play it ' If there is something previous in the queue, play it
if m.global.queueManager.callFunc("getPosition") > 0 if queueManager.callFunc("getPosition") > 0
m.top.control = "stop" m.top.control = "stop"
session.video.Delete()
m.global.sceneManager.callFunc("clearPreviousScene") m.global.sceneManager.callFunc("clearPreviousScene")
m.global.queueManager.callFunc("moveBack") queueManager.callFunc("moveBack")
m.global.queueManager.callFunc("playQueue") queueManager.callFunc("playQueue")
end if end if
return return
@ -451,7 +462,12 @@ sub onVideoContentLoaded()
availableSubtitleTrackIndex = availSubtitleTrackIdx(selectedSubtitle.Track.TrackName) availableSubtitleTrackIndex = availSubtitleTrackIdx(selectedSubtitle.Track.TrackName)
if availableSubtitleTrackIndex <> -1 if availableSubtitleTrackIndex <> -1
if not selectedSubtitle.IsEncoded if not selectedSubtitle.IsEncoded
m.top.globalCaptionMode = "On" if selectedSubtitle.IsForced
' If IsForced, make sure to remember the Roku global setting so we
' can set it back when the video is done playing.
m.originalClosedCaptionState = m.top.globalCaptionMode
m.top.globalCaptionMode = "On"
end if
m.top.subtitleTrack = m.top.availableSubtitleTracks[availableSubtitleTrackIndex].TrackName m.top.subtitleTrack = m.top.availableSubtitleTracks[availableSubtitleTrackIndex].TrackName
end if end if
end if end if
@ -517,12 +533,14 @@ sub showNextEpisodeButton()
if m.osd.visible then return if m.osd.visible then return
if m.top.content.contenttype <> 4 then return ' only display when content is type "Episode" if m.top.content.contenttype <> 4 then return ' only display when content is type "Episode"
if m.nextupbuttonseconds = 0 then return ' is the button disabled? if m.nextupbuttonseconds = 0 then return ' is the button disabled?
if m.nextEpisodeButton.opacity <> 0 then return
userSettings = m.global.session.user.settings
if userSettings["playback.playnextepisode"] = "disabled" then return
if userSettings["playback.playnextepisode"] = "webclient" and not m.global.session.user.Configuration.EnableNextEpisodeAutoPlay then return
if m.nextEpisodeButton.opacity = 0 and m.global.session.user.configuration.EnableNextEpisodeAutoPlay m.nextEpisodeButton.visible = true
m.nextEpisodeButton.visible = true m.showNextEpisodeButtonAnimation.control = "start"
m.showNextEpisodeButtonAnimation.control = "start" m.nextEpisodeButton.setFocus(true)
m.nextEpisodeButton.setFocus(true)
end if
end sub end sub
' '
@ -600,6 +618,7 @@ end sub
' '
' When Video Player state changes ' When Video Player state changes
sub onState(msg) sub onState(msg)
m.log.debug("start onState()", m.top.state)
if isValid(m.captionTask) if isValid(m.captionTask)
m.captionTask.playerState = m.top.state + m.top.globalCaptionMode m.captionTask.playerState = m.top.state + m.top.globalCaptionMode
end if end if
@ -607,23 +626,26 @@ sub onState(msg)
' Pass video state into OSD ' Pass video state into OSD
m.osd.playbackState = m.top.state m.osd.playbackState = m.top.state
' When buffering, start timer to monitor buffering process if m.top.state = "buffering"
if m.top.state = "buffering" and m.bufferCheckTimer <> invalid ' When buffering, start timer to monitor buffering process
if isValid(m.bufferCheckTimer)
' start timer m.bufferCheckTimer.control = "start"
m.bufferCheckTimer.control = "start" m.bufferCheckTimer.ObserveField("fire", "bufferCheck")
m.bufferCheckTimer.ObserveField("fire", "bufferCheck") end if
else if m.top.state = "error" else if m.top.state = "error"
m.log.error(m.top.errorCode, m.top.errorMsg, m.top.errorStr, m.top.errorCode)
print m.top.errorInfo
if not m.playReported and m.top.transcodeAvailable if not m.playReported and m.top.transcodeAvailable
m.top.retryWithTranscoding = true ' If playback was not reported, retry with transcoding m.top.retryWithTranscoding = true ' If playback was not reported, retry with transcoding
else else
' If an error was encountered, Display dialog ' If an error was encountered, Display dialog
showPlaybackErrorDialog(tr("Error During Playback")) showPlaybackErrorDialog(tr("Error During Playback"))
session.video.Delete()
end if end if
' Stop playback and exit player
m.top.control = "stop"
m.top.backPressed = true
else if m.top.state = "playing" else if m.top.state = "playing"
' Check if next episode is available ' Check if next episode is available
@ -649,16 +671,24 @@ sub onState(msg)
m.playbackTimer.control = "stop" m.playbackTimer.control = "stop"
ReportPlayback("stop") ReportPlayback("stop")
m.playReported = false m.playReported = false
session.video.Delete()
else if m.top.state = "finished"
m.playbackTimer.control = "stop"
ReportPlayback("finished")
session.video.Delete()
else
m.log.warning("Unhandled state", m.top.state, m.playReported, m.playFinished)
end if end if
m.log.debug("end onState()", m.top.state)
end sub end sub
' '
' Report playback to server ' Report playback to server
sub ReportPlayback(state = "update" as string) sub ReportPlayback(state = "update" as string)
if m.top.position = invalid then return if m.top.position = invalid then return
m.log.debug("start ReportPlayback()", state, int(m.top.position))
params = { params = {
"ItemId": m.top.id, "ItemId": m.top.id,
"PlaySessionId": m.top.PlaySessionId, "PlaySessionId": m.top.PlaySessionId,
@ -673,10 +703,18 @@ sub ReportPlayback(state = "update" as string)
m.bufferCheckTimer.duration = 30 m.bufferCheckTimer.duration = 30
end if end if
if (state = "stop" or state = "finished") and m.originalClosedCaptionState <> invalid
m.log.debug("ReportPlayback() setting", m.top.globalCaptionMode, "back to", m.originalClosedCaptionState)
m.top.globalCaptionMode = m.originalClosedCaptionState
m.originalClosedCaptionState = invalid
end if
' Report playstate via worker task ' Report playstate via worker task
playstateTask = m.global.playstateTask playstateTask = m.global.playstateTask
playstateTask.setFields({ status: state, params: params }) playstateTask.setFields({ status: state, params: params })
playstateTask.control = "RUN" playstateTask.control = "RUN"
m.log.debug("end ReportPlayback()", state, int(m.top.position))
end sub end sub
' '
@ -702,7 +740,7 @@ sub bufferCheck(msg)
' Stop playback and exit player ' Stop playback and exit player
m.top.control = "stop" m.top.control = "stop"
m.top.backPressed = true session.video.Delete()
end if end if
end if end if
@ -772,6 +810,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
if key = "OK" and m.nextEpisodeButton.hasfocus() and not m.top.trickPlayBar.visible if key = "OK" and m.nextEpisodeButton.hasfocus() and not m.top.trickPlayBar.visible
m.top.control = "stop" m.top.control = "stop"
m.top.state = "finished" m.top.state = "finished"
session.video.Delete()
hideNextEpisodeButton() hideNextEpisodeButton()
return true return true
else else
@ -846,6 +885,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
if key = "back" if key = "back"
m.top.control = "stop" m.top.control = "stop"
session.video.Delete()
end if end if
return false return false

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More