Documentation

Programmez des écrans à partir d’un tableur

Un lieu garde son horaire dans un tableur : un code d’écran, un nom de fichier, un début et une fin sur chaque ligne. Importez la feuille et screenRIG vérifie chaque ligne par rapport à vos écrans et à vos médias, nomme chaque problème par ligne et colonne, fait un aperçu du calendrier que suivraient vos écrans, et applique tout ou rien.

De la feuille aux écrans

  1. Partez du modèle. Enregistrez le modèle en CSV ou XLSX, ou utilisez votre propre feuille avec les mêmes colonnes.
  2. Remplissez une ligne par ligne d’horaire. Nommez l’écran (ou un dossier ou une étiquette), le fichier, le début et la fin.
  3. Importez-la. Déposez le fichier dans la boîte de dialogue Importer de l’onglet Horaire du tableau de bord, ou exécutez screenrig schedule import FILE.
  4. Corrigez les lignes en erreur. Chaque erreur nomme la ligne, la colonne et un code. Modifiez la cellule dans la boîte de dialogue, ou modifiez la feuille et importez-la de nouveau.
  5. Vérifiez l’aperçu. Il liste les niveaux que la feuille crée, ceux qu’elle modifie ou supprime, et le calendrier des écrans qu’elle touche.
  6. Publiez. Toutes les lignes s’appliquent ensemble ou aucune ne s’applique.

Les étapes 1 à 5 n’écrivent rien. Un écran a besoin d’un fuseau horaire (screen set-timezone) et d’une liste de lecture par défaut (screen assign) avant qu’une ligne puisse le programmer, et un fichier doit être une image ou une vidéo approuvée.

La feuille

La première ligne nomme les colonnes. Chaque ligne suivante est une ligne d’horaire. Les lignes vides sont ignorées. Une feuille est un fichier CSV (UTF-8, séparé par des virgules ou des points-virgules) ou un classeur XLSX, et un classeur XLSX est lu à partir de sa première feuille.

ColonneLu aussi commeContenu
targetscreen, screen code, code, room, room id, screen name, screen idLes écrans que la ligne programme. Requis
contentfile, file name, media, asset, playlistCe qui est diffusé. Requis
startstart date, from, beginQuand la ligne commence
endend date, until, stopQuand la ligne se termine
timezonetime zone, tzLe fuseau dans lequel les heures de la ligne sont écrites
daysweekdays, dayLes jours de la semaine où la ligne est diffusée
daily startwindow start, time fromL’heure du jour où chaque plage de diffusion s’ouvre
daily endwindow end, time toL’heure du jour où chaque plage de diffusion se ferme
priorityDe 0 à 100. Une valeur élevée l’emporte sur une valeur basse. Par défaut : 0
namelevel, labelUn nom pour le niveau que crée la ligne
displaydisplays, outputLes sorties du mur vidéo sur lesquelles la ligne est diffusée, comme 1 ou 1,2

Les en-têtes correspondent sans tenir compte de la casse, des espaces et de la ponctuation. Une colonne que rien ne lit est ignorée, et l’aperçu la liste. Une ligne a besoin d’un target, d’un content et d’au moins un parmi start, end, days ou une plage quotidienne.

Screen,File,Start,End,Timezone,Days,Daily start,Daily end,Priority,Name
LOBBY-01,welcome-spring.jpg,2026-11-05 18:00,2026-11-08 02:00,America/Los_Angeles,,,,0,
folder:Casino Floor,happy-hour.mp4,2026-11-05,2026-11-30,,Mon-Fri,16:00,19:00,5,Happy hour
tag:elevators,playlist:Holiday loop,2026-12-01 09:00,2026-12-26,,,,,0,
  • La ligne 2 diffuse welcome-spring.jpg sur l’écran dont le code est LOBBY-01 de 18 h le 5 novembre à 2 h le 8 novembre, heure du Pacifique.
  • La ligne 3 diffuse happy-hour.mp4 sur chaque écran du dossier Casino Floor et des dossiers qu’il contient, de 16 h à 19 h en semaine, du 5 novembre à la fin du 30 novembre.
  • La ligne 4 diffuse la liste de lecture Holiday loop sur chaque écran portant l’étiquette elevators, de 9 h le 1er décembre à la fin du 25 décembre.

Cibles

