Filmotech ScriptEdit - Trucs et astuces

Ce document vise à aider à l'écriture et la lecture des scripts ; il est centré sur la programmation Xojo, et aborde :
  • Les notions de base : variables et tableaux - boucles (FOR… et DO…).
  • L'utilisation de ScriptEdit (3.5.0) - dont Debug pour tester de petits programmes et mettre au point un script.
  • La notion de procédure et fonction.

Avertissement

Xojo a utilisé, et utilise encore en partie, la terminologie Visual Basic (V.B.), mais il tend maintenant à s'en affranchir. La compatibilité V.B. est néanmoins maintenue.
Pour assurer la comptabilité avec les anciennes versions de Filmotech, les scripts sont, pour l'instant, encore écrits avec la terminologie V.B.

Les variables

Toutes les variables doivent être déclarées par Dim nom as Type (ou avec la nouvelle terminologie Xojo Var nom as Type)
http://docs.xojo.com/Dim, http://docs.xojo.com/Var

Dim i, indice as Integer     (ou Var i, indice as Integer)
Dim chaine, texte as String  (Var chaine, texte as String)
Dim condition as Boolean     (Var condition as Boolean)
Dim x as Double              (Var x as Double)

Noms

Pas de différence entre MAJUSCULES et minuscules (noms “insensibles à la case”); ainsi, Debut et debut représentent la même variable

Cette règle vaut également pour les noms réservés comme dim, integer, …

Les lettres accentuées sont autorisées dans Xojo. Mais attention : début et debut sont 2 variables différentes. L'habitude est cependant d'éviter les lettres accentuées.

Types

Principaux types utilisés dans les scripts : Integer, String, Boolean, Double

Integer

Cf. type entier. Type entier “historique” dit “signé” ; Correspond à Int32 sur les machines 32 bits (de -2 147 483 648 à 2 147 483647), codés sur 4 octets. Sur les machine 64 bits Integer correspond à Int64 (-9,223,372,036,854,775,808 à +9,223,372,036,854,775,807), codé sur 8 octets.

valeur par défaut = 0

String

Cf. Type chaine de caractères. Type chaine de caractères : suite de caractères tels lettres, chiffres, signes de ponctuation, etc. La longueur de la chaine n'est limitée que par la mémoire disponible.
Les valeurs doivent être mises entre guillemets. Si la chaine contient des guillemets, ils doivent être doublés.

chaine = "bonjour"
texte = "il a dit ""bonjour"""

