npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xiboplayer/core

v0.7.16

Published

xiboplayer core orchestration and lifecycle management

Readme

@xiboplayer/core

Pure orchestration engine for Xibo players — manages collection cycles, layout state machines, offline mode, and lifecycle events.

Overview

The core package is the central orchestrator of a Xibo player. It manages:

  • Collection cycle — periodic CMS polling (RegisterDisplay, RequiredFiles, Schedule) with CRC32 optimization to skip redundant downloads
  • Layout scheduling — builds a playback queue from CMS schedule with support for campaigns, dayparting, priorities, and maxPlaysPerHour constraints
  • Layout state machine — controls which layout is playing, handles XMR interrupts (changeLayout, overlayLayout), layout overrides with auto-revert, and synchronized transitions in multi-display setups
  • Offline mode — falls back to IndexedDB-cached schedule and media when CMS is unreachable, with exponential backoff retry (30s -> 60s -> 120s -> normal interval)
  • Event bus — emits 50+ lifecycle events (collection-start, register-complete, layout-prepare-request, layout-current, offline-mode, timeline-updated, etc.)
  • XMR integration — WebSocket-based real-time messaging for remote commands (layout changes, purge, screenshots, geo-location, commands, triggers)
  • Multi-display sync — coordinates synchronized layout transitions and video playback across multiple displays via optional SyncManager
  • Layout blacklisting — automatic fallback when a layout fails to render 3+ times
  • Data connectors — real-time polling of external data sources (weather, feeds, APIs) for dynamic content widgets
  • Timeline calculation — predicts next 2 hours of layout playback with duration estimation and missing media detection

Architecture

+-----------------------------------------------------------------+
| PlayerCore (Pure Orchestration)                                 |
|                                                                 |
|  +-------------+--------------+--------------+                  |
|  | Collection  | Layout State | Offline      |                  |
|  | Cycle       | Machine      | Cache (IDB)  |                  |
|  +-------------+--------------+--------------+                  |
|                                                                 |
|  Events emitted (NO DOM manipulation):                          |
|  collection-start, schedule-received, download-request,         |
|  layout-prepare-request, layout-current, layout-expire-current, |
|  offline-mode, timeline-updated, sync-config, xmr-connected    |
+-----------------------------------------------------------------+
                             |
+-----------------------------------------------------------------+
| Dependencies (injected)                                         |
+-----------------------------------------------------------------+
| @xiboplayer/xmds     -> XMDS client (RegisterDisplay, etc.)    |
| @xiboplayer/schedule  -> Schedule queue builder, layout eval    |
| @xiboplayer/cache     -> Blob storage (media files, XLFs)      |
| @xiboplayer/renderer  -> Layout rendering (platform-specific)  |
| @xiboplayer/utils     -> Logger, EventEmitter, config          |
| @xiboplayer/sync      -> Multi-display SyncManager (optional)  |
+-----------------------------------------------------------------+
                             |
+-----------------------------------------------------------------+
| Platform Layer (PWA / Electron / Chromium / Mobile)             |
| - Renders layouts via renderer                                  |
| - Handles UI updates, status display, progress indicators       |
| - Manages storage, downloads via cache pkg                      |
| - Listens to core events and updates the DOM                    |
+-----------------------------------------------------------------+

Key principle: PlayerCore emits events; it does not manipulate the UI. The platform layer listens to these events and implements the actual rendering, DOM updates, and platform-specific behaviors.

Installation

npm install @xiboplayer/core

Usage

Basic setup

import { PlayerCore } from '@xiboplayer/core';

const core = new PlayerCore({
  config: displayConfig,
  xmds: xmdsClient,
  cache: cacheClient,
  schedule: scheduleManager,
  renderer: rendererInstance,
  xmrWrapper: XmrClass,
  statsCollector: statsClient,
  displaySettings: dsManager,
});

core.on('collection-start', () => console.log('Polling CMS...'));
core.on('schedule-received', (schedule) => console.log('Schedule updated'));
core.on('download-request', ({ files, layoutOrder }) => {
  downloadQueue(files, layoutOrder);
});

core.on('layout-prepare-request', (layoutId) => {
  renderer.renderLayout(layoutId);
});

core.on('offline-mode', (isOffline) => {
  updateStatusDisplay(isOffline ? 'Offline' : 'Online');
});

await core.collect();

Event handling

// Layout lifecycle
core.on('layout-prepare-request', (layoutId) => showLoadingBar());
core.on('layout-current', (layoutId) => hideLoadingBar());
core.on('layout-expire-current', () => fadeOutAndCleanup());

// Timeline/schedule preview
core.on('timeline-updated', (timeline) => {
  // timeline: [{ layoutFile, startTime, endTime, duration, missingMedia, isDefault }]
  updateTimelineOverlay(timeline);
});

// Offline
core.on('offline-mode', (isOffline) => {
  if (isOffline) showOfflineBanner('Using cached schedule');
  else hideOfflineBanner();
});

Layout overrides (XMR)

// Change to a specific layout, auto-revert after duration
core.changeLayout(layoutId, { duration: 30 });

// Overlay: push a layout on top of current content
core.overlayLayout(layoutId, { duration: 10 });

// Manual revert
await core.revertToSchedule();

Multi-display sync

import { SyncManager } from '@xiboplayer/sync';

const syncManager = new SyncManager({
  displayId: 'screen-1',
  syncConfig: regResult.syncConfig,
  onLayoutChange: async (layoutId) => {
    await renderer.prepareLayout(layoutId);
    syncManager.reportReady(layoutId);
  },
  onLayoutShow: (layoutId) => renderer.show(layoutId),
});