Une cible est l’une des suivantes :

  • Un écran. Un identifiant d’écran, la valeur d’un champ quelconque de l’écran (un code de salle, un numéro de magasin) ou le nom de l’écran. --code-field ou code_field limite la correspondance à un seul champ, comme code ou room_id.
  • Un dossier. folder:NAME ou folder:Parent/Child. Il atteint le dossier et tous les dossiers qu’il contient.
  • Une étiquette. tag:NAME atteint chaque écran portant l’étiquette.

Plusieurs cibles dans une même cellule sont séparées par ; ou |, comme dans LOBBY-01;LOBBY-02|tag:elevators.

Contenu

  • Un fichier. Le nom d’un fichier multimédia du projet, ou le nom de fichier d’origine d’un téléversement converti. Le fichier est diffusé en plein écran. La première validation qui utilise un fichier crée la liste de lecture à fichier unique Scheduled: FILE, et les importations suivantes la réutilisent.
  • Une liste de lecture. playlist:NAME ou un identifiant de liste de lecture. La liste de lecture a une version approuvée et n’est pas un modèle.

Heures

  • Dates et heures. 2026-11-05 18:00, 2026-11-05T18:00, 11/5/2026 6:00 PM et les cellules de date des tableurs sont lues. Une heure avec un décalage comme Z ou +02:00 est refusée.
  • L’horloge propre à chaque écran. Les heures sont lues sur l’horloge des écrans que la ligne atteint, donc 18:00 correspond à 18 h où que l’écran se trouve.
  • Un autre fuseau. Une cellule timezone (ou le timezone de la requête) indique que la ligne est écrite dans ce fuseau. Les heures sont converties dans le fuseau des écrans quand tous les écrans de la ligne partagent un même fuseau. Une ligne qui atteint des écrans de plusieurs fuseaux laisse timezone vide et lit l’horloge propre à chaque écran.
  • Une date seule comme fin ferme ce jour : 2026-11-30 se termine à la fin du 30 novembre. Une date seule comme début commence à minuit.
  • Sans fin la ligne reste diffusée jusqu’à ce qu’une importation ultérieure la supprime. L’aperçu avertit avec open_end.
  • Jours. Mon-Fri, Mon,Wed,Fri, Sat,Sun, weekdays, weekends ou daily. Une ligne avec days et sans plage quotidienne est diffusée toute la journée ces jours-là.
  • Une plage quotidienne. daily start et daily end donnent les heures de chaque jour, comme 16:00 et 19:00 ou 4:00 PM et 7:00 PM. Donnez les deux. Une fin égale ou antérieure au début passe minuit et appartient au jour où elle commence. Sans days, la plage s’applique tous les jours.

Aperçu et erreurs

L’aperçu vérifie chaque ligne et chaque cellule avant que rien soit écrit. Une ligne en erreur est montrée avec ses cellules, et chaque erreur nomme la colonne, un code et ce qu’il faut changer.

CodeColonneSignification et correction
requiredtarget, content, daily start, daily endLa cellule est vide, ou une seule des cellules de la plage quotidienne est remplie. Remplissez-la
unknown_screentargetAucun écran n’a cet identifiant, cette valeur de champ ni ce nom. Vérifiez le code, ou le champ que nomme code_field
ambiguous_screentargetLa valeur correspond à plusieurs écrans. Utilisez l’identifiant de l’écran ou un code unique
unknown_foldertargetAucun dossier d’écrans ne porte ce nom. Vérifiez l’orthographe
ambiguous_foldertargetPlusieurs dossiers portent ce nom. Écrivez le chemin, comme folder:Hotel/Casino Floor
unknown_tagtargetAucun écran n’a l’étiquette. Vérifiez l’orthographe
unknown_filecontentAucun fichier ni aucune liste de lecture ne porte ce nom. Téléversez le fichier, ou corrigez le nom
ambiguous_filecontentPlusieurs fichiers portent ce nom. Renommez-en un, ou écrivez playlist:NAME
not_playablecontentLe fichier n’est pas une image ni une vidéo, le média attend un examen, ou la liste de lecture est un modèle ou n’a pas de version approuvée. Approuvez-la, ou choisissez-en une autre
invalid_timestart, end, daily start, daily endLa cellule n’est pas une date et une heure, ou elle porte un décalage de fuseau. Écrivez 2026-11-05 18:00
reversed_timesendLa fin n’est pas après le début. Corrigez l’une ou l’autre
past_endendLa fin est passée. Reculez-la, ou retirez la ligne
no_timingstartLa ligne ne dit rien sur le moment. Donnez un début, une fin, des jours ou une plage quotidienne
invalid_valuedays, priority, displayLa cellule n’est pas une liste de jours comme Mon-Fri, un nombre entier de 0 à 100, ou des numéros d’affichage comme 1,2
timezonetimezoneLe fuseau est inconnu, ou la cible contient des écrans de plusieurs fuseaux. Utilisez un fuseau comme America/Los_Angeles, ou laissez vide
screen_not_readytargetUn écran n’a pas de fuseau horaire ou pas de liste de lecture par défaut. Exécutez screen set-timezone ou screen assign
overlappriorityDeux lignes sont en vigueur en même temps sur un écran à la même priorité. Donnez une priorité différente à l’une, ou déplacez une heure
limittargetUn écran aurait plus de 32 niveaux propres, ou l’organisation plus de 100 campagnes (chaque niveau partagé en est une). Fusionnez des lignes, ou ciblez un dossier ou une étiquette

