HMS

Home Media Server for Roku Players
git clone https://www.brianlane.com/git/HMS
Log | Files | Refs | README | LICENSE

commit 6b2b6eea9a671689cfe19d50028c54de9787ef4c
parent 63142b2a425a52524f5404e81918641dcee82ce0
Author: Brian C. Lane <bcl@ibrianlane.com>
Date:   Mon, 27 May 2013 18:34:56 -0700

Change main function to mediaServer

Diffstat:
DHMS/source/appDisplayDirectory.brs | 334-------------------------------------------------------------------------------
MHMS/source/appMain.brs | 20+-------------------
AHMS/source/appMediaServer.brs | 334+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 335 insertions(+), 353 deletions(-)

diff --git a/HMS/source/appDisplayDirectory.brs b/HMS/source/appDisplayDirectory.brs @@ -1,334 +0,0 @@ -'******************************************************************** -'** Home Media Server Application - Main -'** Copyright (c) 2010-2013 Brian C. Lane All Rights Reserved. -'******************************************************************** - -'****************************************************** -'** Display a scrolling grid of everything on the server -'****************************************************** -Function displayDirectory( url As String ) As Object - print "url: ";url - - port=CreateObject("roMessagePort") - grid = CreateObject("roGridScreen") - grid.SetMessagePort(port) - grid.SetDisplayMode("scale-to-fit") - - ' Build list of Category Names from the top level directories - listing = getDirectoryListing(url) - if listing = invalid then - print "Failed to get directory listing for ";url - return invalid - end if - categories = displayFiles(listing, {}, true) - Sort(categories, function(k) - return LCase(k[0]) - end function) - - ' Setup Grid with categories - titles = CreateObject("roArray", categories.Count(), false) - titles.Push("Search") - for i = 0 to categories.Count()-1 - print "Category: :";categories[i][0] - titles.Push(getLastElement(categories[i][0])) - end for - grid.SetupLists(titles.Count()) - grid.SetListNames(titles) - - ' Hold all the movie objects - screen = CreateObject("roArray", categories.Count(), false) - - ' Add as utility row - grid.SetContentList(0, getUtilRow(url)) - screen.Push(search) - - ' run the grid - showTimeBreadcrumb(grid, true) - grid.SetFocusedListitem(0, 1) - grid.Show() - - loadingDialog = ShowPleaseWait("Loading Movies...", "") - total = 0 - ' Setup each category's list - for i = 0 to categories.Count()-1 - cat_url = url + "/" + categories[i][0] - listing = getDirectoryListing(cat_url) - listing_hash = CreateObject("roAssociativeArray") - for each f in listing - listing_hash.AddReplace(f, "") - end for - - ' What kind of directory is this? - dirType = directoryType(listing_hash) - if dirType = 1 then - displayList = displayFiles(listing, { jpg : true }) - else if dirType = 2 then - displayList = displayFiles(listing, { mp3 : true }) - else if dirType = 3 then - displayList = displayFiles(listing, { mp4 : true, m4v : true, mov : true, wmv : true } ) - else if dirType = 4 then - displayList = displayFiles(listing, { mp4 : true, m4v : true, mov : true, wmv : true } ) - end if - - total = total + displayList.Count() - loadingDialog.SetTitle("Loading Movie #"+Stri(total)) - if dirType <> 0 then - Sort(displayList, function(k) - return LCase(k[0]) - end function) - list = CreateObject("roArray", displayList.Count(), false) - for j = 0 to displayList.Count()-1 - list.Push(MovieObject(displayList[j], cat_url, listing_hash)) - end for - grid.SetContentList(1+i, list) - screen.Push(list) - else - grid.SetContentList(1+i, []) - screen.Push([]) - end if - end for - loadingDialog.Close() - - while true - msg = wait(30000, port) - if type(msg) = "roGridScreenEvent" then - if msg.isScreenClosed() then - return -1 - elseif msg.isListItemFocused() - print "Focused msg: ";msg.GetMessage();"row: ";msg.GetIndex(); - print " col: ";msg.GetData() - elseif msg.isListItemSelected() - print "Selected msg: ";msg.GetMessage();"row: ";msg.GetIndex(); - print " col: ";msg.GetData() - - if msg.GetIndex() = 0 and msg.GetData() = 0 then - checkServerUrl(true) - else if msg.GetIndex() = 0 and msg.GetData() = 1 then - ' search returns a roArray of MovieObjects - results = searchScreen(screen) - - ' Make a new search rot - searchRow = getUtilRow(url) - searchRow.Append(results) - ' Remove the old one and add the new one, selecting first result - screen.Shift() - screen.Unshift(searchRow) - grid.SetContentList(0, searchRow) - grid.SetFocusedListitem(0, 2) - else - playMovie(screen[msg.GetIndex()][msg.GetData()]) - end if - endif - else if msg = invalid then - showTimeBreadcrumb(grid, true) - endif - end while -End Function - - -'************************************* -'** Get the utility row (Setup, Search) -'************************************* -Function getUtilRow(url As String) As Object - ' Setup the Search/Setup entries for first row - search = CreateObject("roArray", 2, true) - o = CreateObject("roAssociativeArray") - o.ContentType = "episode" - o.Title = "Setup" - o.SDPosterUrl = url+"/Setup-SD.png" - o.HDPosterUrl = url+"/Setup-HD.png" - search.Push(o) - - o = CreateObject("roAssociativeArray") - o.ContentType = "episode" - o.Title = "Search" - o.SDPosterUrl = url+"/Search-SD.png" - o.HDPosterUrl = url+"/Search-HD.png" - search.Push(o) - - return search -End Function - -'********************************** -'** Return the type of the directory -'********************************** -Function directoryType(listing_hash As Object) As Integer - if listing_hash.DoesExist("photos") then - return 1 - else if listing_hash.DoesExist("songs") then - return 2 - else if listing_hash.DoesExist("episodes") then - return 3 - else if listing_hash.DoesExist("movies") then - return 4 - end if - return 0 -End Function - - -'****************************************** -'** Create an object with the movie metadata -'****************************************** -Function MovieObject(file As Object, url As String, listing_hash as Object) As Object - o = CreateObject("roAssociativeArray") - o.ContentType = "movie" - o.ShortDescriptionLine1 = file[1]["basename"] - - ' Default images - o.SDPosterUrl = url+"default-SD.png" - o.HDPosterUrl = url+"default-HD.png" - - ' Search for SD & HD images and .bif files - if listing_hash.DoesExist(file[1]["basename"]+"-SD.png") then - o.SDPosterUrl = url+file[1]["basename"]+"-SD.png" - else if listing_hash.DoesExist(file[1]["basename"]+"-SD.jpg") then - o.SDPosterUrl = url+file[1]["basename"]+"-SD.jpg" - else if listing_hash.DoesExist(file[1]["basename"]+"-HD.png") then - o.HDPosterUrl = url+file[1]["basename"]+"-HD.png" - else if listing_hash.DoesExist(file[1]["basename"]+"-HD.jpg") then - o.HDPosterUrl = url+file[1]["basename"]+"-HD.jpg" - else if listing_hash.DoesExist(file[1]["basename"]+"-SD.bif") then - o.SDBifUrl = url+file[1]["basename"]+"-SD.bif" - else if listing_hash.DoesExist(file[1]["basename"]+"-HD.bif") then - o.HDBifUrl = url+file[1]["basename"]+"-HD.bif" - else if listing_hash.DoesExist(file[1]["basename"]+".txt") then - o.Description = getDescription(url+file[1]["basename"]+".txt") - end if - o.IsHD = false - o.HDBranded = false - o.Rating = "NR" - o.StarRating = 100 - o.Title = file[1]["basename"] - o.Length = 0 - - ' Video related stuff (can I put this all in the same object?) - o.StreamBitrates = [0] - o.StreamUrls = [url + file[0]] - o.StreamQualities = ["SD"] - - streamFormat = { mp4 : "mp4", m4v : "mp4", mov : "mp4", - wmv : "wmv", hls : "hls" - } - if streamFormat.DoesExist(file[1]["extension"].Mid(1)) then - o.StreamFormat = streamFormat[file[1]["extension"].Mid(1)] - else - o.StreamFormat = ["mp4"] - end if - - return o -End Function - -'******************************** -'** Set breadcrumb to current time -'******************************** -Function showTimeBreadcrumb(screen As Object, use_ampm As Boolean) - now = CreateObject("roDateTime") - now.ToLocalTime() - hour = now.GetHours() - if use_ampm then - if hour < 12 then - ampm = " AM" - else - ampm = " PM" - if hour > 12 then - hour = hour - 12 - end if - end if - end if - hour = tostr(hour) - minutes = now.GetMinutes() - if minutes < 10 then - minutes = "0"+tostr(minutes) - else - minutes = tostr(minutes) - end if - bc = now.AsDateStringNoParam()+" "+hour+":"+minutes+ampm - screen.SetBreadcrumbText(bc, "") -End Function - -'************************************* -'** Get the last position for the movie -'************************************* -Function getLastPosition(movie As Object) As Integer - ' use movie.Title as the filename - lastPos = ReadAsciiFile("tmp:/"+movie.Title) - print "Last position of ";movie.Title;" is ";lastPos - if lastPos <> "" then - return strtoi(lastPos) - end if - return 0 -End Function - -'****************************************************** -'** Return a list of the Videos and directories -'** -'** Videos end in the following extensions -'** .mp4 .m4v .mov .wmv -'****************************************************** -Function displayFiles( files As Object, fileTypes As Object, dirs=false As Boolean ) As Object - list = [] - for each f in files - ' This expects the path to have a system volume at the start - p = CreateObject("roPath", "pkg:/" + f) - if p.IsValid() and f.Left(1) <> "." then - fileType = fileTypes[p.Split().extension.mid(1)] - if (dirs and f.Right(1) = "/") or fileType = true then - list.push([f, p.Split()]) - end if - end if - end for - - return list -End Function - -'****************************************************** -'** Play the video using the data from the movie -'** metadata object passed to it -'****************************************************** -Sub playMovie(movie as Object) - p = CreateObject("roMessagePort") - video = CreateObject("roVideoScreen") - video.setMessagePort(p) - video.SetPositionNotificationPeriod(15) - - movie.PlayStart = getLastPosition(movie) - video.SetContent(movie) - video.show() - - lastPos = 0 - while true - msg = wait(0, video.GetMessagePort()) - if type(msg) = "roVideoScreenEvent" - if msg.isScreenClosed() then 'ScreenClosed event - exit while - else if msg.isPlaybackPosition() then - lastPos = msg.GetIndex() - WriteAsciiFile("tmp:/"+movie.Title, tostr(lastPos)) - else if msg.isfullresult() then - DeleteFile("tmp:/"+movie.Title) - else if msg.isRequestFailed() then - print "play failed: "; msg.GetMessage() - else - print "Unknown event: "; msg.GetType(); " msg: "; msg.GetMessage() - end if - end if - end while -End Sub - -'****************************************************** -'** Check to see if a description file (.txt) exists -'** and read it into a string. -'** And if it is missing return "" -'****************************************************** -Function getDescription(url As String) - print "Retrieving description from ";url - http = CreateObject("roUrlTransfer") - http.SetUrl(url) - resp = http.GetToString() - - if resp <> invalid then - return resp - end if - return "" -End Function - diff --git a/HMS/source/appMain.brs b/HMS/source/appMain.brs @@ -6,12 +6,6 @@ Sub Main() 'initialize theme attributes like titles, logos and overhang color initTheme() - screen = PreShowPosterScreen() - if screen = invalid then - print "Error creating initial poster screen" - return - end if - ' Get server url and make sure it is valid valid_dir = false force_edit = false @@ -24,7 +18,7 @@ Sub Main() end if end while - displayDirectory("http://"+RegRead("ServerURL")) + mediaServer("http://"+RegRead("ServerURL")) End Sub @@ -54,15 +48,3 @@ Sub initTheme() End Sub -'************************************************************* -'** Setup something as a placeholder while we load -'************************************************************* -Function preShowPosterScreen() As Object - port=CreateObject("roMessagePort") - screen = CreateObject("roPosterScreen") - screen.SetMessagePort(port) - screen.SetListStyle("flat-category") - screen.Show() - return screen -End Function - diff --git a/HMS/source/appMediaServer.brs b/HMS/source/appMediaServer.brs @@ -0,0 +1,334 @@ +'******************************************************************** +'** Home Media Server Application - Main +'** Copyright (c) 2010-2013 Brian C. Lane All Rights Reserved. +'******************************************************************** + +'****************************************************** +'** Display a scrolling grid of everything on the server +'****************************************************** +Function mediaServer( url As String ) As Object + print "url: ";url + + port=CreateObject("roMessagePort") + grid = CreateObject("roGridScreen") + grid.SetMessagePort(port) + grid.SetDisplayMode("scale-to-fit") + + ' Build list of Category Names from the top level directories + listing = getDirectoryListing(url) + if listing = invalid then + print "Failed to get directory listing for ";url + return invalid + end if + categories = displayFiles(listing, {}, true) + Sort(categories, function(k) + return LCase(k[0]) + end function) + + ' Setup Grid with categories + titles = CreateObject("roArray", categories.Count(), false) + titles.Push("Search") + for i = 0 to categories.Count()-1 + print "Category: :";categories[i][0] + titles.Push(getLastElement(categories[i][0])) + end for + grid.SetupLists(titles.Count()) + grid.SetListNames(titles) + + ' Hold all the movie objects + screen = CreateObject("roArray", categories.Count(), false) + + ' Add as utility row + grid.SetContentList(0, getUtilRow(url)) + screen.Push(search) + + ' run the grid + showTimeBreadcrumb(grid, true) + grid.SetFocusedListitem(0, 1) + grid.Show() + + loadingDialog = ShowPleaseWait("Loading Movies...", "") + total = 0 + ' Setup each category's list + for i = 0 to categories.Count()-1 + cat_url = url + "/" + categories[i][0] + listing = getDirectoryListing(cat_url) + listing_hash = CreateObject("roAssociativeArray") + for each f in listing + listing_hash.AddReplace(f, "") + end for + + ' What kind of directory is this? + dirType = directoryType(listing_hash) + if dirType = 1 then + displayList = displayFiles(listing, { jpg : true }) + else if dirType = 2 then + displayList = displayFiles(listing, { mp3 : true }) + else if dirType = 3 then + displayList = displayFiles(listing, { mp4 : true, m4v : true, mov : true, wmv : true } ) + else if dirType = 4 then + displayList = displayFiles(listing, { mp4 : true, m4v : true, mov : true, wmv : true } ) + end if + + total = total + displayList.Count() + loadingDialog.SetTitle("Loading Movie #"+Stri(total)) + if dirType <> 0 then + Sort(displayList, function(k) + return LCase(k[0]) + end function) + list = CreateObject("roArray", displayList.Count(), false) + for j = 0 to displayList.Count()-1 + list.Push(MovieObject(displayList[j], cat_url, listing_hash)) + end for + grid.SetContentList(1+i, list) + screen.Push(list) + else + grid.SetContentList(1+i, []) + screen.Push([]) + end if + end for + loadingDialog.Close() + + while true + msg = wait(30000, port) + if type(msg) = "roGridScreenEvent" then + if msg.isScreenClosed() then + return -1 + elseif msg.isListItemFocused() + print "Focused msg: ";msg.GetMessage();"row: ";msg.GetIndex(); + print " col: ";msg.GetData() + elseif msg.isListItemSelected() + print "Selected msg: ";msg.GetMessage();"row: ";msg.GetIndex(); + print " col: ";msg.GetData() + + if msg.GetIndex() = 0 and msg.GetData() = 0 then + checkServerUrl(true) + else if msg.GetIndex() = 0 and msg.GetData() = 1 then + ' search returns a roArray of MovieObjects + results = searchScreen(screen) + + ' Make a new search rot + searchRow = getUtilRow(url) + searchRow.Append(results) + ' Remove the old one and add the new one, selecting first result + screen.Shift() + screen.Unshift(searchRow) + grid.SetContentList(0, searchRow) + grid.SetFocusedListitem(0, 2) + else + playMovie(screen[msg.GetIndex()][msg.GetData()]) + end if + endif + else if msg = invalid then + showTimeBreadcrumb(grid, true) + endif + end while +End Function + + +'************************************* +'** Get the utility row (Setup, Search) +'************************************* +Function getUtilRow(url As String) As Object + ' Setup the Search/Setup entries for first row + search = CreateObject("roArray", 2, true) + o = CreateObject("roAssociativeArray") + o.ContentType = "episode" + o.Title = "Setup" + o.SDPosterUrl = url+"/Setup-SD.png" + o.HDPosterUrl = url+"/Setup-HD.png" + search.Push(o) + + o = CreateObject("roAssociativeArray") + o.ContentType = "episode" + o.Title = "Search" + o.SDPosterUrl = url+"/Search-SD.png" + o.HDPosterUrl = url+"/Search-HD.png" + search.Push(o) + + return search +End Function + +'********************************** +'** Return the type of the directory +'********************************** +Function directoryType(listing_hash As Object) As Integer + if listing_hash.DoesExist("photos") then + return 1 + else if listing_hash.DoesExist("songs") then + return 2 + else if listing_hash.DoesExist("episodes") then + return 3 + else if listing_hash.DoesExist("movies") then + return 4 + end if + return 0 +End Function + + +'****************************************** +'** Create an object with the movie metadata +'****************************************** +Function MovieObject(file As Object, url As String, listing_hash as Object) As Object + o = CreateObject("roAssociativeArray") + o.ContentType = "movie" + o.ShortDescriptionLine1 = file[1]["basename"] + + ' Default images + o.SDPosterUrl = url+"default-SD.png" + o.HDPosterUrl = url+"default-HD.png" + + ' Search for SD & HD images and .bif files + if listing_hash.DoesExist(file[1]["basename"]+"-SD.png") then + o.SDPosterUrl = url+file[1]["basename"]+"-SD.png" + else if listing_hash.DoesExist(file[1]["basename"]+"-SD.jpg") then + o.SDPosterUrl = url+file[1]["basename"]+"-SD.jpg" + else if listing_hash.DoesExist(file[1]["basename"]+"-HD.png") then + o.HDPosterUrl = url+file[1]["basename"]+"-HD.png" + else if listing_hash.DoesExist(file[1]["basename"]+"-HD.jpg") then + o.HDPosterUrl = url+file[1]["basename"]+"-HD.jpg" + else if listing_hash.DoesExist(file[1]["basename"]+"-SD.bif") then + o.SDBifUrl = url+file[1]["basename"]+"-SD.bif" + else if listing_hash.DoesExist(file[1]["basename"]+"-HD.bif") then + o.HDBifUrl = url+file[1]["basename"]+"-HD.bif" + else if listing_hash.DoesExist(file[1]["basename"]+".txt") then + o.Description = getDescription(url+file[1]["basename"]+".txt") + end if + o.IsHD = false + o.HDBranded = false + o.Rating = "NR" + o.StarRating = 100 + o.Title = file[1]["basename"] + o.Length = 0 + + ' Video related stuff (can I put this all in the same object?) + o.StreamBitrates = [0] + o.StreamUrls = [url + file[0]] + o.StreamQualities = ["SD"] + + streamFormat = { mp4 : "mp4", m4v : "mp4", mov : "mp4", + wmv : "wmv", hls : "hls" + } + if streamFormat.DoesExist(file[1]["extension"].Mid(1)) then + o.StreamFormat = streamFormat[file[1]["extension"].Mid(1)] + else + o.StreamFormat = ["mp4"] + end if + + return o +End Function + +'******************************** +'** Set breadcrumb to current time +'******************************** +Function showTimeBreadcrumb(screen As Object, use_ampm As Boolean) + now = CreateObject("roDateTime") + now.ToLocalTime() + hour = now.GetHours() + if use_ampm then + if hour < 12 then + ampm = " AM" + else + ampm = " PM" + if hour > 12 then + hour = hour - 12 + end if + end if + end if + hour = tostr(hour) + minutes = now.GetMinutes() + if minutes < 10 then + minutes = "0"+tostr(minutes) + else + minutes = tostr(minutes) + end if + bc = now.AsDateStringNoParam()+" "+hour+":"+minutes+ampm + screen.SetBreadcrumbText(bc, "") +End Function + +'************************************* +'** Get the last position for the movie +'************************************* +Function getLastPosition(movie As Object) As Integer + ' use movie.Title as the filename + lastPos = ReadAsciiFile("tmp:/"+movie.Title) + print "Last position of ";movie.Title;" is ";lastPos + if lastPos <> "" then + return strtoi(lastPos) + end if + return 0 +End Function + +'****************************************************** +'** Return a list of the Videos and directories +'** +'** Videos end in the following extensions +'** .mp4 .m4v .mov .wmv +'****************************************************** +Function displayFiles( files As Object, fileTypes As Object, dirs=false As Boolean ) As Object + list = [] + for each f in files + ' This expects the path to have a system volume at the start + p = CreateObject("roPath", "pkg:/" + f) + if p.IsValid() and f.Left(1) <> "." then + fileType = fileTypes[p.Split().extension.mid(1)] + if (dirs and f.Right(1) = "/") or fileType = true then + list.push([f, p.Split()]) + end if + end if + end for + + return list +End Function + +'****************************************************** +'** Play the video using the data from the movie +'** metadata object passed to it +'****************************************************** +Sub playMovie(movie as Object) + p = CreateObject("roMessagePort") + video = CreateObject("roVideoScreen") + video.setMessagePort(p) + video.SetPositionNotificationPeriod(15) + + movie.PlayStart = getLastPosition(movie) + video.SetContent(movie) + video.show() + + lastPos = 0 + while true + msg = wait(0, video.GetMessagePort()) + if type(msg) = "roVideoScreenEvent" + if msg.isScreenClosed() then 'ScreenClosed event + exit while + else if msg.isPlaybackPosition() then + lastPos = msg.GetIndex() + WriteAsciiFile("tmp:/"+movie.Title, tostr(lastPos)) + else if msg.isfullresult() then + DeleteFile("tmp:/"+movie.Title) + else if msg.isRequestFailed() then + print "play failed: "; msg.GetMessage() + else + print "Unknown event: "; msg.GetType(); " msg: "; msg.GetMessage() + end if + end if + end while +End Sub + +'****************************************************** +'** Check to see if a description file (.txt) exists +'** and read it into a string. +'** And if it is missing return "" +'****************************************************** +Function getDescription(url As String) + print "Retrieving description from ";url + http = CreateObject("roUrlTransfer") + http.SetUrl(url) + resp = http.GetToString() + + if resp <> invalid then + return resp + end if + return "" +End Function +