Giter Club home page Giter Club logo

maestro-roku's Introduction

A development platform for building roku channels in brighterscript

build GitHub NPM Version

Why maestro?

Maestro Makes roku development easier, especially for experienced software engineers from other platforms

I believe that experienced developers from android, ios, c#, web, node, etc, should be able to be productive on a roku app in no more than a week, just as they would on any other platform. So I wrote maestro to make that possible.

Maestro is built to:

  • Raise velocity
  • Increase productivity
  • Reduce learning
  • Simply cross-skilling
  • Make roku development more fun
  • Produce roku apps that can be maintained by non roku developer
  • Produce roku apps that can be unit tested easily
  • Write code that can be tested and breakpoint debugged, outside of SG views (which are slow as hell, and prone to crashing when breakpoint debugging)

Quick start

Sideload without building

Building sample apps/playing with maestro frameork

  1. git clone https://github.com/georgejecook/maestro-roku-sample.git
  2. npm install
  3. npm run ropm
  4. open the project in vscode
  5. ensusre you have the brighterscript vscode extension installed
  6. .vscode/.env.sample to .vscode/.env and edit the ROKU_DEV_TARGET and ROKU_DEVPASSWORD variables, to match your roku device.
  7. launch the SAMPLE APP dev target.

note, some sample screens will lose focus when you back out of them. Sorry about that! We will fix that soon - for now, just press home and launch again.

Interesting notions

In bsconfig.json, you can change the rokuLog settings to control how logging works (this is part of roku-log)

  • use strip flag to remove logs
  • use insertPkgPath to inject the file details into each log line - if you set the vscode brightscript plugin setting "brightscript.output.hyperlinkFormat": to "FilenameAndFunction", then the output will automatically include clickable hyperlinks, which is a very pleasant deubgging experience.

Sample project

We maintain a simple sample project with sensible examples, which can show you everything you can do with maestro. It is WIP.

Presently the project may be broken - we will get it fixed up, with a more full example of how to use maestro to build a FULL app in 2024Q2

Docs

Maestro-roku docs can be found here

IMPORTANT!! ropm hook

Because of the way that maestro plugin generates certain files, ropm can will cause errors when you install maestro. You will have to include a script to fix any of these broken files, and run it after you ropm hook.

files

scripts/maestro-ropm-hook.js

/* eslint-disable github/array-foreach */
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable @typescript-eslint/no-require-imports */
const fs = require('fs-extra');
const path = require('path');

let sourceDir = path.join(__dirname, '..', 'src', 'components', 'roku_modules', 'maestro');

try {
    fs.readdirSync(sourceDir).forEach(file => {
        let filePath = path.join(sourceDir, file);
        if (filePath.endsWith('Task.xml')) {

            let text = fs.readFileSync(filePath, 'utf8');
            let r = /\/roku_modules\/rokucommunity_bslib/gim;
            text = text.replace(r, '/roku_modules/maestro');
            fs.writeFileSync(filePath, text);
        }
    });
} catch (e) {
}

package.json

Change your ropm task, as follows. in package.json, scripts:

"ropm": "node scripts/maestro-ropm-hook.js ropm copy",

maestro-roku's People

Contributors

arturocuya avatar cewert avatar georgejecook avatar mark-nba avatar nsillik avatar rdaci23 avatar vanjapin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

maestro-roku's Issues

I clone the sample but doesn't work

AN-MacBook-Pro:samples allan$ npm run build-dev

> [email protected] build-dev /Users/allan/projects/360sports/maestro-roku/samples
> node scripts/run.js dev

building "dev" (/Users/allan/projects/360sports/maestro-roku/samples/bsconfig-dev.json
[11:50:08:3500 AM]  Loading 2 plugins for cwd "/Users/allan/projects/360sports/maestro-roku/samples"
building all comp files...
Generating node class NavMenu isIDEBuild? false
Generating node class NavMenuItem isIDEBuild? false
Generating node class NavItem isIDEBuild? false

src/source/controls/NavMenu.bs:1:9 - error BS1004: Referenced file does not exist.

 1  import "pkg:/source/view/BaseView.bs"
 1          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 


src/source/controls/NavMenuItem.bs:1:9 - error BS1004: Referenced file does not exist.

 1  import "pkg:/source/view/BaseView.bs"
 1          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] build-dev: `node scripts/run.js dev`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] build-dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/allan/.npm/_logs/2021-06-18T09_50_09_318Z-debug.log
AN-MacBook-Pro:samples allan$ 

Warn when event is used as one way vm binding

The following xml should generate a diagnostic:

  <mv_Poster
        id='poster'
        uri='{{posterUri}}'
        visible='{{isPosterVisible}}'
        loadStatus='{{onPosterLoadStatusChange(value)}}'

in this case, onPosterLoadStatusChange is an event!

add interpolate view json api

want to be able to interpolate view json, so we can animate it using generic animator.

consider:

onAnimationUpdate(fraction as float)
  m.interpolateViewJson(m.isSelected ? m.selectedViewJson m.normalJson, m.top)
end function

make it so that createSGNode can take an array of args, in stead of aa)

this will make it really easy for situations where there are multiple styles driving a components style, e.g. from styleManager, with runtime tweaks. Consider:

    m.titleLabel = mc.createSGNode("mv_Label", m.labelGroup, "titleLabel", style.titleLabel)
    m.titleLabel.setFields({
      size: [w - 10, 0]
      translation: [5, h + 10]
    })

this would be better as:

    m.titleLabel = mc.createSGNode("mv_Label", m.labelGroup, "titleLabel", [style.titleLabel, {
      size: [w - 10, 0]
      translation: [5, h + 10]
    }])

look ahead distance not used correctly

