Merge branch 'unstable' into Add-Episode-Aired-Date-to-details
This commit is contained in:
commit
f2498d93da
2
.github/workflows/auto-close-stale-pr.yml
vendored
2
.github/workflows/auto-close-stale-pr.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
|||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@3de2653986ebd134983c79fe2be5d45cc3d9f4e1 # tag=v6
|
||||
- uses: actions/stale@5ebf00ea0e4c1561e9b43a292ed34424fb1d4578 # tag=v6
|
||||
with:
|
||||
days-before-issue-stale: -1
|
||||
days-before-issue-close: -1
|
||||
|
|
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
|
@ -8,14 +8,14 @@ jobs:
|
|||
run:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3
|
||||
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
|
||||
with:
|
||||
node-version: "14.12.0"
|
||||
- run: npm ci
|
||||
- run: npx ropm install
|
||||
- run: make dev
|
||||
- uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # tag=v3
|
||||
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # tag=v3
|
||||
with:
|
||||
name: Jellyfin-Roku-dev-${{ github.sha }}
|
||||
path: ${{ github.workspace }}/out/staging
|
||||
|
|
4
.github/workflows/master-release.yml
vendored
4
.github/workflows/master-release.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
|||
run: awk 'BEGIN { FS="=" } /^minor_version/ { print "MINOR="$2; }' manifest >> $GITHUB_ENV
|
||||
- name: "Find and save build_version from manifest"
|
||||
run: awk 'BEGIN { FS="=" } /^build_version/ { print "BUILD="$2; }' manifest >> $GITHUB_ENV
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3
|
||||
- uses: vimtor/action-zip@5f1c4aa587ea41db1110df6a99981dbe19cee310 # tag=v1
|
||||
with:
|
||||
recursive: false
|
||||
|
@ -36,7 +36,7 @@ jobs:
|
|||
prerelease: false
|
||||
title: v${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.BUILD }}
|
||||
files: ${{ github.workspace }}/jellyfin_v${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.BUILD }}.zip
|
||||
- uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # tag=v3
|
||||
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # tag=v3
|
||||
with:
|
||||
name: jellyfin_v${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.BUILD }}.zip
|
||||
path: ${{ github.workspace }}/jellyfin_v${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.BUILD }}.zip
|
||||
|
|
4
.github/workflows/unstable-release.yml
vendored
4
.github/workflows/unstable-release.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
|||
run: awk 'BEGIN { FS="=" } /^minor_version/ { print "MINOR="$2; }' manifest >> $GITHUB_ENV
|
||||
- name: "Find and save build_version from manifest"
|
||||
run: awk 'BEGIN { FS="=" } /^build_version/ { print "BUILD="$2; }' manifest >> $GITHUB_ENV
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3
|
||||
- uses: vimtor/action-zip@5f1c4aa587ea41db1110df6a99981dbe19cee310 # tag=v1
|
||||
with:
|
||||
recursive: false
|
||||
|
@ -35,7 +35,7 @@ jobs:
|
|||
prerelease: true
|
||||
title: v${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.BUILD }}
|
||||
files: ${{ github.workspace }}/jellyfin_v${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.BUILD }}.zip
|
||||
- uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # tag=v3
|
||||
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # tag=v3
|
||||
with:
|
||||
name: jellyfin_v${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.BUILD }}.zip
|
||||
path: ${{ github.workspace }}/jellyfin_v${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.BUILD }}.zip
|
||||
|
|
2
Makefile
2
Makefile
|
@ -12,7 +12,7 @@
|
|||
##########################################################################
|
||||
|
||||
APPNAME = Jellyfin_Roku
|
||||
VERSION = 1.4.12
|
||||
VERSION = 1.6.2
|
||||
ROKU_TEST_ID = 1
|
||||
ROKU_TEST_WAIT_DURATION = 5
|
||||
|
||||
|
|
13
components/GetNextEpisodeTask.brs
Normal file
13
components/GetNextEpisodeTask.brs
Normal file
|
@ -0,0 +1,13 @@
|
|||
sub init()
|
||||
m.top.functionName = "getNextEpisodeTask"
|
||||
end sub
|
||||
|
||||
sub getNextEpisodeTask()
|
||||
m.nextEpisodeData = api_API().shows.getepisodes(m.top.showID, {
|
||||
UserId: get_setting("active_user"),
|
||||
StartItemId: m.top.videoID,
|
||||
Limit: 2
|
||||
})
|
||||
|
||||
m.top.nextEpisodeData = m.nextEpisodeData
|
||||
end sub
|
12
components/GetNextEpisodeTask.xml
Normal file
12
components/GetNextEpisodeTask.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<component name="GetNextEpisodeTask" extends="Task">
|
||||
<interface>
|
||||
<field id="videoID" type="string" />
|
||||
<field id="showID" type="string" />
|
||||
<field id="nextEpisodeData" type="assocarray" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="GetNextEpisodeTask.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/roku_modules/api/api.brs" />
|
||||
</component>
|
42
components/ItemGrid/GridItemSmall.brs
Normal file
42
components/ItemGrid/GridItemSmall.brs
Normal file
|
@ -0,0 +1,42 @@
|
|||
sub init()
|
||||
m.itemPoster = m.top.findNode("itemPoster")
|
||||
m.posterText = m.top.findNode("posterText")
|
||||
m.posterText.font.size = 30
|
||||
m.backdrop = m.top.findNode("backdrop")
|
||||
|
||||
m.itemPoster.observeField("loadStatus", "onPosterLoadStatusChanged")
|
||||
|
||||
'Parent is MarkupGrid and it's parent is the ItemGrid
|
||||
m.topParent = m.top.GetParent().GetParent()
|
||||
|
||||
'Get the imageDisplayMode for these grid items
|
||||
if m.topParent.imageDisplayMode <> invalid
|
||||
m.itemPoster.loadDisplayMode = m.topParent.imageDisplayMode
|
||||
end if
|
||||
|
||||
end sub
|
||||
|
||||
sub itemContentChanged()
|
||||
m.backdrop.blendColor = "#101010"
|
||||
|
||||
itemData = m.top.itemContent
|
||||
|
||||
if not isValid(itemData) then return
|
||||
|
||||
m.itemPoster.uri = itemData.PosterUrl
|
||||
m.posterText.text = itemData.title
|
||||
|
||||
'If Poster not loaded, ensure "blue box" is shown until loaded
|
||||
if m.itemPoster.loadStatus <> "ready"
|
||||
m.backdrop.visible = true
|
||||
m.posterText.visible = true
|
||||
end if
|
||||
end sub
|
||||
|
||||
'Hide backdrop and text when poster loaded
|
||||
sub onPosterLoadStatusChanged()
|
||||
if m.itemPoster.loadStatus = "ready"
|
||||
m.backdrop.visible = false
|
||||
m.posterText.visible = false
|
||||
end if
|
||||
end sub
|
16
components/ItemGrid/GridItemSmall.xml
Normal file
16
components/ItemGrid/GridItemSmall.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="GridItemSmall" extends="Group">
|
||||
<children>
|
||||
<Poster id="backdrop" translation="[0,15]" width="230" height="320" loadDisplayMode="scaleToZoom" uri="pkg:/images/white.9.png" />
|
||||
<Poster id="itemPoster" translation="[0,15]" width="230" height="320" loadDisplayMode="scaleToZoom" />
|
||||
<Poster id="itemIcon" width="50" height="50" translation="[230,10]" />
|
||||
<Label id="posterText" width="230" height="320" translation="[5,5]" horizAlign="center" vertAlign="center" ellipsizeOnBoundary="true" wrap="true" />
|
||||
</children>
|
||||
<interface>
|
||||
<field id="itemContent" type="node" onChange="itemContentChanged" />
|
||||
<field id="itemHasFocus" type="boolean" onChange="focusChanged" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="GridItemSmall.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
</component>
|
|
@ -320,13 +320,14 @@ end sub
|
|||
|
||||
' Set Photo Album view, sort, and filter options
|
||||
sub setPhotoAlbumOptions(options)
|
||||
' TODO/FIXME: Show shuffle options once implemented
|
||||
' options.views = [
|
||||
' { "Title": tr("Don't Shuffle"), "Name": "singlephoto"}
|
||||
' { "Title": tr("Shuffle"), "Name": "shufflephoto"}
|
||||
' ]
|
||||
options.views = []
|
||||
options.views = [
|
||||
{ "Title": tr("Slideshow Off"), "Name": "singlephoto" }
|
||||
{ "Title": tr("Slideshow On"), "Name": "slideshowphoto" }
|
||||
{ "Title": tr("Random Off"), "Name": "singlephoto" }
|
||||
{ "Title": tr("Random On"), "Name": "randomphoto" }
|
||||
]
|
||||
options.sort = []
|
||||
options.filter = []
|
||||
end sub
|
||||
|
||||
' Set Default view, sort, and filter options
|
||||
|
@ -574,14 +575,17 @@ sub optionsClosed()
|
|||
end if
|
||||
end if
|
||||
|
||||
if m.top.parentItem.Type = "CollectionFolder" or m.top.parentItem.CollectionType = "CollectionFolder"
|
||||
' Did the user just request "Shuffle" on a PhotoAlbum?
|
||||
if m.top.parentItem.Type = "CollectionFolder" or m.top.parentItem.Type = "Folder" or m.top.parentItem.CollectionType = "CollectionFolder"
|
||||
' Did the user just request "Random" on a PhotoAlbum?
|
||||
if m.options.view = "singlephoto"
|
||||
' TODO/FIXME: Stop shuffling here
|
||||
print "TODO/FIXME: Stop any shuffling here"
|
||||
else if m.options.view = "shufflephoto"
|
||||
' TODO/FIXME: Start shuffling here
|
||||
print "TODO/FIXME: Start shuffle here"
|
||||
set_user_setting("photos.slideshow", "false")
|
||||
set_user_setting("photos.random", "false")
|
||||
else if m.options.view = "slideshowphoto"
|
||||
set_user_setting("photos.slideshow", "true")
|
||||
set_user_setting("photos.random", "false")
|
||||
else if m.options.view = "randomphoto"
|
||||
set_user_setting("photos.random", "true")
|
||||
set_user_setting("photos.slideshow", "false")
|
||||
end if
|
||||
end if
|
||||
|
||||
|
@ -724,9 +728,10 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
return true
|
||||
else if itemToPlay <> invalid and itemToPlay.type = "Photo"
|
||||
' Spawn photo player task
|
||||
photoPlayer = CreateObject("roSgNode", "PhotoPlayerTask")
|
||||
photoPlayer.itemContent = itemToPlay
|
||||
photoPlayer.control = "RUN"
|
||||
photoPlayer = CreateObject("roSgNode", "PhotoDetails")
|
||||
photoPlayer.items = markupGrid
|
||||
photoPlayer.itemIndex = markupGrid.itemFocused
|
||||
m.global.sceneManager.callfunc("pushScene", photoPlayer)
|
||||
return true
|
||||
end if
|
||||
else if key = "left" and topGrp.isinFocusChain()
|
||||
|
|
|
@ -20,6 +20,16 @@ sub loadItems()
|
|||
sort_order = "Descending"
|
||||
end if
|
||||
|
||||
if m.top.ItemType = "LogoImage"
|
||||
logoImageExists = api_API().items.headimageurlbyname(m.top.itemId, "logo")
|
||||
if logoImageExists
|
||||
m.top.content = [api_API().items.getimageurl(m.top.itemId, "logo", 0, { "maxHeight": 500, "maxWidth": 500, "quality": "90" })]
|
||||
else
|
||||
m.top.content = []
|
||||
end if
|
||||
|
||||
return
|
||||
end if
|
||||
|
||||
params = {
|
||||
limit: m.top.limit,
|
||||
|
@ -117,7 +127,49 @@ sub loadItems()
|
|||
else if item.type = "Episode"
|
||||
tmp = CreateObject("roSGNode", "TVEpisode")
|
||||
else if item.Type = "Genre"
|
||||
tmp = CreateObject("roSGNode", "FolderData")
|
||||
tmp = CreateObject("roSGNode", "ContentNode")
|
||||
tmp.title = item.name
|
||||
|
||||
genreData = api_API().users.getitemsbyquery(get_setting("active_user"), {
|
||||
SortBy: "Random",
|
||||
SortOrder: "Ascending",
|
||||
IncludeItemTypes: "Movie",
|
||||
Recursive: true,
|
||||
Fields: "PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo",
|
||||
ImageTypeLimit: 1,
|
||||
EnableImageTypes: "Primary",
|
||||
Limit: 6,
|
||||
GenreIds: item.id,
|
||||
EnableTotalRecordCount: false,
|
||||
ParentId: m.top.itemId
|
||||
})
|
||||
|
||||
if genreData.Items.Count() > 5
|
||||
' Add View All item to the start of the row
|
||||
row = tmp.createChild("FolderData")
|
||||
row.parentFolder = m.top.itemId
|
||||
genreMovieImage = api_API().items.getimageurl(item.id)
|
||||
row.title = item.name
|
||||
row.json = item
|
||||
row.FHDPOSTERURL = genreMovieImage
|
||||
row.HDPOSTERURL = genreMovieImage
|
||||
row.SDPOSTERURL = genreMovieImage
|
||||
row.type = "Folder"
|
||||
end if
|
||||
|
||||
for each genreMovie in genreData.Items
|
||||
row = tmp.createChild("MovieData")
|
||||
|
||||
genreMovieImage = api_API().items.getimageurl(genreMovie.id)
|
||||
row.title = genreMovie.name
|
||||
row.FHDPOSTERURL = genreMovieImage
|
||||
row.HDPOSTERURL = genreMovieImage
|
||||
row.SDPOSTERURL = genreMovieImage
|
||||
row.json = genreMovie
|
||||
row.id = genreMovie.id
|
||||
row.type = genreMovie.type
|
||||
end for
|
||||
|
||||
else if item.Type = "Studio"
|
||||
tmp = CreateObject("roSGNode", "FolderData")
|
||||
else if item.Type = "MusicAlbum"
|
||||
|
@ -135,12 +187,16 @@ sub loadItems()
|
|||
else
|
||||
print "[LoadItems] Unknown Type: " item.Type
|
||||
end if
|
||||
|
||||
if tmp <> invalid
|
||||
if item.Type <> "Genre"
|
||||
tmp.parentFolder = m.top.itemId
|
||||
tmp.json = item
|
||||
if item.UserData <> invalid and item.UserData.isFavorite <> invalid
|
||||
tmp.favorite = item.UserData.isFavorite
|
||||
end if
|
||||
end if
|
||||
|
||||
results.push(tmp)
|
||||
end if
|
||||
end for
|
||||
|
|
790
components/ItemGrid/MovieLibraryView.brs
Normal file
790
components/ItemGrid/MovieLibraryView.brs
Normal file
|
@ -0,0 +1,790 @@
|
|||
sub setupNodes()
|
||||
m.options = m.top.findNode("options")
|
||||
m.itemGrid = m.top.findNode("itemGrid")
|
||||
m.voiceBox = m.top.findNode("voiceBox")
|
||||
m.backdrop = m.top.findNode("backdrop")
|
||||
m.newBackdrop = m.top.findNode("backdropTransition")
|
||||
m.emptyText = m.top.findNode("emptyText")
|
||||
m.selectedMovieName = m.top.findNode("selectedMovieName")
|
||||
m.selectedMovieOverview = m.top.findNode("selectedMovieOverview")
|
||||
m.selectedMovieProductionYear = m.top.findNode("selectedMovieProductionYear")
|
||||
m.selectedMovieOfficialRating = m.top.findNode("selectedMovieOfficialRating")
|
||||
m.movieLogo = m.top.findNode("movieLogo")
|
||||
m.swapAnimation = m.top.findNode("backroundSwapAnimation")
|
||||
m.spinner = m.top.findNode("spinner")
|
||||
m.Alpha = m.top.findNode("AlphaMenu")
|
||||
m.AlphaSelected = m.top.findNode("AlphaSelected")
|
||||
m.micButton = m.top.findNode("micButton")
|
||||
m.micButtonText = m.top.findNode("micButtonText")
|
||||
m.communityRatingGroup = m.top.findNode("communityRatingGroup")
|
||||
m.criticRatingIcon = m.top.findNode("criticRatingIcon")
|
||||
m.criticRatingGroup = m.top.findNode("criticRatingGroup")
|
||||
m.overhang = m.top.getScene().findNode("overhang")
|
||||
m.genreList = m.top.findNode("genrelist")
|
||||
m.infoGroup = m.top.findNode("infoGroup")
|
||||
end sub
|
||||
|
||||
sub init()
|
||||
setupNodes()
|
||||
|
||||
m.overhang.isVisible = false
|
||||
|
||||
m.showItemCount = get_user_setting("itemgrid.showItemCount") = "true"
|
||||
|
||||
m.swapAnimation.observeField("state", "swapDone")
|
||||
|
||||
m.loadedRows = 0
|
||||
m.loadedItems = 0
|
||||
|
||||
m.data = CreateObject("roSGNode", "ContentNode")
|
||||
|
||||
m.itemGrid.content = m.data
|
||||
|
||||
m.genreData = CreateObject("roSGNode", "ContentNode")
|
||||
m.genreList.observeField("itemSelected", "onGenreItemSelected")
|
||||
m.genreList.content = m.genreData
|
||||
|
||||
m.itemGrid.observeField("itemFocused", "onItemFocused")
|
||||
m.itemGrid.observeField("itemSelected", "onItemSelected")
|
||||
m.itemGrid.observeField("alphaSelected", "onItemalphaSelected")
|
||||
|
||||
'Voice filter setup
|
||||
m.voiceBox.voiceEnabled = true
|
||||
m.voiceBox.active = true
|
||||
m.voiceBox.observeField("text", "onvoiceFilter")
|
||||
'set voice help text
|
||||
m.voiceBox.hintText = tr("Use voice remote to search")
|
||||
|
||||
'backdrop
|
||||
m.newBackdrop.observeField("loadStatus", "newBGLoaded")
|
||||
|
||||
'Background Image Queued for loading
|
||||
m.queuedBGUri = ""
|
||||
|
||||
'Item sort - maybe load defaults from user prefs?
|
||||
m.sortField = "SortName"
|
||||
m.sortAscending = true
|
||||
|
||||
m.filter = "All"
|
||||
m.favorite = "Favorite"
|
||||
|
||||
m.loadItemsTask = createObject("roSGNode", "LoadItemsTask2")
|
||||
m.loadLogoTask = createObject("roSGNode", "LoadItemsTask2")
|
||||
|
||||
'set inital counts for overhang before content is loaded.
|
||||
m.loadItemsTask.totalRecordCount = 0
|
||||
|
||||
m.spinner.visible = true
|
||||
|
||||
'Get reset folder setting
|
||||
m.resetGrid = get_user_setting("itemgrid.reset") = "true"
|
||||
|
||||
'Check if device has voice remote
|
||||
devinfo = CreateObject("roDeviceInfo")
|
||||
|
||||
'Hide voice search if device does not have voice remote
|
||||
if devinfo.HasFeature("voice_remote") = false
|
||||
m.micButton.visible = false
|
||||
m.micButtonText.visible = false
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub OnScreenHidden()
|
||||
if not m.overhang.isVisible
|
||||
m.overhang.disableMoveAnimation = true
|
||||
m.overhang.isVisible = true
|
||||
m.overhang.disableMoveAnimation = false
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub OnScreenShown()
|
||||
m.overhang.isVisible = false
|
||||
|
||||
if m.top.lastFocus <> invalid
|
||||
m.top.lastFocus.setFocus(true)
|
||||
else
|
||||
m.top.setFocus(true)
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
'Load initial set of Data
|
||||
sub loadInitialItems()
|
||||
m.loadItemsTask.control = "stop"
|
||||
m.spinner.visible = true
|
||||
|
||||
if m.top.parentItem.json.Type = "CollectionFolder"
|
||||
m.top.HomeLibraryItem = m.top.parentItem.Id
|
||||
end if
|
||||
|
||||
if m.top.parentItem.backdropUrl <> invalid
|
||||
SetBackground(m.top.parentItem.backdropUrl)
|
||||
else
|
||||
SetBackground("")
|
||||
end if
|
||||
|
||||
m.sortField = get_user_setting("display." + m.top.parentItem.Id + ".sortField")
|
||||
sortAscendingStr = get_user_setting("display." + m.top.parentItem.Id + ".sortAscending")
|
||||
m.filter = get_user_setting("display." + m.top.parentItem.Id + ".filter")
|
||||
m.view = get_user_setting("display." + m.top.parentItem.Id + ".landing")
|
||||
|
||||
if not isValid(m.sortField) then m.sortField = "SortName"
|
||||
if not isValid(m.filter) then m.filter = "All"
|
||||
if not isValid(m.view) then m.view = "Movies"
|
||||
|
||||
if sortAscendingStr = invalid or sortAscendingStr = "true"
|
||||
m.sortAscending = true
|
||||
else
|
||||
m.sortAscending = false
|
||||
end if
|
||||
|
||||
if m.top.parentItem.json.type = "Studio"
|
||||
m.loadItemsTask.studioIds = m.top.parentItem.id
|
||||
m.loadItemsTask.itemId = m.top.parentItem.parentFolder
|
||||
m.loadItemsTask.genreIds = ""
|
||||
else if m.top.parentItem.json.type = "Genre"
|
||||
m.loadItemsTask.genreIds = m.top.parentItem.id
|
||||
m.loadItemsTask.itemId = m.top.parentItem.parentFolder
|
||||
m.loadItemsTask.studioIds = ""
|
||||
else if m.view = "Movies" or m.options.view = "Movies"
|
||||
m.loadItemsTask.studioIds = ""
|
||||
m.loadItemsTask.genreIds = ""
|
||||
else
|
||||
m.loadItemsTask.itemId = m.top.parentItem.Id
|
||||
end if
|
||||
|
||||
m.loadItemsTask.nameStartsWith = m.top.alphaSelected
|
||||
m.loadItemsTask.searchTerm = m.voiceBox.text
|
||||
m.emptyText.visible = false
|
||||
m.loadItemsTask.sortField = m.sortField
|
||||
m.loadItemsTask.sortAscending = m.sortAscending
|
||||
m.loadItemsTask.filter = m.filter
|
||||
m.loadItemsTask.startIndex = 0
|
||||
|
||||
' Load Item Types
|
||||
if getCollectionType() = "movies"
|
||||
m.loadItemsTask.itemType = "Movie"
|
||||
m.loadItemsTask.itemId = m.top.parentItem.Id
|
||||
end if
|
||||
|
||||
' By default we load movies
|
||||
m.loadItemsTask.studioIds = ""
|
||||
m.loadItemsTask.view = "Movies"
|
||||
m.itemGrid.translation = "[96, 650]"
|
||||
m.itemGrid.numRows = "2"
|
||||
m.selectedMovieOverview.visible = true
|
||||
m.infoGroup.visible = true
|
||||
|
||||
if m.options.view = "Studios" or m.view = "Studios"
|
||||
m.itemGrid.translation = "[96, 60]"
|
||||
m.itemGrid.numRows = "3"
|
||||
m.loadItemsTask.view = "Networks"
|
||||
m.top.imageDisplayMode = "scaleToFit"
|
||||
m.selectedMovieOverview.visible = false
|
||||
m.infoGroup.visible = false
|
||||
else if m.options.view = "Genres" or m.view = "Genres"
|
||||
m.loadItemsTask.StudioIds = m.top.parentItem.Id
|
||||
m.loadItemsTask.view = "Genres"
|
||||
m.movieLogo.visible = false
|
||||
m.selectedMovieName.visible = false
|
||||
m.selectedMovieOverview.visible = false
|
||||
m.infoGroup.visible = false
|
||||
end if
|
||||
|
||||
m.loadItemsTask.observeField("content", "ItemDataLoaded")
|
||||
m.spinner.visible = true
|
||||
m.loadItemsTask.control = "RUN"
|
||||
SetUpOptions()
|
||||
end sub
|
||||
|
||||
' Set Movies view, sort, and filter options
|
||||
sub setMoviesOptions(options)
|
||||
|
||||
options.views = [
|
||||
{ "Title": tr("Movies"), "Name": "Movies" },
|
||||
{ "Title": tr("Studios"), "Name": "Studios" },
|
||||
{ "Title": tr("Genres"), "Name": "Genres" }
|
||||
]
|
||||
|
||||
if m.top.parentItem.json.type = "Genre"
|
||||
options.views = [
|
||||
{ "Title": tr("Movies"), "Name": "Movies" }
|
||||
]
|
||||
end if
|
||||
|
||||
options.sort = [
|
||||
{ "Title": tr("TITLE"), "Name": "SortName" },
|
||||
{ "Title": tr("IMDB_RATING"), "Name": "CommunityRating" },
|
||||
{ "Title": tr("CRITIC_RATING"), "Name": "CriticRating" },
|
||||
{ "Title": tr("DATE_ADDED"), "Name": "DateCreated" },
|
||||
{ "Title": tr("DATE_PLAYED"), "Name": "DatePlayed" },
|
||||
{ "Title": tr("OFFICIAL_RATING"), "Name": "OfficialRating" },
|
||||
{ "Title": tr("PLAY_COUNT"), "Name": "PlayCount" },
|
||||
{ "Title": tr("RELEASE_DATE"), "Name": "PremiereDate" },
|
||||
{ "Title": tr("RUNTIME"), "Name": "Runtime" }
|
||||
]
|
||||
|
||||
options.filter = [
|
||||
{ "Title": tr("All"), "Name": "All" },
|
||||
{ "Title": tr("Favorites"), "Name": "Favorites" }
|
||||
]
|
||||
|
||||
if m.options.view = "Genres" or m.view = "Genres"
|
||||
options.sort = []
|
||||
options.filter = []
|
||||
end if
|
||||
|
||||
if m.options.view = "Studios" or m.view = "Studios"
|
||||
options.sort = [
|
||||
{ "Title": tr("TITLE"), "Name": "SortName" },
|
||||
{ "Title": tr("DATE_ADDED"), "Name": "DateCreated" },
|
||||
]
|
||||
end if
|
||||
end sub
|
||||
|
||||
' Return parent collection type
|
||||
function getCollectionType() as string
|
||||
if m.top.parentItem.collectionType = invalid
|
||||
return m.top.parentItem.Type
|
||||
else
|
||||
return m.top.parentItem.CollectionType
|
||||
end if
|
||||
end function
|
||||
|
||||
' Search string array for search value. Return if it's found
|
||||
function inStringArray(array, searchValue) as boolean
|
||||
for each item in array
|
||||
if lcase(item) = lcase(searchValue) then return true
|
||||
end for
|
||||
return false
|
||||
end function
|
||||
|
||||
' Data to display when options button selected
|
||||
sub SetUpOptions()
|
||||
options = {}
|
||||
options.filter = []
|
||||
options.favorite = []
|
||||
|
||||
setMoviesOptions(options)
|
||||
|
||||
' Set selected view option
|
||||
for each o in options.views
|
||||
if o.Name = m.view
|
||||
o.Selected = true
|
||||
o.Ascending = m.sortAscending
|
||||
m.options.view = o.Name
|
||||
end if
|
||||
end for
|
||||
|
||||
' Set selected sort option
|
||||
for each o in options.sort
|
||||
if o.Name = m.sortField
|
||||
o.Selected = true
|
||||
o.Ascending = m.sortAscending
|
||||
m.options.sortField = o.Name
|
||||
end if
|
||||
end for
|
||||
|
||||
' Set selected filter option
|
||||
for each o in options.filter
|
||||
if o.Name = m.filter
|
||||
o.Selected = true
|
||||
m.options.filter = o.Name
|
||||
end if
|
||||
end for
|
||||
|
||||
m.options.options = options
|
||||
end sub
|
||||
|
||||
'
|
||||
' Logo Image Loaded Event Handler
|
||||
sub LogoImageLoaded(msg)
|
||||
data = msg.GetData()
|
||||
m.loadLogoTask.unobserveField("content")
|
||||
m.loadLogoTask.content = []
|
||||
|
||||
if data.Count() > 0
|
||||
m.movieLogo.uri = data[0]
|
||||
m.movieLogo.visible = true
|
||||
else
|
||||
m.selectedMovieName.visible = true
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
'Handle loaded data, and add to Grid
|
||||
sub ItemDataLoaded(msg)
|
||||
m.top.alphaActive = false
|
||||
itemData = msg.GetData()
|
||||
m.loadItemsTask.unobserveField("content")
|
||||
m.loadItemsTask.content = []
|
||||
|
||||
if itemData = invalid
|
||||
m.Loading = false
|
||||
return
|
||||
end if
|
||||
|
||||
if m.loadItemsTask.view = "Genres"
|
||||
' Reset genre list data
|
||||
m.genreData.removeChildren(m.genreData.getChildren(-1, 0))
|
||||
|
||||
for each item in itemData
|
||||
m.genreData.appendChild(item)
|
||||
end for
|
||||
|
||||
m.itemGrid.opacity = "0"
|
||||
m.genreList.opacity = "1"
|
||||
|
||||
m.itemGrid.setFocus(false)
|
||||
m.genreList.setFocus(true)
|
||||
|
||||
m.loading = false
|
||||
m.spinner.visible = false
|
||||
return
|
||||
end if
|
||||
|
||||
m.itemGrid.opacity = "1"
|
||||
m.genreList.opacity = "0"
|
||||
|
||||
m.itemGrid.setFocus(true)
|
||||
m.genreList.setFocus(false)
|
||||
|
||||
for each item in itemData
|
||||
m.data.appendChild(item)
|
||||
end for
|
||||
|
||||
'Update the stored counts
|
||||
m.loadedItems = m.itemGrid.content.getChildCount()
|
||||
m.loadedRows = m.loadedItems / m.itemGrid.numColumns
|
||||
m.Loading = false
|
||||
'If there are no items to display, show message
|
||||
if m.loadedItems = 0
|
||||
m.emptyText.text = tr("NO_ITEMS").Replace("%1", m.top.parentItem.Type)
|
||||
m.emptyText.visible = true
|
||||
end if
|
||||
|
||||
m.spinner.visible = false
|
||||
end sub
|
||||
|
||||
'
|
||||
'Set Selected Movie Name
|
||||
sub SetName(movieName as string)
|
||||
m.selectedMovieName.text = movieName
|
||||
end sub
|
||||
|
||||
'
|
||||
'Set Selected Movie Overview
|
||||
sub SetOverview(movieOverview as string)
|
||||
m.selectedMovieOverview.text = movieOverview
|
||||
end sub
|
||||
|
||||
'
|
||||
'Set Selected Movie OfficialRating
|
||||
sub SetOfficialRating(movieOfficialRating as string)
|
||||
m.selectedMovieOfficialRating.text = movieOfficialRating
|
||||
end sub
|
||||
|
||||
'
|
||||
'Set Selected Movie ProductionYear
|
||||
sub SetProductionYear(movieProductionYear)
|
||||
m.selectedMovieProductionYear.text = movieProductionYear
|
||||
end sub
|
||||
|
||||
'
|
||||
'Set Background Image
|
||||
sub SetBackground(backgroundUri as string)
|
||||
if backgroundUri = ""
|
||||
m.backdrop.opacity = 0
|
||||
end if
|
||||
|
||||
'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"
|
||||
m.queuedBGUri = backgroundUri
|
||||
return
|
||||
end if
|
||||
|
||||
m.newBackdrop.uri = backgroundUri
|
||||
end sub
|
||||
|
||||
'
|
||||
'Handle new item being focused
|
||||
sub onItemFocused()
|
||||
focusedRow = m.itemGrid.currFocusRow
|
||||
|
||||
itemInt = m.itemGrid.itemFocused
|
||||
|
||||
' If no selected item, set background to parent backdrop
|
||||
if itemInt = -1
|
||||
return
|
||||
end if
|
||||
|
||||
m.movieLogo.visible = false
|
||||
m.selectedMovieName.visible = false
|
||||
|
||||
' Load more data if focus is within last 5 rows, and there are more items to load
|
||||
if focusedRow >= m.loadedRows - 5 and m.loadeditems < m.loadItemsTask.totalRecordCount
|
||||
loadMoreData()
|
||||
end if
|
||||
|
||||
m.selectedFavoriteItem = getItemFocused()
|
||||
m.communityRatingGroup.visible = false
|
||||
m.criticRatingGroup.visible = false
|
||||
|
||||
if m.options.view = "Studios" or m.view = "Studios"
|
||||
return
|
||||
end if
|
||||
|
||||
itemData = m.selectedFavoriteItem.json
|
||||
|
||||
if isValid(itemData.communityRating)
|
||||
setFieldText("communityRating", int(itemData.communityRating * 10) / 10)
|
||||
m.communityRatingGroup.visible = true
|
||||
end if
|
||||
|
||||
if isValid(itemData.CriticRating)
|
||||
setFieldText("criticRatingLabel", itemData.criticRating)
|
||||
|
||||
tomato = "pkg:/images/rotten.png"
|
||||
|
||||
if itemData.CriticRating > 60
|
||||
tomato = "pkg:/images/fresh.png"
|
||||
end if
|
||||
|
||||
m.criticRatingIcon.uri = tomato
|
||||
m.criticRatingGroup.visible = true
|
||||
end if
|
||||
|
||||
if isValid(itemData.Name)
|
||||
SetName(itemData.Name)
|
||||
else
|
||||
SetName("")
|
||||
end if
|
||||
|
||||
if isValid(itemData.Overview)
|
||||
SetOverview(itemData.Overview)
|
||||
else
|
||||
SetOverview("")
|
||||
end if
|
||||
|
||||
if isValid(itemData.ProductionYear)
|
||||
SetProductionYear(str(itemData.ProductionYear))
|
||||
else
|
||||
SetProductionYear("")
|
||||
end if
|
||||
|
||||
if type(itemData.RunTimeTicks) = "LongInteger"
|
||||
setFieldText("runtime", stri(getRuntime(itemData.RunTimeTicks)) + " mins")
|
||||
else
|
||||
setFieldText("runtime", "")
|
||||
end if
|
||||
|
||||
if isValid(itemData.OfficialRating)
|
||||
SetOfficialRating(itemData.OfficialRating)
|
||||
else
|
||||
SetOfficialRating("")
|
||||
end if
|
||||
|
||||
m.loadLogoTask.itemId = itemData.id
|
||||
m.loadLogoTask.itemType = "LogoImage"
|
||||
m.loadLogoTask.observeField("content", "LogoImageLoaded")
|
||||
m.loadLogoTask.control = "RUN"
|
||||
|
||||
' Set Background to item backdrop
|
||||
SetBackground(m.selectedFavoriteItem.backdropUrl)
|
||||
end sub
|
||||
|
||||
function getRuntime(runTimeTicks) as integer
|
||||
return round(runTimeTicks / 600000000.0)
|
||||
end function
|
||||
|
||||
function round(f as float) as integer
|
||||
' BrightScript only has a "floor" round
|
||||
' This compares floor to floor + 1 to find which is closer
|
||||
m = int(f)
|
||||
n = m + 1
|
||||
x = abs(f - m)
|
||||
y = abs(f - n)
|
||||
if y > x
|
||||
return m
|
||||
else
|
||||
return n
|
||||
end if
|
||||
end function
|
||||
|
||||
sub setFieldText(field, value)
|
||||
node = m.top.findNode(field)
|
||||
if node = invalid or value = invalid then return
|
||||
|
||||
' Handle non strings... Which _shouldn't_ happen, but hey
|
||||
if type(value) = "roInt" or type(value) = "Integer"
|
||||
value = str(value)
|
||||
else if type(value) = "roFloat" or type(value) = "Float"
|
||||
value = str(value)
|
||||
else if type(value) <> "roString" and type(value) <> "String"
|
||||
value = ""
|
||||
end if
|
||||
|
||||
node.text = value
|
||||
end sub
|
||||
|
||||
'
|
||||
'When Image Loading Status changes
|
||||
sub newBGLoaded()
|
||||
'If image load was sucessful, start the fade swap
|
||||
if m.newBackdrop.loadStatus = "ready"
|
||||
m.swapAnimation.control = "start"
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
'Swap Complete
|
||||
sub swapDone()
|
||||
if m.swapAnimation.state = "stopped"
|
||||
'Set main BG node image and hide transitioning node
|
||||
m.backdrop.uri = m.newBackdrop.uri
|
||||
m.backdrop.opacity = 1
|
||||
m.newBackdrop.opacity = 0
|
||||
|
||||
'If there is another one to load
|
||||
if m.newBackdrop.uri <> m.queuedBGUri and m.queuedBGUri <> ""
|
||||
SetBackground(m.queuedBGUri)
|
||||
m.queuedBGUri = ""
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
'Load next set of items
|
||||
sub loadMoreData()
|
||||
m.spinner.visible = true
|
||||
if m.Loading = true then return
|
||||
m.Loading = true
|
||||
m.loadItemsTask.startIndex = m.loadedItems
|
||||
m.loadItemsTask.observeField("content", "ItemDataLoaded")
|
||||
m.loadItemsTask.control = "RUN"
|
||||
end sub
|
||||
|
||||
'
|
||||
'Item Selected
|
||||
sub onItemSelected()
|
||||
m.top.selectedItem = m.itemGrid.content.getChild(m.itemGrid.itemSelected)
|
||||
end sub
|
||||
|
||||
'
|
||||
'Returns Focused Item
|
||||
function getItemFocused()
|
||||
return m.itemGrid.content.getChild(m.itemGrid.itemFocused)
|
||||
end function
|
||||
|
||||
'
|
||||
'Genre Item Selected
|
||||
sub onGenreItemSelected()
|
||||
m.top.selectedItem = m.genreList.content.getChild(m.genreList.rowItemSelected[0]).getChild(m.genreList.rowItemSelected[1])
|
||||
end sub
|
||||
|
||||
sub onItemalphaSelected()
|
||||
if m.top.alphaSelected <> ""
|
||||
m.loadedRows = 0
|
||||
m.loadedItems = 0
|
||||
|
||||
m.data = CreateObject("roSGNode", "ContentNode")
|
||||
m.itemGrid.content = m.data
|
||||
|
||||
m.genreData = CreateObject("roSGNode", "ContentNode")
|
||||
m.genreList.content = m.genreData
|
||||
|
||||
m.loadItemsTask.searchTerm = ""
|
||||
m.VoiceBox.text = ""
|
||||
m.loadItemsTask.nameStartsWith = m.alpha.itemAlphaSelected
|
||||
m.spinner.visible = true
|
||||
loadInitialItems()
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub onvoiceFilter()
|
||||
if m.VoiceBox.text <> ""
|
||||
m.loadedRows = 0
|
||||
m.loadedItems = 0
|
||||
m.data = CreateObject("roSGNode", "ContentNode")
|
||||
m.itemGrid.content = m.data
|
||||
m.top.alphaSelected = ""
|
||||
m.loadItemsTask.NameStartsWith = " "
|
||||
m.loadItemsTask.searchTerm = m.voiceBox.text
|
||||
m.loadItemsTask.recursive = true
|
||||
m.spinner.visible = true
|
||||
loadInitialItems()
|
||||
end if
|
||||
end sub
|
||||
|
||||
|
||||
'
|
||||
'Check if options updated and any reloading required
|
||||
sub optionsClosed()
|
||||
reload = false
|
||||
|
||||
if m.options.sortField <> m.sortField or m.options.sortAscending <> m.sortAscending
|
||||
m.sortField = m.options.sortField
|
||||
m.sortAscending = m.options.sortAscending
|
||||
reload = true
|
||||
|
||||
sortAscendingStr = "true"
|
||||
|
||||
'Store sort settings
|
||||
if not m.sortAscending
|
||||
sortAscendingStr = "false"
|
||||
end if
|
||||
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".sortField", m.sortField)
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".sortAscending", sortAscendingStr)
|
||||
end if
|
||||
|
||||
if m.options.filter <> m.filter
|
||||
m.filter = m.options.filter
|
||||
reload = true
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".filter", m.options.filter)
|
||||
end if
|
||||
|
||||
m.view = get_user_setting("display." + m.top.parentItem.Id + ".landing")
|
||||
|
||||
if m.options.view <> m.view
|
||||
m.view = m.options.view
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".landing", m.view)
|
||||
|
||||
' Reset any filtering or search terms
|
||||
m.top.alphaSelected = ""
|
||||
m.loadItemsTask.NameStartsWith = " "
|
||||
m.loadItemsTask.searchTerm = ""
|
||||
m.filter = "All"
|
||||
m.sortField = "SortName"
|
||||
m.sortAscending = true
|
||||
|
||||
' Reset view to defaults
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".sortField", m.sortField)
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".sortAscending", "true")
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".filter", m.filter)
|
||||
|
||||
reload = true
|
||||
end if
|
||||
|
||||
if reload
|
||||
m.loadedRows = 0
|
||||
m.loadedItems = 0
|
||||
m.data = CreateObject("roSGNode", "ContentNode")
|
||||
m.itemGrid.content = m.data
|
||||
loadInitialItems()
|
||||
end if
|
||||
|
||||
m.itemGrid.setFocus(m.itemGrid.opacity = 1)
|
||||
m.genreList.setFocus(m.genreList.opacity = 1)
|
||||
end sub
|
||||
|
||||
sub onChannelSelected(msg)
|
||||
node = msg.getRoSGNode()
|
||||
m.top.lastFocus = lastFocusedChild(node)
|
||||
if node.watchChannel <> invalid
|
||||
' Clone the node when it's reused/update in the TimeGrid it doesn't automatically start playing
|
||||
m.top.selectedItem = node.watchChannel.clone(false)
|
||||
end if
|
||||
end sub
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
if not press then return false
|
||||
|
||||
if key = "left" and m.voiceBox.isinFocusChain()
|
||||
m.itemGrid.setFocus(m.itemGrid.opacity = 1)
|
||||
m.genreList.setFocus(m.genreList.opacity = 1)
|
||||
m.voiceBox.setFocus(false)
|
||||
end if
|
||||
|
||||
if key = "options"
|
||||
if m.options.visible = true
|
||||
m.options.visible = false
|
||||
m.top.removeChild(m.options)
|
||||
optionsClosed()
|
||||
else
|
||||
|
||||
itemSelected = m.selectedFavoriteItem
|
||||
if itemSelected <> invalid
|
||||
m.options.selectedFavoriteItem = itemSelected
|
||||
end if
|
||||
|
||||
m.options.visible = true
|
||||
m.top.appendChild(m.options)
|
||||
m.options.setFocus(true)
|
||||
end if
|
||||
return true
|
||||
else if key = "back"
|
||||
if m.options.visible = true
|
||||
m.options.visible = false
|
||||
optionsClosed()
|
||||
return true
|
||||
else
|
||||
m.global.sceneManager.callfunc("popScene")
|
||||
m.loadItemsTask.control = "stop"
|
||||
return true
|
||||
end if
|
||||
else if key = "play" or key = "OK"
|
||||
|
||||
itemToPlay = getItemFocused()
|
||||
|
||||
if itemToPlay <> invalid and (itemToPlay.type = "Movie" or itemToPlay.type = "Episode")
|
||||
m.top.quickPlayNode = itemToPlay
|
||||
return true
|
||||
end if
|
||||
else if key = "left"
|
||||
if m.itemGrid.isinFocusChain()
|
||||
m.top.alphaActive = true
|
||||
m.itemGrid.setFocus(false)
|
||||
alpha = m.alpha.getChild(0).findNode("Alphamenu")
|
||||
alpha.setFocus(true)
|
||||
return true
|
||||
else if m.genreList.isinFocusChain()
|
||||
m.top.alphaActive = true
|
||||
m.genreList.setFocus(false)
|
||||
alpha = m.alpha.getChild(0).findNode("Alphamenu")
|
||||
alpha.setFocus(true)
|
||||
return true
|
||||
end if
|
||||
|
||||
else if key = "right" and m.Alpha.isinFocusChain()
|
||||
m.top.alphaActive = false
|
||||
m.Alpha.setFocus(false)
|
||||
m.Alpha.visible = true
|
||||
|
||||
m.itemGrid.setFocus(m.itemGrid.opacity = 1)
|
||||
m.genreList.setFocus(m.genreList.opacity = 1)
|
||||
|
||||
return true
|
||||
|
||||
else if key = "replay" and m.itemGrid.isinFocusChain()
|
||||
if m.resetGrid = true
|
||||
m.itemGrid.animateToItem = 0
|
||||
else
|
||||
m.itemGrid.jumpToItem = 0
|
||||
end if
|
||||
|
||||
else if key = "replay" and m.genreList.isinFocusChain()
|
||||
if m.resetGrid = true
|
||||
m.genreList.animateToItem = 0
|
||||
else
|
||||
m.genreList.jumpToItem = 0
|
||||
end if
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "replay"
|
||||
m.spinner.visible = true
|
||||
m.loadItemsTask.searchTerm = ""
|
||||
m.loadItemsTask.nameStartsWith = ""
|
||||
m.voiceBox.text = ""
|
||||
m.top.alphaSelected = ""
|
||||
m.loadItemsTask.filter = "All"
|
||||
m.filter = "All"
|
||||
m.data = CreateObject("roSGNode", "ContentNode")
|
||||
m.itemGrid.content = m.data
|
||||
loadInitialItems()
|
||||
return true
|
||||
end if
|
||||
|
||||
return false
|
||||
end function
|
65
components/ItemGrid/MovieLibraryView.xml
Normal file
65
components/ItemGrid/MovieLibraryView.xml
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="MovieLibraryView" extends="JFScreen">
|
||||
<children>
|
||||
<Rectangle id="screenSaverBackground" width="1920" height="1080" color="#000000" />
|
||||
|
||||
<VoiceTextEditBox id="VoiceBox" visible="true" width = "40" translation = "[52, 120]" />
|
||||
<Rectangle id="VoiceBoxCover" height="240" width="100" color="0x000000ff" translation = "[25, 75]" />
|
||||
|
||||
<maskGroup translation="[820, 0]" id="backgroundMask" maskUri="pkg:/images/backgroundmask.png" maskSize="[1220,700]">
|
||||
<poster id="backdrop" loadDisplayMode="scaleToFill" width="1100" height="700" opacity="1" />
|
||||
<poster id="backdropTransition" loadDisplayMode="scaleToFill" width="1100" height="700" opacity="1" />
|
||||
</maskGroup>
|
||||
|
||||
<Label id="selectedMovieName" visible="false" translation="[120, 40]" wrap="true" font="font:LargeBoldSystemFont" width="850" height="196" horizAlign="left" vertAlign="center" />
|
||||
<Poster id="movieLogo" visible="false" translation="[120, 40]" loadDisplayMode="scaleToFit" width="384" height="196" />
|
||||
|
||||
<LayoutGroup layoutDirection="horiz" translation="[120, 270]" itemSpacings="[30]" id="infoGroup">
|
||||
<Label id="selectedMovieProductionYear" font="font:SmallestSystemFont" />
|
||||
<Label id="runtime" font="font:SmallestSystemFont" />
|
||||
<Label id="selectedMovieOfficialRating" font="font:SmallestSystemFont" />
|
||||
|
||||
<LayoutGroup id="communityRatingGroup" visible="false" layoutDirection="horiz" itemSpacings="[-5]">
|
||||
<Poster id="star" uri="pkg:/images/sharp_star_white_18dp.png" height="28" width="28" blendColor="#00a4dcFF" />
|
||||
<Label id="communityRating" font="font:SmallestSystemFont" />
|
||||
</LayoutGroup>
|
||||
|
||||
<LayoutGroup layoutDirection="horiz" id="criticRatingGroup">
|
||||
<Poster id="criticRatingIcon" height="28" width="28" />
|
||||
<Label id="criticRatingLabel" font="font:SmallestSystemFont" />
|
||||
</LayoutGroup>
|
||||
</LayoutGroup>
|
||||
|
||||
<Label id="selectedMovieOverview" font="font:SmallestSystemFont" translation="[120, 360]" wrap="true" lineSpacing="20" maxLines="5" width="850" ellipsisText="..." />
|
||||
|
||||
<MarkupGrid id="itemGrid" itemComponentName="GridItemSmall" numColumns="7" numRows="2" vertFocusAnimationStyle="fixed" itemSize="[230, 310]" itemSpacing="[20, 20]" />
|
||||
<RowList opacity="0" id="genrelist" translation="[120, 60]" showRowLabel="true" itemComponentName="GridItemSmall" numColumns="1" numRows="3" vertFocusAnimationStyle="fixed" itemSize = "[1900, 360]" rowItemSize="[ [230, 320] ]" rowItemSpacing="[ [20, 0] ]" itemSpacing="[0, 60]" />
|
||||
|
||||
<Label id="micButtonText" font="font:SmallSystemFont" visible="false" />
|
||||
<Button id = "micButton" maxWidth = "20" translation = "[20, 120]" iconUri = "pkg:/images/icons/mic_icon.png"/>
|
||||
<Label translation="[0,540]" id="emptyText" font="font:LargeSystemFont" width="1910" horizAlign="center" vertAlign="center" height="64" visible="false" />
|
||||
<ItemGridOptions id="options" visible="false" />
|
||||
<Spinner id="spinner" translation="[900, 450]" />
|
||||
<Animation id="backroundSwapAnimation" duration="1" repeat="false" easeFunction="linear">
|
||||
<FloatFieldInterpolator id = "fadeinLoading" key="[0.0, 1.0]" keyValue="[ 0.00, 1.00 ]" fieldToInterp="backdropTransition.opacity" />
|
||||
<FloatFieldInterpolator id = "fadeoutLoaded" key="[0.0, 1.0]" keyValue="[ 1.00, 0.00 ]" fieldToInterp="backdrop.opacity" />
|
||||
</Animation>
|
||||
<Alpha id="AlphaMenu" />
|
||||
</children>
|
||||
<interface>
|
||||
<field id="HomeLibraryItem" type="string"/>
|
||||
<field id="parentItem" type="node" onChange="loadInitialItems" />
|
||||
<field id="selectedItem" type="node" alwaysNotify="true" />
|
||||
<field id="quickPlayNode" type="node" alwaysNotify="true" />
|
||||
<field id="imageDisplayMode" type="string" value="scaleToZoom" />
|
||||
<field id="AlphaSelected" type="string" alias="AlphaMenu.itemAlphaSelected" alwaysNotify="true" onChange="onItemAlphaSelected" />
|
||||
<field id="alphaActive" type="boolean" value="false" />
|
||||
<field id="jumpToItem" type="integer" value="" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/api/baserequest.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/api/Image.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/deviceCapabilities.brs" />
|
||||
<script type="text/brightscript" uri="MovieLibraryView.brs" />
|
||||
</component>
|
|
@ -25,19 +25,14 @@ sub init()
|
|||
' get system preference clock format (12/24hr)
|
||||
di = CreateObject("roDeviceInfo")
|
||||
m.clockFormat = di.GetClockFormat()
|
||||
|
||||
' grab current time
|
||||
currentTime = CreateObject("roDateTime")
|
||||
currentTime.ToLocalTime()
|
||||
m.currentHours = currentTime.GetHours()
|
||||
m.currentMinutes = currentTime.GetMinutes()
|
||||
m.overlayHours = m.top.findNode("overlayHours")
|
||||
m.overlayMinutes = m.top.findNode("overlayMinutes")
|
||||
m.overlayMeridian = m.top.findNode("overlayMeridian")
|
||||
|
||||
' start timer
|
||||
m.currentTimeTimer = m.top.findNode("currentTimeTimer")
|
||||
m.currentTimeTimer.control = "start"
|
||||
m.currentTimeTimer.ObserveField("fire", "updateTime")
|
||||
|
||||
updateTimeDisplay()
|
||||
end if
|
||||
|
||||
setClockVisibility()
|
||||
|
@ -97,64 +92,50 @@ sub updateUser()
|
|||
end sub
|
||||
|
||||
sub updateTime()
|
||||
if (m.currentMinutes + 1) > 59
|
||||
m.currentHours = m.currentHours + 1
|
||||
m.currentMinutes = 0
|
||||
else
|
||||
m.currentMinutes = m.currentMinutes + 1
|
||||
end if
|
||||
|
||||
m.currentTime = CreateObject("roDateTime")
|
||||
m.currentTime.ToLocalTime()
|
||||
m.currentTimeTimer.duration = 60 - m.currentTime.GetSeconds()
|
||||
m.currentHours = m.currentTime.GetHours()
|
||||
m.currentMinutes = m.currentTime.GetMinutes()
|
||||
updateTimeDisplay()
|
||||
end sub
|
||||
|
||||
sub resetTime()
|
||||
m.currentTimeTimer.control = "stop"
|
||||
|
||||
currentTime = CreateObject("roDateTime")
|
||||
m.currentTimeTimer.control = "start"
|
||||
|
||||
currentTime.ToLocalTime()
|
||||
|
||||
m.currentHours = currentTime.GetHours()
|
||||
m.currentMinutes = currentTime.GetMinutes()
|
||||
|
||||
updateTimeDisplay()
|
||||
updateTime()
|
||||
end sub
|
||||
|
||||
sub updateTimeDisplay()
|
||||
overlayHours = m.top.findNode("overlayHours")
|
||||
overlayMinutes = m.top.findNode("overlayMinutes")
|
||||
overlayMeridian = m.top.findNode("overlayMeridian")
|
||||
|
||||
if m.clockFormat = "24h"
|
||||
overlayMeridian.text = ""
|
||||
m.overlayMeridian.text = ""
|
||||
if m.currentHours < 10
|
||||
overlayHours.text = "0" + StrI(m.currentHours).trim()
|
||||
m.overlayHours.text = "0" + StrI(m.currentHours).trim()
|
||||
else
|
||||
overlayHours.text = m.currentHours
|
||||
m.overlayHours.text = m.currentHours
|
||||
end if
|
||||
else
|
||||
if m.currentHours < 12
|
||||
overlayMeridian.text = "AM"
|
||||
m.overlayMeridian.text = "AM"
|
||||
if m.currentHours = 0
|
||||
overlayHours.text = "12"
|
||||
m.overlayHours.text = "12"
|
||||
else
|
||||
overlayHours.text = m.currentHours
|
||||
m.overlayHours.text = m.currentHours
|
||||
end if
|
||||
else
|
||||
overlayMeridian.text = "PM"
|
||||
m.overlayMeridian.text = "PM"
|
||||
if m.currentHours = 12
|
||||
overlayHours.text = "12"
|
||||
m.overlayHours.text = "12"
|
||||
else
|
||||
overlayHours.text = m.currentHours - 12
|
||||
m.overlayHours.text = m.currentHours - 12
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
if m.currentMinutes < 10
|
||||
overlayMinutes.text = "0" + StrI(m.currentMinutes).trim()
|
||||
m.overlayMinutes.text = "0" + StrI(m.currentMinutes).trim()
|
||||
else
|
||||
overlayMinutes.text = m.currentMinutes
|
||||
m.overlayMinutes.text = m.currentMinutes
|
||||
end if
|
||||
end sub
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ sub init()
|
|||
m.playbackTimer = m.top.findNode("playbackTimer")
|
||||
m.bufferCheckTimer = m.top.findNode("bufferCheckTimer")
|
||||
m.top.observeField("state", "onState")
|
||||
m.top.observeField("content", "onContentChange")
|
||||
|
||||
m.playbackTimer.observeField("fire", "ReportPlayback")
|
||||
m.bufferPercentage = 0 ' Track whether content is being loaded
|
||||
m.playReported = false
|
||||
|
@ -12,6 +14,88 @@ sub init()
|
|||
clockNode = findNodeBySubtype(m.top, "clock")
|
||||
if clockNode[0] <> invalid then clockNode[0].parent.removeChild(clockNode[0].node)
|
||||
end if
|
||||
|
||||
'Play Next Episode button
|
||||
m.nextEpisodeButton = m.top.findNode("nextEpisode")
|
||||
m.nextEpisodeButton.text = tr("Next Episode")
|
||||
m.nextEpisodeButton.setFocus(false)
|
||||
|
||||
m.showNextEpisodeButtonAnimation = m.top.findNode("showNextEpisodeButton")
|
||||
m.hideNextEpisodeButtonAnimation = m.top.findNode("hideNextEpisodeButton")
|
||||
|
||||
m.checkedForNextEpisode = false
|
||||
m.getNextEpisodeTask = createObject("roSGNode", "GetNextEpisodeTask")
|
||||
m.getNextEpisodeTask.observeField("nextEpisodeData", "onNextEpisodeDataLoaded")
|
||||
|
||||
end sub
|
||||
|
||||
' Event handler for when video content field changes
|
||||
sub onContentChange()
|
||||
if not isValid(m.top.content) then return
|
||||
|
||||
m.top.observeField("position", "onPositionChanged")
|
||||
|
||||
' If video content type is not episode, remove position observer
|
||||
if m.top.content.contenttype <> 4
|
||||
m.top.unobserveField("position")
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub onNextEpisodeDataLoaded()
|
||||
m.checkedForNextEpisode = true
|
||||
|
||||
m.top.observeField("position", "onPositionChanged")
|
||||
|
||||
if m.getNextEpisodeTask.nextEpisodeData.Items.count() <> 2
|
||||
m.top.unobserveField("position")
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
' Runs Next Episode button animation and sets focus to button
|
||||
sub showNextEpisodeButton()
|
||||
if not m.nextEpisodeButton.visible
|
||||
m.showNextEpisodeButtonAnimation.control = "start"
|
||||
m.nextEpisodeButton.setFocus(true)
|
||||
m.nextEpisodeButton.visible = true
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
'Update count down text
|
||||
sub updateCount()
|
||||
m.nextEpisodeButton.text = tr("Next Episode") + " " + Int(m.top.runTime - m.top.position).toStr()
|
||||
end sub
|
||||
|
||||
'
|
||||
' Runs hide Next Episode button animation and sets focus back to video
|
||||
sub hideNextEpisodeButton()
|
||||
m.hideNextEpisodeButtonAnimation.control = "start"
|
||||
m.nextEpisodeButton.setFocus(false)
|
||||
m.top.setFocus(true)
|
||||
end sub
|
||||
|
||||
' Checks if we need to display the Next Episode button
|
||||
sub checkTimeToDisplayNextEpisode()
|
||||
if int(m.top.position) >= (m.top.runTime - 30)
|
||||
showNextEpisodeButton()
|
||||
updateCount()
|
||||
return
|
||||
end if
|
||||
|
||||
if m.nextEpisodeButton.visible or m.nextEpisodeButton.hasFocus()
|
||||
m.nextEpisodeButton.visible = false
|
||||
m.nextEpisodeButton.setFocus(false)
|
||||
end if
|
||||
end sub
|
||||
|
||||
' When Video Player state changes
|
||||
sub onPositionChanged()
|
||||
' Check if dialog is open
|
||||
m.dialog = m.top.getScene().findNode("dialogBackground")
|
||||
if not isValid(m.dialog)
|
||||
checkTimeToDisplayNextEpisode()
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
|
@ -40,6 +124,16 @@ sub onState(msg)
|
|||
m.top.control = "stop"
|
||||
m.top.backPressed = true
|
||||
else if m.top.state = "playing"
|
||||
|
||||
' Check if next episde is available
|
||||
if isValid(m.top.showID)
|
||||
if m.top.showID <> "" and not m.checkedForNextEpisode and m.top.content.contenttype = 4
|
||||
m.getNextEpisodeTask.showID = m.top.showID
|
||||
m.getNextEpisodeTask.videoID = m.top.id
|
||||
m.getNextEpisodeTask.control = "RUN"
|
||||
end if
|
||||
end if
|
||||
|
||||
if m.playReported = false
|
||||
ReportPlayback("start")
|
||||
m.playReported = true
|
||||
|
@ -126,12 +220,24 @@ sub dialogClosed(msg)
|
|||
sourceNode.close = true
|
||||
end sub
|
||||
|
||||
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
|
||||
if key = "OK" and m.nextEpisodeButton.hasfocus() and m.top.trickPlayMode = "play"
|
||||
m.top.state = "finished"
|
||||
hideNextEpisodeButton()
|
||||
return true
|
||||
else
|
||||
'Hide Next Episode Button
|
||||
if m.nextEpisodeButton.visible or m.nextEpisodeButton.hasFocus()
|
||||
m.nextEpisodeButton.visible = false
|
||||
m.nextEpisodeButton.setFocus(false)
|
||||
m.top.setFocus(true)
|
||||
end if
|
||||
end if
|
||||
|
||||
if not press then return false
|
||||
|
||||
if m.top.Subtitles.count() and key = "down"
|
||||
if key = "down"
|
||||
m.top.selectSubtitlePressed = true
|
||||
return true
|
||||
else if key = "up"
|
||||
|
|
|
@ -22,12 +22,24 @@
|
|||
<field id="videoId" type="string" />
|
||||
<field id="mediaSourceId" type="string" />
|
||||
<field id="audioIndex" type="integer" />
|
||||
<field id="runTime" type="integer" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="JFVideo.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/roku_modules/api/api.brs" />
|
||||
|
||||
<children>
|
||||
<timer id="playbackTimer" repeat="true" duration="30" />
|
||||
<timer id="bufferCheckTimer" repeat="true" />
|
||||
<JFButton id="nextEpisode" opacity="0" textColor="#f0f0f0" focusedTextColor="#202020" focusFootprintBitmapUri="pkg:/images/option-menu-bg.9.png" focusBitmapUri="pkg:/images/white.9.png" translation="[1500, 900]" />
|
||||
|
||||
<!--animation for the play next episode button-->
|
||||
<Animation id="showNextEpisodeButton" duration="1.0" repeat="false" easeFunction="inQuad">
|
||||
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[0.0, .9]" fieldToInterp="nextEpisode.opacity" />
|
||||
</Animation>
|
||||
<Animation id="hideNextEpisodeButton" duration=".2" repeat="false" easeFunction="inQuad">
|
||||
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[.9, 0]" fieldToInterp="nextEpisode.opacity" />
|
||||
</Animation>
|
||||
</children>
|
||||
</component>
|
|
@ -8,12 +8,14 @@ sub setFields()
|
|||
m.top.watched = json.UserData.played
|
||||
m.top.Type = "Movie"
|
||||
|
||||
if json.MediaSourceCount <> invalid and json.MediaSourceCount > 1
|
||||
if isValid(json.MediaSourceCount) and json.MediaSourceCount > 1
|
||||
if isValid(json.MediaSources)
|
||||
m.top.mediaSources = []
|
||||
for each source in json.MediaSources
|
||||
m.top.mediaSources.push(source)
|
||||
end for
|
||||
end if
|
||||
end if
|
||||
|
||||
if json.ProductionYear <> invalid
|
||||
m.top.SubTitle = json.ProductionYear
|
||||
|
@ -49,10 +51,12 @@ sub setPoster()
|
|||
end if
|
||||
|
||||
' Add Backdrop Image
|
||||
if m.top.json.BackdropImageTags <> invalid
|
||||
if m.top.json.BackdropImageTags[0] <> invalid
|
||||
imgParams = { "maxHeight": 720, "maxWidth": 1280 }
|
||||
m.top.backdropURL = ImageURL(m.top.json.id, "Backdrop", imgParams)
|
||||
end if
|
||||
end if
|
||||
|
||||
end if
|
||||
end sub
|
||||
|
|
|
@ -12,4 +12,5 @@
|
|||
<script type="text/brightscript" uri="pkg:/source/api/Image.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/api/baserequest.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
|
||||
</component>
|
||||
|
|
|
@ -146,7 +146,13 @@ end sub
|
|||
'
|
||||
' Clear previous scene from group stack
|
||||
sub clearPreviousScene()
|
||||
m.groups.Delete(2)
|
||||
m.groups.pop()
|
||||
end sub
|
||||
|
||||
'
|
||||
' Delete scene from group stack at passed index
|
||||
sub deleteSceneAtIndex(index = 1)
|
||||
m.groups.Delete(index)
|
||||
end sub
|
||||
|
||||
'
|
||||
|
|
|
@ -133,6 +133,7 @@ sub itemContentChanged()
|
|||
end if
|
||||
return
|
||||
end if
|
||||
|
||||
if itemData.type = "Series"
|
||||
|
||||
m.itemText.text = itemData.name
|
||||
|
@ -170,6 +171,34 @@ sub itemContentChanged()
|
|||
return
|
||||
end if
|
||||
|
||||
if itemData.type = "MusicArtist"
|
||||
m.itemText.text = itemData.name
|
||||
m.itemTextExtra.text = itemData.json.AlbumArtist
|
||||
m.itemPoster.uri = ImageURL(itemData.id)
|
||||
return
|
||||
end if
|
||||
|
||||
if itemData.type = "Audio"
|
||||
m.itemText.text = itemData.name
|
||||
m.itemTextExtra.text = itemData.json.AlbumArtist
|
||||
m.itemPoster.uri = ImageURL(itemData.id)
|
||||
return
|
||||
end if
|
||||
|
||||
if itemData.type = "TvChannel"
|
||||
m.itemText.text = itemData.name
|
||||
m.itemTextExtra.text = itemData.json.AlbumArtist
|
||||
m.itemPoster.uri = ImageURL(itemData.id)
|
||||
return
|
||||
end if
|
||||
|
||||
if itemData.type = "Season"
|
||||
m.itemText.text = itemData.json.SeriesName
|
||||
m.itemTextExtra.text = itemData.name
|
||||
m.itemPoster.uri = ImageURL(itemData.id)
|
||||
return
|
||||
end if
|
||||
|
||||
print "Unhandled Home Item Type: " + itemData.type
|
||||
|
||||
end sub
|
||||
|
|
|
@ -19,13 +19,19 @@ sub init()
|
|||
' Load the Libraries from API via task
|
||||
m.LoadLibrariesTask = createObject("roSGNode", "LoadItemsTask")
|
||||
m.LoadLibrariesTask.observeField("content", "onLibrariesLoaded")
|
||||
|
||||
' set up tesk nodes for other rows
|
||||
m.LoadContinueTask = createObject("roSGNode", "LoadItemsTask")
|
||||
m.LoadContinueTask.itemsToLoad = "continue"
|
||||
|
||||
m.LoadNextUpTask = createObject("roSGNode", "LoadItemsTask")
|
||||
m.LoadNextUpTask.itemsToLoad = "nextUp"
|
||||
|
||||
m.LoadOnNowTask = createObject("roSGNode", "LoadItemsTask")
|
||||
m.LoadOnNowTask.itemsToLoad = "onNow"
|
||||
|
||||
m.LoadFavoritesTask = createObject("roSGNode", "LoadItemsTask")
|
||||
m.LoadFavoritesTask.itemsToLoad = "favorites"
|
||||
end sub
|
||||
|
||||
sub loadLibraries()
|
||||
|
@ -61,20 +67,28 @@ sub onLibrariesLoaded()
|
|||
continueRow.title = tr("Continue Watching")
|
||||
nextUpRow = content.CreateChild("HomeRow")
|
||||
nextUpRow.title = tr("Next Up >")
|
||||
|
||||
favoritesRow = content.CreateChild("HomeRow")
|
||||
favoritesRow.title = tr("Favorites")
|
||||
|
||||
sizeArray = [
|
||||
[464, 311], ' My Media
|
||||
[464, 331], ' Continue Watching
|
||||
[464, 331] ' Next Up
|
||||
[464, 331], ' Next Up
|
||||
[464, 331] ' Favorites
|
||||
]
|
||||
|
||||
haveLiveTV = false
|
||||
' validate library data
|
||||
if m.libraryData <> invalid and m.libraryData.count() > 0
|
||||
userConfig = m.top.userConfig
|
||||
|
||||
' populate My Media row
|
||||
filteredMedia = filterNodeArray(m.libraryData, "id", userConfig.MyMediaExcludes)
|
||||
for each item in filteredMedia
|
||||
mediaRow.appendChild(item)
|
||||
end for
|
||||
|
||||
' create a "Latest In" row for each library
|
||||
filteredLatest = filterNodeArray(m.libraryData, "id", userConfig.LatestItemsExcludes)
|
||||
for each lib in filteredLatest
|
||||
|
@ -99,6 +113,10 @@ sub onLibrariesLoaded()
|
|||
m.LoadContinueTask.observeField("content", "updateContinueItems")
|
||||
m.LoadContinueTask.control = "RUN"
|
||||
|
||||
' Load the Favorites Data
|
||||
m.LoadFavoritesTask.observeField("content", "updateFavoritesItems")
|
||||
m.LoadFavoritesTask.control = "RUN"
|
||||
|
||||
' If we have Live TV access, load "On Now" data
|
||||
if haveLiveTV
|
||||
m.LoadOnNowTask.observeField("content", "updateOnNowItems")
|
||||
|
@ -116,6 +134,51 @@ sub updateHomeRows()
|
|||
m.LoadContinueTask.control = "RUN"
|
||||
end sub
|
||||
|
||||
sub updateFavoritesItems()
|
||||
itemData = m.LoadFavoritesTask.content
|
||||
m.LoadFavoritesTask.unobserveField("content")
|
||||
m.LoadFavoritesTask.content = []
|
||||
|
||||
if itemData = invalid then return
|
||||
|
||||
homeRows = m.top.content
|
||||
rowIndex = getRowIndex("Favorites")
|
||||
|
||||
if itemData.count() < 1
|
||||
if rowIndex <> invalid
|
||||
' remove the row
|
||||
deleteFromSizeArray(rowIndex)
|
||||
homeRows.removeChildIndex(rowIndex)
|
||||
end if
|
||||
else
|
||||
' remake row using the new data
|
||||
row = CreateObject("roSGNode", "HomeRow")
|
||||
row.title = tr("Favorites")
|
||||
itemSize = [464, 331]
|
||||
|
||||
for each item in itemData
|
||||
usePoster = true
|
||||
|
||||
if lcase(item.type) = "episode" or lcase(item.type) = "audio" or lcase(item.type) = "musicartist"
|
||||
usePoster = false
|
||||
end if
|
||||
|
||||
item.usePoster = usePoster
|
||||
item.imageWidth = row.imageWidth
|
||||
row.appendChild(item)
|
||||
end for
|
||||
|
||||
if rowIndex = invalid
|
||||
' insert new row under "My Media"
|
||||
updateSizeArray(itemSize, 1)
|
||||
homeRows.insertChild(row, 1)
|
||||
else
|
||||
' replace the old row
|
||||
homeRows.replaceChild(row, rowIndex)
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub updateContinueItems()
|
||||
itemData = m.LoadContinueTask.content
|
||||
m.LoadContinueTask.unobserveField("content")
|
||||
|
|
|
@ -100,6 +100,27 @@ sub loadItems()
|
|||
end if
|
||||
end for
|
||||
|
||||
else if m.top.itemsToLoad = "favorites"
|
||||
|
||||
url = Substitute("Users/{0}/Items", get_setting("active_user"))
|
||||
|
||||
params = {}
|
||||
params["Filters"] = "IsFavorite"
|
||||
params["Limit"] = 20
|
||||
params["recursive"] = true
|
||||
params["sortby"] = "random"
|
||||
|
||||
resp = APIRequest(url, params)
|
||||
data = getJson(resp)
|
||||
for each item in data.Items
|
||||
' Skip Books for now as we don't support it (issue #558)
|
||||
if item.Type <> "Book"
|
||||
tmp = CreateObject("roSGNode", "HomeData")
|
||||
tmp.json = item
|
||||
results.push(tmp)
|
||||
end if
|
||||
end for
|
||||
|
||||
else if m.top.itemsToLoad = "onNow"
|
||||
url = "LiveTv/Programs/Recommended"
|
||||
params = {}
|
||||
|
|
|
@ -288,6 +288,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
gridGrp.setFocus(true)
|
||||
return true
|
||||
else if key = "back"
|
||||
m.LoadChannelsTask.control = "stop"
|
||||
m.global.sceneManager.callFunc("popScene")
|
||||
return true
|
||||
end if
|
||||
|
|
|
@ -103,10 +103,6 @@ sub itemContentChanged()
|
|||
setFieldText("director", tr("Director") + ": " + directors.join(", "))
|
||||
end if
|
||||
|
||||
if itemData.mediaStreams[0] <> invalid
|
||||
setFieldText("video_codec", tr("Video") + ": " + itemData.mediaStreams[0].displayTitle)
|
||||
end if
|
||||
|
||||
if get_user_setting("ui.details.hidetagline") = "false"
|
||||
if itemData.taglines.count() > 0
|
||||
setFieldText("tagline", itemData.taglines[0])
|
||||
|
@ -132,11 +128,28 @@ end sub
|
|||
sub SetUpVideoOptions(streams)
|
||||
|
||||
videos = []
|
||||
codecDetailsSet = false
|
||||
|
||||
for i = 0 to streams.Count() - 1
|
||||
if streams[i].VideoType = "VideoFile"
|
||||
codec = ""
|
||||
if streams[i].mediaStreams <> invalid and streams[i].mediaStreams.Count() > 0 then codec = streams[i].mediaStreams[0].displayTitle
|
||||
if streams[i].mediaStreams <> invalid and streams[i].mediaStreams.Count() > 0
|
||||
|
||||
' find the first (default) video track to get the codec for the details screen
|
||||
if codecDetailsSet = false
|
||||
for index = 0 to streams[i].mediaStreams.Count() - 1
|
||||
if streams[i].mediaStreams[index].Type = "Video"
|
||||
setFieldText("video_codec", tr("Video") + ": " + streams[i].mediaStreams[index].displayTitle)
|
||||
codecDetailsSet = true
|
||||
exit for
|
||||
end if
|
||||
end for
|
||||
end if
|
||||
|
||||
codec = streams[i].mediaStreams[0].displayTitle
|
||||
end if
|
||||
|
||||
' Create options for user to switch between video tracks
|
||||
videos.push({
|
||||
"Title": streams[i].Name,
|
||||
"Description": tr("Video"),
|
||||
|
|
|
@ -408,7 +408,7 @@ sub onMetaDataLoaded()
|
|||
if data <> invalid and data.count() > 0
|
||||
|
||||
' Use metadata to load backdrop image
|
||||
if isvalid(data.json)
|
||||
if isValid(data.json)
|
||||
if isValid(data.json.ArtistItems)
|
||||
if data.json.ArtistItems.count() > 0
|
||||
if isValid(data.json.ArtistItems[0].id)
|
||||
|
|
|
@ -1,21 +1,123 @@
|
|||
sub init()
|
||||
m.top.optionsAvailable = false ' Change once Shuffle option is added
|
||||
m.top.optionsAvailable = true
|
||||
m.top.overhangVisible = false
|
||||
m.slideshowTimer = m.top.findNode("slideshowTimer")
|
||||
m.slideshowTimer.observeField("fire", "nextSlide")
|
||||
m.status = m.top.findNode("status")
|
||||
m.textBackground = m.top.findNode("background")
|
||||
m.statusTimer = m.top.findNode("statusTimer")
|
||||
m.statusTimer.observeField("fire", "statusUpdate")
|
||||
m.slideshow = get_user_setting("photos.slideshow")
|
||||
m.random = get_user_setting("photos.random")
|
||||
|
||||
m.showStatusAnimation = m.top.findNode("showStatusAnimation")
|
||||
m.hideStatusAnimation = m.top.findNode("hideStatusAnimation")
|
||||
|
||||
itemContentChanged()
|
||||
end sub
|
||||
|
||||
sub itemContentChanged()
|
||||
if isValidToContinue(m.top.itemIndex)
|
||||
m.LoadLibrariesTask = createObject("roSGNode", "LoadPhotoTask")
|
||||
m.LoadLibrariesTask.itemContent = m.top.itemContent
|
||||
itemContent = m.top.items.content.getChild(m.top.itemIndex)
|
||||
m.LoadLibrariesTask.itemContent = itemContent
|
||||
m.LoadLibrariesTask.observeField("results", "onPhotoLoaded")
|
||||
m.LoadLibrariesTask.control = "RUN"
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub onPhotoLoaded()
|
||||
if m.LoadLibrariesTask.results <> invalid
|
||||
photo = m.top.findNode("photo")
|
||||
photo.uri = m.LoadLibrariesTask.results
|
||||
|
||||
if m.slideshow = "true" or m.random = "true"
|
||||
' user has requested either a slideshow or random...
|
||||
m.slideshowTimer.control = "start"
|
||||
end if
|
||||
else
|
||||
'Show user error here (for example if it's not a supported image type)
|
||||
message_dialog("This image type is not supported.")
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub nextSlide()
|
||||
m.slideshowTimer.control = "stop"
|
||||
|
||||
if m.slideshow = "true"
|
||||
if isValidToContinue(m.top.itemIndex + 1)
|
||||
m.top.itemIndex++
|
||||
m.slideshowTimer.control = "start"
|
||||
end if
|
||||
else if m.random = "true"
|
||||
index = rnd(m.top.items.content.getChildCount() - 1)
|
||||
if isValidToContinue(index)
|
||||
m.top.itemIndex = index
|
||||
m.slideshowTimer.control = "start"
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub statusUpdate()
|
||||
m.statusTimer.control = "stop"
|
||||
m.hideStatusAnimation.control = "start"
|
||||
end sub
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
if not press then return false
|
||||
|
||||
if key = "right"
|
||||
if isValidToContinue(m.top.itemIndex + 1)
|
||||
m.slideshowTimer.control = "stop"
|
||||
m.top.itemIndex++
|
||||
end if
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "left"
|
||||
if isValidToContinue(m.top.itemIndex - 1)
|
||||
m.slideshowTimer.control = "stop"
|
||||
m.top.itemIndex--
|
||||
end if
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "play"
|
||||
if m.slideshowTimer.control = "start"
|
||||
' stop the slideshow if the user hits "pause"
|
||||
m.slideshowTimer.control = "stop"
|
||||
m.status.text = tr("Slideshow Paused")
|
||||
if m.textBackground.opacity = 0
|
||||
m.showStatusAnimation.control = "start"
|
||||
end if
|
||||
m.statusTimer.control = "start"
|
||||
else
|
||||
' start the slideshow if the user hits "play"
|
||||
m.status.text = tr("Slideshow Resumed")
|
||||
if m.textBackground.opacity = 0
|
||||
m.showStatusAnimation.control = "start"
|
||||
end if
|
||||
m.slideshow = "true"
|
||||
m.statusTimer.control = "start"
|
||||
m.slideshowTimer.control = "start"
|
||||
end if
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "options"
|
||||
' Options (random etc) is done on itemGrid
|
||||
return true
|
||||
end if
|
||||
|
||||
return false
|
||||
end function
|
||||
|
||||
function isValidToContinue(index as integer)
|
||||
if isValid(m.top.items) and isValid(m.top.items.content)
|
||||
if index >= 0 and index < m.top.items.content.getChildCount()
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
|
||||
return false
|
||||
end function
|
||||
|
|
|
@ -1,13 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="PhotoDetails" extends="JFGroup">
|
||||
<children>
|
||||
<LayoutGroup id="toplevel">
|
||||
<Poster id="photo" width="1920" height="1080" loadDisplayMode="scaleToFit"/>
|
||||
</LayoutGroup>
|
||||
<Rectangle id="background" color="0x101010EE" height="120" width="500" Translation="[700, -150]" opacity="0">
|
||||
<Label id="status" font="font:MediumSystemFont" height="100" width="500" horizAlign="center" vertAlign="bottom"/>
|
||||
</Rectangle>
|
||||
<Timer id="slideshowTimer" duration="5" repeat="false" />
|
||||
<Timer id="statusTimer" duration="2" repeat="false" />
|
||||
|
||||
<Animation id="showStatusAnimation" duration="1" repeat="false">
|
||||
<FloatFieldInterpolator key="[0.0, 0.1]" keyValue="[0, 1]" fieldToInterp="background.opacity" />
|
||||
<Vector2DFieldInterpolator key="[0.1, 1]" keyValue="[[700, -150], [700, -5]]" fieldToInterp="background.translation" />
|
||||
</Animation>
|
||||
<Animation id="hideStatusAnimation" duration="1" repeat="false">
|
||||
<Vector2DFieldInterpolator key="[0.0, 0.9]" keyValue="[[700, -5], [700, -150]]" fieldToInterp="background.translation" />
|
||||
<FloatFieldInterpolator key="[0.9, 1]" keyValue="[1, 0]" fieldToInterp="background.opacity" />
|
||||
</Animation>
|
||||
|
||||
</children>
|
||||
<interface>
|
||||
<field id="itemContent" type="node" onChange="itemContentChanged" />
|
||||
<field id="items" type="node" />
|
||||
<field id="itemIndex" type="integer" value="-1" onChange="itemContentChanged" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="PhotoDetails.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
</component>
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
sub init()
|
||||
m.top.functionName = "loadItems"
|
||||
end sub
|
||||
|
||||
sub loadItems()
|
||||
item = m.top.itemContent
|
||||
|
||||
group = CreateObject("roSGNode", "PhotoDetails")
|
||||
group.optionsAvailable = false
|
||||
m.global.sceneManager.callFunc("pushScene", group)
|
||||
|
||||
group.itemContent = item
|
||||
|
||||
' TODO/FIXME:
|
||||
' Wait some time and move to the next photo...
|
||||
|
||||
end sub
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<component name="PhotoPlayerTask" extends="Task">
|
||||
<interface>
|
||||
<field id="itemContent" type="node" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="PhotoPlayerTask.brs" />
|
||||
</component>
|
|
@ -48,7 +48,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
m.searchAlphabox.textEditBox.translation = "[0, 0]"
|
||||
end if
|
||||
|
||||
if key = "left" and m.searchSelect.isinFocusChain() and (m.searchSelect.currFocusColumn = -1 or m.searchSelect.currFocusColumn = 0)
|
||||
if key = "left" and m.searchSelect.isinFocusChain()
|
||||
m.searchAlphabox.setFocus(true)
|
||||
return true
|
||||
else if key = "right"
|
||||
|
|
|
@ -36,8 +36,14 @@ sub itemContentChanged()
|
|||
|
||||
m.poster.uri = imageUrl
|
||||
|
||||
if type(itemData.RunTimeTicks) = "LongInteger"
|
||||
m.top.findNode("runtime").text = stri(getRuntime()).trim() + " mins"
|
||||
if type(itemData.RunTimeTicks) = "roInt" or type(itemData.RunTimeTicks) = "LongInteger"
|
||||
runTime = getRuntime()
|
||||
if runTime < 2
|
||||
m.top.findNode("runtime").text = "1 min"
|
||||
else
|
||||
m.top.findNode("runtime").text = stri(runTime).trim() + " mins"
|
||||
end if
|
||||
|
||||
if get_user_setting("ui.design.hideclock") <> "true"
|
||||
m.top.findNode("endtime").text = tr("Ends at %1").Replace("%1", getEndTime())
|
||||
end if
|
||||
|
|
|
@ -3648,5 +3648,9 @@
|
|||
<translation>Úroveň</translation>
|
||||
<extracomment>Video profile level</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Credentials?</source>
|
||||
<translation>Uložit přihlašovací údaje?</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<name>default</name>
|
||||
<message>
|
||||
<source>192.168.1.100:8096 or https://example.com/jellyfin</source>
|
||||
<translation>192.168.1.100:8096 or https://example.com/jellyfin</translation>
|
||||
<translation>default192.168.1.100:8096 or https://example.com/jellyfin</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
|
@ -1666,5 +1666,454 @@
|
|||
<source>Save Credentials?</source>
|
||||
<translation>Save Credentials?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Version</source>
|
||||
<translation>Version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Item Titles</source>
|
||||
<translation>Item Titles</translation>
|
||||
<extracomment>UI -> Media Grid -> Item Title in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Credentials?</source>
|
||||
<translation>Save Credentials?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Born</source>
|
||||
<translation>Born</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Age</source>
|
||||
<translation>Age</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>More Like This</source>
|
||||
<translation>More Like This</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Special Features</source>
|
||||
<translation>Special Features</translation>
|
||||
<message>
|
||||
<source>Press 'OK' to Close</source>
|
||||
<translation>Press 'OK' to Close</translation>
|
||||
</message>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Shows</source>
|
||||
<translation>TV Shows</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>View Channel</source>
|
||||
<translation>View Channel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Record</source>
|
||||
<translation>Record</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Record Series</source>
|
||||
<translation>Record Series</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Recording</source>
|
||||
<translation>Cancel Recording</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Unknown</translation>
|
||||
<extracomment>Title for a cast member for which we have no information for</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enter the server name or IP address</source>
|
||||
<translation>Enter the server name or IP address</translation>
|
||||
<extracomment>Title of KeyboardDialog when manually entering a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cast & Crew</source>
|
||||
<translation>Cast & Crew</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pick a Jellyfin server from the local network</source>
|
||||
<translation>Select an available Jellyfin server from your local network:</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to pick a server from a list</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error Getting Playback Information</source>
|
||||
<translation>Error Getting Playback Information</translation>
|
||||
<extracomment>Dialog Title: Received error from server when trying to get information about the selected item for playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>An error was encountered while playing this item. Server did not provide required transcoding data.</source>
|
||||
<translation>An error was encountered while playing this item. Server did not provide required transcoding data.</translation>
|
||||
<extracomment>Content of message box when trying to play an item which requires transcoding, and the server did not provide transcode url</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playback</source>
|
||||
<translation>Playback</translation>
|
||||
<extracomment>Title for Playback section in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>MPEG-2 Support</source>
|
||||
<translation>MPEG-2 Support</translation>
|
||||
<extracomment>Settings Menu - Title for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Support Direct Play of MPEG-2 content (e.g., Live TV). This will prevent transcoding of MPEG-2 content, but uses significantly more bandwidth.</source>
|
||||
<translation>Support Direct Play of MPEG-2 content (e.g., Live TV). This will prevent transcoding of MPEG-2 content, but uses significantly more bandwidth.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>User Interface</source>
|
||||
<translation>User Interface</translation>
|
||||
<extracomment>Title for User Interface section in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Media Grid</source>
|
||||
<translation>Media Grid</translation>
|
||||
<extracomment>UI -> Media Grid section in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Media Grid options.</source>
|
||||
<translation>Media Grid options.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always show the titles below the poster images. (If disabled, the title will be shown under the highlighted item only).</source>
|
||||
<translation>Always show the titles below the poster images. (If disabled, the title will be shown under the highlighted item only).</translation>
|
||||
<extracomment>Description for option in Setting Screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Item Count</source>
|
||||
<translation>Item Count</translation>
|
||||
<extracomment>UI -> Media Grid -> Item Count in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show item count in the library and index of selected item.</source>
|
||||
<translation>Show item count in the library and index of selected item.</translation>
|
||||
<extracomment>Description for option in Setting Screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set Favorite</source>
|
||||
<translation>Set Favourite</translation>
|
||||
<extracomment>Button Text - When pressed, sets item as Favorite</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set Watched</source>
|
||||
<translation>Set Watched</translation>
|
||||
<extracomment>Button Text - When pressed, marks item as Warched</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Go to series</source>
|
||||
<translation>Go to series</translation>
|
||||
<extracomment>Continue Watching Popup Menu - Navigate to the Series Detail Page</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Saved</source>
|
||||
<translation>Delete Saved</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Movies</source>
|
||||
<translation>Films</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Series Recording</source>
|
||||
<translation>Cancel Series Recording</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Close</source>
|
||||
<translation>Close</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On Now</source>
|
||||
<translation>On Now</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Died</source>
|
||||
<translation>Died</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>...or enter server URL manually:</source>
|
||||
<translation>If no server is listed above, you may also enter the server URL manually:</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to manually enter a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enabled</source>
|
||||
<translation>Enabled</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabled</source>
|
||||
<translation>Disabled</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use voice remote to search</source>
|
||||
<translation>Use voice remote to search</translation>
|
||||
<extracomment>Help text in search voice text box</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use the replay button to slowly animate to the first item in the folder. (If disabled, the folder will reset to the first item immediately).</source>
|
||||
<translation>Use the replay button to slowly animate to the first item in the folder. (If disabled, the folder will reset to the first item immediately).</translation>
|
||||
<extracomment>Description for option in Setting Screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options for TV Shows.</source>
|
||||
<translation>Options for TV Shows.</translation>
|
||||
<extracomment>Description for TV Shows user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cinema Mode brings the theater experience straight to your living room with the ability to play custom intros before the main feature.</source>
|
||||
<translation>Cinema Mode brings the cinema experience straight to your living room with the ability to play custom intros before the main feature.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hides all clocks in Jellyfin. Jellyfin will need to be closed and reopened for change to take effect.</source>
|
||||
<translation>Hides all clocks in Jellyfin. Jellyfin will need to be closed and reopened for change to take effect.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Settings relating to playback and supported codec and media types.</source>
|
||||
<translation>Settings relating to playback and supported codec and media types.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Settings relating to how the application looks.</source>
|
||||
<translation>Settings relating to how the application looks.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Studios</source>
|
||||
<translation>Studios</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Return to Top</source>
|
||||
<translation>Return to Top</translation>
|
||||
<extracomment>UI -> Media Grid -> Item Title in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Details Page</source>
|
||||
<translation>Details Page</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hide Taglines</source>
|
||||
<translation>Hide Taglines</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Splashscreen as Screensaver Background</source>
|
||||
<translation>Use Splashscreen as Screensaver Background</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playback Information</source>
|
||||
<translation>Playback Information</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Transcoding Information</source>
|
||||
<translation>Transcoding Information</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Video Codec</source>
|
||||
<translation>Video Codec</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio Codec</source>
|
||||
<translation>Audio Codec</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>direct</source>
|
||||
<translation>direct</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Level</source>
|
||||
<translation>Level</translation>
|
||||
<extracomment>Video profile level</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Bit Rate</source>
|
||||
<translation>Bit Rate</translation>
|
||||
<extracomment>Video streaming bit rate</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Size</source>
|
||||
<translation>Size</translation>
|
||||
<extracomment>Video size</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>WxH</source>
|
||||
<translation>WxH</translation>
|
||||
<extracomment>Video width x height</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quick Connect</source>
|
||||
<translation>Quick Connect</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Here is your Quick Connect code:</source>
|
||||
<translation>Here is your Quick Connect code:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>(Dialog will close automatically)</source>
|
||||
<translation>(Dialogue will close automatically)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play Trailer</source>
|
||||
<translation>Play Trailer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Home Page</source>
|
||||
<translation>Home Page</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options for Home Page.</source>
|
||||
<translation>Options for Home Page.</translation>
|
||||
<extracomment>Description for Home Page user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cinema Mode</source>
|
||||
<translation>Cinema Mode</translation>
|
||||
<extracomment>Settings Menu - Title for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Splashscreen as Home Background</source>
|
||||
<translation>Use Splashscreen as Home Background</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Design Elements</source>
|
||||
<translation>Design Elements</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Screensaver</source>
|
||||
<translation>Screensaver</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Search now</source>
|
||||
<translation>Search now</translation>
|
||||
<extracomment>Help text in search Box</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Go to episode</source>
|
||||
<translation>Go to episode</translation>
|
||||
<extracomment>Continue Watching Popup Menu - Navigate to the Episode Detail Page</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Go to season</source>
|
||||
<translation>Go to season</translation>
|
||||
<extracomment>Continue Watching Popup Menu - Navigate to the Season Page</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>You can search for Titles, People, Live TV Channels and more</source>
|
||||
<translation>You can search for Titles, People, Live TV Channels and more</translation>
|
||||
<extracomment>Help text in search results</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 of %2</source>
|
||||
<translation>%1 of %2</translation>
|
||||
<extracomment>Item position and count. %1 = current item. %2 = total number of items</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>There was an error authenticating via Quick Connect.</source>
|
||||
<translation>There was an error authenticating via Quick Connect.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Networks</source>
|
||||
<translation>Networks</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shows</source>
|
||||
<translation>Shows</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options for Details pages.</source>
|
||||
<translation>Options for Details pages.</translation>
|
||||
<extracomment>Description for Details page user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hides tagline text on details pages.</source>
|
||||
<translation>Hides tagline text on details pages.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Blur Unwatched Episodes</source>
|
||||
<translation>Blur Unwatched Episodes</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>If enabled, images of unwatched episodes will be blurred.</source>
|
||||
<translation>If enabled, images of unwatched episodes will be blurred.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options for Jellyfin's screensaver.</source>
|
||||
<translation>Options for Jellyfin's screensaver.</translation>
|
||||
<extracomment>Description for Screensaver user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use generated splashscreen image as Jellyfin's screensaver background. Jellyfin will need to be closed and reopened for change to take effect.</source>
|
||||
<translation>Use generated splashscreen image as Jellyfin's screensaver background. Jellyfin will need to be closed and reopened for change to take effect.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options that alter the design of Jellyfin.</source>
|
||||
<translation>Options that alter the design of Jellyfin.</translation>
|
||||
<extracomment>Description for Design Elements user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use generated splashscreen image as Jellyfin's home background. Jellyfin will need to be closed and reopened for change to take effect.</source>
|
||||
<translation>Use generated splashscreen image as Jellyfin's home background. Jellyfin will need to be closed and reopened for change to take effect.</translation>
|
||||
<extracomment>Description for option in Setting Screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hide Clock</source>
|
||||
<translation>Hide Clock</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Max Days Next Up</source>
|
||||
<translation>Max Days Next Up</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set the maximum amount of days a show should stay in the 'Next Up' list without watching it.</source>
|
||||
<translation>Set the maximum amount of days a show should stay in the 'Next Up' list without watching it.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reason</source>
|
||||
<translation>Reason</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Total Bitrate</source>
|
||||
<translation>Total Bitrate</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio Channels</source>
|
||||
<translation>Audio Channels</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stream Information</source>
|
||||
<translation>Stream Information</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Codec</source>
|
||||
<translation>Codec</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Codec Tag</source>
|
||||
<translation>Codec Tag</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Container</source>
|
||||
<translation>Container</translation>
|
||||
<extracomment>Video streaming container</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Video range type</source>
|
||||
<translation>Video range type</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pixel format</source>
|
||||
<translation>Pixel format</translation>
|
||||
<extracomment>Video pixel format</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to find any albums or songs belonging to this artist</source>
|
||||
<translation>Unable to find any albums or songs belonging to this artist</translation>
|
||||
<extracomment>Popup message when we find no audio data for an artist</extracomment>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -489,6 +489,16 @@
|
|||
<translation>Support Direct Play of MPEG-2 content (e.g., Live TV). This will prevent transcoding of MPEG-2 content, but uses significantly more bandwidth.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>AV1 Support</source>
|
||||
<translation>AV1 Support</translation>
|
||||
<extracomment>Settings Menu - Title for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>** EXPERIMENTAL** Support Direct Play of AV1 content if this Roku device supports it.</source>
|
||||
<translation>** EXPERIMENTAL** Support Direct Play of AV1 content if this Roku device supports it.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enabled</source>
|
||||
<translation>Enabled</translation>
|
||||
|
@ -703,11 +713,34 @@
|
|||
<translation>Hides all clocks in Jellyfin. Jellyfin will need to be closed and reopened for change to take effect.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Next episode</source>
|
||||
<translation>Next episode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play Trailer</source>
|
||||
<translation>Play Trailer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Direct Play H.264 Unsupported Profile Levels</source>
|
||||
<translation>Direct Play H.264 Unsupported Profile Levels</translation>
|
||||
<extracomment>Settings Menu - Title for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Attempt Direct Play for H.264 media with unsupported profile levels before falling back to transcoding if it fails.</source>
|
||||
<translation>Attempt Direct Play for H.264 media with unsupported profile levels before falling back to transcoding if it fails.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Direct Play HEVC Unsupported Profile Levels</source>
|
||||
<translation>Direct Play HEVC Unsupported Profile Levels</translation>
|
||||
<extracomment>Settings Menu - Title for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Attempt Direct Play for HEVC media with unsupported profile levels before falling back to trancoding if it fails.</source>
|
||||
<translation>Attempt Direct Play for HEVC media with unsupported profile levels before falling back to trancoding if it fails.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<source>Settings relating to playback and supported codec and media types.</source>
|
||||
<translation>Settings relating to playback and supported codec and media types.</translation>
|
||||
</message>
|
||||
|
@ -822,5 +855,39 @@
|
|||
<translation>Aired</translation>
|
||||
<extracomment>Aired date label</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Slideshow Off</source>
|
||||
<translation>Slideshow Off</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Slideshow On</source>
|
||||
<translation>Slideshow On</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Slideshow Paused</source>
|
||||
<translation>Slideshow Paused</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Slideshow Resumed</source>
|
||||
<translation>Slideshow Resumed</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Random Off</source>
|
||||
<translation>Random Off</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Random On</source>
|
||||
<translation>Random On</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MPEG-4 Support</source>
|
||||
<translation>MPEG-4 Support</translation>
|
||||
<extracomment>Settings Menu - Title for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Support Direct Play of MPEG-4 content. This may need to be disabled for playback of DIVX encoded video files.</source>
|
||||
<translation>Support Direct Play of MPEG-4 content. This may need to be disabled for playback of DIVX encoded video files.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -1614,5 +1614,104 @@
|
|||
<source>Save Credentials?</source>
|
||||
<translation>Guardar credenciales?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Credentials?</source>
|
||||
<translation>Guardar Credenciales?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error Retrieving Content</source>
|
||||
<translation>Error al recuperar contenido</translation>
|
||||
<extracomment>Dialog title when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>An error was encountered while playing this item.</source>
|
||||
<translation>Se ha encontrado un error mientras se reproducía este ítem.</translation>
|
||||
<extracomment>Dialog detail when error occurs during playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error loading Channel Data</source>
|
||||
<translation>Error al cargar datos del canal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Movies</source>
|
||||
<translation>Peliculas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Shows</source>
|
||||
<translation>Programa de TV</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>today</source>
|
||||
<translation>Hoy</translation>
|
||||
<extracomment>Current day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>yesterday</source>
|
||||
<translation>Ayer</translation>
|
||||
<extracomment>Previous day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error During Playback</source>
|
||||
<translation>Error durante la reproducción</translation>
|
||||
<extracomment>Dialog title when error occurs during playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Name or Title field of media item</comment>
|
||||
<source>TITLE</source>
|
||||
<translation>Nombre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CRITIC_RATING</source>
|
||||
<translation>Calificación de los Críticos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Monday</source>
|
||||
<translation>Lunes</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading Channel Data</source>
|
||||
<translation>Cargando información del canal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Saved</source>
|
||||
<translation>Borrado confirmado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There was an error retrieving the data for this item from the server.</source>
|
||||
<translation>Ocurrió un error al recuperar los datos para este ítem desde el servidor.</translation>
|
||||
<extracomment>Dialog detail when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to load Channel Data from the server</source>
|
||||
<translation>No se pudo cargar los datos del canal desde el servidor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Message displayed in Item Grid when no item to display. %1 is container type (e.g. Boxset, Collection, Folder, etc)</comment>
|
||||
<source>NO_ITEMS</source>
|
||||
<translation>Este %1 no contiene ítems</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>IMDB_RATING</source>
|
||||
<translation>Calificación IMDb</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Special Features</source>
|
||||
<translation>Funciones especiales</translation>
|
||||
<message>
|
||||
<source>Press 'OK' to Close</source>
|
||||
<translation>Press 'OK' to Close</translation>
|
||||
</message>
|
||||
</message>
|
||||
<message>
|
||||
<source>tomorrow</source>
|
||||
<translation>Mañana</translation>
|
||||
<extracomment>Next day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sunday</source>
|
||||
<translation>Domingo</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -1328,5 +1328,22 @@
|
|||
<source>Save Credentials?</source>
|
||||
<translation>Guardar credenciales?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Credentials?</source>
|
||||
<translation>¿Guardar credenciales?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Saved</source>
|
||||
<translation>Eliminar guardado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On Now</source>
|
||||
<translation>Ahora</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error Retrieving Content</source>
|
||||
<translation>Error al recuperar contenido</translation>
|
||||
<extracomment>Dialog title when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -1884,5 +1884,320 @@
|
|||
<source>TITLE</source>
|
||||
<translation>Nombre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error loading Channel Data</source>
|
||||
<translation>Error de Reproducción de Contenido de Canal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sign Out</source>
|
||||
<translation>Terminar Sesión</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Saved</source>
|
||||
<translation>Borrar Credenciales</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Age</source>
|
||||
<translation>Edad</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CRITIC_RATING</source>
|
||||
<translation>Criticas Raiting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Born</source>
|
||||
<translation>Nacido/a</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>today</source>
|
||||
<translation>hoy</translation>
|
||||
<extracomment>Current day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading Channel Data</source>
|
||||
<translation>Reproduciendo Contenido de Canal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Channels</source>
|
||||
<translation>Canales</translation>
|
||||
<extracomment>Menu option for showing Live TV Channel List</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Died</source>
|
||||
<translation>Muerto/a</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>View Channel</source>
|
||||
<translation>Ver Canales</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>...or enter server URL manually:</source>
|
||||
<translation>si no hay servidores disponibles, puedes agregar manualmente la URL</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to manually enter a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>There was an error retrieving the data for this item from the server.</source>
|
||||
<translation>Ha ocurrido un error tratando de recuperar la información desde el servidor.</translation>
|
||||
<extracomment>Dialog detail when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Message displayed in Item Grid when no item to display. %1 is container type (e.g. Boxset, Collection, Folder, etc)</comment>
|
||||
<source>NO_ITEMS</source>
|
||||
<translation>Este %1 no contiene elementos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>IMDB_RATING</source>
|
||||
<translation>IMDb Raiting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DATE_ADDED</source>
|
||||
<translation>Fecha Agregada</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DATE_PLAYED</source>
|
||||
<translation>Fecha Reproducida</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Movies</source>
|
||||
<translation>Películas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>yesterday</source>
|
||||
<translation>ayer</translation>
|
||||
<extracomment>Previous day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>tomorrow</source>
|
||||
<translation>mañana</translation>
|
||||
<extracomment>Next day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Tuesday</source>
|
||||
<translation>Martes</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Thursday</source>
|
||||
<translation>Jueves</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Friday</source>
|
||||
<translation>Viernes</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Title of Tab for options to filter library content</comment>
|
||||
<source>TAB_FILTER</source>
|
||||
<translation>Filtro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sunday</source>
|
||||
<translation>Domingo</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Monday</source>
|
||||
<translation>Lunes</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Wednesday</source>
|
||||
<translation>Miercoles</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Saturday</source>
|
||||
<translation>Sabado</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Started at</source>
|
||||
<translation>Comienza a</translation>
|
||||
<extracomment>(Past Tense) For defining time when a program started today (e.g. Started at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Live</source>
|
||||
<translation>En Vivo</translation>
|
||||
<extracomment>If TV Show is being broadcast live (not pre-recorded)</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Repeat</source>
|
||||
<translation>Repetir</translation>
|
||||
<extracomment>If TV Shows has previously been broadcasted</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Guide</source>
|
||||
<translation>Guia de Television</translation>
|
||||
<extracomment>Menu option for showing Live TV Guide / Schedule</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Record</source>
|
||||
<translation>Grabar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Record Series</source>
|
||||
<translation>Grabar Series</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Close</source>
|
||||
<translation>Cerrar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>desconocido</translation>
|
||||
<extracomment>Title for a cast member for which we have no information for</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connecting to Server</source>
|
||||
<translation>Conectando con el Servidor</translation>
|
||||
<extracomment>Message to display to user while client is attempting to connect to the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Not found</source>
|
||||
<translation>No se ha encontrado</translation>
|
||||
<extracomment>Title of message box when the requested content is not found on the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Credentials?</source>
|
||||
<translation>Guardar Credenciales?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Name or Title field of media item</comment>
|
||||
<source>TITLE</source>
|
||||
<translation>Nombre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>An error was encountered while playing this item.</source>
|
||||
<translation>Ha ocurrido un error al reproducir este contenido.</translation>
|
||||
<extracomment>Dialog detail when error occurs during playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error Retrieving Content</source>
|
||||
<translation>Error Recuperando Contenido</translation>
|
||||
<extracomment>Dialog title when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>OFFICIAL_RATING</source>
|
||||
<translation>Padres Raiting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Change Server</source>
|
||||
<translation>Cambiar de Servidor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Title of Tab for options to sort library content</comment>
|
||||
<source>TAB_SORT</source>
|
||||
<translation>Clasificar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Title of Tab for switching "views" when looking at a library</comment>
|
||||
<source>TAB_VIEW</source>
|
||||
<translation>Vista</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>RUNTIME</source>
|
||||
<translation>Tiempo de Ejecución</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error During Playback</source>
|
||||
<translation>Error Durante la Reproducción</translation>
|
||||
<extracomment>Dialog title when error occurs during playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to load Channel Data from the server</source>
|
||||
<translation>No se ha podido reproducir el Contenido del Canal de este servidor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>RELEASE_DATE</source>
|
||||
<translation>Fecha de Premiere</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PLAY_COUNT</source>
|
||||
<translation>Cuenta de Reproducción</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>More Like This</source>
|
||||
<translation>Mas de este Estilo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Special Features</source>
|
||||
<translation>Funciones Especiales</translation>
|
||||
<message>
|
||||
<source>Press 'OK' to Close</source>
|
||||
<translation>Press 'OK' to Close</translation>
|
||||
</message>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Shows</source>
|
||||
<translation>Programas de Televisión</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ends at</source>
|
||||
<translation>Termina a</translation>
|
||||
<extracomment>(Past Tense) For defining a day and time when a program ended (e.g. Ended Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Recording</source>
|
||||
<translation>Cancelar la grabación</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Series Recording</source>
|
||||
<translation>Cancelar la grabación de Series</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pick a Jellyfin server from the local network</source>
|
||||
<translation>Elige un servidor Jellyfin disponible de la red local</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to pick a server from a list</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Started</source>
|
||||
<translation>Comenzó</translation>
|
||||
<extracomment>(Past Tense) For defining a day and time when a program started (e.g. Started Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts at</source>
|
||||
<translation>Comenzó a</translation>
|
||||
<extracomment>(Future Tense) For defining time when a program will start today (e.g. Starts at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts</source>
|
||||
<translation>Comienza</translation>
|
||||
<extracomment>(Future Tense) For defining a day and time when a program will start (e.g. Starts Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ended at</source>
|
||||
<translation>Terminó</translation>
|
||||
<extracomment>(Past Tense) For defining time when a program will ended (e.g. Ended at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enter the server name or IP address</source>
|
||||
<translation>Agregar el nombre del servidor o direccion de IP</translation>
|
||||
<extracomment>Title of KeyboardDialog when manually entering a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pick a Jellyfin server from the local network</source>
|
||||
<translation>Elige un servidor Jellyfin disponible de la red local:</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to pick a server from a list</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>...or enter server URL manually:</source>
|
||||
<translation>si no hay servidores disponibles, puedes agregar manualmente la URL:</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to manually enter a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>There was an error retrieving the data for this item from the server.</source>
|
||||
<translation>Ha ocurrido un error tratando de recuperar la información desde el servidor.</translation>
|
||||
<extracomment>Dialog detail when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading Channel Data</source>
|
||||
<translation>Reproduciendo Contenido de Canal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Message displayed in Item Grid when no item to display. %1 is container type (e.g. Boxset, Collection, Folder, etc)</comment>
|
||||
<source>NO_ITEMS</source>
|
||||
<translation>Este %1 no contiene elementos</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -2825,7 +2825,7 @@
|
|||
<translation>Caractéristiques spéciales</translation>
|
||||
<message>
|
||||
<source>Press 'OK' to Close</source>
|
||||
<translation>Press 'OK' to Close</translation>
|
||||
<translation>Appuyez sur 'OK' pour fermer</translation>
|
||||
</message>
|
||||
</message>
|
||||
<message>
|
||||
|
@ -3381,5 +3381,665 @@
|
|||
<source>Delete Saved</source>
|
||||
<translation>Supprimer les informations enregistrées</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cast & Crew</source>
|
||||
<translation>Casting et équipe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Shows</source>
|
||||
<translation>Séries télé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Monday</source>
|
||||
<translation>Lundi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ends at</source>
|
||||
<translation>Fini à</translation>
|
||||
<extracomment>(Past Tense) For defining a day and time when a program ended (e.g. Ended Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>CRITIC_RATING</source>
|
||||
<translation>Note des critiques</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PLAY_COUNT</source>
|
||||
<translation>Nombre de lecture</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Born</source>
|
||||
<translation>Né/Née</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Died</source>
|
||||
<translation>Mort</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Special Features</source>
|
||||
<translation>Caractéristiques spéciales</translation>
|
||||
<message>
|
||||
<source>Press 'OK' to Close</source>
|
||||
<translation>Press 'OK' to Close</translation>
|
||||
</message>
|
||||
</message>
|
||||
<message>
|
||||
<source>Movies</source>
|
||||
<translation>Films</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Tuesday</source>
|
||||
<translation>Mardi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Repeat</source>
|
||||
<translation>Répéter</translation>
|
||||
<extracomment>If TV Shows has previously been broadcasted</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>OFFICIAL_RATING</source>
|
||||
<translation>Classification parentale</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>yesterday</source>
|
||||
<translation>hier</translation>
|
||||
<extracomment>Previous day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>tomorrow</source>
|
||||
<translation>demain</translation>
|
||||
<extracomment>Next day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sunday</source>
|
||||
<translation>Dimanche</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Wednesday</source>
|
||||
<translation>Mercredi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Thursday</source>
|
||||
<translation>Jeudi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Friday</source>
|
||||
<translation>Vendredi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts at</source>
|
||||
<translation>Commence à</translation>
|
||||
<extracomment>(Future Tense) For defining time when a program will start today (e.g. Starts at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts</source>
|
||||
<translation type="unfinished">Débute</translation>
|
||||
<extracomment>(Future Tense) For defining a day and time when a program will start (e.g. Starts Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Started</source>
|
||||
<translation>Commencé</translation>
|
||||
<extracomment>(Past Tense) For defining a day and time when a program started (e.g. Started Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>On Now</source>
|
||||
<translation>Maintenant</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error Retrieving Content</source>
|
||||
<translation>Erreur lors de la récupération du contenu</translation>
|
||||
<extracomment>Dialog title when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error During Playback</source>
|
||||
<translation>Erreur lors de la lecture</translation>
|
||||
<extracomment>Dialog title when error occurs during playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>There was an error retrieving the data for this item from the server.</source>
|
||||
<translation>Une erreur s'est produite lors de la récupération des données de cet élément à partir du serveur.</translation>
|
||||
<extracomment>Dialog detail when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>An error was encountered while playing this item.</source>
|
||||
<translation>Une erreur s'est produite lors de la lecture de cet élément.</translation>
|
||||
<extracomment>Dialog detail when error occurs during playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading Channel Data</source>
|
||||
<translation>Chargement des données de la chaîne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error loading Channel Data</source>
|
||||
<translation>Erreur lors du chargement des données de la chaîne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to load Channel Data from the server</source>
|
||||
<translation>Impossible de charger les données de la chaîne à partir du serveur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Message displayed in Item Grid when no item to display. %1 is container type (e.g. Boxset, Collection, Folder, etc)</comment>
|
||||
<source>NO_ITEMS</source>
|
||||
<translation>Ce %1 ne contient aucun élément</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Name or Title field of media item</comment>
|
||||
<source>TITLE</source>
|
||||
<translation>Nom</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>IMDB_RATING</source>
|
||||
<translation>Classement IMDb</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DATE_ADDED</source>
|
||||
<translation>Date d'ajout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DATE_PLAYED</source>
|
||||
<translation>Date de lecture</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>RUNTIME</source>
|
||||
<translation>Durée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Title of Tab for switching "views" when looking at a library</comment>
|
||||
<source>TAB_VIEW</source>
|
||||
<translation>Visualiser</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Title of Tab for options to sort library content</comment>
|
||||
<source>TAB_SORT</source>
|
||||
<translation>Trier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Title of Tab for options to filter library content</comment>
|
||||
<source>TAB_FILTER</source>
|
||||
<translation>Filtrer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Age</source>
|
||||
<translation>Âge</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>More Like This</source>
|
||||
<translation>Similaires</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>today</source>
|
||||
<translation>aujourd'hui</translation>
|
||||
<extracomment>Current day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Saturday</source>
|
||||
<translation>Samedi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Started at</source>
|
||||
<translation>Commencé à</translation>
|
||||
<extracomment>(Past Tense) For defining time when a program started today (e.g. Started at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ended at</source>
|
||||
<translation>Fini à</translation>
|
||||
<extracomment>(Past Tense) For defining time when a program will ended (e.g. Ended at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Live</source>
|
||||
<translation>En direct</translation>
|
||||
<extracomment>If TV Show is being broadcast live (not pre-recorded)</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Channels</source>
|
||||
<translation>Chaînes</translation>
|
||||
<extracomment>Menu option for showing Live TV Channel List</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>RELEASE_DATE</source>
|
||||
<translation>Date de sortie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Return to Top</source>
|
||||
<translation>Retour en haut</translation>
|
||||
<extracomment>UI -> Media Grid -> Item Title in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Here is your Quick Connect code:</source>
|
||||
<translation>Voici votre code Quick Connect :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error Getting Playback Information</source>
|
||||
<translation>Erreur lors de l'obtention des informations de lecture</translation>
|
||||
<extracomment>Dialog Title: Received error from server when trying to get information about the selected item for playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pick a Jellyfin server from the local network</source>
|
||||
<translation>Sélectionnez un serveur Jellyfin disponible sur votre réseau local :</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to pick a server from a list</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Recording</source>
|
||||
<translation>Annuler l'enregistrement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Record</source>
|
||||
<translation>Enregistrer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Screensaver</source>
|
||||
<translation>Écran de veille</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Go to episode</source>
|
||||
<translation>Aller à l'épisode</translation>
|
||||
<extracomment>Continue Watching Popup Menu - Navigate to the Episode Detail Page</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Go to series</source>
|
||||
<translation>Aller à la série</translation>
|
||||
<extracomment>Continue Watching Popup Menu - Navigate to the Series Detail Page</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Studios</source>
|
||||
<translation>Studios</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Search now</source>
|
||||
<translation>Rechercher maintenant</translation>
|
||||
<extracomment>Help text in search Box</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>You can search for Titles, People, Live TV Channels and more</source>
|
||||
<translation>Vous pouvez rechercher des titres, des personnes, des chaînes de télévision en direct et plus encore</translation>
|
||||
<extracomment>Help text in search results</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quick Connect</source>
|
||||
<translation>Quick Connect</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 of %2</source>
|
||||
<translation>%1 sur %2</translation>
|
||||
<extracomment>Item position and count. %1 = current item. %2 = total number of items</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options for Jellyfin's screensaver.</source>
|
||||
<translation>Options de l'écran de veille de Jellyfin.</translation>
|
||||
<extracomment>Description for Screensaver user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cinema Mode</source>
|
||||
<translation>Mode Cinéma</translation>
|
||||
<extracomment>Settings Menu - Title for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cinema Mode brings the theater experience straight to your living room with the ability to play custom intros before the main feature.</source>
|
||||
<translation>Le Mode Cinéma vous fait vivre l'expérience du cinéma directement dans votre salon en vous permettant de diffuser des intros personnalisées avant le film.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>WxH</source>
|
||||
<translation>WxH</translation>
|
||||
<extracomment>Video width x height</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shows</source>
|
||||
<translation>Séries</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Networks</source>
|
||||
<translation>Réseaux</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>User Interface</source>
|
||||
<translation>Interface Utilisateur</translation>
|
||||
<extracomment>Title for User Interface section in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Close</source>
|
||||
<translation>Fermer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play Trailer</source>
|
||||
<translation>Lire la bande-annonce</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Item Count</source>
|
||||
<translation>Nombre d'éléments</translation>
|
||||
<extracomment>UI -> Media Grid -> Item Count in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Version</source>
|
||||
<translation>Version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connecting to Server</source>
|
||||
<translation>Connexion au Serveur</translation>
|
||||
<extracomment>Message to display to user while client is attempting to connect to the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Guide</source>
|
||||
<translation>Guide Télé</translation>
|
||||
<extracomment>Menu option for showing Live TV Guide / Schedule</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Not found</source>
|
||||
<translation>Introuvable</translation>
|
||||
<extracomment>Title of message box when the requested content is not found on the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>The requested content does not exist on the server</source>
|
||||
<translation>Le contenu demandé n'existe pas sur le serveur</translation>
|
||||
<extracomment>Content of message box when the requested content is not found on the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enter the server name or IP address</source>
|
||||
<translation>Entrer le nom du serveur ou son adresse IP</translation>
|
||||
<extracomment>Title of KeyboardDialog when manually entering a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Go to season</source>
|
||||
<translation>Aller à la saison</translation>
|
||||
<extracomment>Continue Watching Popup Menu - Navigate to the Season Page</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options for TV Shows.</source>
|
||||
<translation>Options pour les Séries Télé.</translation>
|
||||
<extracomment>Description for TV Shows user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Blur Unwatched Episodes</source>
|
||||
<translation>Flouter les épisodes non visionnés</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>If enabled, images of unwatched episodes will be blurred.</source>
|
||||
<translation>Si activé, les images des épisodes non visionnés seront floutées.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Video Codec</source>
|
||||
<translation>Codec Vidéo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio Codec</source>
|
||||
<translation>Codec Audio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio Channels</source>
|
||||
<translation>Canaux Audio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Codec</source>
|
||||
<translation>Codec</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Codec Tag</source>
|
||||
<translation>Balise de Codec</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Container</source>
|
||||
<translation>Conteneur</translation>
|
||||
<extracomment>Video streaming container</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Size</source>
|
||||
<translation>Taille</translation>
|
||||
<extracomment>Video size</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Inconnu</translation>
|
||||
<extracomment>Title for a cast member for which we have no information for</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enabled</source>
|
||||
<translation>Activé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabled</source>
|
||||
<translation>Désactivé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playback</source>
|
||||
<translation>Lecture</translation>
|
||||
<extracomment>Title for Playback section in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>An error was encountered while playing this item. Server did not provide required transcoding data.</source>
|
||||
<translation>Une erreur a été rencontrée lors de la lecture de ce fichier. Le serveur n'a pas communiqué les données nécessaires pour le transcodage.</translation>
|
||||
<extracomment>Content of message box when trying to play an item which requires transcoding, and the server did not provide transcode url</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always show the titles below the poster images. (If disabled, the title will be shown under the highlighted item only).</source>
|
||||
<translation>Toujours afficher les titres sous les images des affiches. (Si désactivé, les titres s'afficherons uniquement sous les éléments en surbrillance).</translation>
|
||||
<extracomment>Description for option in Setting Screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show item count in the library and index of selected item.</source>
|
||||
<translation>Afficher le nombre d'éléments dans la bibliotèque et l'index de l'élément sélectionné.</translation>
|
||||
<extracomment>Description for option in Setting Screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use voice remote to search</source>
|
||||
<translation>Utiliser la télécomande vocale pour rechercher</translation>
|
||||
<extracomment>Help text in search voice text box</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>(Dialog will close automatically)</source>
|
||||
<translation>(La boîte de dialogue se fermera automatiquement)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use the replay button to slowly animate to the first item in the folder. (If disabled, the folder will reset to the first item immediately).</source>
|
||||
<translation>Utiliser la touche Replay pour lentement animer la sélection du première élément du dossier. (Si désactivé, le premier élément du dossier sera immédiatement sélectionné).</translation>
|
||||
<extracomment>Description for option in Setting Screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options for Details pages.</source>
|
||||
<translation>Options des Pages de Détails.</translation>
|
||||
<extracomment>Description for Details page user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options for TV Shows.</source>
|
||||
<translation>Options pour les Séries Télévisée.</translation>
|
||||
<extracomment>Description for TV Shows user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>View Channel</source>
|
||||
<translation>Voir la Chaîne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Splashscreen as Screensaver Background</source>
|
||||
<translation>Utiliser le Splash Screen comme fond d'écran de veille</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>WxH</source>
|
||||
<translation>LxH</translation>
|
||||
<extracomment>Video width x height</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use generated splashscreen image as Jellyfin's screensaver background. Jellyfin will need to be closed and reopened for change to take effect.</source>
|
||||
<translation>Utiliser le Splash Screen généré comme fond d'écran de veille de Jellyfin. Jellyfin devra être fermé et rouvert pour que le changement prenne effet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use generated splashscreen image as Jellyfin's home background. Jellyfin will need to be closed and reopened for change to take effect.</source>
|
||||
<translation>Utiliser le Splash Screen généré comme arrière plan principal de Jellyfin. Jellyfin devra être fermé et rouvert pour que le changement prenne effet.</translation>
|
||||
<extracomment>Description for option in Setting Screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hide Clock</source>
|
||||
<translation>Masquer l'Horloge</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hides all clocks in Jellyfin. Jellyfin will need to be closed and reopened for change to take effect.</source>
|
||||
<translation>Masquer toutes les horloges dans Jellyfin. Jellyfin devra être fermé et rouvert pour que le changement prenne effet.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Settings relating to how the application looks.</source>
|
||||
<translation>Réglages relatifs à l'apparence de l'application.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pixel format</source>
|
||||
<translation>Format des pixels</translation>
|
||||
<extracomment>Video pixel format</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to find any albums or songs belonging to this artist</source>
|
||||
<translation>Aucuns n'albums ni chansons ont été trouvés pour cet artiste</translation>
|
||||
<extracomment>Popup message when we find no audio data for an artist</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts</source>
|
||||
<translation>Débute</translation>
|
||||
<extracomment>(Future Tense) For defining a day and time when a program will start (e.g. Starts Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Record Series</source>
|
||||
<translation>Enregistrer la Série</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hide Taglines</source>
|
||||
<translation>Masquer les étiquettes</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Media Grid options.</source>
|
||||
<translation>Options de la Grille Média.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set Favorite</source>
|
||||
<translation>Mettre en Favori</translation>
|
||||
<extracomment>Button Text - When pressed, sets item as Favorite</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Details Page</source>
|
||||
<translation>Page de Détails</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options for Home Page.</source>
|
||||
<translation>Options pour la Page d'Accueil.</translation>
|
||||
<extracomment>Description for Home Page user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Max Days Next Up</source>
|
||||
<translation>Nombre Max de jours dans Suivant</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set the maximum amount of days a show should stay in the 'Next Up' list without watching it.</source>
|
||||
<translation>Définir le nombre maximum de jours une émission doit rester dans la liste "Suivant" sans la regarder.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playback Information</source>
|
||||
<translation>Informations de Lecture</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Design Elements</source>
|
||||
<translation>Élements de Désign</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Home Page</source>
|
||||
<translation>Page d'Accueil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Transcoding Information</source>
|
||||
<translation>Informations de Transcodage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Options that alter the design of Jellyfin.</source>
|
||||
<translation>Options qui modifient le design de Jellyfin.</translation>
|
||||
<extracomment>Description for Design Elements user settings.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Splashscreen as Home Background</source>
|
||||
<translation>Utiliser le Splash Screen comme arrière-plan principal</translation>
|
||||
<extracomment>Option Title in user setting screen</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Media Grid</source>
|
||||
<translation>Grille Média</translation>
|
||||
<extracomment>UI -> Media Grid section in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>MPEG-2 Support</source>
|
||||
<translation>Support MPEG-2</translation>
|
||||
<extracomment>Settings Menu - Title for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Series Recording</source>
|
||||
<translation>Annuler l'enregistrement de la Série</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>...or enter server URL manually:</source>
|
||||
<translation>Si aucun serveur n'est affiché ci-dessus vous pouvez également saisir l'adresse IP du serveur manuellement :</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to manually enter a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Support Direct Play of MPEG-2 content (e.g., Live TV). This will prevent transcoding of MPEG-2 content, but uses significantly more bandwidth.</source>
|
||||
<translation>Prise en charge de la lecture directe du codec MPEG-2 (ex., Live TV). Cela empêchera le transcodage du contenu MPEG-2 mais utilisera sensiblement plus de bande passante.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Item Titles</source>
|
||||
<translation>Titres des éléments</translation>
|
||||
<extracomment>UI -> Media Grid -> Item Title in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set Watched</source>
|
||||
<translation>Mettre en Visionné</translation>
|
||||
<extracomment>Button Text - When pressed, marks item as Warched</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>There was an error authenticating via Quick Connect.</source>
|
||||
<translation>Une erreur s'est produite lors de l'autentification via Quick Connect.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hides tagline text on details pages.</source>
|
||||
<translation>Masquer les étiquettes sur la page des détails.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Settings relating to playback and supported codec and media types.</source>
|
||||
<translation>Réglages relatifs à la lecture, aux codecs pris en charges et aux types de médias.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reason</source>
|
||||
<translation>Raison</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>direct</source>
|
||||
<translation>direct</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Total Bitrate</source>
|
||||
<translation>Débit Total</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stream Information</source>
|
||||
<translation>Informations du Flux</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Level</source>
|
||||
<translation>Niveau</translation>
|
||||
<extracomment>Video profile level</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Bit Rate</source>
|
||||
<translation>Débit</translation>
|
||||
<extracomment>Video streaming bit rate</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Video range type</source>
|
||||
<translation>Différents types de vidéo</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -7642,5 +7642,17 @@ elemeket</translation>
|
|||
<source>Save Credentials?</source>
|
||||
<translation>Mented a hitelesítő adatokat?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Saved</source>
|
||||
<translation>Mentettek Törlése</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Credentials?</source>
|
||||
<translation>Mented a hitelesítő adatokat?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On Now</source>
|
||||
<translation>Most</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -1718,5 +1718,208 @@
|
|||
<source>TAB_FILTER</source>
|
||||
<translation>Filtro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>An error was encountered while playing this item.</source>
|
||||
<translation>È stato riscontrato un errore durante la riproduzione di questo oggetto.</translation>
|
||||
<extracomment>Dialog detail when error occurs during playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cast & Crew</source>
|
||||
<translation>Cast & Crew</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Shows</source>
|
||||
<translation>Serie TV</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Wednesday</source>
|
||||
<translation>Mercoledi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Thursday</source>
|
||||
<translation>Giovedi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Started</source>
|
||||
<translation>Iniziato</translation>
|
||||
<extracomment>(Past Tense) For defining a day and time when a program started (e.g. Started Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts</source>
|
||||
<translation>Inizia</translation>
|
||||
<extracomment>(Future Tense) For defining a day and time when a program will start (e.g. Starts Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ends at</source>
|
||||
<translation>Termina alle</translation>
|
||||
<extracomment>(Past Tense) For defining a day and time when a program ended (e.g. Ended Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Guide</source>
|
||||
<translation>Guida TV</translation>
|
||||
<extracomment>Menu option for showing Live TV Guide / Schedule</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connecting to Server</source>
|
||||
<translation>In Connessione al Server</translation>
|
||||
<extracomment>Message to display to user while client is attempting to connect to the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>The requested content does not exist on the server</source>
|
||||
<translation>Il contenuto richiesto non esiste sul server</translation>
|
||||
<extracomment>Content of message box when the requested content is not found on the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enter the server name or IP address</source>
|
||||
<translation>Inserisci il nome o l'IP del server</translation>
|
||||
<extracomment>Title of KeyboardDialog when manually entering a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pick a Jellyfin server from the local network</source>
|
||||
<translation>Scegli un server Jellyfin dalla rete locale</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to pick a server from a list</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>...or enter server URL manually:</source>
|
||||
<translation>Se il server non è nella lista, puoi anche inserire l'URL:</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to manually enter a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error Getting Playback Information</source>
|
||||
<translation>Errore nel recupero delle informazioni di riproduzione</translation>
|
||||
<extracomment>Dialog Title: Received error from server when trying to get information about the selected item for playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Tuesday</source>
|
||||
<translation>Martedi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>today</source>
|
||||
<translation>oggi</translation>
|
||||
<extracomment>Current day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Close</source>
|
||||
<translation>Chiudi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Press 'OK' to Close</source>
|
||||
<translation>Premi "OK" per Chiudere</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Movies</source>
|
||||
<translation>Film</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>yesterday</source>
|
||||
<translation>ieri</translation>
|
||||
<extracomment>Previous day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>tomorrow</source>
|
||||
<translation>domani</translation>
|
||||
<extracomment>Next day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sunday</source>
|
||||
<translation>Domenica</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Monday</source>
|
||||
<translation>Lunedi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Friday</source>
|
||||
<translation>Venerdi</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Saturday</source>
|
||||
<translation>Sabato</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Started at</source>
|
||||
<translation>Iniziato il</translation>
|
||||
<extracomment>(Past Tense) For defining time when a program started today (e.g. Started at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts at</source>
|
||||
<translation>Inizia il</translation>
|
||||
<extracomment>(Future Tense) For defining time when a program will start today (e.g. Starts at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Recording</source>
|
||||
<translation>Interrompi Registrazione</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Series Recording</source>
|
||||
<translation>Interrompi Registrazione Seria</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Not found</source>
|
||||
<translation>Non trovato</translation>
|
||||
<extracomment>Title of message box when the requested content is not found on the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ended at</source>
|
||||
<translation>Terminato alle</translation>
|
||||
<extracomment>(Past Tense) For defining time when a program will ended (e.g. Ended at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Live</source>
|
||||
<translation>In diretta</translation>
|
||||
<extracomment>If TV Show is being broadcast live (not pre-recorded)</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Repeat</source>
|
||||
<translation>Replica</translation>
|
||||
<extracomment>If TV Shows has previously been broadcasted</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Channels</source>
|
||||
<translation>Canali</translation>
|
||||
<extracomment>Menu option for showing Live TV Channel List</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>View Channel</source>
|
||||
<translation>Visione del Canale</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Record</source>
|
||||
<translation>Registra</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Sconosciuto</translation>
|
||||
<extracomment>Title for a cast member for which we have no information for</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>OFFICIAL_RATING</source>
|
||||
<translation>Controllo Parentale</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pick a Jellyfin server from the local network</source>
|
||||
<translation>Scegli un server Jellyfin dalla rete locale:</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to pick a server from a list</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Credentials?</source>
|
||||
<translation>Salvare le credenziali?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Change Server</source>
|
||||
<translation>Cambia server</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error During Playback</source>
|
||||
<translation>Errore durante la riproduzione</translation>
|
||||
<extracomment>Dialog title when error occurs during playback</extracomment>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -2553,5 +2553,95 @@ não contém itens</translation>
|
|||
<source>Change Server</source>
|
||||
<translation>Alterar servidor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Change Server</source>
|
||||
<translation>Mudar Servidor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sign Out</source>
|
||||
<translation>Sair</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Credentials?</source>
|
||||
<translation>Salvar Credenciais?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Saved</source>
|
||||
<translation>Deletar Salvos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On Now</source>
|
||||
<translation>Passando Agora</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error Retrieving Content</source>
|
||||
<translation>Erro ao Carregar Conteúdo</translation>
|
||||
<extracomment>Dialog title when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error During Playback</source>
|
||||
<translation>Erro Durante Reprodução</translation>
|
||||
<extracomment>Dialog title when error occurs during playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>There was an error retrieving the data for this item from the server.</source>
|
||||
<translation>Houve um erro ao coletar dados do servidor para este item.</translation>
|
||||
<extracomment>Dialog detail when unable to load Content from Server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading Channel Data</source>
|
||||
<translation>Carregando dados do canal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Message displayed in Item Grid when no item to display. %1 is container type (e.g. Boxset, Collection, Folder, etc)</comment>
|
||||
<source>NO_ITEMS</source>
|
||||
<translation>Este %1 não possui itens</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Name or Title field of media item</comment>
|
||||
<source>TITLE</source>
|
||||
<translation>Nome</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DATE_PLAYED</source>
|
||||
<translation>Data de Reprodução</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>IMDB_RATING</source>
|
||||
<translation>Avaliação IMDb</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>RELEASE_DATE</source>
|
||||
<translation>Data de Lançamento</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>An error was encountered while playing this item.</source>
|
||||
<translation>Um erro foi encontrado enquanto reproduzindo este item.</translation>
|
||||
<extracomment>Dialog detail when error occurs during playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error loading Channel Data</source>
|
||||
<translation>Erro ao carregar os dados do canal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to load Channel Data from the server</source>
|
||||
<translation>Não foi possível carregar do servidor os dados do canal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CRITIC_RATING</source>
|
||||
<translation>Avaliação de críticos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DATE_ADDED</source>
|
||||
<translation>Data de Adição</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PLAY_COUNT</source>
|
||||
<translation>Número de Reproduções</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>OFFICIAL_RATING</source>
|
||||
<translation>Classificação Etária</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -671,5 +671,292 @@
|
|||
<source>Save Credentials?</source>
|
||||
<translation>Uložiť poverenia?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Credentials?</source>
|
||||
<translation>Uložiť prihlasovacie údaje?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Monday</source>
|
||||
<translation>Pondelok</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Started at</source>
|
||||
<translation>Začalo o</translation>
|
||||
<extracomment>(Past Tense) For defining time when a program started today (e.g. Started at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>View Channel</source>
|
||||
<translation>Zobraziť kanál</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Record Series</source>
|
||||
<translation>Séria nahrávok</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Series Recording</source>
|
||||
<translation>Zrušiť nahrávanie série</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connecting to Server</source>
|
||||
<translation>Pripája sa k serveru</translation>
|
||||
<extracomment>Message to display to user while client is attempting to connect to the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enter the server name or IP address</source>
|
||||
<translation>Zadajte názov servera alebo IP adresu</translation>
|
||||
<extracomment>Title of KeyboardDialog when manually entering a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error Getting Playback Information</source>
|
||||
<translation>Chyba pri získavaní informácií o prehrávaní</translation>
|
||||
<extracomment>Dialog Title: Received error from server when trying to get information about the selected item for playback</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>An error was encountered while playing this item. Server did not provide required transcoding data.</source>
|
||||
<translation>Pri prehrávaní tejto položky sa vyskytla chyba. Server neposkytol požadované údaje na prekódovanie.</translation>
|
||||
<extracomment>Content of message box when trying to play an item which requires transcoding, and the server did not provide transcode url</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Live</source>
|
||||
<translation>Naživo</translation>
|
||||
<extracomment>If TV Show is being broadcast live (not pre-recorded)</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Friday</source>
|
||||
<translation>Piatok</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Saved</source>
|
||||
<translation>Odstrániť uložené</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On Now</source>
|
||||
<translation>Teraz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DATE_PLAYED</source>
|
||||
<translation>Dátum hrania</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Guide</source>
|
||||
<translation>TV sprievodca</translation>
|
||||
<extracomment>Menu option for showing Live TV Guide / Schedule</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Born</source>
|
||||
<translation>Narodený</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cast & Crew</source>
|
||||
<translation>Herci & štáb</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>More Like This</source>
|
||||
<translation>Viac takých</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Movies</source>
|
||||
<translation>Filmy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Tuesday</source>
|
||||
<translation>Utorok</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts</source>
|
||||
<translation>Začína</translation>
|
||||
<extracomment>(Future Tense) For defining a day and time when a program will start (e.g. Starts Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ended at</source>
|
||||
<translation>Skončil o</translation>
|
||||
<extracomment>(Past Tense) For defining time when a program will ended (e.g. Ended at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>The requested content does not exist on the server</source>
|
||||
<translation>Požadovaný obsah na serveri neexistuje</translation>
|
||||
<extracomment>Content of message box when the requested content is not found on the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Name or Title field of media item</comment>
|
||||
<source>TITLE</source>
|
||||
<translation>Meno</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PLAY_COUNT</source>
|
||||
<translation>Počet prehrania</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Died</source>
|
||||
<translation>Zomrel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Age</source>
|
||||
<translation>Vek</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Special Features</source>
|
||||
<translation>Špeciálne vlastnosti</translation>
|
||||
<message>
|
||||
<source>Press 'OK' to Close</source>
|
||||
<translation>Press 'OK' to Close</translation>
|
||||
</message>
|
||||
</message>
|
||||
<message>
|
||||
<source>Press 'OK' to Close</source>
|
||||
<translation>Zatvorte stlačením tlačidla „OK“</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>tomorrow</source>
|
||||
<translation>zajtra</translation>
|
||||
<extracomment>Next day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sunday</source>
|
||||
<translation>Nedeľa</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Wednesday</source>
|
||||
<translation>Streda</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Saturday</source>
|
||||
<translation>Sobota</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Started</source>
|
||||
<translation>Začalo</translation>
|
||||
<extracomment>(Past Tense) For defining a day and time when a program started (e.g. Started Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts at</source>
|
||||
<translation>Začne</translation>
|
||||
<extracomment>(Future Tense) For defining time when a program will start today (e.g. Starts at 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ends at</source>
|
||||
<translation>Končí o</translation>
|
||||
<extracomment>(Past Tense) For defining a day and time when a program ended (e.g. Ended Wednesday, 08:00) </extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Not found</source>
|
||||
<translation>Nenájdené</translation>
|
||||
<extracomment>Title of message box when the requested content is not found on the server</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Title of Tab for options to sort library content</comment>
|
||||
<source>TAB_SORT</source>
|
||||
<translation>Triediť</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>RUNTIME</source>
|
||||
<translation>Beh programu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Version</source>
|
||||
<translation>Verzia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Message displayed in Item Grid when no item to display. %1 is container type (e.g. Boxset, Collection, Folder, etc)</comment>
|
||||
<source>NO_ITEMS</source>
|
||||
<translation>Tento %1 neobsahuje žiadne položky</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>IMDB_RATING</source>
|
||||
<translation>IMDB hodnotenie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DATE_ADDED</source>
|
||||
<translation>Dátum pridania</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>OFFICIAL_RATING</source>
|
||||
<translation>Rodičovské hodnotenie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>RELEASE_DATE</source>
|
||||
<translation>Dátum vydania</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Title of Tab for switching "views" when looking at a library</comment>
|
||||
<source>TAB_VIEW</source>
|
||||
<translation>Vyhliadka</translation>
|
||||
</message>
|
||||
<message>
|
||||
<comment>Title of Tab for options to filter library content</comment>
|
||||
<source>TAB_FILTER</source>
|
||||
<translation>Filter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TV Shows</source>
|
||||
<translation>TV relácie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>today</source>
|
||||
<translation>dnes</translation>
|
||||
<extracomment>Current day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>yesterday</source>
|
||||
<translation>včera</translation>
|
||||
<extracomment>Previous day</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Thursday</source>
|
||||
<translation>Štvrtok</translation>
|
||||
<extracomment>Day of Week</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Repeat</source>
|
||||
<translation>Opakujte</translation>
|
||||
<extracomment>If TV Shows has previously been broadcasted</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Channels</source>
|
||||
<translation>Kanály</translation>
|
||||
<extracomment>Menu option for showing Live TV Channel List</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Record</source>
|
||||
<translation>Záznam</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel Recording</source>
|
||||
<translation>Zrušiť nahrávanie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Close</source>
|
||||
<translation>Zavrieť</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pick a Jellyfin server from the local network</source>
|
||||
<translation>Vyberte dostupný server Jellyfin z vašej lokálnej siete:</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to pick a server from a list</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>...or enter server URL manually:</source>
|
||||
<translation>Ak vyššie nie je uvedený žiadny server, adresu URL servera môžete zadať aj ručne:</translation>
|
||||
<extracomment>Instructions on initial app launch when the user is asked to manually enter a server URL</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>CRITIC_RATING</source>
|
||||
<translation>Hodnotenie kritikov</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Neznámy</translation>
|
||||
<extracomment>Title for a cast member for which we have no information for</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playback</source>
|
||||
<translation>Prehrávanie</translation>
|
||||
<extracomment>Title for Playback section in user setting screen.</extracomment>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
4
manifest
4
manifest
|
@ -1,8 +1,8 @@
|
|||
## Channel Details
|
||||
title=Jellyfin
|
||||
major_version=1
|
||||
minor_version=5
|
||||
build_version=0
|
||||
minor_version=6
|
||||
build_version=2
|
||||
|
||||
### Main Menu Icons / Channel Poster Artwork
|
||||
mm_icon_focus_fhd=pkg:/images/channel-poster_fhd.png
|
||||
|
|
547
package-lock.json
generated
547
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "jellyfin-roku",
|
||||
"version": "1.4.12",
|
||||
"version": "1.6.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "jellyfin-roku",
|
||||
"version": "1.4.12",
|
||||
"version": "1.6.2",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-2.0",
|
||||
"dependencies": {
|
||||
|
@ -18,7 +18,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@rokucommunity/bslint": "0.7.5",
|
||||
"brighterscript": "0.57.2",
|
||||
"brighterscript": "0.61.0",
|
||||
"rooibos-cli": "1.4.0",
|
||||
"ropm": "0.10.10"
|
||||
}
|
||||
|
@ -829,9 +829,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/brighterscript": {
|
||||
"version": "0.57.2",
|
||||
"resolved": "https://registry.npmjs.org/brighterscript/-/brighterscript-0.57.2.tgz",
|
||||
"integrity": "sha512-idvz7lVLSN1mM/VoDt4/uJPFqdydSgCro2eIwT9vqV8z/1iNLpUtvXCWfeAbWxsbJkXWtmQq4GPkklCxc4OjrQ==",
|
||||
"version": "0.61.0",
|
||||
"resolved": "https://registry.npmjs.org/brighterscript/-/brighterscript-0.61.0.tgz",
|
||||
"integrity": "sha512-T7ndcFfzTBc3xq/tGgsCD91rEARMMDKsKXaw97cJ44bgEuu6Q8NaTM5KW7E81pMaCgPOMCl0k9k/npLejm4PNg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@rokucommunity/bslib": "^0.1.1",
|
||||
|
@ -855,7 +855,7 @@
|
|||
"p-settle": "^2.1.0",
|
||||
"parse-ms": "^2.1.0",
|
||||
"require-relative": "^0.8.7",
|
||||
"roku-deploy": "^3.8.1",
|
||||
"roku-deploy": "^3.9.2",
|
||||
"serialize-error": "^7.0.1",
|
||||
"source-map": "^0.7.3",
|
||||
"vscode-languageserver": "7.0.0",
|
||||
|
@ -1156,9 +1156,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/brighterscript/node_modules/anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
|
@ -2797,9 +2797,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
|
@ -4296,9 +4296,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
@ -5121,9 +5121,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/roku-deploy": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/roku-deploy/-/roku-deploy-3.8.1.tgz",
|
||||
"integrity": "sha512-b8Q2IvBdEka4XIBNLU9CumPDto8X5zCmWQwwFfBPkJqwDnJ4U47GqKCJp1dHdmAY9H/JRYIj2TmFE4cTOUiTNw==",
|
||||
"version": "3.9.2",
|
||||
"resolved": "https://registry.npmjs.org/roku-deploy/-/roku-deploy-3.9.2.tgz",
|
||||
"integrity": "sha512-2LZyR4EhaFrka1gVmcuJO/f42tqz4clGImboVLCNem1q/PcFV5cnXNZRfqDI+MZ/n8eJto71JlZkcc7TDLt/EQ==",
|
||||
"dependencies": {
|
||||
"chalk": "^2.4.2",
|
||||
"dateformat": "^3.0.3",
|
||||
|
@ -5133,9 +5133,9 @@
|
|||
"is-glob": "^4.0.3",
|
||||
"jsonc-parser": "^2.3.0",
|
||||
"jszip": "^3.6.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"moment": "^2.29.1",
|
||||
"parse-ms": "^2.1.0",
|
||||
"picomatch": "^2.2.1",
|
||||
"request": "^2.88.0",
|
||||
"temp-dir": "^2.0.0",
|
||||
"xml2js": "^0.4.23"
|
||||
|
@ -5269,6 +5269,139 @@
|
|||
"chevrotain": "7.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/brighterscript": {
|
||||
"version": "0.57.2",
|
||||
"resolved": "https://registry.npmjs.org/brighterscript/-/brighterscript-0.57.2.tgz",
|
||||
"integrity": "sha512-idvz7lVLSN1mM/VoDt4/uJPFqdydSgCro2eIwT9vqV8z/1iNLpUtvXCWfeAbWxsbJkXWtmQq4GPkklCxc4OjrQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@rokucommunity/bslib": "^0.1.1",
|
||||
"@xml-tools/parser": "^1.0.7",
|
||||
"array-flat-polyfill": "^1.0.1",
|
||||
"chalk": "^2.4.2",
|
||||
"chevrotain": "^7.0.1",
|
||||
"chokidar": "^3.5.1",
|
||||
"clear": "^0.1.0",
|
||||
"cross-platform-clear-console": "^2.3.0",
|
||||
"debounce-promise": "^3.1.0",
|
||||
"eventemitter3": "^4.0.0",
|
||||
"fast-glob": "^3.2.11",
|
||||
"file-url": "^3.0.0",
|
||||
"fs-extra": "^8.0.0",
|
||||
"jsonc-parser": "^2.3.0",
|
||||
"long": "^3.2.0",
|
||||
"luxon": "^1.8.3",
|
||||
"minimatch": "^3.0.4",
|
||||
"moment": "^2.23.0",
|
||||
"p-settle": "^2.1.0",
|
||||
"parse-ms": "^2.1.0",
|
||||
"require-relative": "^0.8.7",
|
||||
"roku-deploy": "^3.8.1",
|
||||
"serialize-error": "^7.0.1",
|
||||
"source-map": "^0.7.3",
|
||||
"vscode-languageserver": "7.0.0",
|
||||
"vscode-languageserver-protocol": "3.16.0",
|
||||
"vscode-languageserver-textdocument": "^1.0.1",
|
||||
"vscode-uri": "^2.1.1",
|
||||
"xml2js": "^0.4.19",
|
||||
"yargs": "^16.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"bsc": "dist/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/brighterscript/node_modules/fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6 <7 || >=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/brighterscript/node_modules/jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||
"dev": true,
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/brighterscript/node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/chevrotain": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz",
|
||||
|
@ -5278,6 +5411,45 @@
|
|||
"regexp-to-ast": "0.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
|
@ -5293,6 +5465,60 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/jsonfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
|
@ -5305,6 +5531,48 @@
|
|||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ropm/node_modules/universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
|
@ -6966,9 +7234,9 @@
|
|||
}
|
||||
},
|
||||
"brighterscript": {
|
||||
"version": "0.57.2",
|
||||
"resolved": "https://registry.npmjs.org/brighterscript/-/brighterscript-0.57.2.tgz",
|
||||
"integrity": "sha512-idvz7lVLSN1mM/VoDt4/uJPFqdydSgCro2eIwT9vqV8z/1iNLpUtvXCWfeAbWxsbJkXWtmQq4GPkklCxc4OjrQ==",
|
||||
"version": "0.61.0",
|
||||
"resolved": "https://registry.npmjs.org/brighterscript/-/brighterscript-0.61.0.tgz",
|
||||
"integrity": "sha512-T7ndcFfzTBc3xq/tGgsCD91rEARMMDKsKXaw97cJ44bgEuu6Q8NaTM5KW7E81pMaCgPOMCl0k9k/npLejm4PNg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@rokucommunity/bslib": "^0.1.1",
|
||||
|
@ -6992,7 +7260,7 @@
|
|||
"p-settle": "^2.1.0",
|
||||
"parse-ms": "^2.1.0",
|
||||
"require-relative": "^0.8.7",
|
||||
"roku-deploy": "^3.8.1",
|
||||
"roku-deploy": "^3.9.2",
|
||||
"serialize-error": "^7.0.1",
|
||||
"source-map": "^0.7.3",
|
||||
"vscode-languageserver": "7.0.0",
|
||||
|
@ -7013,9 +7281,9 @@
|
|||
}
|
||||
},
|
||||
"anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
|
@ -8537,9 +8805,9 @@
|
|||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||
},
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
|
||||
"dev": true
|
||||
},
|
||||
"define-property": {
|
||||
|
@ -9715,9 +9983,9 @@
|
|||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
@ -10335,9 +10603,9 @@
|
|||
}
|
||||
},
|
||||
"roku-deploy": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/roku-deploy/-/roku-deploy-3.8.1.tgz",
|
||||
"integrity": "sha512-b8Q2IvBdEka4XIBNLU9CumPDto8X5zCmWQwwFfBPkJqwDnJ4U47GqKCJp1dHdmAY9H/JRYIj2TmFE4cTOUiTNw==",
|
||||
"version": "3.9.2",
|
||||
"resolved": "https://registry.npmjs.org/roku-deploy/-/roku-deploy-3.9.2.tgz",
|
||||
"integrity": "sha512-2LZyR4EhaFrka1gVmcuJO/f42tqz4clGImboVLCNem1q/PcFV5cnXNZRfqDI+MZ/n8eJto71JlZkcc7TDLt/EQ==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"dateformat": "^3.0.3",
|
||||
|
@ -10347,9 +10615,9 @@
|
|||
"is-glob": "^4.0.3",
|
||||
"jsonc-parser": "^2.3.0",
|
||||
"jszip": "^3.6.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"moment": "^2.29.1",
|
||||
"parse-ms": "^2.1.0",
|
||||
"picomatch": "^2.2.1",
|
||||
"request": "^2.88.0",
|
||||
"temp-dir": "^2.0.0",
|
||||
"xml2js": "^0.4.23"
|
||||
|
@ -10455,6 +10723,117 @@
|
|||
"chevrotain": "7.1.1"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true
|
||||
},
|
||||
"braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"brighterscript": {
|
||||
"version": "0.57.2",
|
||||
"resolved": "https://registry.npmjs.org/brighterscript/-/brighterscript-0.57.2.tgz",
|
||||
"integrity": "sha512-idvz7lVLSN1mM/VoDt4/uJPFqdydSgCro2eIwT9vqV8z/1iNLpUtvXCWfeAbWxsbJkXWtmQq4GPkklCxc4OjrQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@rokucommunity/bslib": "^0.1.1",
|
||||
"@xml-tools/parser": "^1.0.7",
|
||||
"array-flat-polyfill": "^1.0.1",
|
||||
"chalk": "^2.4.2",
|
||||
"chevrotain": "^7.0.1",
|
||||
"chokidar": "^3.5.1",
|
||||
"clear": "^0.1.0",
|
||||
"cross-platform-clear-console": "^2.3.0",
|
||||
"debounce-promise": "^3.1.0",
|
||||
"eventemitter3": "^4.0.0",
|
||||
"fast-glob": "^3.2.11",
|
||||
"file-url": "^3.0.0",
|
||||
"fs-extra": "^8.0.0",
|
||||
"jsonc-parser": "^2.3.0",
|
||||
"long": "^3.2.0",
|
||||
"luxon": "^1.8.3",
|
||||
"minimatch": "^3.0.4",
|
||||
"moment": "^2.23.0",
|
||||
"p-settle": "^2.1.0",
|
||||
"parse-ms": "^2.1.0",
|
||||
"require-relative": "^0.8.7",
|
||||
"roku-deploy": "^3.8.1",
|
||||
"serialize-error": "^7.0.1",
|
||||
"source-map": "^0.7.3",
|
||||
"vscode-languageserver": "7.0.0",
|
||||
"vscode-languageserver-protocol": "3.16.0",
|
||||
"vscode-languageserver-textdocument": "^1.0.1",
|
||||
"vscode-uri": "^2.1.1",
|
||||
"xml2js": "^0.4.19",
|
||||
"yargs": "^16.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"chevrotain": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz",
|
||||
|
@ -10464,6 +10843,31 @@
|
|||
"regexp-to-ast": "0.5.0"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
|
@ -10476,6 +10880,45 @@
|
|||
"universalify": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
|
@ -10486,6 +10929,36 @@
|
|||
"universalify": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "jellyfin-roku",
|
||||
"version": "1.4.12",
|
||||
"version": "1.6.2",
|
||||
"description": "Roku app for Jellyfin media server",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
|
@ -8,7 +8,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@rokucommunity/bslint": "0.7.5",
|
||||
"brighterscript": "0.57.2",
|
||||
"brighterscript": "0.61.0",
|
||||
"rooibos-cli": "1.4.0",
|
||||
"ropm": "0.10.10"
|
||||
},
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
"title": "Playback",
|
||||
"description": "Settings relating to playback and supported codec and media types.",
|
||||
"children": [
|
||||
{
|
||||
"title": "AV1 Support",
|
||||
"description": "** EXPERIMENTAL** Support Direct Play of AV1 content if this Roku device supports it.",
|
||||
"settingName": "playback.av1",
|
||||
"type": "bool",
|
||||
"default": "false"
|
||||
},
|
||||
{
|
||||
"title": "MPEG-2 Support",
|
||||
"description": "Support Direct Play of MPEG-2 content (e.g., Live TV). This will prevent transcoding of MPEG-2 content, but uses significantly more bandwidth.",
|
||||
|
@ -11,12 +18,26 @@
|
|||
"default": "false"
|
||||
},
|
||||
{
|
||||
"title": "Attempt Direct Play (Profile Lvl)",
|
||||
"description": "Attempt Direct Play for H.264 media with unsupported profile levels (> 4.2) before falling back to transcoding if it fails.",
|
||||
"title": "MPEG-4 Support",
|
||||
"description": "Support Direct Play of MPEG-4 content. This may need to be disabled for playback of DIVX encoded video files.",
|
||||
"settingName": "playback.mpeg4",
|
||||
"type": "bool",
|
||||
"default": "true"
|
||||
},
|
||||
{
|
||||
"title": "Direct Play H.264 Unsupported Profile Levels",
|
||||
"description": "Attempt Direct Play for H.264 media with unsupported profile levels before falling back to transcoding if it fails.",
|
||||
"settingName": "playback.tryDirect.h264ProfileLevel",
|
||||
"type": "bool",
|
||||
"default": "true"
|
||||
},
|
||||
{
|
||||
"title": "Direct Play HEVC Unsupported Profile Levels",
|
||||
"description": "Attempt Direct Play for HEVC media with unsupported profile levels before falling back to trancoding if it fails.",
|
||||
"settingName": "playback.tryDirect.hevcProfileLevel",
|
||||
"type": "bool",
|
||||
"default": "true"
|
||||
},
|
||||
{
|
||||
"title": "Cinema Mode",
|
||||
"description": "Cinema Mode brings the theater experience straight to your living room with the ability to play custom intros before the main feature.",
|
||||
|
|
|
@ -13,13 +13,6 @@ sub Main (args as dynamic) as void
|
|||
WriteAsciiFile("tmp:/scene.temp", "")
|
||||
MoveFile("tmp:/scene.temp", "tmp:/scene")
|
||||
|
||||
' Temporary code to migrate MPEG2 setting from device setting to user setting
|
||||
' Added for 1.4.13 release and should probably be removed for 1.4.15
|
||||
if get_setting("playback.mpeg2") <> invalid and registry_read("playback.mpeg2", get_setting("active_user")) = invalid
|
||||
set_user_setting("playback.mpeg2", get_setting("playback.mpeg2"))
|
||||
end if
|
||||
' End Temporary code
|
||||
|
||||
m.port = CreateObject("roMessagePort")
|
||||
m.screen.setMessagePort(m.port)
|
||||
m.scene = m.screen.CreateScene("JFScene")
|
||||
|
@ -110,8 +103,20 @@ sub Main (args as dynamic) as void
|
|||
else if isNodeEvent(msg, "selectedItem")
|
||||
' If you select a library from ANYWHERE, follow this flow
|
||||
selectedItem = msg.getData()
|
||||
|
||||
m.selectedItemType = selectedItem.type
|
||||
if selectedItem.type = "CollectionFolder" or selectedItem.type = "UserView" or selectedItem.type = "Folder" or selectedItem.type = "Channel" or selectedItem.type = "Boxset"
|
||||
'
|
||||
if selectedItem.type = "CollectionFolder"
|
||||
if selectedItem.collectionType = "movies"
|
||||
group = CreateMovieLibraryView(selectedItem)
|
||||
else
|
||||
group = CreateItemGrid(selectedItem)
|
||||
end if
|
||||
sceneManager.callFunc("pushScene", group)
|
||||
else if selectedItem.type = "Folder" and selectedItem.json.type = "Genre"
|
||||
group = CreateMovieLibraryView(selectedItem)
|
||||
sceneManager.callFunc("pushScene", group)
|
||||
else if selectedItem.type = "UserView" or selectedItem.type = "Folder" or selectedItem.type = "Channel" or selectedItem.type = "Boxset"
|
||||
group = CreateItemGrid(selectedItem)
|
||||
sceneManager.callFunc("pushScene", group)
|
||||
else if selectedItem.type = "Episode"
|
||||
|
@ -128,6 +133,8 @@ sub Main (args as dynamic) as void
|
|||
end if
|
||||
else if selectedItem.type = "Series"
|
||||
group = CreateSeriesDetailsGroup(selectedItem.json)
|
||||
else if selectedItem.type = "Season"
|
||||
group = CreateSeasonDetailsGroupByID(selectedItem.json.SeriesId, selectedItem.id)
|
||||
else if selectedItem.type = "Movie"
|
||||
' open movie detail page
|
||||
group = CreateMovieDetailsGroup(selectedItem)
|
||||
|
@ -332,7 +339,7 @@ sub Main (args as dynamic) as void
|
|||
|
||||
video_id = trailerData[0].id
|
||||
|
||||
video = CreateVideoPlayerGroup(video_id, mediaSourceId, audio_stream_idx)
|
||||
video = CreateVideoPlayerGroup(video_id, mediaSourceId, audio_stream_idx, false, false)
|
||||
if video <> invalid and video.errorMsg <> "introaborted"
|
||||
sceneManager.callFunc("pushScene", video)
|
||||
end if
|
||||
|
@ -420,7 +427,7 @@ sub Main (args as dynamic) as void
|
|||
if m.selectedItemType = "TvChannel" and node.state = "finished"
|
||||
video = CreateVideoPlayerGroup(node.id)
|
||||
m.global.sceneManager.callFunc("pushScene", video)
|
||||
m.global.sceneManager.callFunc("clearPreviousScene")
|
||||
m.global.sceneManager.callFunc("deleteSceneAtIndex", 2)
|
||||
else if node.state = "finished"
|
||||
node.control = "stop"
|
||||
|
||||
|
@ -437,12 +444,6 @@ sub Main (args as dynamic) as void
|
|||
autoPlayNextEpisode(node.id, node.showID)
|
||||
end if
|
||||
end if
|
||||
'else if isNodeEvent(msg, "selectedExtra")
|
||||
'rl = msg.getData()
|
||||
'sel = rl.rowItemSelected
|
||||
'? "msg.getfield():" + msg.getField()
|
||||
'stop
|
||||
'CreatePersonView(msg.getData())
|
||||
else if type(msg) = "roDeviceInfoEvent"
|
||||
event = msg.GetInfo()
|
||||
group = sceneManager.callFunc("getActiveScene")
|
||||
|
|
|
@ -453,6 +453,20 @@ function CreateSeasonDetailsGroup(series, season)
|
|||
return group
|
||||
end function
|
||||
|
||||
function CreateSeasonDetailsGroupByID(seriesID, seasonID)
|
||||
group = CreateObject("roSGNode", "TVEpisodes")
|
||||
group.optionsAvailable = false
|
||||
m.global.sceneManager.callFunc("pushScene", group)
|
||||
|
||||
group.seasonData = ItemMetaData(seasonID).json
|
||||
group.objects = TVEpisodes(seriesID, seasonID)
|
||||
|
||||
group.observeField("episodeSelected", m.port)
|
||||
group.observeField("quickPlayNode", m.port)
|
||||
|
||||
return group
|
||||
end function
|
||||
|
||||
function CreateItemGrid(libraryItem)
|
||||
group = CreateObject("roSGNode", "ItemGrid")
|
||||
group.parentItem = libraryItem
|
||||
|
@ -461,6 +475,14 @@ function CreateItemGrid(libraryItem)
|
|||
return group
|
||||
end function
|
||||
|
||||
function CreateMovieLibraryView(libraryItem)
|
||||
group = CreateObject("roSGNode", "MovieLibraryView")
|
||||
group.parentItem = libraryItem
|
||||
group.optionsAvailable = true
|
||||
group.observeField("selectedItem", m.port)
|
||||
return group
|
||||
end function
|
||||
|
||||
function CreateSearchPage()
|
||||
' Search + Results Page
|
||||
group = CreateObject("roSGNode", "searchResults")
|
||||
|
@ -570,17 +592,6 @@ function CreatePersonView(personData as object) as object
|
|||
return person
|
||||
end function
|
||||
|
||||
function CreatePhotoPage(photo)
|
||||
group = CreateObject("roSGNode", "PhotoDetails")
|
||||
group.optionsAvailable = true
|
||||
m.global.sceneManager.callFunc("pushScene", group)
|
||||
|
||||
group.itemContent = photo
|
||||
|
||||
return group
|
||||
|
||||
end function
|
||||
|
||||
sub UpdateSavedServerList()
|
||||
server = get_setting("server")
|
||||
username = get_setting("username")
|
||||
|
|
|
@ -45,6 +45,11 @@ sub AddVideoContent(video, mediaSourceId, audio_stream_idx = 1, subtitle_idx = -
|
|||
end if
|
||||
end if
|
||||
|
||||
if m.videotype = "Episode" or m.videotype = "Series"
|
||||
video.runTime = (meta.json.RunTimeTicks / 10000000.0)
|
||||
video.content.contenttype = "episode"
|
||||
end if
|
||||
|
||||
video.content.title = meta.title
|
||||
video.showID = meta.showID
|
||||
|
||||
|
@ -213,18 +218,22 @@ sub AddVideoContent(video, mediaSourceId, audio_stream_idx = 1, subtitle_idx = -
|
|||
fully_external = false
|
||||
|
||||
|
||||
' For h264 video, Roku spec states that it supports and Encoding level 4.1 and 4.2.
|
||||
' 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
|
||||
' artifacts. If the user preference is set, and the only reason the server says we need to
|
||||
' transcode is that the Envoding 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.
|
||||
if meta.live = false and get_user_setting("playback.tryDirect.h264ProfileLevel") = "true" and m.playbackInfo.MediaSources[0].TranscodingUrl <> invalid and forceTranscoding = false and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = "h264"
|
||||
if m.playbackInfo.MediaSources[0].MediaStreams.Count() > 0 and meta.live = false
|
||||
tryDirectPlay = get_user_setting("playback.tryDirect.h264ProfileLevel") = "true" and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = "h264"
|
||||
tryDirectPlay = tryDirectPlay or (get_user_setting("playback.tryDirect.hevcProfileLevel") = "true" and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = "hevc")
|
||||
if tryDirectPlay and m.playbackInfo.MediaSources[0].TranscodingUrl <> invalid and forceTranscoding = false
|
||||
transcodingReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl)
|
||||
if transcodingReasons.Count() = 1 and transcodingReasons[0] = "VideoLevelNotSupported"
|
||||
video.directPlaySupported = true
|
||||
video.transcodeAvailable = true
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
if video.directPlaySupported
|
||||
protocol = LCase(m.playbackInfo.MediaSources[0].Protocol)
|
||||
|
@ -420,7 +429,7 @@ sub autoPlayNextEpisode(videoID as string, showID as string)
|
|||
if data <> invalid and data.Items.Count() = 2
|
||||
' setup new video node
|
||||
nextVideo = CreateVideoPlayerGroup(data.Items[1].Id, invalid, 1, false, false)
|
||||
' remove last video scene
|
||||
' remove last videoplayer scene
|
||||
m.global.sceneManager.callFunc("clearPreviousScene")
|
||||
if nextVideo <> invalid
|
||||
m.global.sceneManager.callFunc("pushScene", nextVideo)
|
||||
|
|
|
@ -329,26 +329,32 @@ function AudioStream(id as string)
|
|||
songData = AudioItem(id)
|
||||
|
||||
content = createObject("RoSGNode", "ContentNode")
|
||||
|
||||
params = {}
|
||||
|
||||
params.append({
|
||||
"Static": "true",
|
||||
"Container": songData.mediaSources[0].container
|
||||
})
|
||||
|
||||
params.MediaSourceId = songData.mediaSources[0].id
|
||||
|
||||
content.url = buildURL(Substitute("Audio/{0}/stream", songData.id), params)
|
||||
content.title = songData.title
|
||||
content.streamformat = songData.mediaSources[0].container
|
||||
|
||||
playbackInfo = ItemPostPlaybackInfo(songData.id, params.MediaSourceId)
|
||||
playbackInfo = ItemPostPlaybackInfo(songData.id, songData.mediaSources[0].id)
|
||||
content.id = playbackInfo.PlaySessionId
|
||||
|
||||
if useTranscodeAudioStream(playbackInfo)
|
||||
' Transcode the audio
|
||||
content.url = buildURL(playbackInfo.mediaSources[0].TranscodingURL)
|
||||
else
|
||||
' Direct Stream the audio
|
||||
params = {
|
||||
"Static": "true",
|
||||
"Container": songData.mediaSources[0].container,
|
||||
"MediaSourceId": songData.mediaSources[0].id
|
||||
}
|
||||
content.streamformat = songData.mediaSources[0].container
|
||||
content.url = buildURL(Substitute("Audio/{0}/stream", songData.id), params)
|
||||
end if
|
||||
|
||||
return content
|
||||
end function
|
||||
|
||||
function useTranscodeAudioStream(playbackInfo)
|
||||
return playbackInfo.mediaSources[0] <> invalid and playbackInfo.mediaSources[0].TranscodingURL <> invalid
|
||||
end function
|
||||
|
||||
function BackdropImage(id as string)
|
||||
imgParams = { "maxHeight": "720", "maxWidth": "1280" }
|
||||
return ImageURL(id, "Backdrop", imgParams)
|
||||
|
|
|
@ -18,6 +18,7 @@ end function
|
|||
|
||||
function getDeviceProfile() as object
|
||||
playMpeg2 = get_user_setting("playback.mpeg2") = "true"
|
||||
playAv1 = get_user_setting("playback.av1") = "true"
|
||||
|
||||
'Check if 5.1 Audio Output connected
|
||||
maxAudioChannels = 2
|
||||
|
@ -26,14 +27,19 @@ function getDeviceProfile() as object
|
|||
maxAudioChannels = 6
|
||||
end if
|
||||
|
||||
if playMpeg2 and di.CanDecodeVideo({ Codec: "mpeg2" }).Result = true
|
||||
tsVideoCodecs = "h264,mpeg2video"
|
||||
else
|
||||
addHevcProfile = false
|
||||
MAIN10 = ""
|
||||
tsVideoCodecs = "h264"
|
||||
if di.CanDecodeVideo({ Codec: "hevc" }).Result = true
|
||||
tsVideoCodecs = "h265,hevc," + tsVideoCodecs
|
||||
addHevcProfile = true
|
||||
if di.CanDecodeVideo({ Codec: "hevc", Profile: "main 10" }).Result
|
||||
MAIN10 = "|main 10"
|
||||
end if
|
||||
end if
|
||||
|
||||
if di.CanDecodeVideo({ Codec: "hevc" }).Result = true
|
||||
tsVideoCodecs = tsVideoCodecs + ",h265,hevc"
|
||||
if playMpeg2 and di.CanDecodeVideo({ Codec: "mpeg2" }).Result = true
|
||||
tsVideoCodecs = tsVideoCodecs + ",mpeg2video"
|
||||
end if
|
||||
|
||||
if di.CanDecodeAudio({ Codec: "ac3" }).result
|
||||
|
@ -42,9 +48,42 @@ function getDeviceProfile() as object
|
|||
tsAudioCodecs = "aac"
|
||||
end if
|
||||
|
||||
addAv1Profile = false
|
||||
if playAv1 and di.CanDecodeVideo({ Codec: "av1" }).result
|
||||
tsVideoCodecs = tsVideoCodecs + ",av1"
|
||||
addAv1Profile = true
|
||||
end if
|
||||
|
||||
addVp9Profile = false
|
||||
if di.CanDecodeVideo({ Codec: "vp9" }).result
|
||||
tsVideoCodecs = tsVideoCodecs + ",vp9"
|
||||
addVp9Profile = true
|
||||
end if
|
||||
|
||||
hevcVideoRangeTypes = "SDR"
|
||||
vp9VideoRangeTypes = "SDR"
|
||||
av1VideoRangeTypes = "SDR"
|
||||
|
||||
dp = di.GetDisplayProperties()
|
||||
if dp.Hdr10 ' or dp.Hdr10Plus?
|
||||
hevcVideoRangeTypes = hevcVideoRangeTypes + "|HDR10"
|
||||
vp9VideoRangeTypes = vp9VideoRangeTypes + "|HDR10"
|
||||
av1VideoRangeTypes = av1VideoRangeTypes + "|HDR10"
|
||||
end if
|
||||
if dp.HLG
|
||||
hevcVideoRangeTypes = hevcVideoRangeTypes + "|HLG"
|
||||
vp9VideoRangeTypes = vp9VideoRangeTypes + "|HLG"
|
||||
av1VideoRangeTypes = av1VideoRangeTypes + "|HLG"
|
||||
end if
|
||||
if dp.DolbyVision
|
||||
hevcVideoRangeTypes = hevcVideoRangeTypes + "|DOVI"
|
||||
'vp9VideoRangeTypes = vp9VideoRangeTypes + ",DOVI" no evidence that vp9 can hold DOVI
|
||||
av1VideoRangeTypes = av1VideoRangeTypes + "|DOVI"
|
||||
end if
|
||||
|
||||
DirectPlayProfile = GetDirectPlayProfiles()
|
||||
|
||||
return {
|
||||
deviceProfile = {
|
||||
"MaxStreamingBitrate": 120000000,
|
||||
"MaxStaticBitrate": 100000000,
|
||||
"MusicStreamingTranscodingBitrate": 192000,
|
||||
|
@ -133,24 +172,6 @@ function getDeviceProfile() as object
|
|||
"IsRequired": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "Video",
|
||||
"Codec": "hevc",
|
||||
"Conditions": [
|
||||
{
|
||||
"Condition": "EqualsAny",
|
||||
"Property": "VideoProfile",
|
||||
"Value": "main",
|
||||
"IsRequired": false
|
||||
},
|
||||
{
|
||||
"Condition": "LessThanEqual",
|
||||
"Property": "VideoLevel",
|
||||
"Value": StrI(120 * 5.1),
|
||||
"IsRequired": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SubtitleProfiles": [
|
||||
|
@ -172,12 +193,68 @@ function getDeviceProfile() as object
|
|||
}
|
||||
]
|
||||
}
|
||||
if addAv1Profile
|
||||
deviceProfile.CodecProfiles.push({
|
||||
"Type": "Video",
|
||||
"Codec": "av1",
|
||||
"Conditions": [
|
||||
{
|
||||
"Condition": "EqualsAny",
|
||||
"Property": "VideoRangeType",
|
||||
"Value": av1VideoRangeTypes,
|
||||
"IsRequired": false
|
||||
}
|
||||
]
|
||||
})
|
||||
end if
|
||||
if addHevcProfile
|
||||
deviceProfile.CodecProfiles.push({
|
||||
"Type": "Video",
|
||||
"Codec": "hevc",
|
||||
"Conditions": [
|
||||
{
|
||||
"Condition": "EqualsAny",
|
||||
"Property": "VideoProfile",
|
||||
"Value": "main" + MAIN10,
|
||||
"IsRequired": false
|
||||
},
|
||||
{
|
||||
"Condition": "EqualsAny",
|
||||
"Property": "VideoRangeType",
|
||||
"Value": hevcVideoRangeTypes,
|
||||
"IsRequired": false
|
||||
},
|
||||
{
|
||||
"Condition": "LessThanEqual",
|
||||
"Property": "VideoLevel",
|
||||
"Value": (120 * 5.1).ToStr(),
|
||||
"IsRequired": false
|
||||
}
|
||||
]
|
||||
})
|
||||
end if
|
||||
if addVp9Profile
|
||||
deviceProfile.CodecProfiles.push({
|
||||
"Type": "Video",
|
||||
"Codec": "vp9",
|
||||
"Conditions": [
|
||||
{
|
||||
"Condition": "EqualsAny",
|
||||
"Property": "VideoRangeType",
|
||||
"Value": vp9VideoRangeTypes,
|
||||
"IsRequired": false
|
||||
}
|
||||
]
|
||||
})
|
||||
end if
|
||||
|
||||
return deviceProfile
|
||||
end function
|
||||
|
||||
|
||||
function GetDirectPlayProfiles() as object
|
||||
|
||||
mp4Video = "h264,mpeg4"
|
||||
mp4Video = "h264"
|
||||
mp4Audio = "mp3,pcm,lpcm,wav"
|
||||
mkvVideo = "h264,vp8"
|
||||
mkvAudio = "mp3,pcm,lpcm,wav"
|
||||
|
@ -202,6 +279,10 @@ function GetDirectPlayProfiles() as object
|
|||
mkvVideo = mkvVideo + ",mpeg2video"
|
||||
end if
|
||||
|
||||
if get_user_setting("playback.mpeg4") = "true"
|
||||
mp4Video = mp4Video + ",mpeg4"
|
||||
end if
|
||||
|
||||
' Check for supported Audio
|
||||
if di.CanDecodeAudio({ Codec: "ac3" }).result
|
||||
mkvAudio = mkvAudio + ",ac3"
|
||||
|
|
Loading…
Reference in New Issue
Block a user