Articles plus anciens

Pour ma veille je suis 281 flux RSS (après avoir fait du ménage ce matin), or il existe quelques sites qui ne proposent qu’une version tronquée des articles, par exemple Numérama :

 

Je comprends leurs motivations mais ça m’enquiquine (pour être poli).

Je me suis donc mis en quête d’un service permettant d’avoir le flux complet à partir d’un flux tronqué.

J’ai tout d’abord trouvé le service Full Text RSS Feed Builder, le premier test n’a pas été concluant le jour même mais semble avoir fonctionné les jours suivants (une histoire de cache dans Google Reader ?)

Mais qu’importe puisqu’entre temps je me suis souvenu que j’avais bookmarké un article décrivant un script remplissant le même rôle et pouvant être auto-hébergéfivefilters : RSS avec les articles complets

Le service s’appelle Create Full-Text Feeds de fivefilters.org

Par contre depuis que Tom@mplius à publié son article (Mai 2010) les conditions de distributions semblent avoir changées, le site fivefilters.org ne propose plus que son service en ligne gratuit mais limité (3 articles max par flux) et il faut payer (20 €) pour avoir les sources et l’auto-héberger.

En cherchant un peu j’ai trouvé le site sur lequel les sources de l’ancienne version sont distribués : http://code.fivefilters.org/p/full-text-rss/

Il s’agit de la version 2.7 et en payant on a la version 2.9, à vous de voir si les changements entre ces 2 versions vous sont nécessaires, en ce qui me me concerne la 2.7 me convient.

Pour l’installation, c’est un peu comme tous les services web :

  • Téléchargement des sources
  • Décompression dans un répertoire de votre serveur web
  • Fixer les droits sur les fichiers pour s’assurer que c’est l’utilisateur faisant  tourner votre serveur web (www-data) qui est propriétaire des fichiers
  • Paramétrage de votre serveur web pour prendre en compte ce nouveau site

Et on peut tester en allant sur l’URL de votre serveur web :

Un peu comme service gratuit fivefilters.org on entre l’URL du flux compléter et on valide.

Par contre à la différence du service gratuit hébergé, on a accès aux options notamment le nombre d’article par flux.

Un petit test avec le flux de Numérama, résultat de la page :

 

On copie l’URL résultante et hop on ajoute le flux dans Google Reader, ça marche parfaitement….

 

J’ai ensuite effectué quelques configurations supplémentaires.

En premier lieu il faut copier le fichier config.php en custom_config.php et éditer ce dernier.

Activation du cache :

Cela se fait simplement en positionnant la variable suivante :

$options->caching = true;

Il faut ensuite créer le répertoire paramétré dans $options->cache_dir et 2 sous répertoires rss et rss-with-key en effet les sources 2.7 ne contiennent pas ces répertoires et s’assurer que ces répertoires appartiennent à l’utilisateur faisant  tourner votre serveur web (www-data).

Protection du service :

Le service fonctionne parfaitement mais je veux en protéger l’accès, en effet je ne souhaite pas que tout le monde puisse l’utiliser.

Full Text Feed contient un mécanisme de clé permettant de différencier les utilisateur avec clé de ceux sans clé (en terme de fonctionnalité), mais malgré ce qui est indiqué dans cette page, l’ajout de la variable $options->key_required à true n’oblige pas l’utilisation d’une clé

J’ai donc modifié les sources pour le permettre. Dans le fichier makefulltextfeed.php j’ai ajouté le test  suivant :

if (($options->key_required) && (!$valid_key)) {
        die('A valid key is mandatory');
}

Après le test suivant :

$valid_key = false;
if (isset($_GET['key']) && isset($_GET['hash']) && isset($options->api_keys[(int)$_GET['key']])) {
        $valid_key = ($_GET['hash'] == sha1($options->api_keys[(int)$_GET['key']].$url));
}

Dans le fichier custom_config.php on indique ensuite la/les clés valides et l’option indiquant qu’une clé est obligatoire :

$options->api_keys = array();
$options->api_keys[1] = 'xxxx';
$options->key_required = true;
15 déc 11

Le problème, j’ai la commande suivante :

 

awk -F":" '{ print "username: " $1 "\t\tuid:" $3 }' /etc/passwd

 

Que je veux définir dans un alias, comme ceci :

 

alias userlist= 'commande'

 

Le problème ma commande contient aussi bien des apostrophes (single quote) que des guillemets (quote).

Vu que j’ai pris le partie de mettre cette commande entre apostrophe, il faut que j’échappe (escape ne anglais ça sonne mieux) les apostrophes de la commande.

