mirror of
https://github.com/jellyfin/jellyfin-roku.git
synced 2024-11-23 06:09:41 +00:00
Merge branch 'master' into expand-homerows
This commit is contained in:
commit
aa5210f758
6
.github/workflows/build-dev.yml
vendored
6
.github/workflows/build-dev.yml
vendored
@ -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
|
||||||
|
2
.github/workflows/build-docs.yml
vendored
2
.github/workflows/build-docs.yml
vendored
@ -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 }}
|
||||||
|
6
.github/workflows/build-prod.yml
vendored
6
.github/workflows/build-prod.yml
vendored
@ -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
|
||||||
|
12
.github/workflows/bump-version.yml
vendored
12
.github/workflows/bump-version.yml
vendored
@ -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
|
||||||
|
2
.github/workflows/deploy-api-docs.yml
vendored
2
.github/workflows/deploy-api-docs.yml
vendored
@ -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
|
||||||
|
6
.github/workflows/roku-analysis.yml
vendored
6
.github/workflows/roku-analysis.yml
vendored
@ -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
18
.vscode/launch.json
vendored
@ -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",
|
||||||
|
2
Makefile
2
Makefile
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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]"
|
||||||
|
@ -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()
|
||||||
|
@ -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]"
|
||||||
|
@ -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
|
||||||
|
|
||||||
'
|
'
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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>
|
||||||
|
@ -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 })
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
@ -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>
|
@ -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
|
||||||
|
@ -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>
|
@ -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
|
||||||
|
@ -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>
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user