Deux avertissements n’arrêtent pas une importation. open_end marque une ligne sans fin. outranked marque une ligne qu’un niveau partagé (une ligne pour plusieurs écrans, un dossier ou une étiquette) recouvre sur un écran.

Une feuille sans ligne, un fichier qui n’est pas en UTF-8, plus de 5 000 lignes, un fichier de plus de 8 MiB, ou une validation qui écrirait plus de 400 horaires propres d’écrans est refusé avec la raison.

Niveaux

Les lignes qui s’accordent sur le contenu, les heures, la priorité, le nom et l’affichage forment un seul niveau. La cible ne fait pas partie de la comparaison, donc dix lignes qui diffusent le même fichier aux mêmes heures sur dix écrans forment un seul niveau.

  • Un écran crée une entrée dans l’horaire propre à cet écran.
  • Plusieurs écrans, un dossier ou une étiquette créent un niveau partagé, une campagne sur cette audience. Un niveau partagé l’emporte sur les niveaux propres d’un écran.

Le regroupement transforme les 200 écrans d’un lieu en une seule campagne plutôt qu’en 200 entrées, et une correction dans la feuille modifie un seul niveau. La colonne name nomme un niveau partagé. Sans elle, le niveau porte le nom de l’importation, du contenu et de la cible, comme dans Spring promos: happy-hour.mp4 on Casino Floor.

Importer de nouveau

Le name d’une importation l’identifie, et la valeur par défaut est import. Importer de nouveau sous le même nom :

  • met à jour les niveaux qu’elle a créés, même quand les dates d’une ligne ont changé ;
  • ajoute les niveaux des nouvelles lignes ;
  • supprime les niveaux dont les lignes ont disparu de la feuille ;
  • ne change rien quand la feuille est la même.

Les niveaux créés par une importation la portent dans leur identifiant (les entrées d’un écran commencent par imp_) et les campagnes portent une marque import. Les niveaux créés à la main ne sont jamais touchés. Utilisez un nom pour une feuille, et un autre nom pour une autre feuille.

Exécuter une importation

Tableau de bord

Ouvrez l’onglet Horaire d’un projet et choisissez Importer. Déposez un fichier CSV ou XLSX. La boîte de dialogue montre un tableau des lignes avec chaque erreur à côté de sa cellule, et vous modifiez la cellule sur place. Elle montre ensuite le calendrier composé des écrans que l’importation modifie. Publier le valide.

Ligne de commande

screenrig schedule template --output schedule.csv
screenrig schedule import schedule.csv --name "Spring promos" --timezone America/Los_Angeles
screenrig schedule import schedule.csv --name "Spring promos" --timezone America/Los_Angeles --commit

schedule import fait un aperçu et n’écrit rien. --commit applique la feuille quand toutes les lignes sont valides.

OptionSens
--name NAMELe nom de l’importation, de 1 à 80 caractères. Par défaut, le nom du fichier sans son extension
--timezone ZONELe fuseau dans lequel les heures sont écrites quand une ligne n’a pas de timezone
--code-field FIELDLire un code d’écran seulement dans ce champ d’écran
--commitAppliquer la feuille
--format csv|xlsxschedule template : le format du modèle
--output FILEschedule template : où l’enregistrer

La commande se termine avec le code 0 pour une feuille valide, 8 quand des lignes ont des erreurs (rien n’est écrit) et 5 quand le projet a changé depuis l’aperçu (exécutez-la de nouveau). FILE est un fichier .csv, .xlsx ou .json, ou - pour l’entrée standard. Un fichier JSON contient un tableau d’objets de ligne, ou {"rows": [...]}, indexés par nom de colonne.