syncManager.start();
core.setSyncManager(syncManager);

Collection Cycle

The collection cycle runs every 300 seconds (configurable via CMS settings):

1. REGISTERDISPLAY
   +- Authenticates display (hardware key)
   +- Returns: settings, syncConfig, commands, checkRf/checkSchedule CRC32
   +- Saves to IndexedDB for offline use

2. CRC32 SKIP OPTIMIZATION
   +- If checkRf unchanged -> skip RequiredFiles
   +- If checkSchedule unchanged -> skip Schedule

3. REQUIREDFILES (if checkRf changed)
   +- Gets media, layouts, resources, dependencies, widgets
   +- Checks for purge items (deleted media to remove)
   +- Resets blacklist (CMS may have fixed layouts)

4. SCHEDULE (if checkSchedule changed)
   +- Gets CMS schedule (layouts, campaigns, dayparting, criteria)
   +- Evaluates criteria (location, time, device, weather, custom)
   +- Builds playback queue with priorities, maxPlaysPerHour, durations

5. LAYOUT QUEUE EVALUATION
   +- Calculates queue from schedule + durations + constraints
   +- If current layout still valid -> keep playing
   +- If expired -> emit layout-expire-current
   +- If no current layout -> emit layout-prepare-request

6. DOWNLOAD MANAGEMENT
   +- Check download window (CMS can restrict to off-peak hours)
   +- Emit download-request with files + layout priority order

7. SUBMIT STATS & LOGS
   +- Proof-of-play, diagnostic logs, fault reports
   +- Multi-display: followers delegate to lead via SyncManager

8. FINALIZE
   +- Calculate timeline (next 2 hours)
   +- Emit timeline-updated, collection-complete
   +- Schedule next cycle

OFFLINE FALLBACK:
   If XMDS fails AND cached schedule exists:
   +- Use cached schedule + cached media
   +- Retry with backoff: 30s -> 60s -> 120s -> normal

Events

| Event | Payload | Description | |-------|---------|-------------| | collection-start | -- | Collection cycle beginning | | collection-complete | -- | Collection cycle finished | | collection-error | (error) | CMS communication failed | | register-complete | (regResult) | RegisterDisplay succeeded | | files-received | (files) | RequiredFiles call succeeded | | schedule-received | (schedule) | Schedule call succeeded | | download-request | (layoutOrder, files) | Download needed files in layout priority order | | layout-prepare-request | (layoutId) | Next layout ready for rendering | | layout-current | (layoutId) | Layout is now playing | | layout-pending | (layoutId, requiredMediaIds) | Layout waiting for media downloads | | layout-expire-current | -- | Current layout duration ended | | layout-already-playing | (layoutId) | Schedule changed but current layout still valid | | no-layouts-scheduled | -- | No layouts match current time | | layout-blacklisted | ({ layoutId, reason, failures }) | Layout failed 3+ times, skipped | | offline-mode | (isOffline) | Entered/exited offline mode | | xmr-connected | (xmrUrl) | XMR WebSocket connected | | sync-config | (syncConfig) | Display is in a sync group | | timeline-updated | (timeline) | Schedule preview for next 2 hours | | screenshot-request | -- | XMR requested screenshot | | revert-to-schedule | -- | Layout override ended | | overlay-layout-request | (layoutId) | Overlay layout requested | | execute-native-command | ({ code, commandString }) | Non-HTTP command for platform | | scheduled-command | (command) | Scheduled command ready | | submit-stats-request | -- | Submit proof-of-play stats | | submit-logs-request | -- | Submit player logs | | submit-faults-request | -- | Submit faults (~60s cycle) |

API Reference

Constructor

new PlayerCore({
  config,              // Display configuration (cmsUrl, hardwareKey, displayName, etc.)
  xmds,                // XMDS client instance
  cache,               // Cache/storage client
  schedule,            // Schedule manager
  renderer,            // Layout renderer
  xmrWrapper,          // XMR WebSocket wrapper class
  statsCollector?,     // Optional proof-of-play tracker
  displaySettings?,    // Optional display settings manager
})

Methods

| Method | Returns | Description | |--------|---------|-------------| | collect() | Promise<void> | Start collection cycle | | collectNow() | Promise<void> | Force immediate collection (clears CRC32 cache) | | collectOffline() | void | Use cached schedule | | getNextLayout() | object \| null | Get next layout from queue, skip blacklisted | | advanceToNextLayout() | void | Pop next layout, emit layout-prepare-request | | advanceToPreviousLayout() | void | Go back in schedule | | setCurrentLayout(layoutId) | void | Mark layout as currently playing | | getCurrentLayoutId() | number \| null | Get currently playing layout ID | | changeLayout(layoutId, opts) | Promise<void> | XMR: change layout with optional duration | | overlayLayout(layoutId, opts) | Promise<void> | XMR: push overlay layout | | revertToSchedule() | Promise<void> | Exit layout override | | reportLayoutFailure(id, reason) | void | Report render failure; blacklist after 3 | | reportLayoutSuccess(id) | void | Clear failure counter | | setSyncManager(syncManager) | void | Attach SyncManager for multi-display | | isSyncLead() | boolean | Check if this display is sync lead | | purgeAll() | Promise<void> | Delete all cache and re-download | | cleanup() | void | Stop all timers, close XMR, remove listeners |

Dependencies

  • @xiboplayer/utils -- logger, events, config

xiboplayer.org · Part of the XiboPlayer SDK