Tag : javascript

RCPI

RCPI, is a Remote Controller for the Raspberry-Pi.

It's a project that I started because I had no batteries in my remote keyboard and I wanted to be able to use an Android phone to control my raspberry pi to play videos.

The main idea was to setup a nodejs server that receive packets to control an OMX player instance.

I first started to use websockets to be able to use any web browser to communicate with the server, but I discovered that on android chrome, the websocket connection stop functioning after the phone goes to sleep, event if you wake it up.
So I switched to UDP as it's simple to implement, and is really close to how a real TV remote controller works, it send a signal even if the TV is powered off.

This project is available on my github : RCPI-Server / RCPI-Android

Server features:

  • Handle a lots of media url, thanks to youtube-dl
  • Check for all media locally available.
  • All default OMX controls available.

Client features:

  • Can use the Share Action to send links to the app.

Preview of the android client :

TODO :

  • Security
  • "Mute" action is not yet implemented
  • Youtube subtitles
  • Cursor navigation
  • Current omx libary has limitations, need to make one
, last updated :

Local resources path in a chrome extension

If you want to import a resource to your local chrome extension, usually you would duplicate the resource itself into another controlled location.

For a simple and local only chrome extension, what I would find somewhat more efficient to import resources is to save only their local path. Unfortunately browser's apis usually don't give that information.

I used a little workaround, that imply to drag/drop a file in the browser's url bar of the chrome extension. Listening on chrome.tabs.onUpdated allow us to access the absolute local path of the file.

The basic idea is :

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo){
  // Check tabId, check changeInfo.status

  if (changeInfo.url.startsWith('file:///')) {
    // use changeInfo.url
  }
});

It mean that when you drop the file in the url bar the browser navigate to the new resource, then in the listener you need to save the url and reload the extension page (you can do both by passing a get parameter when reloading the extension).

With that in mind, we can use the example to add a check if the tab that fired the event is an extension page.

See the complete implementation bellow :


var baseUrl = chrome.extension.getURL('myextension.html');
var tabIds = [];     // List of the extension tabs
var tabsLoaded = {}; // Status of these tabs

function is_tab_from_ext(tabId){
  return tabIds.indexOf(tabId) > -1;
};

function remove_tab(tabId){
  if (is_tab_from_ext(tabId)){
    tabIds.splice(tabIds.indexOf(tabId), 1);
    delete tabsLoaded[tabId];
  }
};

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo){
  if (changeInfo.status === 'loading'){
    // if loading extension page
    if (changeInfo.url === baseUrl) {
      if (!is_tab_from_ext(tabId)){
        tabIds.push(tabId);
        tabsLoaded[tabId] = false;
      }
      return;
    }
  }

  if (is_tab_from_ext(tabId)){
    if (changeInfo.status === 'complete'){
      // save tab status
      tabsLoaded[tabId] = true;
      return;
    }
  }

  // if new url is a local path
  if (tabsLoaded[tabId]){
    if (typeof changeInfo.url === 'string') {
      // local path check 
      if (changeInfo.url.startsWith('file:///')) {

          // Example
          // changeInfo.url contain the url of the local resource
          chrome.tabs.update(tabId, {url: baseUrl+"?path="+changeInfo.url}, function () {});

      }
      else{
        // tab is updating new url that is not a file, remove tab from list
        remove_tab(tabId);
      }
    }
  }
});

chrome.tabs.onRemoved.addListener(function(tabId) {
  remove_tab(tabId);
});

This code hasn't been used in production and will be updated. I use it in REPR, a project still in development.

, last updated :