J’ai tenté le slash \’ et le doublement d’apostrophe  » sans succès et j’ai trouvé la (une) solution ici, il faut utiliser ‘\ »

Mon alias est donc :

 

alias userlist='awk -F":" '\''{ print "username: " $1 "\t\tuid:" $3 }'\'' /etc/passwd'

 

 

Pour info cet alias donne la liste des utilisateurs présent sur le système et leur uid :

 

username: root          uid:0
username: daemon        uid:1
username: bin           uid:2
username: sys           uid:3
username: sync          uid:4
username: games         uid:5

 

Commentaires fermés

Comme indiqué ici j’utilise le script de sebsauvage Shaarli pour stocker mes bookmarks (et peut être un jour les partager)

En attendant d’installer et d’utiliser RSSLounge (un jour je vais le tester) j’utilise Google Reader et je veux pouvoir ajouter un marque-page dans mon Shaarli directement depuis Google Reader.

Et c’est super simple.

On va dnas les paramètres de Google Reader en cliquant sur le petit engrenage en haut à droite de l’interface de Google Reader

 

Ensuite on se place sur l’onglet « Envoyer à »

 

Puis on clique sur « créer un lien personnalisé » (tout en bas)

Pour le nom on met ce que l’on veut et pour l’URL on met l’adresse de son Shaarli avec les paramètres title, url et source ainsi (à adapter) :

http://www.[votre domaine]/shaarli/index.php?post=${url}&title=${title}&source=greader

Et voila on peut revenir à l’interface de Google Reader et tout en bas des articles dans l’option « Envoyer à », votre lien Shaarli apparaît :

Edit 23/04/2012 : Modification du script pour télécharger via http au lieu de rtmp

 

Mieux vaut tard que jamais, j’ai découvert la série Bref ce week-end.

Cette série diffusé durant le grand-journal fait le buzz et est surtout très drôle, rythmé, bref superbe.

Par contre la regarder en direct pendant le grand journal, ce n’est pas possible pour moi, la regarder en différé sur le site de Canal+ non plus, il me fallait donc trouver un moyen pour la télécharger automatiquement et pouvoir la regarder tranquillement sur mon HTPC.

Il existe divers scripts et programmes pour télécharger les émissions de Canal+, je devais en trouver un qui fonctionne, qui puisse être planifié (exécuté tous les jours et qui garde en mémoire les épisode déjà téléchargés) et surtout headless (en ligne de commande).

Mon point de départ, ce thread d’Ubuntu-fr.org et j’ai trouvé mon bonheur en page 16 avec le script de vincentp010 (recopié en fin d’article)

Ce script en Python se base sur un tableau des ids des émissions à télécharger :

emissions=[
48,    # GUIGNOLS
252,   # SAV
254,   # GROLAND
201,   # ZAPPING
104# GRAND JOURNAL
249# PETIT JOURNAL
37,   # ACTION DISCRETE
39,   # LA MATINALE
47,   # PEPITES DU NET
62,   # LE BOUCAN DU JOUR
215# LE MEILLEUR DU HIER
]

Restait à trouver l’id de l’émission Bref.

Après quelques recherches infructueuses je suis tombé sur cette URL qui liste toutes les émissions de Canal+.

Bref à l’id 627, j’ai donc modifié le tableau émission ainsi :

emissions=[
627,    # BREF
]

Paramétré les chemins (penser à créer les répertoires) et nom de fichier :

homedir = os.path.expanduser('~/bin')
HISTORIQUE = homedir + "/.cplus_hist"
output_dir = "/data/downloads/videos/canalplus"

Installé flvstreamer :

sudo aptitude install flvstreamer

Pour finir le script est planifié en crontab et le boulot est fait….

 

Script de téléchargement des séries Canal+ de vincentp010 :

#!/usr/bin/python
# -*- coding:Utf-8 -*-
 
###########################################################################
# Copyright (C) 2010  La_Poigne                                           #
# This program is free software: you can redistribute it and/or modify    #
#  it under the terms of the GNU General Public License as published by   #
#  the Free Software Foundation, either version 2 of the License, or      #
#  any later version.                                                     #
# This program is distributed in the hope that it will be useful,         #
#  but WITHOUT ANY WARRANTY without even the implied warranty of          #
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          #
#  GNU General Public License for more details.                           #
# You should have received a copy of the GNU General Public License       #
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.  #
###########################################################################
#
#Script pour telecharger les emission du site canalplus.fr
#Fonctionne en theorie sur tous les OS
#
#Changelog:
#V 0.1
#21-12-2010 : Creation
#V 0.2
#22-12-2010 : Reglage probleme encodage dans fichier log
#V 0.3
#23-12-2010 : Ajout d'une option "--log" et prise en compte de l'absence du tag sous-titre
 
 
 