Valeur par défaut = “”
Remarque : Retour charriot (carriage return (CR)) est un caractère, de code 13. Pour le rendre actif dans une chaine il faut écrire CHR(13). Il est obligatoire entre chaque acteur ou réalisateur.
NB : Dans la documentation Xojo, à l'intitulé String, on a See Also qui renvoie aux opérateurs et fonctions relatifs aux chaines - comme Trim (supprime les espaces en début et fin d'une chaine), inStr (position d'une chaine dans une autre) ou NthFiled (extrait une sous-chaine d'une chaine, en fonction d'un séparateur).

A propos de NthField (NthField) et du fait que les “” doivent être doublés dans les constantes chaines, on a souvent à extraire une sous-chaine d'une chaine ou le séparateur est “ ; ex tiré du script SensCritique :

'soit par ex la ligne i : <a href="https://www.netflix.com/title/1089727" target="_blank" class="product-providers__item">
'soit à en extraire l'adresse : https://www.netflix.com/title/1089727, en utilisant NthField et le séparateur " 
  adresse = NthField(fmt_ValeurLigne(i), """" , 2 )
  ' il y a 4 ", ce qui n'est pas à priori évident...

Boolean

Cf. Type booléen. Type booléen (en hommage au mathématicien George Boole), ne prend que 2 valeurs True (vrai) ou False (faux).
Valeur par défaut = False

dim condition as Boolean
condition = left( fmt_ValeurLigne( i ) , 1 ) <> "<" AND trim(fmt_ValeurLigne( i )) <> ""

Remarque : 2 valeurs booléennes peuvent être reliées par OR (ou “inclusif”) ou AND.

  • condition1 OR condition2 est VRAI si et seulement si l'une au moins des 2 conditions est VRAIE
  • condition1 AND condition2 est VRAI si et seulement si les 2 conditions sont VRAIES.

Double

Cf.Type réel. Type réel double précision (±4.94065645841246544176568792868221372e-324 à ±1.79769313486231570814527423731704357e+308), codé sur 8 octets. A utiliser systématiquement (donc éviter le type Single, réel simple précision).

valeur par défaut = 0.0

Les tableaux

Cf. Tableaux (Arrays). Ensemble de valeurs numérotées à partir de 0, ayant toutes le même type.

dim acteurs, tableau() as string
dim a, b, c as string
 
a= "Fabrice Luchini"
b= "Emmanuelle Seigner"
c = "Yolande Moreau"
 
tableau.append a
tableau.append b
tableau.append c
 
fmt_DebugMsg(tableau(0))  'affiche la première valeur du tableau dans la fenêtre de débogage
 
acteurs = join(tableau, chr(13)) 'concatène les valeurs dans tableau dans une chaine ; chr13) comme séparateur
fmt_AfficheMessage(acteurs)
' fmt_DebugMsg(acteurs)  n'afficherait que la valeur de la chaine avant le 1er CR  (pour fmt_DebugMsg il n'y a qu'une ligne disponible)
redim tableau(-1)  ' réinitialise le tableau
acteurs = join(tableau, chr(13))
fmt_AfficheMessage(acteurs) 'donc chaine vide

Remarques :

  • Les parenthèses (seules) après le nom de la variable tableau indique qu'il s'agit d'un tableau “dynamique”, cad dont le nombre d'éléments (la dimension) n'est pas précisé. Si l'on voulait déclarer un tableau de 10 valeurs de type chaine, on écrirait par ex : Dim MonTableau(9) as String (ne pas oublier que le premier élément a l'indice 0).
  • Pour un tableau dynamique append (ou commande équivalente) est obligatoire ; tableau(0) = a provoquerait une erreur.

Tester un programme dans ScriptEdit

Il est possible de tester de petits programmes dans ScriptEdit pour voir comment se comportent tels ou tels éléments dans un futur script. A titre d'exemple on peut tester le programme ci-dessus sur les tableaux.

  • Lancer ScriptEdit.
  • Le programme doit être écrit dans Requete des titres (on peut copier / coller le programme ci-dessus, ou l'écrire…).
  • Cliquer sur “Enregistrer” (donner un nom au programme)
  • Exécuter : cliquer sur “Tester”, puis bouton “Recherche” - cliquer sur “OK” pour sortir.

La structure de boucle

C'est une notion qui, au début, peut être délicate…

Il y a deux principales structures de boucle : la boucle Pour (For…next) et la boucle Répéter (Do…loop).

Boucle Pour

syntaxe générale :

For i = debut to fin.  'i de type integer
 [instructions]
 [Exit] 'facultatif
 [instructions)]
Next

Les instructions entre For et Next seront exécutées n fois (n “passages” dans la boucle, n = fin - debut + 1). Lors du premier passage i aura la valeur debut; à la fin du premier passage le compteur i est augmenté d'une unité, etc.
En général debut = 1

La gestion du compteur est automatique

Tester la boucle Pour dans Scriptedit

NB : Pour fmt_DebugMsg et fmt_AfficheMessage, le paramètre peut être mis ou non entre parenthèses.
On peut donc écrire fmt_DebugMsg(“Bonjour”) ou fmt_DebugMsg “Bonjour”

Exemple

L'idée est de faire afficher la valeur du compteur i à chaque passage dans la boucle (avec un test, car on a un affichage particulier pour i = 1).

Cet exemple montre qu'on sort de la boucle avec i = n+ 1

' NB : str(nombre), fonction qui convertit un nombre en chaine de caractères
' str(i) obligatoire, car le paramètre de fmt_DebugMsg doit être de type chaine
 
Dim i, n as Integer
n= 5
For i = 1 to n
  if  i = 1 then
    fmt_DebugMsg "premier passage dans la boucle" + "   " +  "i = " + str(i)
  else
    fmt_DebugMsg str(i) + " ème passage dans la boucle" + "   " +  "i = " + str(i)
  end if
Next
fmt_DebugMsg "i = " +str(i) + " en sortie de boucle"

NB : Une boucle Pour For i = debut to fin n'est pas exécutée si debut > fin (on sort alors de la boucle avec i = debut)

Boucle Répéter

syntaxe :

test en fin de boucle
la boucle est exécutée au moins une fois
test en début de boucle
la boucle ne sera pas exécutée si condition = true
Do
[instructions]
loop until condition
Do until condition
[instructions]
loop

La différence entre une boucle Pour et une boucle Répéter tient essentiellement au fait que : dans une boucle Pour le nombre de passage(s) est déterminé à l'avance (géré par un compteur) - même si la boucle peut être interrompue par exit ; dans une boucle Répéter, il est indéterminé : on ne sait pas a priori au bout de combien de passage(s) condition sera vraie.

  • NB : Il faut bien gérer la condition d'arrêt d'une boucle Répéter, car si elle n'est jamais vraie, la boucle sera “infinie”; le programme ne s'arrêtera pas et il faudra l'interrompre depuis le système d'exploitation.

Boucle Répéter dans Scriptedit - fmt_Recherche

Nous utiliserons la fonction fmt_Recherche(chaine_cherchée, Ligne_début, [ligne_fin], valeur exacte : True, sinon : False) ; la fonction renvoie -1 si aucune valeur trouvée ; fmt_IndexRecherche est la valeur de la ligne de chaine_cherchée.

Ex : script CinemaMontreal_fr.XML, Analyse des titres ; sur l'ensemble des lignes de la page HTML les titres sont délimités par <h3 class='movietitle'> ; il faut exclure TV ; id est utilisé pour “analyse du détail”

dim searchString as String = "<h3 class='movietitle'>"
index = 350
do until fmt_Recherche(searchString,index,true) = -1
  id = NthField( fmt_ValeurLigne(fmt_IndexRecherche+1 ) , "'" , 2 )
  if right(id,2) <> "tv" then 
    date = str(val(right(id, 4)))
    if date < "1900" then date =""
    titre = fmt_ValeurLigne( fmt_IndexRecherche+2 )
    titre=replaceall(titre, "&apos;", "'")
    titre  = titre + " (" + date +")"  
    fmt_MemoriseTitre  (id , titre )
  end if
  index = fmt_IndexRecherche+3 
loop

Pour progresser dans la page HTML il faut naturellement augmenter la valeur de index à chaque passage dans la boucle Do (ici index = fmt_IndexRecherche+3)
Après le dernier film on ne trouve plus <h3 class='movietitle'>, donc fmt_Recherche sera égal à -1.

Notion de procédure

Plutôt que d'écrire toutes les instructions de manière séquentielle, on en regroupe certaines dans des “procédures” pour accomplir des tâches spécifiques, par ex : recherche des notes, des acteurs, etc.

Sub Nom_Procedure(). 'il peut y avoir des paramètres

[déclarations variables]
instructions

End Sub

Les variables déclarées sont locales à la procédure ; si elles ont le même nom que certaines du programme “principal” ou “appelant”, elles prennent le pas sur les variables de même nom de ce programme.
Les variables du programme appelant (de noms différents) peuvent être utilisées dans la procédure.

Procédure dans ScriptEdit, Analyse du détail

Dans SensCritique, on prend des informations dans la page d'accueil des films, mais aussi dans la page Casting.
Les deux sont analysées par ScriptEdit dans Analyse du détail, ce qui oblige à avoir 2 procédures : une Film (Sub Film()…) pour la page d'accueil et une Casting (Sub casting ()…) (pour les acteurs, rôles,…).

Pour passer de l'une à l'autre on utilise fmt_RequeteDetailSuite(“get”, adresse_page, fmt_parametreDetail)

fmt_parametreDetail = ”“ par défaut

if fmt_parametreDetail = "" then
  dim chaine as string
  dim note as boolean = fmt_valeur("InclureNotes") = "OUI"
  film
  if note then Snotes 'Snotes : procédure de traitement des notes
  chaine = fmt_IdentifiantDetail + "/details"
  fmt_RequeteDetailSuite("get", chaine, "details")  'relance analyse du détail
elseif fmt_parametreDetail = "details" then
  casting
end if

Pour exécuter une procédure, il suffit de mettre son nom dans le “code” (film, casting, Snotes - sans parenthèses dans la mesure où il n'y a pas de paramètre) (après son exécution le programme continue séquentiellement)

Les procédures peuvent être écrites n'importe où dans le code. Une procédure peut en appeler une autre.

NB : If note est bien sûr équivalent à If note = true (mais ce serait redondant car on teste toujours après If si la condition est vraie) ;
If note = false peut s'écrire If Not note.

Procédure, paramètres

Exemple d'un script perso Unifrance : mettre en clair des lettres accentuées (qui sont codées dans la page HTML)

sub accents(byref P as string)
  P = replaceall(P, "&iuml;", "ï")
  P = replaceall(P, "&rsquo;", "'")
  P = replaceall(P, "&ntilde;", "ñ")
  P = replaceall(P, "&iacute;", "í")
  P = replaceall(P, "&uuml;", "ü")
  P = replaceall(P, "&aacute;", "á")
  P = replaceall(P, "&yuml;", "ÿ")
  P = replaceall(P, "&oelig;", "œ")
  P = replaceall(P, "&oslash;", "ø")
end sub

Procédure qui sera appelée pour titre, realisateurs : accents(titre), accents(realisateurs)
Pourquoi byref ?
Parce que sans Byref (“passage paramètre par valeur” : passage par défaut), P serait exclusivement local à la procédure.
Or on veut qu'il affecte la valeur du paramètre appelant (titre, realisateur, …) : il doit partager la même adresse mémoire que lui, la même “référence”. Byref : passage de paramètre par “référence”

NB : il y a une procédure similaire dans le script DVDEmpire_BR_DVD.XML

Fonctions

Une fonction est une procédure qui renvoie une valeur d'un type donné.

Reprenons l'exemple de la procédure accents ci-dessus, mais écrit sous forme de fonction Faccents.

function Faccents(P as string) as string
  P = replaceall(P, "&iuml;", "ï")
  P = replaceall(P, "&rsquo;", "'")
  P = replaceall(P, "&ntilde;", "ñ")
  P = replaceall(P, "&iacute;", "í")
  P = replaceall(P, "&uuml;", "ü")
  P = replaceall(P, "&aacute;", "á")
  P = replaceall(P, "&yuml;", "ÿ")
  P = replaceall(P, "&oelig;", "œ")
  P = replaceall(P, "&oslash;", "ø")
  return P 'P est la valeur renvoyée par la fonction
end function

Il suffit d'écrire : titre = Faccents(titre) ou realisateur = Faccents(realisateur)
(P est naturellement transmis par valeur)

Programme à tester : une chaine (string) peut-elle être considérée comme une date comprise entre “1900” et “2099” (Dans les scripts le champ année est de type string) ? test_date.xml.zip
Comprend une procédure et une fonction (passage paramètre par valeur). (La fonction testdate est utilsée dans les scripts CinemaMontreal)

Cases à cocher, boutons d'option

Exemple SensCritique :

Tester inclure les notes et inclure les rôles : (on peut utiliser des booléens)

dim character as boolean = fmt_valeur(“InclureRoles”) = “OUI”

dim note as boolean = (fmt_valeur(“InclureNotes”) = “OUI ”) ' les parenthèses ne sont pas obligatoires

Tester les boutons d'option (un seul suffit dans la mesure où il n'y en a que 2)

dim choixTitre as boolean = fmt_Valeur(“RadioBouton”) = “Titre”