API

Envoyez la feuille sous forme de lignes JSON, ou comme corps CSV ou XLSX avec les réglages en paramètres de requête. L’aperçu demande un accès en lecture. La validation demande des identifiants avec accès en écriture, qu’accorde une personne qui peut approuver dans le tableau de bord.

curl -s https://api.screenrig.ai/api/schedule/imports/preview \
  --header "Authorization: Bearer $SCREENRIG_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "Spring promos",
    "timezone": "America/Los_Angeles",
    "rows": [
      {"target": "LOBBY-01", "content": "welcome-spring.jpg", "start": "2026-11-05 18:00", "end": "2026-11-08 02:00"},
      {"target": "folder:Casino Floor", "content": "happy-hour.mp4", "start": "2026-11-05", "end": "2026-11-30",
       "days": "Mon-Fri", "daily_start": "16:00", "daily_end": "19:00", "priority": 5, "name": "Happy hour"}
    ]
  }'

La même feuille en fichier :

curl -s "https://api.screenrig.ai/api/schedule/imports/preview?name=Spring%20promos&timezone=America/Los_Angeles" \
  --header "Authorization: Bearer $SCREENRIG_TOKEN" \
  --header "Content-Type: text/csv" \
  --data-binary @schedule.csv

La réponse, abrégée :

{
  "name": "Spring promos",
  "valid": false,
  "fingerprint": "FINGERPRINT",
  "columns": ["target", "content", "start", "end", "days", "daily_start", "daily_end", "priority", "name"],
  "summary": {"rows": 2, "rows_with_errors": 1, "levels": 1, "creates": 1, "updates": 0,
              "unchanged": 0, "removes": 0, "screens": 1, "playlists": 1},
  "rows": [
    {"row": 2, "status": "ok", "level": "LEVEL_KEY"},
    {"row": 3, "status": "error",
     "errors": [{"column": "content", "code": "unknown_file",
                 "message": "No file or playlist is named \"happy-hour.mp4\"."}]}
  ],
  "levels": [{"key": "LEVEL_KEY", "action": "create", "home": "screen", "screen_id": "scr_LOBBY",
              "content": {"kind": "file", "id": "med_WELCOME", "name": "welcome-spring.jpg"},
              "screens": 1, "priority": 0, "from": "2026-11-05T18:00", "until": "2026-11-08T02:00", "rows": [2]}],
  "removals": []
}

rows[].cells renvoie les cellules de chaque ligne telles que la feuille les a données, pour qu’un client les corrige et renvoie les lignes. valid est true quand aucune ligne n’a d’erreur. calendar a la forme de GET /api/schedule/calendar et montre les écrans que l’importation modifie tels qu’ils seraient après une validation.

La validation envoie la même feuille et le fingerprint de son aperçu, comme membre du corps JSON ou comme paramètre de requête avec un fichier. Envoyez un Idempotency-Key pour réessayer sans risque.

curl -s https://api.screenrig.ai/api/schedule/imports \
  --header "Authorization: Bearer $SCREENRIG_TOKEN" \
  --header "Idempotency-Key: spring-promos-1" \
  --header "Content-Type: application/json" \
  --data @commit.json

La réponse contient preview et applied, les décomptes de ce qui a été créé, mis à jour, laissé inchangé et supprimé, avec les écrans écrits et les listes de lecture créées. Une validation est refusée, sans rien écrire, comme suit :

ProblèmeStatutSignification et correction
schedule_import_invalid422Des lignes contiennent des erreurs. Corrigez-les et refaites un aperçu
schedule_import_stale409Des écrans, médias, listes de lecture ou niveaux ont changé depuis l’aperçu, ou les lignes se lisent autrement. Refaites un aperçu et validez avec la nouvelle empreinte

GET /api/schedule/imports/template?format=csv et format=xlsx répondent au modèle.

Limites

  • 5 000 lignes et 8 MiB par feuille.
  • 32 niveaux propres par écran. Une organisation contient jusqu’à 100 campagnes, tous projets confondus, et chaque niveau partagé en est une.
  • 400 horaires propres d’écrans écrits par validation. Une ligne de dossier ou d’étiquette atteint un nombre quelconque d’écrans.
  • Un nom d’importation compte de 1 à 80 caractères.