import os, urllib, subprocess, time, sys 
from xml.dom import minidom
 
 
# Numeros des emissions a telecharger, commentez celles que vous ne voulez pas
emissions=[
627,	# BREF
#48,    # GUIGNOLS
#252,   # SAV
#254,   # GROLAND
#201,   # ZAPPING
#104,  # GRAND JOURNAL
#249,  # PETIT JOURNAL
#37,   # ACTION DISCRETE
#39,   # LA MATINALE
#47,   # PEPITES DU NET
#62,   # LE BOUCAN DU JOUR
#215,  # LE MEILLEUR DU HIER
]
 
# Qualite de la video
#qualite = "BAS_DEBIT"
#qualite = "HAUT_DEBIT"
qualite = "HD"
 
# Repertoires (pensez a les creer avant)
homedir = os.path.expanduser('~/bin')
HISTORIQUE = homedir + "/.cplus_hist"
output_dir = "/data/downloads/videos/canalplus"
 
 
 
# Ne rien modifier sous cette ligne
# Sauf pour ameliorer le fonctionnement ;)
 
logfile = os.path.join(homedir, "canal.log")
urlXMLEmissions = "http://www.canalplus.fr/rest/bootstrap.php?/bigplayer/getMEAs/"
urlXMLVid = "http://www.canalplus.fr/rest/bootstrap.php?/bigplayer/getVideos/"
 
# Parse Mea file to get videos id
def ParseMeas(xmldoc):
   ids = []
   meas = xmldoc.getElementsByTagName('MEA')
   for i in meas:
      if i.getElementsByTagName('ID')[0].childNodes != []:
         id = i.getElementsByTagName('ID')[0].childNodes[0].nodeValue
         ids.append(id)
   return ids
 
# Parse video file to get name and url
def ParseVid(xmldoc):
   names = []
   urlVids = []
   videos = xmldoc.getElementsByTagName('VIDEO')
   for i in videos:
      titrage = i.getElementsByTagName('INFOS')[0].getElementsByTagName('TITRAGE')[0]
      if titrage.getElementsByTagName('TITRE')[0].childNodes != []:
         titre = titrage.getElementsByTagName('TITRE')[0].childNodes[0].nodeValue
         if titrage.getElementsByTagName('SOUS_TITRE')[0].childNodes != []:
            stitre = titrage.getElementsByTagName('SOUS_TITRE')[0].childNodes[0].nodeValue
            date = "_" + stitre
         else:
            date = ""
         name = titre + date
         name = name.replace(' ', '.').replace('/', '-')
         videos = i.getElementsByTagName('MEDIA')[0].getElementsByTagName('VIDEOS')[0]
         rtmp= videos.getElementsByTagName(qualite)[0].childNodes[0].nodeValue
         names.append(name)
         urlVids.append(rtmp)
   return names, urlVids
 
# Execute command and write stdout in file var
def execute(params, file):
   p = subprocess.Popen(params,stdout=file)
   p.wait()
   return p.returncode
 
def addHistory(name):
   file = open(HISTORIQUE, 'a')
   file.write(name.encode('utf-8') + '\n')
   file.close()
 
def checkHistory(name):
   findvalue = 0
   file = open(HISTORIQUE, 'r')
   for line in file:
      if line.decode('utf-8') == name + '\n':
         findvalue = 1
   file.close()
   return findvalue
 
def downXml(url):
   try:
      xmlFileSock=urllib.urlopen(url)
      xmlFile = xmlFileSock.read()
   except Exception, e:
      return 1
   try:
      xmldoc = minidom.parseString(xmlFile)
   except Exception, e:
      xmldoc = 1
   return xmldoc
 
 
