From 8d829e2025e3c3d31e1e8a3c77aca135d8011b2f Mon Sep 17 00:00:00 2001 From: Martin Kralik Date: Thu, 22 Nov 2012 16:30:35 +0100 Subject: [PATCH 1/6] Ked skonci playlist novy nacitame zo suboru. Teda nielen ked sa zmeni schedule, ale vzdy ked sa minie playlist. Mohlo by to fixnut nejake race conditiony ked sa chcel hrat playlist s obrazkami ktore este nestihli byt prekodovane na video. Aj ked by to imho nemalo robit problem. --- server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/server.py b/server.py index 1febd6e..fc27acd 100644 --- a/server.py +++ b/server.py @@ -47,6 +47,7 @@ def process_schedule(self, schedule): pass def get_playlist(self): + self.process_schedule(read_text_file(self.schedule_file)) today = date.today() return [video.filename for video in self.videos if video.start_date <= today and video.end_date >= today] From ceb14e89d367b404b467537bbe99e06fe9a67ad4 Mon Sep 17 00:00:00 2001 From: Martin Kralik Date: Thu, 22 Nov 2012 16:38:34 +0100 Subject: [PATCH 2/6] Zmena parametrov pre mplayer. S nastavenim mplayeru na fullscreen na telke boli problemy, tak sme to nejak hackli (aj) pomocou parametrov mplayeru. --- infoboard/videoplayer.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/infoboard/videoplayer.py b/infoboard/videoplayer.py index 87042fc..ce35d54 100644 --- a/infoboard/videoplayer.py +++ b/infoboard/videoplayer.py @@ -10,8 +10,12 @@ def __init__(self): '-slave', # don't quit when there is no file to play '-idle', - # fullscreen - '-fs', + # Fullscreen is hard to setup on second screen, + # which is currently our use case. + # We use fixed window size instead + # and maximize it with external program "maximus". + # '-fs', + '-zoom', '-x', '1920', '-y', '1080', # no way to control mplayer in other way '-input', 'nodefault-bindings:conf=/dev/null', # reuse same window for playing all videos From 3d5624a88c7cb45c4ab209494cdd2a77a8f7e4a2 Mon Sep 17 00:00:00 2001 From: Martin Kralik Date: Mon, 26 Nov 2012 01:09:49 +0100 Subject: [PATCH 3/6] Viac schedule suborov. Schedule sa najnovsie nacitava zo vsetkych .txt suborov z adresaru schedule. Ich spracovanie by chcelo refaktoring. On file change staci robit encoding obrazkov. --- infoboard/watcher.py | 7 ++++--- server.py | 33 +++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/infoboard/watcher.py b/infoboard/watcher.py index 1ea36b5..3eabe4f 100644 --- a/infoboard/watcher.py +++ b/infoboard/watcher.py @@ -4,12 +4,13 @@ class Watcher: """Executes provided function when chosen file changes.""" - def __init__(self, filename, folder, callback=lambda x: None): + def __init__(self, folder, callback=lambda x: None): self.callback = callback event_handler = FileSystemEventHandler() def handler(e): - if e.src_path.endswith('/' + filename): - self.callback(read_text_file(e.src_path)) + path = e.src_path + if path.endswith('.txt'): + self.callback(path, read_text_file(path)) # this happens also when file is created event_handler.on_modified = handler self.observer = Observer() diff --git a/server.py b/server.py index fc27acd..25114d1 100644 --- a/server.py +++ b/server.py @@ -1,8 +1,11 @@ +import glob import sys import time import re import logging import infoboard +import itertools +import os from datetime import date from infoboard.video import Video from infoboard.videoplayer import VideoPlayer @@ -11,13 +14,13 @@ class Infoboard: - def __init__(self, watcher, player, schedule_file): - self.videos = [] + def __init__(self, watcher, player, schedule_dir): + self.videos = {} self._setup_logging() watcher.set_callback(self.process_schedule) self.watcher = watcher self.player = player - self.schedule_file = schedule_file + self.schedule_dir = schedule_dir def _setup_logging(self): logger = logging.getLogger('infoboard') @@ -32,30 +35,36 @@ def _setup_logging(self): logger.addHandler(ch) def run(self): - self.process_schedule(read_text_file(self.schedule_file)) + self.process_all_schedules() self.watcher.start() self.player.play(self) - def process_schedule(self, schedule): - self.videos = [] + def process_schedule(self, key, schedule): + self.videos[key] = [] for line in schedule.split('\n'): line = line.strip() if (not line) or line.startswith('#'): continue try: - self.videos.append(infoboard.video.Video(line)) + self.videos[key].append(infoboard.video.Video(line)) except ValueError: pass + def process_all_schedules(self): + for filename in glob.glob(self.schedule_dir + '/*.txt'): + filename = os.path.abspath(filename) + self.process_schedule(filename, read_text_file(filename)) + + def get_playlist(self): - self.process_schedule(read_text_file(self.schedule_file)) + self.process_all_schedules() today = date.today() - return [video.filename for video in self.videos + all_videos = itertools.chain.from_iterable(self.videos.values()) + return [video.filename for video in all_videos if video.start_date <= today and video.end_date >= today] if __name__ == "__main__": - schedule_file = 'schedule.txt' v = infoboard.videoplayer.VideoPlayer() - w = infoboard.watcher.Watcher(schedule_file, 'schedule') - ib = Infoboard(w, v, 'schedule/'+schedule_file) + w = infoboard.watcher.Watcher('schedule') + ib = Infoboard(w, v, 'schedule') ib.run() From a2803eb2f5551a6008e19e4c66bbdd394743235e Mon Sep 17 00:00:00 2001 From: Martin Kralik Date: Mon, 26 Nov 2012 02:16:19 +0100 Subject: [PATCH 4/6] Video ktore sa prave enkoduje je ulozene v /tmp. Po dokonceni enkodovania sa presunie do priecinku videos. Tato zmena ma zabranit teoretickemu pokusu o prehratie nekompletneho videa. V pythone nejdu nejak pekne retazit procesy, preto som pustenie dvoch po sebe iducich procesov musel urobit v novom procese. --- infoboard/video.py | 54 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/infoboard/video.py b/infoboard/video.py index c13f918..5585090 100644 --- a/infoboard/video.py +++ b/infoboard/video.py @@ -1,9 +1,26 @@ import os.path import logging import subprocess +import multiprocessing from datetime import date from subprocess import PIPE +def _runInSequence(first_process, second_process): + """ + Spawns new process which manages to run two processes in sequence. + These two are specified by subprocess.Popen args argument. + """ + def runInProcess(first_process, second_process): + proc = subprocess.Popen(first_process) + proc.wait() + subprocess.Popen(second_process) + return + process = multiprocessing.Process(target=runInProcess, + args=(first_process, second_process)) + process.start() + # returns immediately after the process starts + return process + class Video: """Parses line containing description of a video. @@ -49,19 +66,24 @@ def __init__(self, line): def _from_image(self, filename, duration): """Created video from picture with requested duration unless it already exists.""" - if not os.path.isfile('videos/' + filename + '.' + duration + '.avi'): - command = ['/usr/bin/mencoder', - # reads commands from stdin - 'mf://pictures/' + filename, - # don't quit when there is no file to play - '-o', 'videos/' + filename + '.' + duration + '.avi', - # fullscreen - '-ovc', 'lavc', - # no way to control mplayer in other way - '-lavcopts', 'vcodec=mjpeg', - # reuse same window for playing all videos - '-fps', '1/' + duration, - # don't print progress - '-ofps', '30' - ] - self.mp_process = subprocess.Popen(command) + videoname = filename + '.' + duration + '.avi' + if os.path.isfile('/tmp/' + videoname): + return + if os.path.isfile('videos/' + videoname): + return + encode = ['/usr/bin/mencoder', + # reads commands from stdin + 'mf://pictures/' + filename, + # don't quit when there is no file to play + '-o', '/tmp/' + videoname, + # fullscreen + '-ovc', 'lavc', + # no way to control mplayer in other way + '-lavcopts', 'vcodec=mjpeg', + # reuse same window for playing all videos + '-fps', '1/' + duration, + # don't print progress + '-ofps', '30' + ] + move_product = ['/bin/mv', '/tmp/' + videoname, 'videos/' + videoname] + _runInSequence(encode, move_product) From f51ef908cb800985977553a7a1c802a95b660c11 Mon Sep 17 00:00:00 2001 From: Martin Kralik Date: Mon, 26 Nov 2012 02:29:49 +0100 Subject: [PATCH 5/6] Nesnazime sa prehrat este neenkodovane videa. Tento bug sposoboval, ze sa mplayer uplne zasekol. Teraz ak natrafime na obrazok, ktory este nema vyrobene video, tak ho dame vyrobit a nedame ho do playlistu. --- infoboard/video.py | 1 + 1 file changed, 1 insertion(+) diff --git a/infoboard/video.py b/infoboard/video.py index 5585090..4f35999 100644 --- a/infoboard/video.py +++ b/infoboard/video.py @@ -87,3 +87,4 @@ def _from_image(self, filename, duration): ] move_product = ['/bin/mv', '/tmp/' + videoname, 'videos/' + videoname] _runInSequence(encode, move_product) + raise ValueError('Picture "{0}" is not yet encoded'.format(filename)) From 1d949763e66686005571d9963e915786a16ff92c Mon Sep 17 00:00:00 2001 From: Martin Kralik Date: Mon, 26 Nov 2012 03:02:01 +0100 Subject: [PATCH 6/6] Schedule subory su do playlistu zaradene podla ich nazvu podla abecedy. --- server.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server.py b/server.py index 25114d1..9a7b720 100644 --- a/server.py +++ b/server.py @@ -4,7 +4,6 @@ import re import logging import infoboard -import itertools import os from datetime import date from infoboard.video import Video @@ -58,7 +57,9 @@ def process_all_schedules(self): def get_playlist(self): self.process_all_schedules() today = date.today() - all_videos = itertools.chain.from_iterable(self.videos.values()) + all_videos = [] + for key in sorted(self.videos.keys()): + all_videos += self.videos[key] return [video.filename for video in all_videos if video.start_date <= today and video.end_date >= today]