Script Surveillance RebelBB
guest23-Oct-2007/23:52:20+2:00
En attendant la nouvelle mouture du script lecture-forum de Didec, voici un petit script qui affiche un message d'alarme quand un nouveau message est posté sur le forum.

Par défaut j'ai reglé le timer avec un scan toutes les 5 minutes.

En cliquant sur le message clignotant
ça lance le browser pour afficher le message en question.

hide - cache la fenêtre qui ne se réactive que si un nouveau message est posté.

Quit - ben ça quitte définitevement.

(heu, j'ai pas pu testé complètement le script au boulot (méchant proxy) ni chez moi (panne de net)
alors je garantis pas que ça marche du premier coup)


Assez bavassé:
REBOL []

timer: 0:05:00 ;nombre de minutes avant le prochain scan du forum
view/new/offset/options layout/tight [H1 red "Démarrage surveillance forum RebelBB"] 300x300 [no-title]
wait 0:00:03 unview/all 
lay: layout/tight [
        across space 0x0 btn [browse href unview/all sav: new] red 300
        btn "hide" [unview/all sav: new] btn "Quit" [quit]
        box 1 rate 1 feel [engage: func [f a e][lay/pane/1/effect/2: first reverse [red blue] show lay/pane/1]]
]
clean: func [blk /local token][trim/lines form remove-each token blk [tag? token ]] 
forever [
        topic: clear [] href: none
        if not parse load/markup read http://www.digicamsoft.com/cgi-bin/rebelBB.cgi [
                thru </FORM> thru </TR> to </td> href: (href: skip href -3) :href
                6 [copy text thru </td> (append topic clean text) any string!] 
                to end
        ][print "Erreur de parsing de RebelBB. Surveillance stopée." halt]
        new: rejoin [topic/1 " (" topic/2 ") from " topic/5]
        href: to-url fourth parse href/1 {" }
        if empty? sav [sav: new]
        if new <> sav [lay/pane/1/text: new view/new lay]
        wait timer
]
guest24-Oct-2007/17:26:46+2:00
Hum hum, le sujet passionne les foules... pas grâve je poste une correction quand même

REBOL []

timer: 0:5:00 ;nombre de minutes avant le prochain scan du forum
inform/timeout layout/tight [TITLE red "Démarrage surveillance forum RebelBB"] 0:00:02
sav: ""
lay: layout/tight [
        across space 0x0 msg: btn [browse href unview/all sav: new] red 300
        btn "hide" [unview/all sav: new] btn "Quit" [quit]
        box 1 rate 1 feel [engage: func [f a e][msg/effect/2: first reverse [red blue] show msg]]
]
clean: func [blk /local token][trim/lines form remove-each token blk [tag? token ]] 
forever [
        topic: clear [] href: none
        if not parse load/markup read http://www.digicamsoft.com/cgi-bin/rebelBB.cgi [
                thru </FORM> thru </TR> 2 [thru tag!] set href tag!
                6 [copy text thru </td> (append topic clean text) any string!] 
                to end
        ][print "Erreur de parsing de RebelBB. Surveillance stopée." halt]
        new: rejoin [topic/1 " (" topic/2 ") from " topic/5]
        href: to-url fourth parse href {" }
        if empty? sav [sav: new]
        if new <> sav [msg/text: new view/new lay]
        wait timer
]
GreG4-Oct-2007/18:47:10+2:00
Salut Guest2

Merci de partager cet outil avec nous!
Concernant la passion des foules... je crois que DideC avait rencontre autant de succes avec Lecture-Forum, et pourtant Lecture-Forum est bien plus avance.

Je crois qu'une bonne idee est d'ajouter un flux RSS au forum, comme l'avait fait Philippe d'ailleurs.

Concernant un client pour le forum, il faudrait d'abord fournir une interface native pour rebol, c'est a dire, un bon mold block au lieu de devoir parser le html.
guest24-Oct-2007/20:25:03+2:00
Mouais, flux RSS ou flux html, ça reste du XML à parser.
Pour REBOL ça ne fait guerre de différence, juste 2 - 3 règles à changer dans le parseur.

L'intérêt essentiel du RSS c'est qu'il existe de très bon clients agrégateur de flux RSS sur le marché dans tout plein de languages mais à la limite on s'en fout, nous on fait du REBOL.

Eventuellement le truc à faire c'est de gérer un timestamp quelque part sur ton site pour ne pas avoir à charger la page du forum si y'a pas de nouveauté.

