Merge branch 'master' into OSDInfo
This commit is contained in:
commit
1b863ba34c
7
.github/workflows/build-dev.yml
vendored
7
.github/workflows/build-dev.yml
vendored
|
@ -3,16 +3,13 @@ name: build-dev
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- "*.*.z"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
dev:
|
dev:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
|
||||||
with:
|
with:
|
||||||
node-version: "lts/*"
|
node-version: "lts/*"
|
||||||
cache: "npm"
|
cache: "npm"
|
||||||
|
@ -22,7 +19,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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4
|
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # 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
|
||||||
|
|
4
.github/workflows/build-prod.yml
vendored
4
.github/workflows/build-prod.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # 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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4
|
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # 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
|
||||||
|
|
235
.github/workflows/bump-version.yml
vendored
Normal file
235
.github/workflows/bump-version.yml
vendored
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
name: "Create PR to bump version"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
targetBranch:
|
||||||
|
description: 'Target Branch'
|
||||||
|
required: true
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- bugfix
|
||||||
|
- master
|
||||||
|
versionType:
|
||||||
|
description: 'What Version to Bump'
|
||||||
|
required: true
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- build
|
||||||
|
- minor
|
||||||
|
- major
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
if: ${{ github.event.inputs.versionType == 'build' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# Setup
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
|
- name: Install required packages
|
||||||
|
uses: awalsh128/cache-apt-pkgs-action@latest
|
||||||
|
with:
|
||||||
|
packages: jq
|
||||||
|
- name: Save targetBranch to env
|
||||||
|
if: github.event.inputs.targetBranch != 'bugfix'
|
||||||
|
run: echo "targetBranch=${{ github.event.inputs.targetBranch }}" >> $GITHUB_ENV
|
||||||
|
# Save old version
|
||||||
|
- name: Find and save old major_version from manifest
|
||||||
|
run: awk 'BEGIN { FS="=" } /^major_version/ { print "oldMajor="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
- name: Find and save old minor_version from manifest
|
||||||
|
run: awk 'BEGIN { FS="=" } /^minor_version/ { print "oldMinor="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
- name: Find and save old build_version from manifest
|
||||||
|
run: awk 'BEGIN { FS="=" } /^build_version/ { print "oldBuild="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
# Bugfix branch
|
||||||
|
- name: Save bugfix branch name
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
run: echo "bugfixBranch=${{ env.oldMajor }}.${{ env.oldMinor }}.z" >> $GITHUB_ENV
|
||||||
|
- name: Update targetBranch with actual bugfix branch name
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
run: echo "targetBranch=${{ env.bugfixBranch }}" >> $GITHUB_ENV
|
||||||
|
- name: Checkout bugfix branch
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
|
with:
|
||||||
|
ref: ${{ env.targetBranch }}
|
||||||
|
# Save old version again if needed
|
||||||
|
- name: Find and save old major_version from manifest
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
run: awk 'BEGIN { FS="=" } /^major_version/ { print "oldMajor="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
- name: Find and save old minor_version from manifest
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
run: awk 'BEGIN { FS="=" } /^minor_version/ { print "oldMinor="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
- name: Find and save old build_version from manifest
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
run: awk 'BEGIN { FS="=" } /^build_version/ { print "oldBuild="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
# Calculate new version
|
||||||
|
- name: Calculate new build_version
|
||||||
|
run: echo "newBuild=$((${{ env.oldBuild }} + 1))" >> $GITHUB_ENV
|
||||||
|
- name: Save new version to env var
|
||||||
|
run: echo "newVersion=${{ env.oldMajor }}.${{ env.oldMinor }}.${{ env.newBuild }}" >> $GITHUB_ENV
|
||||||
|
- name: Save a copy of newVersion without periods to env var
|
||||||
|
run: echo "newVersionSlug=${{ env.newVersion }}" | sed -e 's/\.//g' >> $GITHUB_ENV
|
||||||
|
# Update files with new versions
|
||||||
|
- name: Update manifest build_version
|
||||||
|
run: sed -i "s/build_version=.*/build_version=${{ env.newBuild }}/g" manifest
|
||||||
|
- name: Update package-lock.json version
|
||||||
|
run: echo "$( jq '.version = "'"${{ env.newVersion }}"'"' package-lock.json )" > package-lock.json
|
||||||
|
- name: Update package-lock.json version 2
|
||||||
|
run: echo "$( jq '.packages."".version = "'"${{ env.newVersion }}"'"' package-lock.json )" > package-lock.json
|
||||||
|
- name: Update package.json version
|
||||||
|
run: echo "$( jq '.version = "'"${{ env.newVersion }}"'"' package.json )" > package.json
|
||||||
|
- name: Update Makefile version
|
||||||
|
run: sed -i "s/VERSION := .*/VERSION := ${{ env.newVersion }}/g" Makefile
|
||||||
|
# Create PR
|
||||||
|
- name: Save new branch name to env
|
||||||
|
run: echo "newBranch=bump-${{ github.event.inputs.targetBranch }}-to-${{ env.newVersionSlug }}" >> $GITHUB_ENV
|
||||||
|
- name: Create PR with new version
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||||
|
run: |-
|
||||||
|
git config user.name "jellyfin-bot"
|
||||||
|
git config user.email "team@jellyfin.org"
|
||||||
|
git checkout -b "${{ env.newBranch }}"
|
||||||
|
git add .
|
||||||
|
git commit -m "Bump ${{ github.event.inputs.versionType }} version"
|
||||||
|
git push --set-upstream origin "${{ env.newBranch }}"
|
||||||
|
gh pr create --title "Bump ${{ github.event.inputs.targetBranch }} branch to ${{ env.newVersion }}" --body "Bump version to prep for next release." --label ignore-changelog --base ${{ env.targetBranch }}
|
||||||
|
minor:
|
||||||
|
if: ${{ github.event.inputs.versionType == 'minor' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# Setup
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
|
- name: Install jq to update json
|
||||||
|
uses: awalsh128/cache-apt-pkgs-action@latest
|
||||||
|
with:
|
||||||
|
packages: jq
|
||||||
|
- name: Save targetBranch to env
|
||||||
|
if: github.event.inputs.targetBranch != 'bugfix'
|
||||||
|
run: echo "targetBranch=${{ github.event.inputs.targetBranch }}" >> $GITHUB_ENV
|
||||||
|
# Save old version
|
||||||
|
- name: Find and save old major_version from manifest
|
||||||
|
run: awk 'BEGIN { FS="=" } /^major_version/ { print "oldMajor="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
- name: Find and save old minor_version from manifest
|
||||||
|
run: awk 'BEGIN { FS="=" } /^minor_version/ { print "oldMinor="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
- name: Find and save old build_version from manifest
|
||||||
|
run: awk 'BEGIN { FS="=" } /^build_version/ { print "oldBuild="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
# Bugfix branch
|
||||||
|
- name: Save bugfix branch name
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
run: echo "bugfixBranch=${{ env.oldMajor }}.${{ env.oldMinor }}.z" >> $GITHUB_ENV
|
||||||
|
- name: Update targetBranch with actual bugfix branch name
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
run: echo "targetBranch=${{ env.bugfixBranch }}" >> $GITHUB_ENV
|
||||||
|
- name: Checkout bugfix branch
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
|
with:
|
||||||
|
ref: ${{ env.targetBranch }}
|
||||||
|
# Calculate new version
|
||||||
|
- name: Calculate new build_version
|
||||||
|
run: echo "newMinor=$((${{ env.oldMinor }} + 1))" >> $GITHUB_ENV
|
||||||
|
- name: Save new version to env var
|
||||||
|
run: echo "newVersion=${{ env.oldMajor }}.${{ env.newMinor }}.0" >> $GITHUB_ENV
|
||||||
|
- name: Save a copy of newVersion without periods to env var
|
||||||
|
run: echo "newVersionSlug=${{ env.newVersion }}" | sed -e 's/\.//g' >> $GITHUB_ENV
|
||||||
|
# Update files with new versions
|
||||||
|
- name: Update manifest minor_version
|
||||||
|
run: sed -i "s/minor_version=.*/minor_version=${{ env.newMinor }}/g" manifest
|
||||||
|
- name: Update manifest build_version
|
||||||
|
run: sed -i "s/build_version=.*/build_version=0/g" manifest
|
||||||
|
- name: Update package-lock.json version
|
||||||
|
run: echo "$( jq '.version = "'"${{ env.newVersion }}"'"' package-lock.json )" > package-lock.json
|
||||||
|
- name: Update package-lock.json version 2
|
||||||
|
run: echo "$( jq '.packages."".version = "'"${{ env.newVersion }}"'"' package-lock.json )" > package-lock.json
|
||||||
|
- name: Update package.json version
|
||||||
|
run: echo "$( jq '.version = "'"${{ env.newVersion }}"'"' package.json )" > package.json
|
||||||
|
- name: Update Makefile version
|
||||||
|
run: sed -i "s/VERSION := .*/VERSION := ${{ env.newVersion }}/g" Makefile
|
||||||
|
# Create PR
|
||||||
|
- name: Save new branch name to env
|
||||||
|
run: echo "newBranch=bump-${{ github.event.inputs.targetBranch }}-to-${{ env.newVersionSlug }}" >> $GITHUB_ENV
|
||||||
|
- name: Create PR with new version
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||||
|
run: |-
|
||||||
|
git config user.name "jellyfin-bot"
|
||||||
|
git config user.email "team@jellyfin.org"
|
||||||
|
git checkout -b "${{ env.newBranch }}"
|
||||||
|
git add .
|
||||||
|
git commit -m "Bump ${{ github.event.inputs.versionType }} version"
|
||||||
|
git push --set-upstream origin "${{ env.newBranch }}"
|
||||||
|
gh pr create --title "Bump ${{ github.event.inputs.targetBranch }} branch to ${{ env.newVersion }}" --body "Bump version to prep for next release." --label ignore-changelog --base ${{ env.targetBranch }}
|
||||||
|
|
||||||
|
major:
|
||||||
|
if: ${{ github.event.inputs.versionType == 'major' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# Setup
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
|
- name: Install jq to update json
|
||||||
|
uses: awalsh128/cache-apt-pkgs-action@latest
|
||||||
|
with:
|
||||||
|
packages: jq
|
||||||
|
- name: Save targetBranch to env
|
||||||
|
if: github.event.inputs.targetBranch != 'bugfix'
|
||||||
|
run: echo "targetBranch=${{ github.event.inputs.targetBranch }}" >> $GITHUB_ENV
|
||||||
|
# Save old version
|
||||||
|
- name: Find and save old major_version from manifest
|
||||||
|
run: awk 'BEGIN { FS="=" } /^major_version/ { print "oldMajor="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
- name: Find and save old minor_version from manifest
|
||||||
|
run: awk 'BEGIN { FS="=" } /^minor_version/ { print "oldMinor="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
- name: Find and save old build_version from manifest
|
||||||
|
run: awk 'BEGIN { FS="=" } /^build_version/ { print "oldBuild="$2; }' manifest >> $GITHUB_ENV
|
||||||
|
# Bugfix branch
|
||||||
|
- name: Save bugfix branch name
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
run: echo "bugfixBranch=${{ env.oldMajor }}.${{ env.oldMinor }}.z" >> $GITHUB_ENV
|
||||||
|
- name: Update targetBranch with actual bugfix branch name
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
run: echo "targetBranch=${{ env.bugfixBranch }}" >> $GITHUB_ENV
|
||||||
|
- name: Checkout bugfix branch
|
||||||
|
if: github.event.inputs.targetBranch == 'bugfix'
|
||||||
|
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
|
with:
|
||||||
|
ref: ${{ env.targetBranch }}
|
||||||
|
# Calculate new version
|
||||||
|
- name: Calculate new build_version
|
||||||
|
run: echo "newMajor=$((${{ env.oldMajor }} + 1))" >> $GITHUB_ENV
|
||||||
|
- name: Save new version to env var
|
||||||
|
run: echo "newVersion=${{ env.newMajor }}.0.0" >> $GITHUB_ENV
|
||||||
|
- name: Save a copy of newVersion without periods to env var
|
||||||
|
run: echo "newVersionSlug=${{ env.newVersion }}" | sed -e 's/\.//g' >> $GITHUB_ENV
|
||||||
|
# Update files with new versions
|
||||||
|
- name: Update manifest major_version
|
||||||
|
run: sed -i "s/major_version=.*/major_version=${{ env.newMajor }}/g" manifest
|
||||||
|
- name: Update manifest minor_version
|
||||||
|
run: sed -i "s/minor_version=.*/minor_version=0/g" manifest
|
||||||
|
- name: Update manifest build_version
|
||||||
|
run: sed -i "s/build_version=.*/build_version=0/g" manifest
|
||||||
|
- name: Update package-lock.json version
|
||||||
|
run: echo "$( jq '.version = "'"${{ env.newVersion }}"'"' package-lock.json )" > package-lock.json
|
||||||
|
- name: Update package-lock.json version 2
|
||||||
|
run: echo "$( jq '.packages."".version = "'"${{ env.newVersion }}"'"' package-lock.json )" > package-lock.json
|
||||||
|
- name: Update package.json version
|
||||||
|
run: echo "$( jq '.version = "'"${{ env.newVersion }}"'"' package.json )" > package.json
|
||||||
|
- name: Update Makefile version
|
||||||
|
run: sed -i "s/VERSION := .*/VERSION := ${{ env.newVersion }}/g" Makefile
|
||||||
|
# Create PR
|
||||||
|
- name: Save new branch name to env
|
||||||
|
run: echo "newBranch=bump-${{ github.event.inputs.targetBranch }}-to-${{ env.newVersionSlug }}" >> $GITHUB_ENV
|
||||||
|
- name: Create PR with new version
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||||
|
run: |-
|
||||||
|
git config user.name "jellyfin-bot"
|
||||||
|
git config user.email "team@jellyfin.org"
|
||||||
|
git checkout -b "${{ env.newBranch }}"
|
||||||
|
git add .
|
||||||
|
git commit -m "Bump ${{ github.event.inputs.versionType }} version"
|
||||||
|
git push --set-upstream origin "${{ env.newBranch }}"
|
||||||
|
gh pr create --title "Bump ${{ github.event.inputs.targetBranch }} branch to ${{ env.newVersion }}" --body "Bump version to prep for next release." --label ignore-changelog --base ${{ env.targetBranch }}
|
||||||
|
|
4
.github/workflows/deploy-api-docs.yml
vendored
4
.github/workflows/deploy-api-docs.yml
vendored
|
@ -34,10 +34,10 @@ jobs:
|
||||||
- name: Setup Pages
|
- name: Setup Pages
|
||||||
uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4
|
uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-pages-artifact@0252fc4ba7626f0298f0cf00902a25c6afc77fa8 # v3
|
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
|
||||||
with:
|
with:
|
||||||
# Only upload the api docs folder
|
# Only upload the api docs folder
|
||||||
path: "docs/api"
|
path: "docs/api"
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@87c3283f01cd6fe19a0ab93a23b2f6fcba5a8e42 # v4
|
uses: actions/deploy-pages@decdde0ac072f6dcbe43649d82d9c635fff5b4e4 # v4
|
||||||
|
|
4
.github/workflows/release-prep.yml
vendored
4
.github/workflows/release-prep.yml
vendored
|
@ -63,7 +63,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
|
||||||
with:
|
with:
|
||||||
node-version: "lts/*"
|
node-version: "lts/*"
|
||||||
cache: "npm"
|
cache: "npm"
|
||||||
|
@ -73,7 +73,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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4
|
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # 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
|
||||||
|
|
2
.github/workflows/roku-analysis.yml
vendored
2
.github/workflows/roku-analysis.yml
vendored
|
@ -12,7 +12,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||||
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
|
||||||
with:
|
with:
|
||||||
node-version: "lts/*"
|
node-version: "lts/*"
|
||||||
cache: "npm"
|
cache: "npm"
|
||||||
|
|
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.0.2
|
VERSION := 2.0.5
|
||||||
|
|
||||||
## usage
|
## usage
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,9 @@
|
||||||
],
|
],
|
||||||
"diagnosticFilters": ["node_modules/**/*", "**/roku_modules/**/*"],
|
"diagnosticFilters": ["node_modules/**/*", "**/roku_modules/**/*"],
|
||||||
"autoImportComponentScript": true,
|
"autoImportComponentScript": true,
|
||||||
"allowBrighterScriptInBrightScript": true,
|
|
||||||
"createPackage": false,
|
"createPackage": false,
|
||||||
"stagingFolderPath": "build",
|
"stagingFolderPath": "build",
|
||||||
|
"retainStagingDir": true,
|
||||||
"plugins": ["rooibos-roku"],
|
"plugins": ["rooibos-roku"],
|
||||||
"rooibos": {
|
"rooibos": {
|
||||||
"isRecordingCodeCoverage": false,
|
"isRecordingCodeCoverage": false,
|
||||||
|
|
|
@ -18,12 +18,13 @@
|
||||||
{
|
{
|
||||||
"src": "settings/**/*",
|
"src": "settings/**/*",
|
||||||
"dest": "settings"
|
"dest": "settings"
|
||||||
}
|
},
|
||||||
|
"manifest"
|
||||||
],
|
],
|
||||||
"diagnosticFilters": ["node_modules/**/*", "**/roku_modules/**/*"],
|
"diagnosticFilters": ["node_modules/**/*", "**/roku_modules/**/*"],
|
||||||
"autoImportComponentScript": true,
|
"autoImportComponentScript": true,
|
||||||
"allowBrighterScriptInBrightScript": true,
|
|
||||||
"stagingFolderPath": "build",
|
"stagingFolderPath": "build",
|
||||||
|
"retainStagingDir": true,
|
||||||
"plugins": ["rooibos-roku"],
|
"plugins": ["rooibos-roku"],
|
||||||
"rooibos": {
|
"rooibos": {
|
||||||
"isRecordingCodeCoverage": false,
|
"isRecordingCodeCoverage": false,
|
||||||
|
|
|
@ -48,7 +48,6 @@
|
||||||
</children>
|
</children>
|
||||||
<interface>
|
<interface>
|
||||||
<field id="selectedItem" type="node" alwaysNotify="true" />
|
<field id="selectedItem" type="node" alwaysNotify="true" />
|
||||||
<field id="focusedChild" type="node" onChange="focusChanged" />
|
|
||||||
<field id="itemAlphaSelected" type="string" />
|
<field id="itemAlphaSelected" type="string" />
|
||||||
</interface>
|
</interface>
|
||||||
</component>
|
</component>
|
|
@ -38,10 +38,13 @@ sub init()
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub itemContentChanged()
|
sub itemContentChanged()
|
||||||
|
m.backdrop.blendColor = "#00a4db" ' set default in case global var is invalid
|
||||||
|
localGlobal = m.global
|
||||||
|
|
||||||
' Set Random background colors from pallet
|
if isValid(localGlobal) and isValid(localGlobal.constants) and isValid(localGlobal.constants.poster_bg_pallet)
|
||||||
posterBackgrounds = m.global.constants.poster_bg_pallet
|
posterBackgrounds = localGlobal.constants.poster_bg_pallet
|
||||||
m.backdrop.blendColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1]
|
m.backdrop.blendColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1]
|
||||||
|
end if
|
||||||
|
|
||||||
itemData = m.top.itemContent
|
itemData = m.top.itemContent
|
||||||
|
|
||||||
|
@ -56,7 +59,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 m.global.session.user.settings["ui.tvshows.disableUnwatchedEpisodeCount"] = false
|
if isValid(localGlobal) and isValid(localGlobal.session) and isValid(localGlobal.session.user) and isValid(localGlobal.session.user.settings)
|
||||||
|
if localGlobal.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
|
||||||
|
@ -67,6 +71,7 @@ sub itemContentChanged()
|
||||||
end if
|
end if
|
||||||
end if
|
end if
|
||||||
end if
|
end if
|
||||||
|
end if
|
||||||
if isValid(itemData.json) and isValid(itemData.json.UserData) and isValid(itemData.json.UserData.Played) and itemData.json.UserData.Played = true
|
if isValid(itemData.json) and isValid(itemData.json.UserData) and isValid(itemData.json.UserData.Played) and itemData.json.UserData.Played = true
|
||||||
m.playedIndicator.visible = true
|
m.playedIndicator.visible = true
|
||||||
end if
|
end if
|
||||||
|
|
|
@ -164,6 +164,8 @@ sub loadItems()
|
||||||
tmp.image = PosterImage(item.id, { "maxHeight": 425, "maxWidth": 290, "quality": "90" })
|
tmp.image = PosterImage(item.id, { "maxHeight": 425, "maxWidth": 290, "quality": "90" })
|
||||||
else if item.type = "Episode"
|
else if item.type = "Episode"
|
||||||
tmp = CreateObject("roSGNode", "TVEpisode")
|
tmp = CreateObject("roSGNode", "TVEpisode")
|
||||||
|
else if LCase(item.Type) = "recording"
|
||||||
|
tmp = CreateObject("roSGNode", "RecordingData")
|
||||||
else if item.Type = "Genre"
|
else if item.Type = "Genre"
|
||||||
tmp = CreateObject("roSGNode", "ContentNode")
|
tmp = CreateObject("roSGNode", "ContentNode")
|
||||||
tmp.title = item.name
|
tmp.title = item.name
|
||||||
|
|
|
@ -82,8 +82,8 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
|
||||||
|
|
||||||
videotype = LCase(meta.type)
|
videotype = LCase(meta.type)
|
||||||
|
|
||||||
' Check for any Live TV streams 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
|
||||||
if isValid(meta.json) and isValid(meta.json.ChannelId)
|
if videotype = "recording" or (isValid(meta.json) and isValid(meta.json.ChannelId))
|
||||||
if isValid(meta.json.EpisodeTitle)
|
if isValid(meta.json.EpisodeTitle)
|
||||||
meta.title = meta.json.EpisodeTitle
|
meta.title = meta.json.EpisodeTitle
|
||||||
else if isValid(meta.json.Name)
|
else if isValid(meta.json.Name)
|
||||||
|
@ -263,7 +263,14 @@ function defaultSubtitleTrackFromVid(videoID) as integer
|
||||||
if not isValidAndNotEmpty(meta.json.MediaSources[0].MediaStreams) then return SubtitleSelection.none
|
if not isValidAndNotEmpty(meta.json.MediaSources[0].MediaStreams) then return SubtitleSelection.none
|
||||||
|
|
||||||
subtitles = sortSubtitles(meta.id, meta.json.MediaSources[0].MediaStreams)
|
subtitles = sortSubtitles(meta.id, meta.json.MediaSources[0].MediaStreams)
|
||||||
selectedAudioLanguage = meta.json.MediaSources[0].MediaStreams[m.top.selectedAudioStreamIndex].Language ?? ""
|
|
||||||
|
selectedAudioLanguage = ""
|
||||||
|
audioMediaStream = meta.json.MediaSources[0].MediaStreams[m.top.selectedAudioStreamIndex]
|
||||||
|
|
||||||
|
' Ensure audio media stream is valid before using language property
|
||||||
|
if isValid(audioMediaStream)
|
||||||
|
selectedAudioLanguage = audioMediaStream.Language ?? ""
|
||||||
|
end if
|
||||||
|
|
||||||
defaultTextSubs = defaultSubtitleTrack(subtitles["text"], selectedAudioLanguage, true) ' Find correct subtitle track (forced text)
|
defaultTextSubs = defaultSubtitleTrack(subtitles["text"], selectedAudioLanguage, true) ' Find correct subtitle track (forced text)
|
||||||
if defaultTextSubs <> SubtitleSelection.none
|
if defaultTextSubs <> SubtitleSelection.none
|
||||||
|
|
|
@ -2,9 +2,10 @@ import "pkg:/source/utils/config.bs"
|
||||||
|
|
||||||
sub init()
|
sub init()
|
||||||
m.top.id = "overhang"
|
m.top.id = "overhang"
|
||||||
' hide seperators till they're needed
|
m.top.translation = [54, 0]
|
||||||
m.leftSeperator = m.top.findNode("overlayLeftSeperator")
|
|
||||||
m.leftSeperator.visible = "false"
|
m.leftGroup = m.top.findNode("overlayLeftGroup")
|
||||||
|
m.rightGroup = m.top.findNode("overlayRightGroup")
|
||||||
m.rightSeperator = m.top.findNode("overlayRightSeperator")
|
m.rightSeperator = m.top.findNode("overlayRightSeperator")
|
||||||
' set font sizes
|
' set font sizes
|
||||||
m.optionText = m.top.findNode("overlayOptionsText")
|
m.optionText = m.top.findNode("overlayOptionsText")
|
||||||
|
@ -38,7 +39,7 @@ end sub
|
||||||
|
|
||||||
sub onVisibleChange()
|
sub onVisibleChange()
|
||||||
if m.top.disableMoveAnimation
|
if m.top.disableMoveAnimation
|
||||||
m.top.translation = [0, 0]
|
m.top.translation = [54, 0]
|
||||||
return
|
return
|
||||||
end if
|
end if
|
||||||
if m.top.isVisible
|
if m.top.isVisible
|
||||||
|
@ -50,16 +51,7 @@ sub onVisibleChange()
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub updateTitle()
|
sub updateTitle()
|
||||||
if m.top.title <> ""
|
|
||||||
m.leftSeperator.visible = "true"
|
|
||||||
else
|
|
||||||
m.leftSeperator.visible = "false"
|
|
||||||
end if
|
|
||||||
m.title.text = m.top.title
|
m.title.text = m.top.title
|
||||||
|
|
||||||
if not m.hideClock
|
|
||||||
resetTime()
|
|
||||||
end if
|
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub setClockVisibility()
|
sub setClockVisibility()
|
||||||
|
@ -84,7 +76,9 @@ end sub
|
||||||
sub updateUser()
|
sub updateUser()
|
||||||
setRightSeperatorVisibility()
|
setRightSeperatorVisibility()
|
||||||
user = m.top.findNode("overlayCurrentUser")
|
user = m.top.findNode("overlayCurrentUser")
|
||||||
|
if isValid(user)
|
||||||
user.text = m.top.currentUser
|
user.text = m.top.currentUser
|
||||||
|
end if
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub updateTime()
|
sub updateTime()
|
||||||
|
@ -145,3 +139,23 @@ sub updateOptions()
|
||||||
m.optionStar.visible = false
|
m.optionStar.visible = false
|
||||||
end if
|
end if
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
' component boolean field isLogoVisibleChange has changed value
|
||||||
|
sub isLogoVisibleChange()
|
||||||
|
isLogoVisible = m.top.isLogoVisible
|
||||||
|
|
||||||
|
scene = m.top.getScene()
|
||||||
|
logo = scene.findNode("overlayLogo")
|
||||||
|
|
||||||
|
if isLogoVisible
|
||||||
|
if not isValid(logo)
|
||||||
|
posterLogo = createLogoPoster()
|
||||||
|
m.leftGroup.insertChild(posterLogo, 0)
|
||||||
|
end if
|
||||||
|
else
|
||||||
|
' remove the logo
|
||||||
|
if isValid(logo)
|
||||||
|
m.leftGroup.removeChild(logo)
|
||||||
|
end if
|
||||||
|
end if
|
||||||
|
end sub
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<component name="JFOverhang" extends="Group">
|
<component name="JFOverhang" extends="Group">
|
||||||
<children>
|
<children>
|
||||||
<Poster id="overlayLogo" uri="pkg:/images/logo.png" translation="[70, 53]" width="270" height="72" />
|
<LayoutGroup id="overlayLeftGroup" layoutDirection="horiz" translation="[54, 54]" itemSpacings="60">
|
||||||
<LayoutGroup id="overlayLeftGroup" layoutDirection="horiz" translation="[375, 53]" itemSpacings="30">
|
<Poster id="overlayLogo" uri="pkg:/images/logo.png" height="66" width="191" />
|
||||||
<Rectangle id="overlayLeftSeperator" color="#666666" width="2" height="64" />
|
|
||||||
<ScrollingLabel id="overlayTitle" font="font:LargeSystemFont" vertAlign="center" height="64" maxWidth="1100" repeatCount="0" />
|
<ScrollingLabel id="overlayTitle" font="font:LargeSystemFont" vertAlign="center" height="64" maxWidth="1100" repeatCount="0" />
|
||||||
</LayoutGroup>
|
</LayoutGroup>
|
||||||
<LayoutGroup id="overlayRightGroup" layoutDirection="horiz" itemSpacings="30" translation="[1820, 53]" horizAlignment="right">
|
<LayoutGroup id="overlayRightGroup" layoutDirection="horiz" itemSpacings="30" translation="[1766, 53]" horizAlignment="right">
|
||||||
<Label id="overlayCurrentUser" font="font:MediumSystemFont" width="300" horizAlign="right" vertAlign="center" height="64" />
|
<Label id="overlayCurrentUser" font="font:MediumSystemFont" width="300" horizAlign="right" vertAlign="center" height="64" />
|
||||||
<Rectangle id="overlayRightSeperator" color="#666666" width="2" height="64" visible="false" />
|
<Rectangle id="overlayRightSeperator" color="#666666" width="2" height="64" visible="false" />
|
||||||
<LayoutGroup id="overlayTimeGroup" layoutDirection="horiz" horizAlignment="right" itemSpacings="0">
|
<LayoutGroup id="overlayTimeGroup" layoutDirection="horiz" horizAlignment="right" itemSpacings="0">
|
||||||
|
@ -17,7 +16,7 @@
|
||||||
</LayoutGroup>
|
</LayoutGroup>
|
||||||
</LayoutGroup>
|
</LayoutGroup>
|
||||||
|
|
||||||
<LayoutGroup layoutDirection="horiz" horizAlignment="right" translation="[1820, 125]" vertAlignment="custom">
|
<LayoutGroup layoutDirection="horiz" horizAlignment="right" translation="[1766, 125]" vertAlignment="custom">
|
||||||
<Label id="overlayOptionsStar" font="font:LargeSystemFont" text="*" />
|
<Label id="overlayOptionsStar" font="font:LargeSystemFont" text="*" />
|
||||||
<Label id="overlayOptionsText" font="font:SmallSystemFont" text="Options" translation="[0,6]" />
|
<Label id="overlayOptionsText" font="font:SmallSystemFont" text="Options" translation="[0,6]" />
|
||||||
</LayoutGroup>
|
</LayoutGroup>
|
||||||
|
@ -38,6 +37,6 @@
|
||||||
<field id="showOptions" value="true" type="boolean" onChange="updateOptions" />
|
<field id="showOptions" value="true" type="boolean" onChange="updateOptions" />
|
||||||
<field id="isVisible" value="true" type="boolean" onChange="onVisibleChange" />
|
<field id="isVisible" value="true" type="boolean" onChange="onVisibleChange" />
|
||||||
<field id="disableMoveAnimation" value="false" type="boolean" />
|
<field id="disableMoveAnimation" value="false" type="boolean" />
|
||||||
<function name="resetTime" />
|
<field id="isLogoVisible" value="true" type="boolean" onChange="isLogoVisibleChange" />
|
||||||
</interface>
|
</interface>
|
||||||
</component>
|
</component>
|
|
@ -1,8 +1,20 @@
|
||||||
|
import "pkg:/source/utils/misc.bs"
|
||||||
|
|
||||||
sub init()
|
sub init()
|
||||||
m.top.setFocus(true)
|
m.top.setFocus(true)
|
||||||
m.top.optionsAvailable = false
|
m.top.optionsAvailable = false
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
' JFScreen hook.
|
||||||
|
sub OnScreenShown()
|
||||||
|
scene = m.top.getScene()
|
||||||
|
overhang = scene.findNode("overhang")
|
||||||
|
if isValid(overhang)
|
||||||
|
overhang.isLogoVisible = true
|
||||||
|
overhang.currentUser = ""
|
||||||
|
end if
|
||||||
|
end sub
|
||||||
|
|
||||||
function onKeyEvent(key as string, press as boolean) as boolean
|
function onKeyEvent(key as string, press as boolean) as boolean
|
||||||
' Returns true if user navigates to a new focusable element
|
' Returns true if user navigates to a new focusable element
|
||||||
if not press then return false
|
if not press then return false
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<component name="LoginScene" extends="JFGroup">
|
<component name="LoginScene" extends="JFScreen">
|
||||||
<children>
|
<children>
|
||||||
<label text="Enter Configuration"
|
<label text="Enter Configuration"
|
||||||
id="prompt"
|
id="prompt"
|
||||||
|
|
|
@ -156,3 +156,14 @@ end function
|
||||||
sub clearErrorMessage()
|
sub clearErrorMessage()
|
||||||
m.top.errorMessage = ""
|
m.top.errorMessage = ""
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
' JFScreen hook called when the screen is displayed by the screen manager
|
||||||
|
sub OnScreenShown()
|
||||||
|
scene = m.top.getScene()
|
||||||
|
overhang = scene.findNode("overhang")
|
||||||
|
if isValid(overhang)
|
||||||
|
overhang.isLogoVisible = true
|
||||||
|
overhang.currentUser = ""
|
||||||
|
overhang.title = ""
|
||||||
|
end if
|
||||||
|
end sub
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<component name="SetServerScreen" extends="JFGroup">
|
<component name="SetServerScreen" extends="JFScreen">
|
||||||
<interface>
|
<interface>
|
||||||
<field id="serverUrl" type="string" alias="serverUrlTextbox.text" />
|
<field id="serverUrl" type="string" alias="serverUrlTextbox.text" />
|
||||||
<field id="serverWidth" alias="serverUrlOutline.width,serverUrlTextbox.width,serverUrlContainer.width,submitSizer.width" value="1620" />
|
<field id="serverWidth" alias="serverUrlOutline.width,serverUrlTextbox.width,serverUrlContainer.width,submitSizer.width" value="1620" />
|
||||||
|
|
|
@ -31,7 +31,7 @@ sub setData()
|
||||||
m.top.iconUrl = "pkg:/images/media_type_icons/folder_white.png"
|
m.top.iconUrl = "pkg:/images/media_type_icons/folder_white.png"
|
||||||
end if
|
end if
|
||||||
|
|
||||||
else if datum.type = "Episode" or datum.type = "MusicVideo"
|
else if datum.type = "Episode" or LCase(datum.type) = "recording" or datum.type = "MusicVideo"
|
||||||
m.top.isWatched = datum.UserData.Played
|
m.top.isWatched = datum.UserData.Played
|
||||||
|
|
||||||
imgParams = {}
|
imgParams = {}
|
||||||
|
|
5
components/data/JFContentItem.bs
Normal file
5
components/data/JFContentItem.bs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
' Called whenever m.top.json changes.
|
||||||
|
' It is expected that each node that extends JFContentItem will override this function
|
||||||
|
sub setFields()
|
||||||
|
|
||||||
|
end sub
|
20
components/data/RecordingData.bs
Normal file
20
components/data/RecordingData.bs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import "pkg:/source/utils/misc.bs"
|
||||||
|
|
||||||
|
sub setFields()
|
||||||
|
datum = m.top.json
|
||||||
|
|
||||||
|
m.top.id = datum.id
|
||||||
|
m.top.title = datum.name
|
||||||
|
m.top.showID = datum.SeriesID
|
||||||
|
m.top.seasonID = datum.SeasonID
|
||||||
|
m.top.overview = datum.overview
|
||||||
|
m.top.favorite = datum.UserData.isFavorite
|
||||||
|
end sub
|
||||||
|
|
||||||
|
sub setPoster()
|
||||||
|
if isValid(m.top.image)
|
||||||
|
m.top.posterURL = m.top.image.url
|
||||||
|
else
|
||||||
|
m.top.posterURL = ""
|
||||||
|
end if
|
||||||
|
end sub
|
18
components/data/RecordingData.xml
Normal file
18
components/data/RecordingData.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<component name="RecordingData" extends="ContentNode">
|
||||||
|
<interface>
|
||||||
|
<field id="id" type="string" />
|
||||||
|
<field id="title" type="string" />
|
||||||
|
<field id="image" type="node" onChange="setPoster" />
|
||||||
|
<field id="posterURL" type="string" />
|
||||||
|
<field id="showID" type="string" />
|
||||||
|
<field id="seasonID" type="string" />
|
||||||
|
<field id="overview" type="string" />
|
||||||
|
<field id="type" type="string" value="Recording" />
|
||||||
|
<field id="startingPoint" type="longinteger" value="0" />
|
||||||
|
<field id="json" type="assocarray" onChange="setFields" />
|
||||||
|
<field id="selectedVideoStreamId" type="string" />
|
||||||
|
<field id="selectedAudioStreamIndex" type="integer" />
|
||||||
|
<field id="favorite" type="boolean" />
|
||||||
|
</interface>
|
||||||
|
</component>
|
|
@ -124,20 +124,18 @@ sub popScene()
|
||||||
stopLoadingSpinner()
|
stopLoadingSpinner()
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
|
||||||
'
|
'
|
||||||
' Return group at top of stack without removing
|
' Return group at top of stack without removing
|
||||||
function getActiveScene() as object
|
function getActiveScene() as object
|
||||||
return m.groups.peek()
|
return m.groups.peek()
|
||||||
end function
|
end function
|
||||||
|
|
||||||
|
|
||||||
'
|
'
|
||||||
' Clear all content from group stack
|
' Clear all content from group stack
|
||||||
sub clearScenes()
|
sub clearScenes()
|
||||||
if m.content <> invalid then m.content.removeChildrenIndex(m.content.getChildCount(), 0)
|
if m.content <> invalid then m.content.removeChildrenIndex(m.content.getChildCount(), 0)
|
||||||
for each group in m.groups
|
for each group in m.groups
|
||||||
if LCase(group.subtype()) = "jfscreen"
|
if type(group) = "roSGNode" and group.isSubtype("JFScreen")
|
||||||
group.callFunc("OnScreenHidden")
|
group.callFunc("OnScreenHidden")
|
||||||
end if
|
end if
|
||||||
end for
|
end for
|
||||||
|
@ -191,35 +189,30 @@ sub registerOverhangData(group)
|
||||||
end if
|
end if
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
|
||||||
'
|
'
|
||||||
' Remove observers for overhang data
|
' Remove observers for overhang data
|
||||||
sub unregisterOverhangData(group)
|
sub unregisterOverhangData(group)
|
||||||
group.unobserveField("overhangTitle")
|
group.unobserveField("overhangTitle")
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
|
||||||
'
|
'
|
||||||
' Update overhang title
|
' Update overhang title
|
||||||
sub updateOverhangTitle(msg)
|
sub updateOverhangTitle(msg)
|
||||||
m.overhang.title = msg.getData()
|
m.overhang.title = msg.getData()
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
|
||||||
'
|
'
|
||||||
' Update options availability
|
' Update options availability
|
||||||
sub updateOptions(msg)
|
sub updateOptions(msg)
|
||||||
m.overhang.showOptions = msg.getData()
|
m.overhang.showOptions = msg.getData()
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
|
||||||
'
|
'
|
||||||
' Update whether the overhang is visible or not
|
' Update whether the overhang is visible or not
|
||||||
sub updateOverhangVisible(msg)
|
sub updateOverhangVisible(msg)
|
||||||
m.overhang.visible = msg.getData()
|
m.overhang.visible = msg.getData()
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
|
||||||
'
|
'
|
||||||
' Update username in overhang
|
' Update username in overhang
|
||||||
sub updateUser()
|
sub updateUser()
|
||||||
|
@ -227,7 +220,6 @@ sub updateUser()
|
||||||
if m.overhang <> invalid then m.overhang.currentUser = m.top.currentUser
|
if m.overhang <> invalid then m.overhang.currentUser = m.top.currentUser
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
|
||||||
'
|
'
|
||||||
' Reset time
|
' Reset time
|
||||||
sub resetTime()
|
sub resetTime()
|
||||||
|
|
|
@ -30,9 +30,16 @@ sub loadLibraries()
|
||||||
m.fadeInFocusBitmap.control = "start"
|
m.fadeInFocusBitmap.control = "start"
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
' JFScreen hook that gets ran as needed.
|
' JFScreen hook called when the screen is displayed by the screen manager
|
||||||
' Used to update the focus, the state of the data, and tells the server about the device profile
|
|
||||||
sub OnScreenShown()
|
sub OnScreenShown()
|
||||||
|
scene = m.top.getScene()
|
||||||
|
overhang = scene.findNode("overhang")
|
||||||
|
if isValid(overhang)
|
||||||
|
overhang.isLogoVisible = true
|
||||||
|
overhang.currentUser = m.global.session.user.name
|
||||||
|
overhang.title = tr("Home")
|
||||||
|
end if
|
||||||
|
|
||||||
if isValid(m.top.lastFocus)
|
if isValid(m.top.lastFocus)
|
||||||
m.top.lastFocus.setFocus(true)
|
m.top.lastFocus.setFocus(true)
|
||||||
else
|
else
|
||||||
|
@ -53,6 +60,17 @@ sub OnScreenShown()
|
||||||
end if
|
end if
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
' JFScreen hook called when the screen is hidden by the screen manager
|
||||||
|
sub OnScreenHidden()
|
||||||
|
scene = m.top.getScene()
|
||||||
|
overhang = scene.findNode("overhang")
|
||||||
|
if isValid(overhang)
|
||||||
|
overhang.isLogoVisible = false
|
||||||
|
overhang.currentUser = ""
|
||||||
|
overhang.title = ""
|
||||||
|
end if
|
||||||
|
end sub
|
||||||
|
|
||||||
' Triggered by m.postTask after completing a post.
|
' Triggered by m.postTask after completing a post.
|
||||||
' Empty the task data when finished.
|
' Empty the task data when finished.
|
||||||
sub postFinished()
|
sub postFinished()
|
||||||
|
|
|
@ -36,9 +36,10 @@ end sub
|
||||||
|
|
||||||
|
|
||||||
sub itemContentChanged()
|
sub itemContentChanged()
|
||||||
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
|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||
|
@ -56,21 +57,22 @@ sub itemContentChanged()
|
||||||
|
|
||||||
if itemData.isWatched
|
if itemData.isWatched
|
||||||
m.playedIndicator.visible = true
|
m.playedIndicator.visible = true
|
||||||
m.unplayedCount.visible = false
|
|
||||||
else
|
else
|
||||||
m.playedIndicator.visible = false
|
m.playedIndicator.visible = false
|
||||||
|
|
||||||
if LCase(itemData.type) = "series"
|
if LCase(itemData.type) = "series"
|
||||||
if m.global.session.user.settings["ui.tvshows.disableUnwatchedEpisodeCount"] = false
|
if isValid(localGlobal) and isValid(localGlobal.session) and isValid(localGlobal.session.user) and isValid(localGlobal.session.user.settings)
|
||||||
|
if not localGlobal.session.user.settings["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
|
if isValid(m.unplayedCount) then m.unplayedCount.visible = true
|
||||||
m.unplayedEpisodeCount.text = itemData.json.UserData.UnplayedItemCount
|
m.unplayedEpisodeCount.text = itemData.json.UserData.UnplayedItemCount
|
||||||
end if
|
end if
|
||||||
end if
|
end if
|
||||||
end if
|
end if
|
||||||
end if
|
end if
|
||||||
end if
|
end if
|
||||||
|
end if
|
||||||
|
|
||||||
' Format the Data based on the type of Home Data
|
' Format the Data based on the type of Home Data
|
||||||
if itemData.type = "CollectionFolder" or itemData.type = "UserView" or itemData.type = "Channel"
|
if itemData.type = "CollectionFolder" or itemData.type = "UserView" or itemData.type = "Channel"
|
||||||
|
@ -121,7 +123,7 @@ sub itemContentChanged()
|
||||||
return
|
return
|
||||||
end if
|
end if
|
||||||
|
|
||||||
if itemData.type = "Episode"
|
if itemData.type = "Episode" or LCase(itemData.type) = "recording"
|
||||||
m.itemText.text = itemData.json.SeriesName
|
m.itemText.text = itemData.json.SeriesName
|
||||||
|
|
||||||
if itemData.PlayedPercentage > 0
|
if itemData.PlayedPercentage > 0
|
||||||
|
|
|
@ -75,12 +75,17 @@ sub processUserSections()
|
||||||
m.expectedRowCount = 1 ' the favorites row is hardcoded to always show atm
|
m.expectedRowCount = 1 ' the favorites row is hardcoded to always show atm
|
||||||
m.processedRowCount = 0
|
m.processedRowCount = 0
|
||||||
|
|
||||||
|
sessionUser = m.global.session.user
|
||||||
|
|
||||||
' calculate expected row count by processing homesections
|
' calculate expected row count by processing homesections
|
||||||
for i = 0 to 6
|
for i = 0 to 6
|
||||||
sectionName = LCase(m.global.session.user.settings["homesection" + i.toStr()])
|
userSection = sessionUser.settings["homesection" + i.toStr()]
|
||||||
|
sectionName = userSection ?? "none"
|
||||||
|
sectionName = LCase(sectionName)
|
||||||
|
|
||||||
if sectionName = "latestmedia"
|
if sectionName = "latestmedia"
|
||||||
' expect 1 row per filtered media library
|
' expect 1 row per filtered media library
|
||||||
m.filteredLatest = filterNodeArray(m.libraryData, "id", m.global.session.user.configuration.LatestItemsExcludes)
|
m.filteredLatest = filterNodeArray(m.libraryData, "id", sessionUser.configuration.LatestItemsExcludes)
|
||||||
for each latestLibrary in m.filteredLatest
|
for each latestLibrary in m.filteredLatest
|
||||||
if latestLibrary.collectionType <> "boxsets" and latestLibrary.collectionType <> "livetv" and latestLibrary.json.CollectionType <> "Program"
|
if latestLibrary.collectionType <> "boxsets" and latestLibrary.collectionType <> "livetv" and latestLibrary.json.CollectionType <> "Program"
|
||||||
m.expectedRowCount++
|
m.expectedRowCount++
|
||||||
|
@ -94,7 +99,10 @@ 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
|
||||||
sectionName = LCase(m.global.session.user.settings["homesection" + i.toStr()])
|
userSection = sessionUser.settings["homesection" + i.toStr()]
|
||||||
|
sectionName = userSection ?? "none"
|
||||||
|
sectionName = LCase(sectionName)
|
||||||
|
|
||||||
sectionLoaded = false
|
sectionLoaded = false
|
||||||
if sectionName <> "none"
|
if sectionName <> "none"
|
||||||
sectionLoaded = addHomeSection(sectionName)
|
sectionLoaded = addHomeSection(sectionName)
|
||||||
|
@ -141,8 +149,13 @@ function getOriginalSectionIndex(sectionName as string) as integer
|
||||||
sectionIndex = 0
|
sectionIndex = 0
|
||||||
indexLatestMediaSection = 0
|
indexLatestMediaSection = 0
|
||||||
|
|
||||||
|
sessionUser = m.global.session.user
|
||||||
|
|
||||||
for i = 0 to 6
|
for i = 0 to 6
|
||||||
settingSectionName = LCase(m.global.session.user.settings["homesection" + i.toStr()])
|
userSection = sessionUser.settings["homesection" + i.toStr()]
|
||||||
|
settingSectionName = userSection ?? "none"
|
||||||
|
settingSectionName = LCase(settingSectionName)
|
||||||
|
|
||||||
if settingSectionName = "latestmedia"
|
if settingSectionName = "latestmedia"
|
||||||
indexLatestMediaSection = i
|
indexLatestMediaSection = i
|
||||||
end if
|
end if
|
||||||
|
|
|
@ -24,6 +24,16 @@ sub redraw()
|
||||||
m.top.findNode("UserRow").translation = [leftBorder, topBorder]
|
m.top.findNode("UserRow").translation = [leftBorder, topBorder]
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
' JFScreen hook called when the screen is displayed by the screen manager
|
||||||
|
sub OnScreenShown()
|
||||||
|
scene = m.top.getScene()
|
||||||
|
overhang = scene.findNode("overhang")
|
||||||
|
if isValid(overhang)
|
||||||
|
overhang.isLogoVisible = true
|
||||||
|
overhang.currentUser = ""
|
||||||
|
end if
|
||||||
|
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
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<component name="UserSelect" extends="JFGroup">
|
<component name="UserSelect" extends="JFScreen">
|
||||||
<children>
|
<children>
|
||||||
<Label text="Please sign in" horizAlign="center" font="font:LargeSystemFont" height="100" width="1920" translation="[0, 200]" />
|
<Label text="Please sign in" horizAlign="center" font="font:LargeSystemFont" height="100" width="1920" translation="[0, 200]" />
|
||||||
<UserRow id="userRow" translation="[130, 360]" />
|
<UserRow id="userRow" translation="[130, 360]" />
|
||||||
|
|
|
@ -125,6 +125,11 @@ sub playQueue()
|
||||||
return
|
return
|
||||||
end if
|
end if
|
||||||
|
|
||||||
|
if nextItemMediaType = "audiobook"
|
||||||
|
CreateAudioPlayerView()
|
||||||
|
return
|
||||||
|
end if
|
||||||
|
|
||||||
if nextItemMediaType = "musicvideo"
|
if nextItemMediaType = "musicvideo"
|
||||||
CreateVideoPlayerView()
|
CreateVideoPlayerView()
|
||||||
return
|
return
|
||||||
|
@ -145,6 +150,11 @@ sub playQueue()
|
||||||
return
|
return
|
||||||
end if
|
end if
|
||||||
|
|
||||||
|
if nextItemMediaType = "recording"
|
||||||
|
CreateVideoPlayerView()
|
||||||
|
return
|
||||||
|
end if
|
||||||
|
|
||||||
if nextItemMediaType = "trailer"
|
if nextItemMediaType = "trailer"
|
||||||
CreateVideoPlayerView()
|
CreateVideoPlayerView()
|
||||||
return
|
return
|
||||||
|
@ -249,6 +259,10 @@ sub setTopStartingPoint(positionTicks)
|
||||||
m.queue[0].startingPoint = positionTicks
|
m.queue[0].startingPoint = positionTicks
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
' getItemType: Returns the media type of the passed item
|
||||||
|
'
|
||||||
|
' @param {dynamic} item - Item to evaluate
|
||||||
|
' @return {string} indicating type of media item is
|
||||||
function getItemType(item) as string
|
function getItemType(item) as string
|
||||||
if isValid(item) and isValid(item.json) and isValid(item.json.mediatype) and item.json.mediatype <> ""
|
if isValid(item) and isValid(item.json) and isValid(item.json.mediatype) and item.json.mediatype <> ""
|
||||||
return LCase(item.json.mediatype)
|
return LCase(item.json.mediatype)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<function name="getHold" />
|
<function name="getHold" />
|
||||||
<function name="getIsShuffled" />
|
<function name="getIsShuffled" />
|
||||||
<function name="getItemByIndex" />
|
<function name="getItemByIndex" />
|
||||||
|
<function name="getItemType" />
|
||||||
<function name="getPosition" />
|
<function name="getPosition" />
|
||||||
<function name="getQueue" />
|
<function name="getQueue" />
|
||||||
<function name="getQueueTypes" />
|
<function name="getQueueTypes" />
|
||||||
|
|
|
@ -5,6 +5,11 @@ import "pkg:/source/utils/config.bs"
|
||||||
|
|
||||||
sub init()
|
sub init()
|
||||||
m.top.optionsAvailable = false
|
m.top.optionsAvailable = false
|
||||||
|
m.inScrubMode = false
|
||||||
|
m.lastRecordedPositionTimestamp = 0
|
||||||
|
m.scrubTimestamp = -1
|
||||||
|
|
||||||
|
m.playlistTypeCount = m.global.queueManager.callFunc("getQueueUniqueTypes").count()
|
||||||
|
|
||||||
setupAudioNode()
|
setupAudioNode()
|
||||||
setupAnimationTasks()
|
setupAnimationTasks()
|
||||||
|
@ -13,9 +18,8 @@ sub init()
|
||||||
setupDataTasks()
|
setupDataTasks()
|
||||||
setupScreenSaver()
|
setupScreenSaver()
|
||||||
|
|
||||||
m.playlistTypeCount = m.global.queueManager.callFunc("getQueueUniqueTypes").count()
|
|
||||||
|
|
||||||
m.buttonCount = m.buttons.getChildCount()
|
m.buttonCount = m.buttons.getChildCount()
|
||||||
|
m.seekPosition.translation = [720 - (m.seekPosition.width / 2), m.seekPosition.translation[1]]
|
||||||
|
|
||||||
m.screenSaverTimeout = 300
|
m.screenSaverTimeout = 300
|
||||||
|
|
||||||
|
@ -32,6 +36,8 @@ sub init()
|
||||||
pageContentChanged()
|
pageContentChanged()
|
||||||
setShuffleIconState()
|
setShuffleIconState()
|
||||||
setLoopButtonImage()
|
setLoopButtonImage()
|
||||||
|
|
||||||
|
m.buttons.setFocus(true)
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub onScreensaverTimeoutLoaded()
|
sub onScreensaverTimeoutLoaded()
|
||||||
|
@ -96,6 +102,20 @@ end sub
|
||||||
sub setupButtons()
|
sub setupButtons()
|
||||||
m.buttons = m.top.findNode("buttons")
|
m.buttons = m.top.findNode("buttons")
|
||||||
m.top.observeField("selectedButtonIndex", "onButtonSelectedChange")
|
m.top.observeField("selectedButtonIndex", "onButtonSelectedChange")
|
||||||
|
|
||||||
|
' If we're playing a mixed playlist, remove the shuffle and loop buttons
|
||||||
|
if m.playlistTypeCount > 1
|
||||||
|
shuffleButton = m.top.findNode("shuffle")
|
||||||
|
m.buttons.removeChild(shuffleButton)
|
||||||
|
|
||||||
|
loopButton = m.top.findNode("loop")
|
||||||
|
m.buttons.removeChild(loopButton)
|
||||||
|
|
||||||
|
m.previouslySelectedButtonIndex = 0
|
||||||
|
m.top.selectedButtonIndex = 1
|
||||||
|
return
|
||||||
|
end if
|
||||||
|
|
||||||
m.previouslySelectedButtonIndex = 1
|
m.previouslySelectedButtonIndex = 1
|
||||||
m.top.selectedButtonIndex = 2
|
m.top.selectedButtonIndex = 2
|
||||||
end sub
|
end sub
|
||||||
|
@ -117,13 +137,18 @@ sub setupInfoNodes()
|
||||||
m.playPosition = m.top.findNode("playPosition")
|
m.playPosition = m.top.findNode("playPosition")
|
||||||
m.bufferPosition = m.top.findNode("bufferPosition")
|
m.bufferPosition = m.top.findNode("bufferPosition")
|
||||||
m.seekBar = m.top.findNode("seekBar")
|
m.seekBar = m.top.findNode("seekBar")
|
||||||
|
m.thumb = m.top.findNode("thumb")
|
||||||
m.shuffleIndicator = m.top.findNode("shuffleIndicator")
|
m.shuffleIndicator = m.top.findNode("shuffleIndicator")
|
||||||
m.loopIndicator = m.top.findNode("loopIndicator")
|
m.loopIndicator = m.top.findNode("loopIndicator")
|
||||||
m.positionTimestamp = m.top.findNode("positionTimestamp")
|
m.positionTimestamp = m.top.findNode("positionTimestamp")
|
||||||
|
m.seekPosition = m.top.findNode("seekPosition")
|
||||||
|
m.seekTimestamp = m.top.findNode("seekTimestamp")
|
||||||
m.totalLengthTimestamp = m.top.findNode("totalLengthTimestamp")
|
m.totalLengthTimestamp = m.top.findNode("totalLengthTimestamp")
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub bufferPositionChanged()
|
sub bufferPositionChanged()
|
||||||
|
if m.inScrubMode then return
|
||||||
|
|
||||||
if not isValid(m.global.audioPlayer.bufferingStatus)
|
if not isValid(m.global.audioPlayer.bufferingStatus)
|
||||||
bufferPositionBarWidth = m.seekBar.width
|
bufferPositionBarWidth = m.seekBar.width
|
||||||
else
|
else
|
||||||
|
@ -141,6 +166,8 @@ sub bufferPositionChanged()
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub audioPositionChanged()
|
sub audioPositionChanged()
|
||||||
|
stopLoadingSpinner()
|
||||||
|
|
||||||
if m.global.audioPlayer.position = 0
|
if m.global.audioPlayer.position = 0
|
||||||
m.playPosition.width = 0
|
m.playPosition.width = 0
|
||||||
end if
|
end if
|
||||||
|
@ -159,14 +186,22 @@ sub audioPositionChanged()
|
||||||
playPositionBarWidth = m.seekBar.width
|
playPositionBarWidth = m.seekBar.width
|
||||||
end if
|
end if
|
||||||
|
|
||||||
|
if not m.inScrubMode
|
||||||
|
moveSeekbarThumb(playPositionBarWidth)
|
||||||
|
' Change the seek position timestamp
|
||||||
|
m.seekTimestamp.text = secondsToHuman(m.global.audioPlayer.position, false)
|
||||||
|
end if
|
||||||
|
|
||||||
' Use animation to make the display smooth
|
' Use animation to make the display smooth
|
||||||
m.playPositionAnimationWidth.keyValue = [m.playPosition.width, playPositionBarWidth]
|
m.playPositionAnimationWidth.keyValue = [m.playPosition.width, playPositionBarWidth]
|
||||||
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.global.audioPlayer.position)
|
||||||
|
m.lastRecordedPositionTimestamp = m.global.audioPlayer.position
|
||||||
m.positionTimestamp.text = secondsToHuman(m.global.audioPlayer.position, false)
|
m.positionTimestamp.text = secondsToHuman(m.global.audioPlayer.position, false)
|
||||||
else
|
else
|
||||||
|
m.lastRecordedPositionTimestamp = 0
|
||||||
m.positionTimestamp.text = "0:00"
|
m.positionTimestamp.text = "0:00"
|
||||||
end if
|
end if
|
||||||
|
|
||||||
|
@ -217,7 +252,9 @@ sub audioStateChanged()
|
||||||
if m.global.audioPlayer.state = "finished"
|
if m.global.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.global.audioPlayer.loopMode = "one"
|
||||||
|
m.scrubTimestamp = -1
|
||||||
playAction()
|
playAction()
|
||||||
|
exitScrubMode()
|
||||||
return
|
return
|
||||||
end if
|
end if
|
||||||
|
|
||||||
|
@ -261,8 +298,28 @@ function playAction() as boolean
|
||||||
end function
|
end function
|
||||||
|
|
||||||
function previousClicked() as boolean
|
function previousClicked() as boolean
|
||||||
if m.playlistTypeCount > 1 then return false
|
currentQueuePosition = m.global.queueManager.callFunc("getPosition")
|
||||||
if m.global.queueManager.callFunc("getPosition") = 0 then return false
|
|
||||||
|
if currentQueuePosition = 0 then return false
|
||||||
|
|
||||||
|
if m.playlistTypeCount > 1
|
||||||
|
previousItem = m.global.queueManager.callFunc("getItemByIndex", currentQueuePosition - 1)
|
||||||
|
previousItemType = m.global.queueManager.callFunc("getItemType", previousItem)
|
||||||
|
|
||||||
|
if previousItemType <> "audio"
|
||||||
|
m.global.audioPlayer.control = "stop"
|
||||||
|
|
||||||
|
m.global.sceneManager.callFunc("clearPreviousScene")
|
||||||
|
m.global.queueManager.callFunc("moveBack")
|
||||||
|
m.global.queueManager.callFunc("playQueue")
|
||||||
|
return true
|
||||||
|
end if
|
||||||
|
end if
|
||||||
|
|
||||||
|
exitScrubMode()
|
||||||
|
|
||||||
|
m.lastRecordedPositionTimestamp = 0
|
||||||
|
m.positionTimestamp.text = "0:00"
|
||||||
|
|
||||||
if m.global.audioPlayer.state = "playing"
|
if m.global.audioPlayer.state = "playing"
|
||||||
m.global.audioPlayer.control = "stop"
|
m.global.audioPlayer.control = "stop"
|
||||||
|
@ -276,7 +333,6 @@ function previousClicked() as boolean
|
||||||
m.global.queueManager.callFunc("moveBack")
|
m.global.queueManager.callFunc("moveBack")
|
||||||
pageContentChanged()
|
pageContentChanged()
|
||||||
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end function
|
end function
|
||||||
|
|
||||||
|
@ -312,7 +368,28 @@ sub setLoopButtonImage()
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
function nextClicked() as boolean
|
function nextClicked() as boolean
|
||||||
if m.playlistTypeCount > 1 then return false
|
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)
|
||||||
|
nextItemType = m.global.queueManager.callFunc("getItemType", nextItem)
|
||||||
|
|
||||||
|
if nextItemType <> "audio"
|
||||||
|
m.global.audioPlayer.control = "stop"
|
||||||
|
|
||||||
|
m.global.sceneManager.callFunc("clearPreviousScene")
|
||||||
|
m.global.queueManager.callFunc("moveForward")
|
||||||
|
m.global.queueManager.callFunc("playQueue")
|
||||||
|
return true
|
||||||
|
end if
|
||||||
|
end if
|
||||||
|
end if
|
||||||
|
|
||||||
|
exitScrubMode()
|
||||||
|
|
||||||
|
m.lastRecordedPositionTimestamp = 0
|
||||||
|
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.global.audioPlayer.loopMode = "one"
|
||||||
|
@ -379,6 +456,8 @@ sub LoadNextSong()
|
||||||
m.global.audioPlayer.control = "stop"
|
m.global.audioPlayer.control = "stop"
|
||||||
end if
|
end if
|
||||||
|
|
||||||
|
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.global.queueManager.callFunc("moveForward")
|
||||||
|
@ -399,9 +478,6 @@ 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()
|
||||||
' Don't show audio buttons if we have a mixed playlist
|
|
||||||
if m.playlistTypeCount > 1 then return
|
|
||||||
|
|
||||||
if m.global.queueManager.callFunc("getCount") > 1
|
if m.global.queueManager.callFunc("getCount") > 1
|
||||||
m.shuffleIndicator.opacity = ".4"
|
m.shuffleIndicator.opacity = ".4"
|
||||||
m.loopIndicator.opacity = ".4"
|
m.loopIndicator.opacity = ".4"
|
||||||
|
@ -544,6 +620,96 @@ sub setBackdropImage(data)
|
||||||
end if
|
end if
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
' setSelectedButtonState: Changes the icon state url for the currently selected button
|
||||||
|
'
|
||||||
|
' @param {string} oldState - current state to replace in icon url
|
||||||
|
' @param {string} newState - state to replace {oldState} with in icon url
|
||||||
|
sub setSelectedButtonState(oldState as string, newState as string)
|
||||||
|
selectedButton = m.buttons.getChild(m.top.selectedButtonIndex)
|
||||||
|
selectedButton.uri = selectedButton.uri.Replace(oldState, newState)
|
||||||
|
end sub
|
||||||
|
|
||||||
|
' processScrubAction: Handles +/- seeking for the audio trickplay bar
|
||||||
|
'
|
||||||
|
' @param {integer} seekStep - seconds to move the trickplay position (negative values allowed)
|
||||||
|
sub processScrubAction(seekStep as integer)
|
||||||
|
' Prepare starting playStart property value
|
||||||
|
if m.scrubTimestamp = -1
|
||||||
|
m.scrubTimestamp = m.lastRecordedPositionTimestamp
|
||||||
|
end if
|
||||||
|
|
||||||
|
' Don't let seek to go past the end of the song
|
||||||
|
if m.scrubTimestamp + seekStep > m.songDuration - 5
|
||||||
|
return
|
||||||
|
end if
|
||||||
|
|
||||||
|
if seekStep > 0
|
||||||
|
' Move seek forward
|
||||||
|
m.scrubTimestamp += seekStep
|
||||||
|
else if m.scrubTimestamp >= Abs(seekStep)
|
||||||
|
' If back seek won't go below 0, move seek back
|
||||||
|
m.scrubTimestamp += seekStep
|
||||||
|
else
|
||||||
|
' Back seek would go below 0, set to 0 directly
|
||||||
|
m.scrubTimestamp = 0
|
||||||
|
end if
|
||||||
|
|
||||||
|
' Move the seedbar thumb forward
|
||||||
|
songPercentComplete = m.scrubTimestamp / m.songDuration
|
||||||
|
playPositionBarWidth = m.seekBar.width * songPercentComplete
|
||||||
|
|
||||||
|
moveSeekbarThumb(playPositionBarWidth)
|
||||||
|
|
||||||
|
' Change the displayed position timestamp
|
||||||
|
m.seekTimestamp.text = secondsToHuman(m.scrubTimestamp, false)
|
||||||
|
end sub
|
||||||
|
|
||||||
|
' resetSeekbarThumb: Resets the thumb to the playing position
|
||||||
|
'
|
||||||
|
sub resetSeekbarThumb()
|
||||||
|
m.scrubTimestamp = -1
|
||||||
|
moveSeekbarThumb(m.playPosition.width)
|
||||||
|
end sub
|
||||||
|
|
||||||
|
' moveSeekbarThumb: Positions the thumb on the seekbar
|
||||||
|
'
|
||||||
|
' @param {float} playPositionBarWidth - width of the play position bar
|
||||||
|
sub moveSeekbarThumb(playPositionBarWidth as float)
|
||||||
|
' Center the thumb on the play position bar
|
||||||
|
thumbPostionLeft = playPositionBarWidth - 10
|
||||||
|
|
||||||
|
' Don't let thumb go below 0
|
||||||
|
if thumbPostionLeft < 0 then thumbPostionLeft = 0
|
||||||
|
|
||||||
|
' Don't let thumb go past end of seekbar
|
||||||
|
if thumbPostionLeft > m.seekBar.width - 25
|
||||||
|
thumbPostionLeft = m.seekBar.width - 25
|
||||||
|
end if
|
||||||
|
|
||||||
|
' Move the thumb
|
||||||
|
m.thumb.translation = [thumbPostionLeft, m.thumb.translation[1]]
|
||||||
|
|
||||||
|
' Move the seek position element so it follows the thumb
|
||||||
|
m.seekPosition.translation = [720 + thumbPostionLeft - (m.seekPosition.width / 2), m.seekPosition.translation[1]]
|
||||||
|
end sub
|
||||||
|
|
||||||
|
' exitScrubMode: Moves player out of scrub mode state, resets back to standard play mode
|
||||||
|
'
|
||||||
|
sub exitScrubMode()
|
||||||
|
m.buttons.setFocus(true)
|
||||||
|
m.thumb.setFocus(false)
|
||||||
|
|
||||||
|
if m.seekPosition.visible
|
||||||
|
m.seekPosition.visible = false
|
||||||
|
end if
|
||||||
|
|
||||||
|
resetSeekbarThumb()
|
||||||
|
|
||||||
|
m.inScrubMode = false
|
||||||
|
m.thumb.visible = false
|
||||||
|
setSelectedButtonState("-default", "-selected")
|
||||||
|
end sub
|
||||||
|
|
||||||
' Process key press events
|
' Process key press events
|
||||||
function onKeyEvent(key as string, press as boolean) as boolean
|
function onKeyEvent(key as string, press as boolean) as boolean
|
||||||
|
|
||||||
|
@ -555,9 +721,58 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
||||||
return true
|
return true
|
||||||
end if
|
end if
|
||||||
|
|
||||||
|
' Key Event handler when m.thumb is in focus
|
||||||
|
if m.thumb.hasFocus()
|
||||||
|
if key = "right"
|
||||||
|
m.inScrubMode = true
|
||||||
|
processScrubAction(10)
|
||||||
|
return true
|
||||||
|
end if
|
||||||
|
|
||||||
|
if key = "left"
|
||||||
|
m.inScrubMode = true
|
||||||
|
processScrubAction(-10)
|
||||||
|
return true
|
||||||
|
end if
|
||||||
|
|
||||||
|
if key = "OK" or key = "play"
|
||||||
|
if m.inScrubMode
|
||||||
|
startLoadingSpinner()
|
||||||
|
m.inScrubMode = false
|
||||||
|
m.global.audioPlayer.seek = m.scrubTimestamp
|
||||||
|
return true
|
||||||
|
end if
|
||||||
|
|
||||||
|
return playAction()
|
||||||
|
end if
|
||||||
|
end if
|
||||||
|
|
||||||
if key = "play"
|
if key = "play"
|
||||||
return playAction()
|
return playAction()
|
||||||
else if key = "back"
|
end if
|
||||||
|
|
||||||
|
if key = "up"
|
||||||
|
if not m.thumb.visible
|
||||||
|
m.thumb.visible = true
|
||||||
|
setSelectedButtonState("-selected", "-default")
|
||||||
|
end if
|
||||||
|
if not m.seekPosition.visible
|
||||||
|
m.seekPosition.visible = true
|
||||||
|
end if
|
||||||
|
|
||||||
|
m.thumb.setFocus(true)
|
||||||
|
m.buttons.setFocus(false)
|
||||||
|
return true
|
||||||
|
end if
|
||||||
|
|
||||||
|
if key = "down"
|
||||||
|
if m.thumb.visible
|
||||||
|
exitScrubMode()
|
||||||
|
end if
|
||||||
|
return true
|
||||||
|
end if
|
||||||
|
|
||||||
|
if key = "back"
|
||||||
m.global.audioPlayer.control = "stop"
|
m.global.audioPlayer.control = "stop"
|
||||||
m.global.audioPlayer.loopMode = ""
|
m.global.audioPlayer.loopMode = ""
|
||||||
else if key = "rewind"
|
else if key = "rewind"
|
||||||
|
@ -565,6 +780,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
||||||
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.global.queueManager.callFunc("getCount") = 1 then return false
|
if m.global.queueManager.callFunc("getCount") = 1 then return false
|
||||||
|
|
||||||
if m.top.selectedButtonIndex > 0
|
if m.top.selectedButtonIndex > 0
|
||||||
|
@ -572,13 +788,17 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
||||||
m.top.selectedButtonIndex = m.top.selectedButtonIndex - 1
|
m.top.selectedButtonIndex = m.top.selectedButtonIndex - 1
|
||||||
end if
|
end if
|
||||||
return true
|
return true
|
||||||
|
end if
|
||||||
else if key = "right"
|
else if key = "right"
|
||||||
|
if m.buttons.hasFocus()
|
||||||
if m.global.queueManager.callFunc("getCount") = 1 then return false
|
if m.global.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
|
||||||
return true
|
return true
|
||||||
|
end if
|
||||||
else if key = "OK"
|
else if key = "OK"
|
||||||
|
if m.buttons.hasFocus()
|
||||||
if m.buttons.getChild(m.top.selectedButtonIndex).id = "play"
|
if m.buttons.getChild(m.top.selectedButtonIndex).id = "play"
|
||||||
return playAction()
|
return playAction()
|
||||||
else if m.buttons.getChild(m.top.selectedButtonIndex).id = "previous"
|
else if m.buttons.getChild(m.top.selectedButtonIndex).id = "previous"
|
||||||
|
@ -592,6 +812,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
||||||
end if
|
end if
|
||||||
end if
|
end if
|
||||||
end if
|
end if
|
||||||
|
end if
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end function
|
end function
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
<Poster id="backdrop" opacity=".5" loadDisplayMode="scaleToZoom" width="1920" height="1200" blendColor="#3f3f3f" />
|
<Poster id="backdrop" opacity=".5" loadDisplayMode="scaleToZoom" width="1920" height="1200" blendColor="#3f3f3f" />
|
||||||
<Poster id="shuffleIndicator" width="64" height="64" uri="pkg:/images/icons/shuffleIndicator-off.png" translation="[1150,775]" opacity="0" />
|
<Poster id="shuffleIndicator" width="64" height="64" uri="pkg:/images/icons/shuffleIndicator-off.png" translation="[1150,775]" opacity="0" />
|
||||||
<Poster id="loopIndicator" width="64" height="64" uri="pkg:/images/icons/loopIndicator-off.png" translation="[700,775]" opacity="0" />
|
<Poster id="loopIndicator" width="64" height="64" uri="pkg:/images/icons/loopIndicator-off.png" translation="[700,775]" opacity="0" />
|
||||||
<Label id="positionTimestamp" width="100" height="25" horizAlign="right" font="font:SmallestSystemFont" translation="[590,825]" color="#999999" text="0:00" />
|
<Label id="positionTimestamp" width="100" height="25" horizAlign="right" font="font:SmallestSystemFont" translation="[590,838]" color="#999999" text="0:00" />
|
||||||
<Label id="totalLengthTimestamp" width="100" height="25" horizAlign="left" font="font:SmallestSystemFont" translation="[1230,825]" color="#999999" />
|
<Label id="totalLengthTimestamp" width="100" height="25" horizAlign="left" font="font:SmallestSystemFont" translation="[1230,838]" color="#999999" />
|
||||||
|
|
||||||
<LayoutGroup id="toplevel" layoutDirection="vert" horizAlignment="center" translation="[960,175]" itemSpacings="[40]">
|
<LayoutGroup id="toplevel" layoutDirection="vert" horizAlignment="center" translation="[960,175]" itemSpacings="[40]">
|
||||||
<LayoutGroup id="main_group" layoutDirection="vert" horizAlignment="center" itemSpacings="[15]">
|
<LayoutGroup id="main_group" layoutDirection="vert" horizAlignment="center" itemSpacings="[15]">
|
||||||
<Poster id="albumCover" width="500" height="500" />
|
<Poster id="albumCover" width="500" height="500" />
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
<Rectangle id="seekBar" color="0x00000099" width="500" height="10">
|
<Rectangle id="seekBar" color="0x00000099" width="500" height="10">
|
||||||
<Rectangle id="bufferPosition" color="0xFFFFFF44" height="10"></Rectangle>
|
<Rectangle id="bufferPosition" color="0xFFFFFF44" height="10"></Rectangle>
|
||||||
<Rectangle id="playPosition" color="#00a4dcFF" height="10"></Rectangle>
|
<Rectangle id="playPosition" color="#00a4dcFF" height="10"></Rectangle>
|
||||||
|
<Poster id="thumb" width="25" height="25" uri="pkg:/images/icons/circle.png" visible="false" translation="[0, -10]" />
|
||||||
</Rectangle>
|
</Rectangle>
|
||||||
<LayoutGroup id="buttons" layoutDirection="horiz" horizAlignment="center" itemSpacings="[45]">
|
<LayoutGroup id="buttons" layoutDirection="horiz" horizAlignment="center" itemSpacings="[45]">
|
||||||
<Poster id="loop" width="64" height="64" uri="pkg:/images/icons/loop-default.png" opacity="0" />
|
<Poster id="loop" width="64" height="64" uri="pkg:/images/icons/loop-default.png" opacity="0" />
|
||||||
|
@ -37,6 +39,9 @@
|
||||||
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[0.0, 1.0]" fieldToInterp="loop.opacity" />
|
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[0.0, 1.0]" fieldToInterp="loop.opacity" />
|
||||||
</Animation>
|
</Animation>
|
||||||
</LayoutGroup>
|
</LayoutGroup>
|
||||||
|
<Rectangle id="seekPosition" visible="false" color="0x00000090" height="40" width="110" translation="[720, 790]">
|
||||||
|
<Label text="0:00" id="seekTimestamp" width="110" height="40" horizAlign="center" vertAlign="center" font="font:SmallestSystemFont" />
|
||||||
|
</Rectangle>
|
||||||
<Rectangle id="screenSaverBackground" width="1920" height="1080" color="#000000" visible="false" />
|
<Rectangle id="screenSaverBackground" width="1920" height="1080" color="#000000" visible="false" />
|
||||||
<Poster id="screenSaverAlbumCover" width="500" height="500" translation="[960,575]" opacity="0" />
|
<Poster id="screenSaverAlbumCover" width="500" height="500" translation="[960,575]" opacity="0" />
|
||||||
<Poster id="PosterOne" width="389" height="104" translation="[960,540]" opacity="0" />
|
<Poster id="PosterOne" width="389" height="104" translation="[960,540]" opacity="0" />
|
||||||
|
|
|
@ -28,7 +28,10 @@ sub itemContentChanged()
|
||||||
end if
|
end if
|
||||||
|
|
||||||
if isValid(itemData.indexNumber)
|
if isValid(itemData.indexNumber)
|
||||||
indexNumber = itemData.indexNumber.toStr() + ". "
|
indexNumber = `${itemData.indexNumber}. `
|
||||||
|
if isValid(itemData.indexNumberEnd)
|
||||||
|
indexNumber = `${itemData.indexNumber}-${itemData.indexNumberEnd}. `
|
||||||
|
end if
|
||||||
else
|
else
|
||||||
indexNumber = ""
|
indexNumber = ""
|
||||||
end if
|
end if
|
||||||
|
|
|
@ -27,8 +27,8 @@ sub init()
|
||||||
m.top.observeField("episodeNumberEnd", "onEpisodeNumberEndChanged")
|
m.top.observeField("episodeNumberEnd", "onEpisodeNumberEndChanged")
|
||||||
m.top.observeField("logoImage", "onLogoImageChanged")
|
m.top.observeField("logoImage", "onLogoImageChanged")
|
||||||
|
|
||||||
m.defaultButtonIndex = 1
|
m.defaultButtonIndex = 2
|
||||||
m.focusedButtonIndex = 1
|
m.focusedButtonIndex = 2
|
||||||
m.optionControlsMoved = false
|
m.optionControlsMoved = false
|
||||||
|
|
||||||
m.videoControls.buttonFocused = m.defaultButtonIndex
|
m.videoControls.buttonFocused = m.defaultButtonIndex
|
||||||
|
@ -171,7 +171,7 @@ sub resetFocusToDefaultButton()
|
||||||
m.videoControls.setFocus(true)
|
m.videoControls.setFocus(true)
|
||||||
m.focusedButtonIndex = m.defaultButtonIndex
|
m.focusedButtonIndex = m.defaultButtonIndex
|
||||||
m.videoControls.getChild(m.defaultButtonIndex).focus = true
|
m.videoControls.getChild(m.defaultButtonIndex).focus = true
|
||||||
m.videoControls.buttonFocused = 1
|
m.videoControls.buttonFocused = m.defaultButtonIndex
|
||||||
m.optionControls.buttonFocused = m.optionControls.getChildCount() - 1
|
m.optionControls.buttonFocused = m.optionControls.getChildCount() - 1
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,11 @@
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<ButtonGroup id="videoControls" itemSpacings="[20]" layoutDirection="horiz" horizAlignment="center" translation="[960,875]">
|
<ButtonGroup id="videoControls" itemSpacings="[20]" layoutDirection="horiz" horizAlignment="center" translation="[960,875]">
|
||||||
|
<IconButton id="itemBack" background="#070707" focusBackground="#00a4dc" padding="35" icon="pkg:/images/icons/itemPrevious.png" height="65" width="100" />
|
||||||
<IconButton id="chapterBack" background="#070707" focusBackground="#00a4dc" padding="16" icon="pkg:/images/icons/previousChapter.png" height="65" width="100" />
|
<IconButton id="chapterBack" background="#070707" focusBackground="#00a4dc" padding="16" icon="pkg:/images/icons/previousChapter.png" height="65" width="100" />
|
||||||
<IconButton id="videoPlayPause" background="#070707" focusBackground="#00a4dc" padding="35" icon="pkg:/images/icons/play.png" height="65" width="100" />
|
<IconButton id="videoPlayPause" background="#070707" focusBackground="#00a4dc" padding="35" icon="pkg:/images/icons/play.png" height="65" width="100" />
|
||||||
<IconButton id="chapterNext" background="#070707" focusBackground="#00a4dc" padding="16" icon="pkg:/images/icons/nextChapter.png" height="65" width="100" />
|
<IconButton id="chapterNext" background="#070707" focusBackground="#00a4dc" padding="16" icon="pkg:/images/icons/nextChapter.png" height="65" width="100" />
|
||||||
|
<IconButton id="itemNext" background="#070707" focusBackground="#00a4dc" padding="35" icon="pkg:/images/icons/itemNext.png" height="65" width="100" />
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<Rectangle id="progressBarBackground" color="0x00000098" width="1714" height="8" translation="[103,970]">
|
<Rectangle id="progressBarBackground" color="0x00000098" width="1714" height="8" translation="[103,970]">
|
||||||
|
|
|
@ -92,6 +92,35 @@ sub handleChapterSkipAction(action as string)
|
||||||
end if
|
end if
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
' handleItemSkipAction: Handles user command to skip items
|
||||||
|
'
|
||||||
|
' @param {string} action - skip action to take
|
||||||
|
sub handleItemSkipAction(action as string)
|
||||||
|
if action = "itemnext"
|
||||||
|
' If there is something next in the queue, play it
|
||||||
|
if m.global.queueManager.callFunc("getPosition") < m.global.queueManager.callFunc("getCount") - 1
|
||||||
|
m.top.control = "stop"
|
||||||
|
m.global.sceneManager.callFunc("clearPreviousScene")
|
||||||
|
m.global.queueManager.callFunc("moveForward")
|
||||||
|
m.global.queueManager.callFunc("playQueue")
|
||||||
|
end if
|
||||||
|
|
||||||
|
return
|
||||||
|
end if
|
||||||
|
|
||||||
|
if action = "itemback"
|
||||||
|
' If there is something previous in the queue, play it
|
||||||
|
if m.global.queueManager.callFunc("getPosition") > 0
|
||||||
|
m.top.control = "stop"
|
||||||
|
m.global.sceneManager.callFunc("clearPreviousScene")
|
||||||
|
m.global.queueManager.callFunc("moveBack")
|
||||||
|
m.global.queueManager.callFunc("playQueue")
|
||||||
|
end if
|
||||||
|
|
||||||
|
return
|
||||||
|
end if
|
||||||
|
end sub
|
||||||
|
|
||||||
' handleHideAction: Handles action to hide OSD menu
|
' handleHideAction: Handles action to hide OSD menu
|
||||||
'
|
'
|
||||||
' @param {boolean} resume - controls whether or not to resume video playback when sub is called
|
' @param {boolean} resume - controls whether or not to resume video playback when sub is called
|
||||||
|
@ -220,6 +249,11 @@ sub onOSDAction()
|
||||||
handleShowVideoInfoPopupAction()
|
handleShowVideoInfoPopupAction()
|
||||||
return
|
return
|
||||||
end if
|
end if
|
||||||
|
|
||||||
|
if action = "itemback" or action = "itemnext"
|
||||||
|
handleItemSkipAction(action)
|
||||||
|
return
|
||||||
|
end if
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
' Only setup caption items if captions are allowed
|
' Only setup caption items if captions are allowed
|
||||||
|
@ -362,6 +396,7 @@ sub onVideoContentLoaded()
|
||||||
m.top.audioIndex = videoContent[0].audioIndex
|
m.top.audioIndex = videoContent[0].audioIndex
|
||||||
m.top.transcodeParams = videoContent[0].transcodeparams
|
m.top.transcodeParams = videoContent[0].transcodeparams
|
||||||
m.chapters = videoContent[0].chapters
|
m.chapters = videoContent[0].chapters
|
||||||
|
m.top.showID = videoContent[0].showID
|
||||||
|
|
||||||
m.osd.itemTitleText = m.top.content.title
|
m.osd.itemTitleText = m.top.content.title
|
||||||
|
|
||||||
|
@ -469,6 +504,11 @@ sub onNextEpisodeDataLoaded()
|
||||||
m.checkedForNextEpisode = true
|
m.checkedForNextEpisode = true
|
||||||
|
|
||||||
m.top.observeField("position", "onPositionChanged")
|
m.top.observeField("position", "onPositionChanged")
|
||||||
|
|
||||||
|
' If there is no next episode, disable next episode button
|
||||||
|
if m.getNextEpisodeTask.nextEpisodeData.Items.count() <> 2
|
||||||
|
m.nextupbuttonseconds = 0
|
||||||
|
end if
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
'
|
'
|
||||||
|
@ -583,7 +623,7 @@ sub onState(msg)
|
||||||
m.top.backPressed = true
|
m.top.backPressed = true
|
||||||
else if m.top.state = "playing"
|
else if m.top.state = "playing"
|
||||||
|
|
||||||
' Check if next episde is available
|
' Check if next episode is available
|
||||||
if isValid(m.top.showID)
|
if isValid(m.top.showID)
|
||||||
if m.top.showID <> "" and not m.checkedForNextEpisode and m.top.content.contenttype = 4
|
if m.top.showID <> "" and not m.checkedForNextEpisode and m.top.content.contenttype = 4
|
||||||
m.getNextEpisodeTask.showID = m.top.showID
|
m.getNextEpisodeTask.showID = m.top.showID
|
||||||
|
|
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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
8
docs/api/components_data_JFContentItem.bs.html
Normal file
8
docs/api/components_data_JFContentItem.bs.html
Normal file
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