if __name__ == "__main__":
 
   debug = False
   if len(sys.argv) == 2:     
     if sys.argv[1] == "--log":
        debug = True
        print "Debug ON"
        logf = open(logfile, "w")
 
   if os.path.exists(HISTORIQUE) == False:
     file = open(HISTORIQUE, 'w')
     file.close()
 
   for num in emissions:
      url = urlXMLEmissions + str(num)
      if debug:
         logf.write(time.strftime("%Y-%m-%d %H:%M:%S") + '\n')
         logf.write("Downloading " + url + '\n')
      xmldoc = downXml(url)
      if xmldoc == 1:
         print "Erreur durant la recuperation de la liste " + str(num)
         if debug:
            logf.write(url + " download error" + '\n')
      else:
         id = ParseMeas(xmldoc)
         if debug:
            logf.write("-> Ids " + str(id) + '\n')
 
         for vid in id:
            url2 = urlXMLVid + vid
            if debug:
              logf.write("Downloading " + url2 + '\n')
            xmldoc2 = downXml(url2)
            if xmldoc2 == 1:
               if debug:
                  logf.write(url2 + " download error" + '\n')
            else:
               names, urlVids = ParseVid(xmldoc2)
               if debug:
                  logf.write("--> names " + str(names) + '\n')
                  logf.write("---> urlvid " + str(urlVids) + '\n')
 
               i = 0
               loop = 0
               while i < len(names):
 
                  check = checkHistory(names[i])
                  if check == 0:
                     if debug:
                       logf.write("Try to download file ")
 
                     basename, extension = os.path.splitext(urlVids[i])
                     flvFile = os.path.join(output_dir , names[i] + extension)
                     if urlVids[i].find("rtmp")!=-1:
                        if debug:
                           logf.write("with flvstreamer" + '\n')
                        params=['flvstreamer', '-r', urlVids[i]]
                        file = open(flvFile, 'w')
                        r = execute(params, file)
                        file.close()
                     else:
                        if debug:
                           logf.write("direct download" + '\n')
                        try:
                           urllib.urlretrieve(urlVids[i], flvFile)
                           r=0
                        except Exception:
                           r=1
                     # If returncode OK, next file
                     if r == 0:
                        if debug:
                          logf.write("Download finished, add file to history " + '\n')
                        addHistory(names[i])
                        loop = 0
                        i += 1
                     else:
                        if os.path.exists(flvFile):
                           os.remove(flvFile)
                        loop += 1
                        # After 5 retry abord file
                        if loop == 5:
                           if debug:
                              logf.write("Download aborded" + '\n')
                           i += 1
                           loop = 0
                        else:
                           if debug:
                              logf.write("Download error" + '\n')
                           print "Download error, retry in 30 seconds"
                           time.sleep(30)
                  else:
                     print "File already downloaded"
                     if debug:
                       logf.write("File already downloaded" + '\n')
 
                     i += 1
 
   if debug:
      logf.close()

PS : si vous cherchez un programme avec une interface graphique qui fait la même chose et bien plus encore, il existe tvdownloader qui est parfait

flvFile = os.path.join(output_dir , names[i] + extension)
if urlVids[i].find(« rtmp »)!=-1:
if debug:
logf.write(« with flvstreamer » + ‘\n’)
params=['flvstreamer', '-r', urlVids[i]]
file = open(flvFile, ‘w’)
r = execute(params, file)
file.close()
else:
if debug:
logf.write(« direct download » + ‘\n’)
try:
urllib.urlretrieve(urlVids[i], flvFile)
r=0
except Exception:
r=1

Lorsque l’on a une base de donnée MySQL et que l’on veut l’administrer le plus souvent on installe phpMyAdmin. Or si on ne souhaite administrer cette base qu’en local (ou via le LAN) je trouve qu’installer une application web n’est pas forcément adapté et j’ai clairement une préférence pour l’installation d’un client dit « lourd »

C’est pour cela que j’installe MySQL Query Browser :

Cet outil est fourni par l’éditeur MySQL lui même.

 

Pour l’installation sur le PC client (desktop) :

sudo aptitude mysql-query-browser

Et sur le serveur il faut faire quelques paramétrages pour autoriser MySQL Query Browser à se connecter.

Éditer votre fichier my.cnf :

sudo vim /etc/mysql/my.cnf

Et commenter la ligne bind-address :

# Instead of skip-networking the default is now to listen only on
 # localhost which is more compatible and is not less secure.
 #bind-address           = 127.0.0.1
 

Il faut ensuite donner les droits à votre utilisateur distant à se connecter, ouvrir une invite de commande mysql :

mysql -u root -p
 Enter password: [votre mot de passe root]

Et lancer les commandes SQL suivante :

mysql> grant all privileges on *.* to [utilisateur souhaité]@[adresse IP de votre machine distante] identified by "[mot de passe souhaité]";
 Query OK, 0 rows affected (0.00 sec)
 
mysql> flush privileges;
 Query OK, 0 rows affected (0.00 sec)
 
mysql> quit
 Bye

Sur le client il ne vous reste plus qu’a vous connecter à MySQL Query Browser avec l’utilisateur et le mot de passe que vous venez de définir :

Rque : Pour des taches plus administratives, dans la même série il existe MySQL Administrator :

Qui s’installe avec :

sudo aptitude install mysql-admin

Rque 2 : il semblerait que ces 2 outils aient fusionnée dans un bundle MySQL Workbench (GUI Tool) mais le paquet n’est pas encore dans les dépôts