<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, sys
import cherrypy
import sqlite3
import re
import argparse
import traceback
import json
import subprocess
import threading
import time

import slideshow
from slideshow.lib import template, browser as browser_factory, slide
from slideshow.pages import instance
from slideshow.pages import slides
from slideshow.pages import maintenance
from slideshow.pages import queue
from slideshow.settings import Settings, ValidationError
from slideshow.daemon import Daemon
from slideshow.video_preview import PreviewCreator
from slideshow.event import subscribe
import slideshow.tools.ipblock

def get_resource_path(*path):
    return os.path.join(os.path.dirname(slideshow.__file__), *path)

def daemon_exists():
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    for program in ['slideshow-daemon', 'slideshow-transition']:
        for path in os.environ["PATH"].split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                break
        else:
            print >> sys.stderr, program, 'could not be found in PATH.'
            return False

    return True

class Command:
    def __init__(self, *args):
        self.cmd = args
        self.process = None
        self.buffer = ''

    def __str__(self):
        return ' '.join(self.cmd)

    def run(self, timeout):
        def target():
            self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            self.buffer += self.process.communicate()[0]

        thread = threading.Thread(target=target)
        thread.start()

        thread.join(timeout)
        if thread.is_alive():
            self.process.terminate()
            thread.join()
        return self.process.returncode, self.buffer

class Root(object):
    slides = slides.Handler()
    maintenance = maintenance.Handler()
    queue = queue.Handler()
    instance = instance.Handler()

    @cherrypy.expose
    def transition(self, name):
        name, ext = os.path.splitext(name)
        if ext != '.gif':
            raise cherrypy._cperror.NotFound()

        settings = Settings()
        filename = 'transition_%s.gif' % name
        dst = os.path.join(settings['Path']['BasePath'], settings['Path']['Temp'], filename)

        cmd = Command('slideshow-transition', '-G', dst, name)
        returncode, output = cmd.run(timeout=15)
        if returncode != 0:
            raise RuntimeError, 'Failed to generate preview: %s' % output

        age = 60 * 60 * 24 * 365
        expires = time.time() + age
        cherrypy.response.headers['Content-Type'] = 'image/gif'
        cherrypy.response.headers['Cache-Control'] = 'public, max-age=%d' % age
        cherrypy.response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(expires))

        def stream():
            with open(dst, 'rb') as fp:
                data = fp.read(4096)
                while len(data) > 0:
                    yield data
                    data = fp.read(4096)
        return stream()
    transition._cp_config = {'response.stream': True}

    @cherrypy.expose
    def index(self):
        raise cherrypy.InternalRedirect('/slides/list')

    @cherrypy.expose
    def logout(self):
        cherrypy.response.headers['www-authenticate'] = 'Digest realm="%s", nonce="foobar", algorithm="MD5", qop="auth"' % cherrypy.request.config['tools.auth_digest.realm']
        raise cherrypy.HTTPError(401, "Unauthorized")

    def logout_error_401(self, status, message, traceback, version):<commit_msg>frontend: handle when it fails to generate preview<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, sys
import cherrypy
import sqlite3
import re
import argparse
import traceback
import json
import subprocess
import threading
import time
import cairo

import slideshow
from slideshow.lib import template, browser as browser_factory, slide
from slideshow.pages import instance
from slideshow.pages import slides
from slideshow.pages import maintenance
from slideshow.pages import queue
from slideshow.settings import Settings, ValidationError
from slideshow.daemon import Daemon
from slideshow.video_preview import PreviewCreator
from slideshow.event import subscribe
import slideshow.tools.ipblock

def get_resource_path(*path):
    return os.path.join(os.path.dirname(slideshow.__file__), *path)

def daemon_exists():
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    for program in ['slideshow-daemon', 'slideshow-transition']:
        for path in os.environ["PATH"].split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                break
        else:
            print >> sys.stderr, program, 'could not be found in PATH.'
            return False

    return True

class Command:
    def __init__(self, *args):
        self.cmd = args
        self.process = None
        self.buffer = ''

    def __str__(self):
        return ' '.join(self.cmd)

    def run(self, timeout):
        def target():
            self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            self.buffer += self.process.communicate()[0]

        thread = threading.Thread(target=target)
        thread.start()

        thread.join(timeout)
        if thread.is_alive():
            self.process.terminate()
            thread.join()
        return self.process.returncode, self.buffer

class Root(object):
    slides = slides.Handler()
    maintenance = maintenance.Handler()
    queue = queue.Handler()
    instance = instance.Handler()

    @cherrypy.expose
    def transition(self, name):
        name, ext = os.path.splitext(name)
        if ext != '.gif':
            raise cherrypy._cperror.NotFound()

        settings = Settings()
        filename = 'transition_%s.gif' % name
        dst = os.path.join(settings['Path']['BasePath'], settings['Path']['Temp'], filename)

        age = 60 * 60 * 24 # 1 day
        expires = time.time() + age
        cherrypy.response.headers['Content-Type'] = 'image/gif'
        cherrypy.response.headers['Cache-Control'] = 'public, max-age=%d' % age
        cherrypy.response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(expires))

        cmd = Command('slideshow-transition', '-G', dst, name)
        returncode, output = cmd.run(timeout=15)
        if returncode != 0:
            surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 228, 170)
            ctx = cairo.Context (surface)
            ctx.set_source_rgb(0.7, 0.7, 0.7)
            ctx.fill()
            ctx.select_font_face('Monospace')
            ctx.set_font_size(9)
            ctx.set_source_rgb(0, 0, 0)
            ctx.move_to(1, 10)
            ctx.show_text('Failed to generate preview:')
            ctx.stroke()
            ctx.move_to(1, 20)
            ctx.show_text(output)
            ctx.stroke()

            cherrypy.response.headers['Content-Type'] = "image/png"
            surface.write_to_png(dst)

        def stream():
            with open(dst, 'rb') as fp:
                data = fp.read(4096)
                while len(data) > 0:
                    yield data
                    data = fp.read(4096)
        return stream()
    transition._cp_config = {'response.stream': True}

    @cherrypy.expose
    def index(self):
        raise cherrypy.InternalRedirect('/slides/list')

    @cherrypy.expose
    def logout(self):
        cherrypy.response.headers['www-authenticate'] = 'Digest realm="%s", nonce="foobar", algorithm="MD5", qop="auth"' % cherrypy.request.config['tools.auth_digest.realm']
        raise cherrypy.HTTPError(401, "Unauthorized")

    def logout_error_401(self, status, message, traceback, version):
{'fraction_non_alphanumeric': 0.11949131201208764, 'fraction_numerical': 0.01057668093679174, 'mean_word_length': 2.587624209575429, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2234616', 'n_tokens_mistral': 2458, 'n_tokens_neox': 2330, 'n_words': 567}