D'une façon générale, je pense que l'intérêt de développer un client complet pour le forum est très limité sinon pour se faire plaisir et passer le temps.
Le seul truc vraiment utile avec un client (à mon avis) c'est d'étre averti en temps (presque réel) quand un nouveau message est posté.
Sinon pour le reste, RebelBB fait très bien le boulot.
GreG4-Oct-2007/21:56:44+2:00
Effectivement, dans ce cas le plus simple serait simplement de renvoyer un mold de la date du dernier post.
Je remonterai ce post lorsque le CGI aura cette fonctionalite.

Pour le flux RSS, c'est juste dans le but d'utiliser les outils existants.
Goldevil4-Oct-2007/22:04:05+2:00
J'aimerais beaucoup un flux RSS. J'utilise Firefox et j'ai 30 flux RSS dans mes favoris. Je les parcours tous les jours et le forum y serait vraiment bienvenu. D'autant plus que certains outils RSS signalent une mise à jour et rendent moins vital un logiciel spécifique (mais rien n'empêche d'écrire un petit soft de lecture de flux RSS avec alerte).
Philippe5-Oct-2007/8:39:12+2:00
Salut,

Dans la version 1.3 de RebelBB que j'avais transmise l'an passé à Greg, lorsqu'un post était ajouté, on faisait appel au script emit-rss.r de Christopher Ross-Gill (un peu modifié), qui créait le fichier xml pour le flux.
Une icône "RSS" dans la page principale renvoyait vers le lien (à l'identique de ce qu'il y a sur Rebol.com).

Piotr Gapinski a posté sur la Lib 1 ou 2 scripts pour le Rss (readers).

===Philippe
Goldevil5-Oct-2007/9:52:19+2:00
J'ai rajouté une protection contre les erreurs réseau. S'il ne parvient pas à se connecter, le script ne plante pas et continue d'attendre. Je pense aussi qu'un timer à 2 minute est plus pratique.

J'ai ajouté aussi des commentaires.

Je ne sais pas tester le code d'où je suis (pare-feu paranoïaque). Quelqu'un peut me dire si cela fonctionne.

REBOL [
	Title: "VerifForum"
	Date: 05-10-2007
	Name: "verif_forum.r"
	
	Version: 1.1.1

	Author: "Karim El Founas"
	Rights:  "Public Domain"
	
	Purpose: { This software runs hidden and alert user when the french rebol forum is updated }
	
	History: [
		1.0.0 [03-10-2007 "First release" "Guest2"]
		1.1.0 [04-10-2007 "Parsing corrected" "Guest2"]
		1.1.1 [05-10-2007 "Commentes added. Correction : protection against network failure" "Goldevil"]
	]
]

timer: 0:2:00 ;nombre de minutes avant le prochain scan du forum

; affichage splash screen (fenêtre modale)
inform/timeout layout/tight [TITLE red "Démarrage surveillance forum RebelBB"] 0:00:02

sav: "" ; contient une sauvegarde du titre du dernier post

; layout de la fenêtre d'alerte
lay: layout/tight [
        across space 0x0 
        msg: btn [
        	browse href 
        	unview/all 
        	sav: new
        ] red 300
        btn "hide" [
        	unview/all 
        	sav: new
        ] 
        btn "Quit" [quit]
        box 1 rate 1 feel [
        	engage: func [f a e][
        		msg/effect/2: first reverse [red blue] 
        		show msg
        	]
        ]
]

; Fonction d'effacement utilisé par le parsing
clean: func [
	blk 
	/local 
		token
][
	trim/lines form remove-each token blk [tag? token ]
] 

