JS Hooks

Some object types allow for custom JS code to be executed.   
The script code can either be the value of the property, or located in a file indicated in the property.   
The code is turned into a function (i.e. `new Function(args, js_code)`) upon initial playlist parsing or reload, hereafter called `JSFun`.  
The `JSFun` arguments and return value are dependent on the parent object type.  
The parent object is exposed as `this` in `JSFun` and can be used to store context information for the JS code.  
  
The code can use the global functions and modules defined, especially:  

- sys: GPAC system module  
- evg: GPAC EVG module  
- os: QuickJS OS module   
- video_playing: video playing state  
- audio_playing: audio playing state  
- video_time: output video time  
- video_timescale: output video timescale  
- video_width: output video width  
- video_height: output video height  
- audio_time: output audio time  
- audio_timescale: output audio timescale  
- samplerate: output audio samplerate  
- channels: output audio channels  
- current_utc_clock: current UTC clock in ms  
- get_media_time: gets media time of output (no argument) or of source with id matching the first argument. Return  

    - -4: not found  
    - -3: not playing  
    - -2: in prefetch  
    - -1: timing not yet known  
    - value: media time in seconds (float)  

- resolve_url: resolves URL given in first argument against media playlist URL and returns the resolved url (string)  
- get_scene(id): gets scene with given ID  
- get_group(id): gets group with given ID  
- mouse_over(evt): returns scene under mouse described by a GPAC event, or null if no scene (picking for scenes with perspective projection is not supported)  
- mouse_over(x, y): returns scene under coordinates {x, y} in pixels, {0,0} representing the center of the frame, x axis oriented towards the right and y axis oriented towards the top  

  
Scene and group options must be accessed through getters and setters:  

- scene.get(prop_name): gets the scene option  
- scene.set(prop_name, value): sets the scene option  
- group.get(prop_name): gets the group option  
- group.set(prop_name, value): sets the group option  

  
__Warning: Results are undefined if JS code modifies the scene/group objects in any other way.__  
  
Other playlist objects (as well as scene and group objects) can be queried using `query_element(ID, propName)` or modified using `update_element(ID, propName, value)` (see playlist update below).     
  
__Warning: There is no protection of global variables and state, write your script carefully!__  
  
Additionally, scripts executed within scene modules can modify the internal playlist using:  

- remove_element(ID):  removes a scene, group, sequence, timer, script or watcher with given ID from playlist  
- parse_element(JSON): parses a root playlist element and add it to the current playlist  
- parse_scene(JSON, parent): parses a scene and add it to `parent` group if not null or root otherwise  
- parse_group(JSON, parent): parses a group and add it to `parent` group if not null or root otherwise  
- reload_playlist(JSON): parses a new playlist (an empty JSON array will reset the playlist). If the calling scene is no longer in the resulting scene tree, it will be added to the root of the scene tree.  

  
All these playlist-related functions must be called within the update() callback of the scene module.