listSettings = ml.listMixin.createListSettings(3000, 2000)

correctly causes the list to create enough rows for 3000 pixels ahead; but the rows dont' get added until pressin gup.

Function doesn't properly handle 2 default integer parameters

I was writing a function the other day with 2 default values, for example:
public function add(x = 5 as integer, y = 10 as integer)

However, when I went to print out what was actually being input to the function by default, I found that:
x = invalid, and y = 10

I haven't tested this with other data types, but it appears at least for integers there is an issue with implementing a function with 2 default parameters.

method [email protected]( m.item ) crash

Error:


BRIGHTSCRIPT: ERROR: Runtime: func_name_resolver failed resolving 'push': pkg:/source/roku_modules/maestro/mx/BaseViewModel.brs(172)

BrightScript Micro Debugger.
Enter any BrightScript statement, debug commands, or HELP.

Suspending threads...
Thread selected:  1*   .../maestro/mx/BaseViewModel.brs(172)   push(view)

Current Function:
167:  function(view)
168:          if mc_isString(view) then
169:              view = m.getViewById(view)
170:          end if
171:  
172:*         push(view)
173:      end function
Source Digest(s): 
pkg: dev 1.0.0 5c134a3aebf3691d3cced531b2e152d8 360Sports

Function is not defined in component's namespace (runtime error &h91) in pkg:/source/roku_modules/maestro/mx/BaseViewModel.brs(172)
Backtrace:
#3  Function $anon_2c8(view As Dynamic) As Dynamic
file/line: pkg:/source/roku_modules/maestro/mx/BaseViewModel.brs(172)
#2  Function $anon_7c(isvisible As Dynamic, selection As Dynamic) As Dynamic
file/line: pkg:/source/main/AppControllerVM.brs(163)
#1  Function $anon_7b(selection As Dynamic) As Dynamic
file/line: pkg:/source/main/AppControllerVM.brs(158)
#0  Function playselection(selection As Dynamic) As Dynamic
file/line: pkg:/components/main/AppController.brs(38)
Local Variables:
view             roSGNode:VideoPlayer refcnt=1
global           Interface:ifGlobal
m                roAssociativeArray refcnt=9 count:105
Threads:
ID    Location                                Source Code
0    pkg:/source/main.brs(24)                msg = wait(0, m.port)
1*   .../maestro/mx/BaseViewModel.brs(172)   push(view)
2    ...nts/debug/RALETrackerTask.brs(1940)  msg = wait(0, inputPort)
*selected

Brightscript Debugger> 

I'm trying to show the videoplayer but it crash

allow batching of component pool baking

create component pool mixin method making it easy to create a bunch of cells in the background without blowing the cpu..
e.g.
mc.pool.createCells(burstSize, callbackFunction, types: [{cellType: quantity}])

Integration of roRegistrySection for authentication app

I created these methods for the registry for basic roku app:


Function GetAuthData() As Dynamic
    sec = CreateObject("roRegistrySection", "Authentication")
    if sec.Exists("UserRegistrationToken")
        return sec.Read("UserRegistrationToken")
    endif
    return invalid
End Function
'
Function SetAuthData(userToken As String) As Void
    print "SetAuthData "; 'userToken;
    sec = CreateObject("roRegistrySection", "Authentication")
    sec.Write("UserRegistrationToken", userToken)
    sec.Flush()
End Function
'
Function GetRefreshTokenData() As Dynamic
    sec = CreateObject("roRegistrySection", "Authentication")
    if sec.Exists("UserRefreshToken")
        return sec.Read("UserRefreshToken")
    endif
    return invalid
End Function
'
Function SetRefreshTokenData(userToken As String) As Void
    print "SetRefreshTokenData "; 'userToken;
    sec = CreateObject("roRegistrySection", "Authentication")
    sec.Write("UserRefreshToken", userToken)
    sec.Flush()
End Function
'
Function GetUserData() As Dynamic
    sec = CreateObject("roRegistrySection", "Authentication")
    if sec.Exists("UserData")
        return sec.Read("UserData")
    endif
    return invalid
End Function
'
Function SetUserData(userToken As String) As Void
    print "SetUserData "; 'userToken;
    sec = CreateObject("roRegistrySection", "Authentication")
    sec.Write("UserData", userToken)
    sec.Flush()
End Function
'
sub DeleteRegistry()
    print "Starting Delete Registry"
    Registry = CreateObject("roRegistry")
    i = 0
    for each section in Registry.GetSectionList()
        RegistrySection = CreateObject("roRegistrySection", section)
        for each key in RegistrySection.GetKeyList()
            i = i+1
            print "Deleting " section + ":" key
            RegistrySection.Delete(key)
        end for
        RegistrySection.flush()
    end for
    print i.toStr() " Registry Keys Deleted"
end sub
'

optimize @debounced callbacks

We probs don't need a separate observer function for each debounced callback
e.g.

    @debounce
    @alwaysnotify
    @observer("redraw")
    public backgroundColor = "#aaaaaa"

    @debounce
    @alwaysnotify
    @observer("redraw")
    public focusedBackgroundColor = "#ffffff"

    @debounce
    @alwaysnotify
    @observer("redraw")
    public disabledBackgroundColor = "#ffffff"

    @debounce
    @alwaysnotify
    @observer("redraw")
    public highlightColor = "#ffffff"

produces:

function on_focusedBackgroundColor()
    addCallback("redraw")
end function

function on_disabledBackgroundColor()
    addCallback("redraw")
end function

function on_highlightColor()
    addCallback("redraw")
end function

one callback would probably suffice

add generic animation

need a generic animation editor that is capable of adding generic animations, which are not connected to a particular animation - so they can be a callback only


Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.