; boucle principale du programme (boucle infinie)
forever [
	topic: clear [] 
	href: none
	; Essai de chargement de la page
	if error? try [
		page_content: read http://www.digicamsoft.com/cgi-bin/rebelBB.cgi
	] [
		page_content: none
	]
	; si chargement réussit
	if page_content [
		; essai de parsing de la page
		if not parse load/markup page_content [
			thru </FORM> thru </TR> 2 [thru tag!] set href tag!
			6 [copy text thru </td> (append topic clean text) any string!] 
			to end
		][
			print "Erreur de parsing de RebelBB. Surveillance stopée." halt
		]
		; composition du titre du dernier post (avec date et auteur)
		new: rejoin [topic/1 " (" topic/2 ") from " topic/5]
		; hyperlien du dernier post
		href: to-url fourth parse href {" }
		; Si la sauvegarde est vide, on la remplit avec le nouveau titre
		if empty? sav [sav: new]
		; Si le nouveau titre est différent de la sauvegarde, on affiche le fenêtre d'alerte
		if new <> sav [
			set-face msg new 
			view/new lay
		]
	]
	; Attente
	wait timer
]
Philippe5-Oct-2007/13:36:42+2:00
Pour le test.
guest25-Oct-2007/17:50:05+2:00
Merci pour le boulot Goldevil !!!

Base de reflexion:
Pourquoi ne pas ajouter la possibilité de scanner plusieurs sites par le même script.
Je propose donc d'externaliser le paramétrage de chaque site dans un sous répertoire /sites

par exemple pour le forum RebelBB, on pourrait avoir le fichier de configuration suivant.

%RebelBB.conf
[

;(obligatoire) nom du Site
site: "RebelBB"

; (obligatoire) url de récupération des données XML à parser (html,RSS, ou autre)
url: http://www.digicamsoft.com/cgi-bin/rebelBB.cgi


; (obligatoire) timer
timer: 0:05:00

;(optionnel) url de vérification pour savoir si les données ont été modifiée
;On effectuera un simple info? sur cette url pour savoir si le site a été modifié.
;Par défaut contient (false) pas de vérification préalable.

;check: false   ; pas de vérification préalable
;check: url     ; Si la variable url contient une page statique, alors le check (info?) peut être fait sur la même page.

;(optionnel) fonction de formatage des données récupérées lors du parsing
;Par défaut toutes les données extraites par le parser sont concaténées (form).
format: does [rejoin [Topic " (" replies ") from:" from]]


;(Obligatoire et toujours situé en fin de config) 
;Parser de type block!: contient la règle de parsing dans un dialecte spécifique 
;la règle ne peut contenir que des TAG! et des variables définies localement

topic: none
replies: none
from: none
[
        </FORM>                 ;positionnement (thru </FORM>) 
        </TR>                   ;positionnement (thru </TR>)
        HREF                    ;mot clé spécial: récupère le contenu href de la première balise <A> rencontrée
        <TD> topic </TD>        ;alimente la variable topic avec contenu de la première balise <TD></TD> rencontrée
        <TD> replies </TD>      ;idem mais alimente la variable replies
        </TD>                   ;ne traite pas la balise <TD></TD> suivante (thru </TD>)
        </TD>                   ;idem
        <TD> from </TD>         ;alimente la variable from avec contenu de la première balise <TD></TD> rencontrée
]



Voilà c'est une idée, qu'en pensez vous ?
guest25-Oct-2007/23:59:29+2:00
Re
D'habitude je poste jamais des trucs pas finis (seulement des trucs pas testés) mais là c'est le weekend et je n'aurais pas accès au net.
Donc en attendant je vous poste l'état des travaux.

Ca commence par le fichier de conf que j'ai légèrement remanié:

;(facultatif) Etat du parseur par défaut state: 'active
;le programme de surveillance ne prend pas en compte les sites dans un état différent de 'active 
;State: 'active

;(obligatoire) nom du Site
site: "RebelBB"

; (obligatoire) url de récupération des données XML à parser (html,RSS, ou autre)
; On peut aussi indiquer un file! (pratique pour les tests, c'est ça le Rebol Powaa !!!)
url: http://www.digicamsoft.com/cgi-bin/rebelBB.cgi


; (obligatoire) timer
timer: 0:05:00

;(optionnel) url de vérification (ou file!) pour savoir si les données ont été modifiée
;La fonction info? est invoquée sur cette url pour savoir si le site a été modifié.
;Par défaut contient (false) pas de vérification préalable.
;check: false   ; pas de vérification préalable
;check: url     ; Si la variable  url contient déjà une page statique, alors le check peut être fait sur la même page 
                ; Dans tous les cas il faut indiquer une url statique sinon ça sert à rien autant le laisser à (false)

;(optionnel) block de formatage des données récupérées lors du parsing
;Par défaut toutes les données extraites par le parser sont concaténées (form).
format: [Site ": " Topic " (" replies ") from:" from]


;(Obligatoire) Parseur de type block!: contient la règle de parsing dans un dialecte spécifique 
;Le parseur ne peut contenir que des TAG! et des noms de variable.
;Les variables ont leur propre contexte, cela signifie qu'on peut utiliser n'importe quel nom sans limitation.
;(y compris des noms déjà définis dans le fichier de configuration, comme url ou site)
; Le seul nom réservé est HREF.

parser: [
        </FORM>                 ;positionnement (thru </FORM>) 
        </TR>                   ;positionnement (thru </TR>)
        HREF                    ;mot clé réservé: récupère le contenu href de la première balise <A> rencontrée
        			;ou de la première balise <link> si il s'agit d'un flux RSS
        <TD> topic </TD>        ;alimente la variable topic avec contenu de la première balise <TD></TD> rencontrée
        <TD> replies </TD>      ;idem mais alimente la variable replies
        </TD>                   ;ne traite pas la balise <TD></TD> suivante (thru </TD>)
        </TD>                   ;idem
        <TD> from </TD>         ;alimente la variable from avec contenu de la première balise <TD></TD> rencontrée
]


Puis ça continue avec le loader qui a pour fonction de contruire un parseur avec les données d'un fichier de conf.
(c'est pas testé, ni fini, donc si y'en a qui se font chier ce weekend, faut pas hésiter...)

REBOL []

; fonction envoie message d'erreur 
signal: func [msg][err?: true print reform ["**" reduce msg]]

; fonction de diagnostique
Warn: func [blk /quit /local state][
        while [not tail? blk][
                set [state blk] do/next blk 
                unless state [signal blk/1 if quit [throw]]
                blk: next blk 
        ]
]

;prototype du fichier de configuration
proto-conf: make object! [
        state: 'active
        site: url: timer: href: parser: format: none 
        check: false
]

tag: Stag: err?: none

; Récupération du lien href à partir d'une balise <a> (html) ou <link> (RSS)
_HREF: [  thru <link> set href </link> (href: attempt [to-url trim/lines href]) 
        | some [set tag tag! (
                stop: either "A" = first href: parse tag none [
                        href: attempt [to-url trim/lines select href "href"] 
                        none
                ][[end skip]]
            ) stop
            | skip
          ]
      ]
      
; Recherche de balise ouvrante polymorphe: Si la variable Stag contient <a> alors Stag? est vrai
; si la balise tag commence par <a ...> 
Stag?: [set tag tag! (stop: either (first parse Stag none) = first parse tag none [none][[end skip]]) stop]

; renvoie une règle de parsing différente selon que tag est une balise ouvrante ou fermante.
rule-tag: func [tag][
        either #"/" = first tag [reduce ['thru tag]][
                compose [(to-paren compose [Stag: (tag)]) some [Stag? break | skip]]
        ]
]

;fonction d'initialisation appelée pour chaque fichier de configuration
;renvoie un objet ou (false) si il y'a des anomalies.
load-conf: func [file [file!]
        /local out wrd locals conf
][
        err?: none
        catch [
                warn/quit [
                  attempt [conf: make proto-conf load file]     ["le fichier de conf:" file "n'est pas au bon format"]
                  conf/state = 'active                          ["Le site " conf/site "est inactivé"] 
                  all [string? conf/site not empty? conf/site]  "site: doit être de type string!"
                  any [url? conf/url file? conf/url]            "url: doit être de type url! ou file!"
                  any [not conf/check file? conf/check url? conf/check] "check: doit être de type url! ou file!"
                  all [time? conf/timer conf/timer > 00:01:00]  "timer: doit être de type time! et supérieur à 00:01:00"
                  any [none? conf/format block? conf/format]   "format doit être de type block!"
                ]
                
                ;Création de la liste des variables locales utilisées dans le parseur
                locals: clear []
                parse conf/parser [some [set var word! (append locals to-set-word var) | skip]]
                locals: make object! append locals 'none
                
                ; localisation des variables utilisées par le parser
                conf/parser: bind conf/parser in locals 'self 

                ; Construction de la fonction format 
                locals: remove-each var cp conf/parser [any [not word? var var = 'href]]
                if none? conf/format [conf/format: append compose ["site:" (in conf 'site)] locals]
                conf/format: does conf/format        

                ;reconstruction d'un parseur compatible Rebol
                out: clear []
                parse conf/parser [
                        some [
                                 set wrd ['| | 'some | 'skip | 'any | 'opt | 'break | 'set | 'copy] 
                                        (signal ["La commande" wrd "n'est pas admise par le parser"])
                                | 'HREF (append out '_HREF)
                                | set var word! set tag tag! (
                                        append out reduce ['copy var rule-tag tag to-paren compose/deep [set [(var)] clean (var)]]
                                )
                                | set tag tag! (append out rule-tag tag)
                                | set wrd any-type! (signal ["La donnée" wrd "n'est pas admise par le parser"])
                        ]
                ]
                conf/parser: append out [to end]
        ] 
        if err? [return false]
        conf
]

BB: load-conf %rebelBB.conf
?? BB
halt
guest29-Oct-2007/0:27:38+2:00
Bon, je pense avoir bien avancé.

Le fichiers de configurations sont à placer dans un sous répertoire %sites/.
Je vous fournis 3 exemples de fichier de configuration
pour 3 sites différents.
Celui concernant le blog de Carl et qui n'a aucun intérêt (vu que Carl modifie son blog 3 fois par an) est juste là pour illustrer le fonctionnement avec un flux RSS (en fait c'est pareil que pour du html mais ça je l'avais déjà annoncé).

A noter que l'on peut spécifier des fichiers comme url de site (en local donc).
Ca permet de réduire le timer à 1 ou 2 secondes seulement pour tester plus facilement.

Ca me fait penser que cette outil pourrait aussi servir à surveiller n'importe quel type de fichiers (ou des logs) sur un réseau.
Si ça intéresse quelqu'un, faudra bosser sur la notion de parseur associé à un fichier de conf car pour l'instant ça n'accepte que des fichiers XML en entrée.

Il reste à trouver un bon design pour la fenêtre d'alerte, car je ne pense pas que l'actuelle soit idéale pour gérer plusieurs sites en Alerte simultanément (actuellement chaque nouvelle alerte remplace la précédente).

Dans ce but, j'ai placé les fonctions de layoutage à la fin du script pour faciliter la tâche aux courageux.
(voir: hide-all, activate et le layout lay)


REBOL [
        Title: "VerifXML"
        Date: 08-10-2007
        Name: "verifXML.r"
        
        Version: 1.0.0

        Author: "Guest2"
        Rights:  "Public Domain"
        
        Purpose: { 
            This software runs hidden and alert user when a list of sites is updated.
            Each Site description is externalized in a .conf file in a sub-directory %sites/
              %sites/
                 |
                 *--- Site1.conf
                 *--- Site2.conf
            See RebelBB.conf for a complete description of a configuration file.
        }
        
        History: [
                1.0.0 [08-10-2007 "First release" "Guest2"]
        ]
]

; fonction envoie message d'erreur 
signal: func [msg][err?: true print reform ["**" reduce msg]]

; fonction de diagnostique
Warn: func [blk /quit /local state][
        while [not tail? blk][
                set [state blk] do/next blk 
                unless state [signal blk/1 if quit [throw]]
                blk: next blk 
        ]
]

; fonction de clignotement pour les boutons 
blink: func [face][
        face/feel: make face/feel [
                cue: func [face][face/effect/2: first reverse [red blue]]
        ]
]
;prototype du fichier de configuration
proto-conf: make object! [
        state: 'active
        site: url: timer: href: parser: format: locals: sav: none 
        check: false
]

href: tag: Stag: err?: pos: none

; Récupération du lien href à partir d'une balise <a> (html) ou <link> (RSS)
_HREF: [  pos: [
        (href: none) thru <link> set href string! </link> (href: attempt [to-url trim/lines href]) 
                | some [set tag tag! (
                        stop: either "A" = first href: parse tag " =" [
                                href: attempt [to-url trim/lines select href "href"] 
                                'break
                        ][[end skip]]
                    ) stop
                    | skip
                  ]
        ] :pos
      ]
      
; Recherche de balise ouvrante polymorphe: Si la variable Stag contient <a> alors Stag? est vrai
; si la balise tag commence par <a ...> 
Stag?: [set tag tag! (stop: either (first parse Stag none) = first parse tag none [none][[end skip]]) stop]

; renvoie une règle de parsing différente selon que tag est une balise ouvrante ou fermante.
rule-tag: func [tag][
        either #"/" = first tag [reduce ['thru tag]][
                compose [(to-paren compose [Stag: (tag)]) some [Stag? break | skip]]
        ]
]

;nettoyage des tag! dans un block et concaténation en un seul string!
clean: func [blk][trim/lines form remove-each token blk [tag? token ]]

;fonction d'initialisation appelée pour chaque fichier de configuration
;renvoie un objet ou (false) si il y'a des anomalies.
load-conf: func [file [file!]
        /local out wrd locals conf
][
        err?: none
        catch [
                warn/quit [
                  attempt [conf: make proto-conf load read file]     ["le fichier de conf:" file "n'est pas au bon format"]
                  conf/state = 'active                          ["Le site " conf/site "est inactivé"] 
                  all [string? conf/site not empty? conf/site]  "site: doit être de type string!"
                  any [url? conf/url file? conf/url]            "url: doit être de type url! ou file!"
                  any [not conf/check file? conf/check url? conf/check] "check: doit être de type url! ou file!"
                  all [time? conf/timer  any [
                        file? conf/url
                        conf/timer > 00:01:00
                        ]
                  ]  "timer: doit être de type time! et supérieur à 00:01:00"
                  any [none? conf/format block? conf/format]   "format doit être de type block!"
                ]
                
                ;Création de la liste des variables locales utilisées dans le parseur
                conf/locals: cp []
                parse conf/parser [some ['HREF | set var word! (append conf/locals to-set-word var) | skip]]
                conf/locals: make object! append conf/locals 'none
                
                ; localisation des variables utilisées par le parser
                conf/parser: bind/copy conf/parser in conf/locals 'self 

                ; Construction de la fonction format 
                if none? conf/format [
                        locals: remove-each var cp conf/parser [any [not word? var var = 'href]]
                        forskip locals 2 [insert locals "-"]
                        conf/format: append reduce [in conf 'site] head locals
                ]
                conf/format: does append/only cp [rejoin] bind/copy conf/format in conf/locals 'self

                ;reconstruction d'un parseur compatible Rebol
                out: clear []
                parse conf/parser [
                        some [
                                 set wrd ['| | 'some | 'skip | 'any | 'opt | 'break | 'set | 'copy] 
                                        (signal ["La commande" wrd "n'est pas admise par le parser"])
                                | 'HREF (append out reduce ['_HREF to-paren reduce [to-set-word (in conf 'href) 'href]])
                                | set var word! set tag tag! (
                                        append out reduce [
                                                'copy var rule-tag tag 
                                                to-paren compose/deep [set [(var)] clean (var)]
                                        ]
                                )
                                | set tag tag! (append out rule-tag tag)
                                | set wrd paren! (append/only out wrd)
                                | set wrd any-type! (signal ["La donnée" wrd "n'est pas admise par le parser"])
                        ]
                ]
                conf/parser: cp append out [to end]
        ] 
        if err? [return false]
        conf
]

; fonction principale (avec boucle forever)
start: func [ /local files site timer new error] [
        catch [
                handler: clear []
                warn/quit [
                        dir? %sites ["Le répertoire de configuration %sites n'existe pas dans" what-dir]
                        not empty? files: remove-each file read %sites/  [
                                "conf" <> last parse file "."
                        ] "Aucun fichier de configuration dans le répertoire %sites/"
                ]
                print': :print
                print: func [msg][
                        append log/text join reform msg newline 
                        log/para/scroll: 0x1 * (log/size - size-text log)    ;scroll text in area
                        show log wait 0.03
                ]
                view/new layout [
                        TITLE "Démarrage surveillance de sites" red
                        log: area "" across
                        cont: btn "Continue" beige [unview/all] btn "Quit" beige [quit] 
                        do [blink cont]
                ]
                error: false
                foreach file files [
                        print ["Loading configuration file" file]
                        either object? site: load-conf join %sites/ file [
                                append handler reduce [0:0 site]
                        ][
                                print ["Le chargement de" file " a échoué"]
                                error: true
                        ]
                ]
                print: :print'
                warn/quit [not empty? handler "Tous les sites sont inactifs, pas de surveillance possible"]
                either not error [
                        wait 2 unview/all        ;Pas d'erreurs, 2 secondes d'attente et la dialog se ferme
                ][
                        cont/rate: 3 show cont   ;fait clignoter le bouton "continue" 
                        do-events
                ]
                forever [
                        ;les sites sont placés dans une pile triée par timer croissant
                        sort/skip handler 2 ; 
                        timer: handler/1 site: handler/2
                        remove/part handler 2
                        forskip handler 2 [handler/1: handler/1 - timer]
                        append handler: head handler reduce [site/timer site]
                        
                        wait timer
                        
                        attempt [
                                parse load/markup read site/url site/parser
                                new: site/format 
                                unless site/sav [site/sav: new]
                                if site/sav <> new [activate site]
                        ]
                ]
        ]
]

; cache la fenêtre d'alerte 
hide-all: does [
        unview/all
        foreach [timer site] handler [site/sav: site/format]
]

; active la fenêtre d'alerte
activate: func [site][
        if msg/text <> site/format [unview/all]
        msg/href: site/href
        msg/text: site/format
        view/new lay
]

; layout de la fenêtre d'alerte
lay: layout/tight [
        across space 0x0 
        
        msg: btn rate 1 [
                if face/href [browse face/href]
                hide-all
        ] red 350 with [href: none]
        do [blink msg]   ;clignotement du bouton
        
        btn "Hide" [hide-all]
        btn "Quit" [quit]
]

start
halt


Fichier de conf RebelBB.conf
;(facultatif) Etat du parseur par défaut state: 'active
;le programme de surveillance ne prend pas en compte les sites dans un état différent de 'active 
;State: 'active

;(obligatoire) nom du Site
site: "RebelBB"

; (obligatoire) url de récupération des données XML à parser (html,RSS, ou autre)
; On peut aussi indiquer un file! (pratique pour les tests, c'est ça le Rebol Powaa !!!)
;url: %forumREBOL.htm
url: http://www.digicamsoft.com/cgi-bin/rebelBB.cgi


; (obligatoire) timer
timer: 0:02

;(optionnel) url de vérification (ou file!) pour savoir si les données ont été modifiée
;La fonction info? est invoquée sur cette url pour savoir si le site a été modifié.
;Par défaut contient (false) pas de vérification préalable.
;check: false   ; pas de vérification préalable
;check: url     ; Si la variable  url contient déjà une page statique, alors le check peut être fait sur la même page 
                ; Dans tous les cas il faut indiquer une url statique sinon ça sert à rien autant le laisser à (false)

;(optionnel) block de formatage des données récupérées lors du parsing
;Par défaut toutes les données extraites par le parser sont concaténées (form).
format: [Site ": " Topic " (" replies ") from: " from]


;(Obligatoire) Parseur de type block!: contient la règle de parsing dans un dialecte spécifique 
;Le parseur ne peut contenir que des TAG! et des noms de variable.
;Les variables ont leur propre contexte, cela signifie qu'on peut utiliser n'importe quel nom sans limitation.
;(y compris des noms déjà définis dans le fichier de configuration, comme url ou site)
; Le seul nom réservé est HREF.

parser: [
        </FORM>                 ;positionnement (thru </FORM>) 
        </TR>                   ;positionnement (thru </TR>)
        HREF                    ;mot clé réservé: récupère le contenu href de la première balise <A> rencontrée
                                ;ou de la première balise <link> si il s'agit d'un flux RSS
        <TD> topic </TD>        ;alimente la variable topic avec contenu de la première balise <TD></TD> rencontrée
           ;(?? topic)          ;Il est possible d'insérer de blocks action de type paren! 
                                ;pour une trace pas exemple, ou un reformatage de variable
        <TD> replies </TD>      ;idem mais alimente la variable replies
        </TD>                   ;ne traite pas la balise <TD></TD> suivante (thru </TD>)
        </TD>                   ;idem
        <TD> from </TD>         ;alimente la variable from avec contenu de la première balise <TD></TD> rencontrée
]



Rebol Mailing List.conf
site: "Rebol ML"
;url: %MailingList.htm
url: http://www.rebol.org/cgi-bin/cgiwrap/rebol/ml-month-index.r
timer: 0:05
format: [site ": " msg " from: " any [attempt [first parse from ":"] from]]
parser: [
 	</TABLE> 								
 	</TR> </TR> </TD> 							
 	<TD> from </TD>    ;adresse e-mail au format  ***::**::***
 	HREF 
 	<TD> msg </TD>
]



Carl's Blog.conf
site: "Carl's blog"
;url: %carl-rss.xml
url: http://www.rebol.com/article/carl-rss.xml
timer: 5:0:0    ; mouais c'est pas souvent donc c'est juste pour l'exemple
parser: [
 	</title> 		;skip first title							
 	<title> title </title> 
 	HREF 
]

Login required to Post.


Powered by RebelBB and REBOL 2.7.8.4.2