From a0416f366189ddd12dec5a41b1062d581a504c4b Mon Sep 17 00:00:00 2001 From: Doug Le Tough Date: Mon, 26 Aug 2019 22:21:55 +1100 Subject: [PATCH] v1.0 --- README.md | 43 ++++++++++++----- logstreamer.py | 128 ++++++++++++++++++++++++++++++++----------------- plip | 0 3 files changed, 115 insertions(+), 56 deletions(-) create mode 100644 plip diff --git a/README.md b/README.md index dd93cb1..6fc5e11 100644 --- a/README.md +++ b/README.md @@ -6,20 +6,41 @@ LogStreamer est un logiciel permettant la diffusion sonore d'un fichier via un s ## Prérequis * python3 -* pigtail -``` -pip3 install pigtail -``` +* oggenc ## Utilisation -* Ajuster les valeurs des constantes LOG et WAV_OUTPUT en fonction des besoins - * LOG: Le log à jouer - * WAV_OUTPUT: Le fichier wav de sortie - * MAX_DURATION: La durée maximale d'une note - * EXCLUDE: Les caractères dont les valeurs sont ajoutées à cette liste ne seront pas traités -* Exécuter ```python3 logstreamer.py``` -* Lire le fichier wav résultant avec un lecteur audio supportant le format wav +``` +logstreamer.py -h + + usage: logstreamer.py [-h] --log LOG [--workdir WORKDIR] [--duration DURATION] + [--amplitude AMPLITUDE] [--framerate FRAMERATE] + [--adjust ADJUST ADJUST] + [--exclude [EXCLUDE [EXCLUDE ...]]] --host HOST --port + PORT --user USER --password PASSWORD --mount MOUNT + [--protocol PROTOCOL] + + optional arguments: + -h, --help show this help message and exit + --log LOG Le fichier de log à traiter (requis) + --workdir WORKDIR Le répertoire de travail (défaut: /tmp) + --duration DURATION La durée d'une note (défaut: 0.008) + --amplitude AMPLITUDE + Le niveau sonore (défaut: 0.5) + --framerate FRAMERATE + Le taux d'échantillonage (défaut: 44100) + --adjust ADJUST ADJUST + Facteurs d'ajustement (défaut: 5000 20000) + --exclude [EXCLUDE [EXCLUDE ...]] + Liste des caractères non traités (défaut: []) + --host HOST Server Icecast2 (requis) + --port PORT Port TCP sur lequel contacter le serveur Icecast2 + (requis) + --user USER Nom d'utilisateur (requis) + --password PASSWORD Mot de passe (requis) + --mount MOUNT Point de montage Icecast2 (requis) + --protocol PROTOCOL Protocol à utiliser (défaut: http) +``` ## TODO diff --git a/logstreamer.py b/logstreamer.py index 77dea44..3cb7f23 100755 --- a/logstreamer.py +++ b/logstreamer.py @@ -1,35 +1,13 @@ #!/bin/env python3 -""" -# Prérequis - -* python3 -* pigtail -``` -pip3 install pigtail -``` - -# Utilisation - -* Ajuster les valeurs des constantes LOG et WAV_OUTPUT en fonction des besoins - * LOG: Le log à jouer - * WAV_OUTPUT: Le fichier wav de sortie - * MAX_DURATION: La durée maximale d'une note - * EXCLUDE: Les caractères dont les valeurs sont ajoutées à cette liste ne seront pas traités -* Exécuter python3 text2wav.py -* Lire le fichier wav résultant avec un lecteur audio supportant le format wav - -""" +import os import wave import math +import shout import struct import random -from pygtail import Pygtail - -LOG = '/var/log/httpd/access_log' -WAV_OUTPUT = '/home/doug/test/test.wav' -MAX_DURATION = 0.08 -EXCLUDE = [] +import argparse +import subprocess def sine_wave(frequency=444, framerate=44100, amplitude=0.5, duration=1): """ @@ -51,25 +29,85 @@ def sine_wave(frequency=444, framerate=44100, amplitude=0.5, duration=1): return struct.pack('<{}h'.format(len(data)), *data) def notes_table(oord): - freq = math.floor(math.log(oord)*5000-20000) - duration = MAX_DURATION + freq = math.fabs(math.floor(math.log(oord)*int(args.adjust[0])-int(args.adjust[1]))) + duration = args.duration return (freq, duration) -with wave.open(WAV_OUTPUT, 'wb') as wave_file: - nchannels = 1 - sampwidth = 2 - framerate = 44100 - wave_file.setnchannels(nchannels) - wave_file.setsampwidth(sampwidth) - wave_file.setframerate(framerate) +def convert2ogg(wav_file, ogg_file): + result = subprocess.call(['oggenc', wav_file, '-o {} --utf8 -t {}'.format(ogg_file, args.log)]) + return result - try: - for line in Pygtail(LOG): - for letter in line: - oord = ord(letter) - freq, duration = notes_table(oord) - if oord not in EXCLUDE: - print("Caractère: {} | Ord: {} | Fréquence: {} | Durée: {}".format(letter, oord, freq, duration)) - wave_file.writeframes(sine_wave(frequency=freq, duration=duration)) - except Exception as e: - print('\033[91m{}\033[0m'.format(e)) +def push_ogg(ogg_file): + icecast = shout.Shout() + icecast.host = args.host + icecast.port = args.port + icecast.user = args.user + icecast.password = args.password + icecast.mount = args.mount + icecast.protocol = args.protocol + icecast.format = 'ogg' + print("Connecting to {}://{}:{}/{}".format(args.protocol, args.host, args.port, args.mount)) + icecast.open() + with open(ogg_file, 'rb') as ogg: + total = 0 + print("- Reading 4096 bytes") + new_buff = ogg.read(4096) + while True: + cur_buff = new_buff + print("- Reading next 4096 bytes") + new_buff = ogg.read(4096) + total += len(cur_buff) + if len(cur_buff) == 0: + print(" - Buffer is empty: EOF") + print(" - Sent: {} bytes".format(total)) + break + print("- Sending 4096 bytes") + icecast.send(cur_buff) + icecast.sync() + +def main(): + wav_output = "{}.wav".format(os.path.basename(args.log).split('.')[0]) + wav_output = os.path.join(args.workdir, wav_output) + ogg_output = "{}.ogg".format(os.path.basename(args.log).split('.')[0]) + ogg_output = os.path.join(args.workdir, ogg_output) + + with wave.open(wav_output, 'wb') as wave_file: + nchannels = 1 + sampwidth = 2 + framerate = args.framerate + wave_file.setnchannels(nchannels) + wave_file.setsampwidth(sampwidth) + wave_file.setframerate(framerate) + try: + with open(args.log, 'r') as log: + for letter in log.read(): + oord = ord(letter) + freq, duration = notes_table(oord) + if oord not in args.exclude: + print("Caractère: {} | Ord: {} | Fréquence: {} | Durée: {}".format(letter, oord, freq, duration)) + wave_file.writeframes(sine_wave(frequency=freq, duration=duration)) + result = convert2ogg(wav_output, ogg_output) + if result == 0: + push_ogg(ogg_output) + else: + raise Exception("Erreur lors de la conversion en OGG: {}".format(result)) + except Exception as e: + print('\033[91m{}\033[0m'.format(e)) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--log', help='Le fichier de log à traiter (requis)', type=str, required=True) + parser.add_argument('--workdir', help='Le répertoire de travail (défaut: /tmp)', type=str, default='/tmp') + parser.add_argument('--duration', help="La durée d'une note (défaut: 0.008)", type=float, default=0.08) + parser.add_argument('--amplitude', help="Le niveau sonore (défaut: 0.5)", type=float, default=0.5) + parser.add_argument('--framerate', help="Le taux d'échantillonage (défaut: 44100)", type=int, default=44100) + parser.add_argument('--adjust', help="Facteurs d'ajustement (défaut: 5000 20000)", nargs=2, default=[5000, 20000]) + parser.add_argument('--exclude', help="Liste des caractères non traités (défaut: [])", nargs="*", default=[]) + parser.add_argument('--host', help="Server Icecast2 (requis)", type=str, required=True) + parser.add_argument('--port', help="Port TCP sur lequel contacter le serveur Icecast2 (requis)", type=int, required=True) + parser.add_argument('--user', help="Nom d'utilisateur (requis)", type=str, required=True) + parser.add_argument('--password', help="Mot de passe (requis)", type=str, required=True) + parser.add_argument('--mount', help="Point de montage Icecast2 (requis)", type=str, required=True) + parser.add_argument('--protocol', help="Protocol à utiliser (défaut: http)", type=str, default='http') + args = parser.parse_args() + main() diff --git a/plip b/plip new file mode 100644 index 0000000..e69de29