pep8'd what I could, including tabs to spaces
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -5,3 +5,4 @@ scanner/floatapp/app.cfg
 | 
			
		||||
*.pyc
 | 
			
		||||
*.min.css
 | 
			
		||||
*.min.js
 | 
			
		||||
.vscode
 | 
			
		||||
@ -1,49 +1,90 @@
 | 
			
		||||
import os.path
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def message(category, text):
 | 
			
		||||
	if message.level <= 0:
 | 
			
		||||
		sep = "  "
 | 
			
		||||
	else:
 | 
			
		||||
		sep = "--"
 | 
			
		||||
	print "%s %s%s[%s]%s%s" % (datetime.now().isoformat(), max(0, message.level) * "  |", sep, category, max(1, (14 - len(category))) * " ", text)
 | 
			
		||||
    if message.level <= 0:
 | 
			
		||||
        sep = "  "
 | 
			
		||||
    else:
 | 
			
		||||
        sep = "--"
 | 
			
		||||
    print "%s %s%s[%s]%s%s" % (
 | 
			
		||||
        datetime.now().isoformat(),
 | 
			
		||||
        max(0, message.level) * "  |",
 | 
			
		||||
        sep,
 | 
			
		||||
        category,
 | 
			
		||||
        max(1, (14 - len(category))) * " ",
 | 
			
		||||
        text)
 | 
			
		||||
message.level = -1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def next_level():
 | 
			
		||||
	message.level += 1
 | 
			
		||||
    message.level += 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def back_level():
 | 
			
		||||
	message.level -= 1
 | 
			
		||||
    message.level -= 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_cache_path_base(base):
 | 
			
		||||
	trim_base.base = base
 | 
			
		||||
    trim_base.base = base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def untrim_base(path):
 | 
			
		||||
	return os.path.join(trim_base.base, path)
 | 
			
		||||
    return os.path.join(trim_base.base, path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def trim_base_custom(path, base):
 | 
			
		||||
	if path.startswith(base):
 | 
			
		||||
		path = path[len(base):]
 | 
			
		||||
	if path.startswith('/'):
 | 
			
		||||
		path = path[1:]
 | 
			
		||||
	return path
 | 
			
		||||
    if path.startswith(base):
 | 
			
		||||
        path = path[len(base):]
 | 
			
		||||
    if path.startswith('/'):
 | 
			
		||||
        path = path[1:]
 | 
			
		||||
    return path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def trim_base(path):
 | 
			
		||||
	return trim_base_custom(path, trim_base.base)
 | 
			
		||||
    return trim_base_custom(path, trim_base.base)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def cache_base(path, filepath=False):
 | 
			
		||||
	if len(path) == 0:
 | 
			
		||||
		return "root"
 | 
			
		||||
	elif filepath and len(path.split(os.sep)) < 2:
 | 
			
		||||
		path = "root-" + path
 | 
			
		||||
	path = trim_base(path).replace('/', '-').replace(' ', '_').replace('(', '').replace('&', '').replace(',', '').replace(')', '').replace('#', '').replace('[', '').replace(']', '').replace('"', '').replace("'", '').replace('_-_', '-').lower()
 | 
			
		||||
	while path.find("--") != -1:
 | 
			
		||||
		path = path.replace("--", "-")
 | 
			
		||||
	while path.find("__") != -1:
 | 
			
		||||
		path = path.replace("__", "_")
 | 
			
		||||
	return path
 | 
			
		||||
    if len(path) == 0:
 | 
			
		||||
        return "root"
 | 
			
		||||
    elif filepath and len(path.split(os.sep)) < 2:
 | 
			
		||||
        path = "root-" + path
 | 
			
		||||
    path = trim_base(path).replace(
 | 
			
		||||
        '/', '-').replace(
 | 
			
		||||
        ' ', '_').replace(
 | 
			
		||||
        '(', '').replace(
 | 
			
		||||
        '&', '').replace(
 | 
			
		||||
        ',', '').replace(
 | 
			
		||||
        ')', '').replace(
 | 
			
		||||
        '#', '').replace(
 | 
			
		||||
        '[', '').replace(
 | 
			
		||||
        ']', '').replace(
 | 
			
		||||
        '"', '').replace(
 | 
			
		||||
        "'", '').replace(
 | 
			
		||||
        '_-_', '-').lower()
 | 
			
		||||
    while path.find("--") != -1:
 | 
			
		||||
        path = path.replace("--", "-")
 | 
			
		||||
    while path.find("__") != -1:
 | 
			
		||||
        path = path.replace("__", "_")
 | 
			
		||||
    return path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def json_cache(path):
 | 
			
		||||
	return cache_base(path) + ".json"
 | 
			
		||||
    return cache_base(path) + ".json"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def image_cache(path, size, square=False):
 | 
			
		||||
	if square:
 | 
			
		||||
		suffix = str(size) + "s"
 | 
			
		||||
	else:
 | 
			
		||||
		suffix = str(size)
 | 
			
		||||
	return cache_base(path, True) + "_" + suffix + ".jpg"
 | 
			
		||||
    if square:
 | 
			
		||||
        suffix = str(size) + "s"
 | 
			
		||||
    else:
 | 
			
		||||
        suffix = str(size)
 | 
			
		||||
    return cache_base(path, True) + "_" + suffix + ".jpg"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def video_cache(path):
 | 
			
		||||
	return cache_base(path, True) + ".mp4"
 | 
			
		||||
    return cache_base(path, True) + ".mp4"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def file_mtime(path):
 | 
			
		||||
	return datetime.fromtimestamp(int(os.path.getmtime(path)))
 | 
			
		||||
    return datetime.fromtimestamp(int(os.path.getmtime(path)))
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -6,129 +6,143 @@ from PhotoAlbum import Photo, Album, PhotoAlbumEncoder
 | 
			
		||||
from CachePath import *
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TreeWalker:
 | 
			
		||||
	def __init__(self, album_path, cache_path):
 | 
			
		||||
		self.album_path = os.path.abspath(album_path).decode(sys.getfilesystemencoding())
 | 
			
		||||
		self.cache_path = os.path.abspath(cache_path).decode(sys.getfilesystemencoding())
 | 
			
		||||
		set_cache_path_base(self.album_path)
 | 
			
		||||
		self.all_albums = list()
 | 
			
		||||
		self.all_photos = list()
 | 
			
		||||
		self.walk(self.album_path)
 | 
			
		||||
		self.big_lists()
 | 
			
		||||
		self.remove_stale()
 | 
			
		||||
		message("complete", "")
 | 
			
		||||
	def walk(self, path):
 | 
			
		||||
		next_level()
 | 
			
		||||
		if not os.access(path, os.R_OK | os.X_OK):
 | 
			
		||||
			message("access denied", os.path.basename(path))
 | 
			
		||||
			back_level()
 | 
			
		||||
			return None
 | 
			
		||||
		message("walking", os.path.basename(path))
 | 
			
		||||
		cache = os.path.join(self.cache_path, json_cache(path))
 | 
			
		||||
		cached = False
 | 
			
		||||
		cached_album = None
 | 
			
		||||
		if os.path.exists(cache):
 | 
			
		||||
			try:
 | 
			
		||||
				cached_album = Album.from_cache(cache)
 | 
			
		||||
				if file_mtime(path) <= file_mtime(cache):
 | 
			
		||||
					message("full cache", os.path.basename(path))
 | 
			
		||||
					cached = True
 | 
			
		||||
					album = cached_album
 | 
			
		||||
					for photo in album.photos:
 | 
			
		||||
						self.all_photos.append(photo)
 | 
			
		||||
				else:
 | 
			
		||||
					message("partial cache", os.path.basename(path))
 | 
			
		||||
			except KeyboardInterrupt:
 | 
			
		||||
				raise
 | 
			
		||||
			except:
 | 
			
		||||
				message("corrupt cache", os.path.basename(path))
 | 
			
		||||
				cached_album = None
 | 
			
		||||
		if not cached:
 | 
			
		||||
			album = Album(path)
 | 
			
		||||
		for entry in os.listdir(path):
 | 
			
		||||
			if entry[0] == '.':
 | 
			
		||||
				continue
 | 
			
		||||
			try:
 | 
			
		||||
				entry = entry.decode(sys.getfilesystemencoding())
 | 
			
		||||
			except KeyboardInterrupt:
 | 
			
		||||
				raise
 | 
			
		||||
			except:
 | 
			
		||||
				next_level()
 | 
			
		||||
				message("unicode error", entry.decode(sys.getfilesystemencoding(), "replace"))
 | 
			
		||||
				back_level()
 | 
			
		||||
				continue
 | 
			
		||||
			entry = os.path.join(path, entry)
 | 
			
		||||
			if os.path.isdir(entry):
 | 
			
		||||
				next_walked_album = self.walk(entry)
 | 
			
		||||
				if next_walked_album is not None:
 | 
			
		||||
					album.add_album(next_walked_album)
 | 
			
		||||
			elif not cached and os.path.isfile(entry):
 | 
			
		||||
				next_level()
 | 
			
		||||
				cache_hit = False
 | 
			
		||||
				if cached_album:
 | 
			
		||||
					cached_photo = cached_album.photo_from_path(entry)
 | 
			
		||||
					if cached_photo and file_mtime(entry) <= cached_photo.attributes["dateTimeFile"]:
 | 
			
		||||
						cache_file = None
 | 
			
		||||
						if "mediaType" in cached_photo.attributes:
 | 
			
		||||
							if cached_photo.attributes["mediaType"] == "video":
 | 
			
		||||
								# if video
 | 
			
		||||
								cache_file = os.path.join(self.cache_path, video_cache(entry))
 | 
			
		||||
							else:
 | 
			
		||||
								# if image
 | 
			
		||||
								cache_file = os.path.join(self.cache_path, image_cache(entry, 1024, False))
 | 
			
		||||
						else:
 | 
			
		||||
							# if image
 | 
			
		||||
							cache_file = os.path.join(self.cache_path, image_cache(entry, 1024, False))
 | 
			
		||||
    def __init__(self, album_path, cache_path):
 | 
			
		||||
        self.album_path = os.path.abspath(
 | 
			
		||||
            album_path).decode(sys.getfilesystemencoding())
 | 
			
		||||
        self.cache_path = os.path.abspath(
 | 
			
		||||
            cache_path).decode(sys.getfilesystemencoding())
 | 
			
		||||
        set_cache_path_base(self.album_path)
 | 
			
		||||
        self.all_albums = list()
 | 
			
		||||
        self.all_photos = list()
 | 
			
		||||
        self.walk(self.album_path)
 | 
			
		||||
        self.big_lists()
 | 
			
		||||
        self.remove_stale()
 | 
			
		||||
        message("complete", "")
 | 
			
		||||
 | 
			
		||||
						# at this point we have full path to cache image/video
 | 
			
		||||
						# check if it actually exists
 | 
			
		||||
						if os.path.exists(cache_file):
 | 
			
		||||
							message("cache hit", os.path.basename(entry))
 | 
			
		||||
							cache_hit = True
 | 
			
		||||
							photo = cached_photo
 | 
			
		||||
    def walk(self, path):
 | 
			
		||||
        next_level()
 | 
			
		||||
        if not os.access(path, os.R_OK | os.X_OK):
 | 
			
		||||
            message("access denied", os.path.basename(path))
 | 
			
		||||
            back_level()
 | 
			
		||||
            return None
 | 
			
		||||
        message("walking", os.path.basename(path))
 | 
			
		||||
        cache = os.path.join(self.cache_path, json_cache(path))
 | 
			
		||||
        cached = False
 | 
			
		||||
        cached_album = None
 | 
			
		||||
        if os.path.exists(cache):
 | 
			
		||||
            try:
 | 
			
		||||
                cached_album = Album.from_cache(cache)
 | 
			
		||||
                if file_mtime(path) <= file_mtime(cache):
 | 
			
		||||
                    message("full cache", os.path.basename(path))
 | 
			
		||||
                    cached = True
 | 
			
		||||
                    album = cached_album
 | 
			
		||||
                    for photo in album.photos:
 | 
			
		||||
                        self.all_photos.append(photo)
 | 
			
		||||
                else:
 | 
			
		||||
                    message("partial cache", os.path.basename(path))
 | 
			
		||||
            except KeyboardInterrupt:
 | 
			
		||||
                raise
 | 
			
		||||
            except:
 | 
			
		||||
                message("corrupt cache", os.path.basename(path))
 | 
			
		||||
                cached_album = None
 | 
			
		||||
        if not cached:
 | 
			
		||||
            album = Album(path)
 | 
			
		||||
        for entry in os.listdir(path):
 | 
			
		||||
            if entry[0] == '.':
 | 
			
		||||
                continue
 | 
			
		||||
            try:
 | 
			
		||||
                entry = entry.decode(sys.getfilesystemencoding())
 | 
			
		||||
            except KeyboardInterrupt:
 | 
			
		||||
                raise
 | 
			
		||||
            except:
 | 
			
		||||
                next_level()
 | 
			
		||||
                message("unicode error", entry.decode(
 | 
			
		||||
                    sys.getfilesystemencoding(), "replace"))
 | 
			
		||||
                back_level()
 | 
			
		||||
                continue
 | 
			
		||||
            entry = os.path.join(path, entry)
 | 
			
		||||
            if os.path.isdir(entry):
 | 
			
		||||
                next_walked_album = self.walk(entry)
 | 
			
		||||
                if next_walked_album is not None:
 | 
			
		||||
                    album.add_album(next_walked_album)
 | 
			
		||||
            elif not cached and os.path.isfile(entry):
 | 
			
		||||
                next_level()
 | 
			
		||||
                cache_hit = False
 | 
			
		||||
                if cached_album:
 | 
			
		||||
                    cached_photo = cached_album.photo_from_path(entry)
 | 
			
		||||
                    if (cached_photo and file_mtime(
 | 
			
		||||
                            entry) <= cached_photo.attributes["dateTimeFile"]):
 | 
			
		||||
                        cache_file = None
 | 
			
		||||
                        if "mediaType" in cached_photo.attributes:
 | 
			
		||||
                            if cached_photo.attributes["mediaType"] == "video":
 | 
			
		||||
                                # if video
 | 
			
		||||
                                cache_file = os.path.join(
 | 
			
		||||
                                    self.cache_path, video_cache(entry))
 | 
			
		||||
                            else:
 | 
			
		||||
                                # if image
 | 
			
		||||
                                cache_file = os.path.join(
 | 
			
		||||
                                    self.cache_path,
 | 
			
		||||
                                    image_cache(entry, 1024, False))
 | 
			
		||||
                        else:
 | 
			
		||||
                            # if image
 | 
			
		||||
                            cache_file = os.path.join(
 | 
			
		||||
                                self.cache_path,
 | 
			
		||||
                                image_cache(entry, 1024, False))
 | 
			
		||||
 | 
			
		||||
				if not cache_hit:
 | 
			
		||||
					message("metainfo", os.path.basename(entry))
 | 
			
		||||
					photo = Photo(entry, self.cache_path)
 | 
			
		||||
				if photo.is_valid:
 | 
			
		||||
					self.all_photos.append(photo)
 | 
			
		||||
					album.add_photo(photo)
 | 
			
		||||
				else:
 | 
			
		||||
					message("unreadable", os.path.basename(entry))
 | 
			
		||||
				back_level()
 | 
			
		||||
		if not album.empty:
 | 
			
		||||
			message("caching", os.path.basename(path))
 | 
			
		||||
			album.cache(self.cache_path)
 | 
			
		||||
			self.all_albums.append(album)
 | 
			
		||||
		else:
 | 
			
		||||
			message("empty", os.path.basename(path))
 | 
			
		||||
		back_level()
 | 
			
		||||
		return album
 | 
			
		||||
	def big_lists(self):
 | 
			
		||||
		photo_list = []
 | 
			
		||||
		self.all_photos.sort()
 | 
			
		||||
		for photo in self.all_photos:
 | 
			
		||||
			photo_list.append(photo.path)
 | 
			
		||||
		message("caching", "all photos path list")
 | 
			
		||||
		fp = open(os.path.join(self.cache_path, "all_photos.json"), 'w')
 | 
			
		||||
		json.dump(photo_list, fp, cls=PhotoAlbumEncoder)
 | 
			
		||||
		fp.close()
 | 
			
		||||
	def remove_stale(self):
 | 
			
		||||
		message("cleanup", "building stale list")
 | 
			
		||||
		all_cache_entries = { "all_photos.json": True, "latest_photos.json": True }
 | 
			
		||||
		for album in self.all_albums:
 | 
			
		||||
			all_cache_entries[album.cache_path] = True
 | 
			
		||||
		for photo in self.all_photos:
 | 
			
		||||
			for entry in photo.image_caches:
 | 
			
		||||
				all_cache_entries[entry] = True
 | 
			
		||||
		message("cleanup", "searching for stale cache entries")
 | 
			
		||||
		for cache in os.listdir(self.cache_path):
 | 
			
		||||
			try:
 | 
			
		||||
				cache = cache.decode(sys.getfilesystemencoding())
 | 
			
		||||
			except KeyboardInterrupt:
 | 
			
		||||
				raise
 | 
			
		||||
			except:
 | 
			
		||||
				pass
 | 
			
		||||
			if cache not in all_cache_entries:
 | 
			
		||||
				message("cleanup", os.path.basename(cache))
 | 
			
		||||
				os.unlink(os.path.join(self.cache_path, cache))
 | 
			
		||||
                        # at this point we have full path to cache image/video
 | 
			
		||||
                        # check if it actually exists
 | 
			
		||||
                        if os.path.exists(cache_file):
 | 
			
		||||
                            message("cache hit", os.path.basename(entry))
 | 
			
		||||
                            cache_hit = True
 | 
			
		||||
                            photo = cached_photo
 | 
			
		||||
 | 
			
		||||
                if not cache_hit:
 | 
			
		||||
                    message("metainfo", os.path.basename(entry))
 | 
			
		||||
                    photo = Photo(entry, self.cache_path)
 | 
			
		||||
                if photo.is_valid:
 | 
			
		||||
                    self.all_photos.append(photo)
 | 
			
		||||
                    album.add_photo(photo)
 | 
			
		||||
                else:
 | 
			
		||||
                    message("unreadable", os.path.basename(entry))
 | 
			
		||||
                back_level()
 | 
			
		||||
        if not album.empty:
 | 
			
		||||
            message("caching", os.path.basename(path))
 | 
			
		||||
            album.cache(self.cache_path)
 | 
			
		||||
            self.all_albums.append(album)
 | 
			
		||||
        else:
 | 
			
		||||
            message("empty", os.path.basename(path))
 | 
			
		||||
        back_level()
 | 
			
		||||
        return album
 | 
			
		||||
 | 
			
		||||
    def big_lists(self):
 | 
			
		||||
        photo_list = []
 | 
			
		||||
        self.all_photos.sort()
 | 
			
		||||
        for photo in self.all_photos:
 | 
			
		||||
            photo_list.append(photo.path)
 | 
			
		||||
        message("caching", "all photos path list")
 | 
			
		||||
        fp = open(os.path.join(self.cache_path, "all_photos.json"), 'w')
 | 
			
		||||
        json.dump(photo_list, fp, cls=PhotoAlbumEncoder)
 | 
			
		||||
        fp.close()
 | 
			
		||||
 | 
			
		||||
    def remove_stale(self):
 | 
			
		||||
        message("cleanup", "building stale list")
 | 
			
		||||
        all_cache_entries = {"all_photos.json": True,
 | 
			
		||||
                             "latest_photos.json": True}
 | 
			
		||||
        for album in self.all_albums:
 | 
			
		||||
            all_cache_entries[album.cache_path] = True
 | 
			
		||||
        for photo in self.all_photos:
 | 
			
		||||
            for entry in photo.image_caches:
 | 
			
		||||
                all_cache_entries[entry] = True
 | 
			
		||||
        message("cleanup", "searching for stale cache entries")
 | 
			
		||||
        for cache in os.listdir(self.cache_path):
 | 
			
		||||
            try:
 | 
			
		||||
                cache = cache.decode(sys.getfilesystemencoding())
 | 
			
		||||
            except KeyboardInterrupt:
 | 
			
		||||
                raise
 | 
			
		||||
            except:
 | 
			
		||||
                pass
 | 
			
		||||
            if cache not in all_cache_entries:
 | 
			
		||||
                message("cleanup", os.path.basename(cache))
 | 
			
		||||
                os.unlink(os.path.join(self.cache_path, cache))
 | 
			
		||||
 | 
			
		||||
@ -2,46 +2,49 @@ from CachePath import message
 | 
			
		||||
import os
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
class VideoToolWrapper(object):
 | 
			
		||||
	def call(self, *args):
 | 
			
		||||
		path = args[-1]
 | 
			
		||||
		for tool in self.wrappers:
 | 
			
		||||
			try:
 | 
			
		||||
				if self.check_output:
 | 
			
		||||
					p = subprocess.check_output((tool,) + args)
 | 
			
		||||
				else:
 | 
			
		||||
					p = subprocess.call((tool,) + args)
 | 
			
		||||
					if p > 0:
 | 
			
		||||
						return False
 | 
			
		||||
					else:
 | 
			
		||||
						return "SUCCESS"
 | 
			
		||||
			except KeyboardInterrupt:
 | 
			
		||||
				if self.cleanup:
 | 
			
		||||
					self.remove(path)
 | 
			
		||||
				raise
 | 
			
		||||
			except OSError:
 | 
			
		||||
				continue
 | 
			
		||||
			except:
 | 
			
		||||
				if self.cleanup:
 | 
			
		||||
					self.remove(path)
 | 
			
		||||
				continue
 | 
			
		||||
			return p
 | 
			
		||||
		return False
 | 
			
		||||
 | 
			
		||||
	def remove(self, path):
 | 
			
		||||
		try:
 | 
			
		||||
			os.unlink(path)
 | 
			
		||||
		except:
 | 
			
		||||
			pass
 | 
			
		||||
class VideoToolWrapper(object):
 | 
			
		||||
    def call(self, *args):
 | 
			
		||||
        path = args[-1]
 | 
			
		||||
        for tool in self.wrappers:
 | 
			
		||||
            try:
 | 
			
		||||
                if self.check_output:
 | 
			
		||||
                    p = subprocess.check_output((tool,) + args)
 | 
			
		||||
                else:
 | 
			
		||||
                    p = subprocess.call((tool,) + args)
 | 
			
		||||
                    if p > 0:
 | 
			
		||||
                        return False
 | 
			
		||||
                    else:
 | 
			
		||||
                        return "SUCCESS"
 | 
			
		||||
            except KeyboardInterrupt:
 | 
			
		||||
                if self.cleanup:
 | 
			
		||||
                    self.remove(path)
 | 
			
		||||
                raise
 | 
			
		||||
            except OSError:
 | 
			
		||||
                continue
 | 
			
		||||
            except:
 | 
			
		||||
                if self.cleanup:
 | 
			
		||||
                    self.remove(path)
 | 
			
		||||
                continue
 | 
			
		||||
            return p
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def remove(self, path):
 | 
			
		||||
        try:
 | 
			
		||||
            os.unlink(path)
 | 
			
		||||
        except:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VideoTranscodeWrapper(VideoToolWrapper):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self.wrappers = ['avconv', 'ffmpeg']
 | 
			
		||||
		self.check_output = False
 | 
			
		||||
		self.cleanup = True
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.wrappers = ['avconv', 'ffmpeg']
 | 
			
		||||
        self.check_output = False
 | 
			
		||||
        self.cleanup = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VideoProbeWrapper(VideoToolWrapper):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self.wrappers = ['avprobe', 'ffprobe']
 | 
			
		||||
		self.check_output = True
 | 
			
		||||
		self.cleanup = False
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.wrappers = ['avprobe', 'ffprobe']
 | 
			
		||||
        self.check_output = True
 | 
			
		||||
        self.cleanup = False
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,9 @@ from flask_login import LoginManager
 | 
			
		||||
import os.path
 | 
			
		||||
 | 
			
		||||
app = Flask(__name__)
 | 
			
		||||
app.config.from_pyfile(os.path.join(os.path.dirname(os.path.abspath(__file__)), "app.cfg"))
 | 
			
		||||
app.config.from_pyfile(
 | 
			
		||||
    os.path.join(os.path.dirname(os.path.abspath(__file__)), "app.cfg"))
 | 
			
		||||
 | 
			
		||||
login_manager = LoginManager()
 | 
			
		||||
import login
 | 
			
		||||
login_manager.setup_app(app)
 | 
			
		||||
 | 
			
		||||
@ -1,118 +1,160 @@
 | 
			
		||||
from floatapp import app
 | 
			
		||||
from floatapp.login import admin_required, login_required, is_authenticated, query_is_photo_user, query_is_admin_user, photo_user, admin_user
 | 
			
		||||
from floatapp.jsonp import jsonp
 | 
			
		||||
from process import send_process
 | 
			
		||||
from TreeWalker import TreeWalker
 | 
			
		||||
from flask import Response, abort, json, request, jsonify
 | 
			
		||||
from flask_login import login_user, current_user
 | 
			
		||||
from random import shuffle
 | 
			
		||||
import os
 | 
			
		||||
from mimetypes import guess_type
 | 
			
		||||
from random import shuffle
 | 
			
		||||
 | 
			
		||||
from flask import Response, abort, json, jsonify, request
 | 
			
		||||
from flask_login import current_user, login_user
 | 
			
		||||
 | 
			
		||||
from floatapp import app
 | 
			
		||||
from floatapp.jsonp import jsonp
 | 
			
		||||
from floatapp.login import (admin_required, admin_user, is_authenticated,
 | 
			
		||||
                            login_required, photo_user, query_is_admin_user,
 | 
			
		||||
                            query_is_photo_user)
 | 
			
		||||
from process import send_process
 | 
			
		||||
from TreeWalker import TreeWalker
 | 
			
		||||
 | 
			
		||||
cwd = os.path.dirname(os.path.abspath(__file__))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route("/scan")
 | 
			
		||||
@admin_required
 | 
			
		||||
def scan_photos():
 | 
			
		||||
	global cwd
 | 
			
		||||
	response = send_process([ "stdbuf", "-oL", os.path.abspath(os.path.join(cwd, "../main.py")),
 | 
			
		||||
				os.path.abspath(app.config["ALBUM_PATH"]), os.path.abspath(app.config["CACHE_PATH"]) ],
 | 
			
		||||
				os.path.join(cwd, "scanner.pid"))
 | 
			
		||||
	response.headers.add("X-Accel-Buffering", "no")
 | 
			
		||||
	response.cache_control.no_cache = True
 | 
			
		||||
	return response
 | 
			
		||||
    global cwd
 | 
			
		||||
    response = send_process([
 | 
			
		||||
            "stdbuf",
 | 
			
		||||
            "-oL",
 | 
			
		||||
            os.path.abspath(os.path.join(cwd, "../venv/bin/python")),
 | 
			
		||||
            os.path.abspath(os.path.join(cwd, "../main.py")),
 | 
			
		||||
            os.path.abspath(app.config["ALBUM_PATH"]),
 | 
			
		||||
            os.path.abspath(app.config["CACHE_PATH"])
 | 
			
		||||
        ],
 | 
			
		||||
        os.path.join(cwd, "scanner.pid"))
 | 
			
		||||
    response.headers.add("X-Accel-Buffering", "no")
 | 
			
		||||
    response.cache_control.no_cache = True
 | 
			
		||||
    return response
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route("/auth")
 | 
			
		||||
def login():
 | 
			
		||||
	success = False
 | 
			
		||||
	if current_user.is_authenticated():
 | 
			
		||||
		success = True
 | 
			
		||||
	elif query_is_photo_user(request.form) or query_is_photo_user(request.args):
 | 
			
		||||
		success = login_user(photo_user, remember=True)
 | 
			
		||||
	elif query_is_admin_user(request.form) or query_is_admin_user(request.args):
 | 
			
		||||
		success = login_user(admin_user, remember=True)
 | 
			
		||||
	if not success:
 | 
			
		||||
		abort(403)
 | 
			
		||||
	return ""
 | 
			
		||||
    success = False
 | 
			
		||||
    if current_user.is_authenticated:
 | 
			
		||||
        success = True
 | 
			
		||||
    elif (query_is_photo_user(request.form) or
 | 
			
		||||
            query_is_photo_user(request.args)):
 | 
			
		||||
        success = login_user(photo_user, remember=True)
 | 
			
		||||
    elif (query_is_admin_user(request.form) or
 | 
			
		||||
            query_is_admin_user(request.args)):
 | 
			
		||||
        success = login_user(admin_user, remember=True)
 | 
			
		||||
    if not success:
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def cache_base(path):
 | 
			
		||||
	path = path.replace('/', '-').replace(' ', '_').replace('(', '').replace('&', '').replace(',', '').replace(')', '').replace('#', '').replace('[', '').replace(']', '').replace('"', '').replace("'", '').replace('_-_', '-').lower()
 | 
			
		||||
	while path.find("--") != -1:
 | 
			
		||||
		path = path.replace("--", "-")
 | 
			
		||||
	while path.find("__") != -1:
 | 
			
		||||
		path = path.replace("__", "_")
 | 
			
		||||
	if len(path) == 0:
 | 
			
		||||
		path = "root"
 | 
			
		||||
	return path
 | 
			
		||||
    path = path.replace(
 | 
			
		||||
        '/', '-').replace(
 | 
			
		||||
        ' ', '_').replace(
 | 
			
		||||
        '(', '').replace(
 | 
			
		||||
        '&', '').replace(
 | 
			
		||||
        ',', '').replace(
 | 
			
		||||
        ')', '').replace(
 | 
			
		||||
        '#', '').replace(
 | 
			
		||||
        '[', '').replace(
 | 
			
		||||
        ']', '').replace(
 | 
			
		||||
        '"', '').replace(
 | 
			
		||||
        "'", '').replace(
 | 
			
		||||
        '_-_', '-').lower()
 | 
			
		||||
 | 
			
		||||
    while path.find("--") != -1:
 | 
			
		||||
        path = path.replace("--", "-")
 | 
			
		||||
 | 
			
		||||
    while path.find("__") != -1:
 | 
			
		||||
        path = path.replace("__", "_")
 | 
			
		||||
 | 
			
		||||
    if len(path) == 0:
 | 
			
		||||
        path = "root"
 | 
			
		||||
 | 
			
		||||
    return path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
auth_list = []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
auth_list = [ ]
 | 
			
		||||
def read_auth_list():
 | 
			
		||||
	global auth_list, cwd
 | 
			
		||||
	f = open(os.path.join(cwd, "auth.txt"), "r")
 | 
			
		||||
	paths = [ ]
 | 
			
		||||
	for path in f:
 | 
			
		||||
		path = path.strip()
 | 
			
		||||
		paths.append(path)
 | 
			
		||||
		paths.append(cache_base(path))
 | 
			
		||||
	f.close()
 | 
			
		||||
	auth_list = paths
 | 
			
		||||
    global auth_list, cwd
 | 
			
		||||
    f = open(os.path.join(cwd, "auth.txt"), "r")
 | 
			
		||||
    paths = []
 | 
			
		||||
    for path in f:
 | 
			
		||||
        path = path.strip()
 | 
			
		||||
        paths.append(path)
 | 
			
		||||
        paths.append(cache_base(path))
 | 
			
		||||
    f.close()
 | 
			
		||||
    auth_list = paths
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# TODO: Make this run via inotify
 | 
			
		||||
read_auth_list()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def check_permissions(path):
 | 
			
		||||
	if not is_authenticated():
 | 
			
		||||
		for auth_path in auth_list:
 | 
			
		||||
			if path.startswith(auth_path):
 | 
			
		||||
				abort(403)
 | 
			
		||||
    if not is_authenticated():
 | 
			
		||||
        for auth_path in auth_list:
 | 
			
		||||
            if path.startswith(auth_path):
 | 
			
		||||
                abort(403)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route("/albums/<path:path>")
 | 
			
		||||
def albums(path):
 | 
			
		||||
	check_permissions(path)
 | 
			
		||||
	return accel_redirect(app.config["ALBUM_ACCEL"], app.config["ALBUM_PATH"], path)
 | 
			
		||||
    check_permissions(path)
 | 
			
		||||
    return accel_redirect(
 | 
			
		||||
        app.config["ALBUM_ACCEL"], app.config["ALBUM_PATH"], path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route("/cache/<path:path>")
 | 
			
		||||
def cache(path):
 | 
			
		||||
	check_permissions(path)
 | 
			
		||||
	return accel_redirect(app.config["CACHE_ACCEL"], app.config["CACHE_PATH"], path)
 | 
			
		||||
    check_permissions(path)
 | 
			
		||||
    return accel_redirect(
 | 
			
		||||
        app.config["CACHE_ACCEL"], app.config["CACHE_PATH"], path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def accel_redirect(internal, real, relative_name):
 | 
			
		||||
	real_path = os.path.join(real, relative_name)
 | 
			
		||||
	internal_path = os.path.join(internal, relative_name)
 | 
			
		||||
	if not os.path.isfile(real_path):
 | 
			
		||||
		abort(404)
 | 
			
		||||
	mimetype = None
 | 
			
		||||
	types = guess_type(real_path)
 | 
			
		||||
	if len(types) != 0:
 | 
			
		||||
		mimetype = types[0]
 | 
			
		||||
	response = Response(mimetype=mimetype)
 | 
			
		||||
	response.headers.add("X-Accel-Redirect", internal_path)
 | 
			
		||||
	response.cache_control.public = True
 | 
			
		||||
	if mimetype == "application/json":
 | 
			
		||||
		response.cache_control.max_age = 3600
 | 
			
		||||
	else:
 | 
			
		||||
		response.cache_control.max_age = 29030400
 | 
			
		||||
	return response
 | 
			
		||||
    real_path = os.path.join(real, relative_name)
 | 
			
		||||
    internal_path = os.path.join(internal, relative_name)
 | 
			
		||||
    if not os.path.isfile(real_path):
 | 
			
		||||
        abort(404)
 | 
			
		||||
    mimetype = None
 | 
			
		||||
    types = guess_type(real_path)
 | 
			
		||||
    if len(types) != 0:
 | 
			
		||||
        mimetype = types[0]
 | 
			
		||||
    response = Response(mimetype=mimetype)
 | 
			
		||||
    response.headers.add("X-Accel-Redirect", internal_path)
 | 
			
		||||
    response.cache_control.public = True
 | 
			
		||||
    if mimetype == "application/json":
 | 
			
		||||
        response.cache_control.max_age = 3600
 | 
			
		||||
    else:
 | 
			
		||||
        response.cache_control.max_age = 29030400
 | 
			
		||||
    return response
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route("/photos")
 | 
			
		||||
@jsonp
 | 
			
		||||
def photos():
 | 
			
		||||
	f = open(os.path.join(app.config["CACHE_PATH"], "all_photos.json"), "r")
 | 
			
		||||
	photos = json.load(f)
 | 
			
		||||
	f.close()
 | 
			
		||||
	if not is_authenticated():
 | 
			
		||||
		def allowed(photo):
 | 
			
		||||
			for auth_path in auth_list:
 | 
			
		||||
				if photo.startswith(auth_path):
 | 
			
		||||
					return False
 | 
			
		||||
			return True
 | 
			
		||||
		photos = [photo for photo in photos if allowed(photo)]
 | 
			
		||||
	count = int(request.args.get("count", len(photos)))
 | 
			
		||||
	random = request.args.get("random") == "true"
 | 
			
		||||
	if random:
 | 
			
		||||
		shuffle(photos)
 | 
			
		||||
	else:
 | 
			
		||||
		photos.reverse()
 | 
			
		||||
	response = jsonify(photos=photos[0:count])
 | 
			
		||||
	response.cache_control.no_cache = True
 | 
			
		||||
	return response
 | 
			
		||||
    f = open(os.path.join(app.config["CACHE_PATH"], "all_photos.json"), "r")
 | 
			
		||||
    photos = json.load(f)
 | 
			
		||||
    f.close()
 | 
			
		||||
    if not is_authenticated():
 | 
			
		||||
        def allowed(photo):
 | 
			
		||||
            for auth_path in auth_list:
 | 
			
		||||
                if photo.startswith(auth_path):
 | 
			
		||||
                    return False
 | 
			
		||||
            return True
 | 
			
		||||
        photos = [photo for photo in photos if allowed(photo)]
 | 
			
		||||
    count = int(request.args.get("count", len(photos)))
 | 
			
		||||
    random = request.args.get("random") == "true"
 | 
			
		||||
    if random:
 | 
			
		||||
        shuffle(photos)
 | 
			
		||||
    else:
 | 
			
		||||
        photos.reverse()
 | 
			
		||||
    response = jsonify(photos=photos[0:count])
 | 
			
		||||
    response.cache_control.no_cache = True
 | 
			
		||||
    return response
 | 
			
		||||
 | 
			
		||||
@ -5,14 +5,16 @@ import re
 | 
			
		||||
 | 
			
		||||
jsonp_validator = re.compile("^[a-zA-Z0-9_\-.]{1,128}$")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def jsonp(f):
 | 
			
		||||
	"""Wraps JSONified output for JSONP"""
 | 
			
		||||
	@wraps(f)
 | 
			
		||||
	def decorated_function(*args, **kwargs):
 | 
			
		||||
		callback = request.args.get('callback', False)
 | 
			
		||||
		if callback and jsonp_validator.match(callback):
 | 
			
		||||
			content = str(callback) + '(' + str(f(*args,**kwargs).data) + ')'
 | 
			
		||||
			return current_app.response_class(content, mimetype='application/javascript')
 | 
			
		||||
		else:
 | 
			
		||||
			return f(*args, **kwargs)
 | 
			
		||||
	return decorated_function
 | 
			
		||||
    """Wraps JSONified output for JSONP"""
 | 
			
		||||
    @wraps(f)
 | 
			
		||||
    def decorated_function(*args, **kwargs):
 | 
			
		||||
        callback = request.args.get('callback', False)
 | 
			
		||||
        if callback and jsonp_validator.match(callback):
 | 
			
		||||
            content = str(callback) + '(' + str(f(*args, **kwargs).data) + ')'
 | 
			
		||||
            return current_app.response_class(
 | 
			
		||||
                content, mimetype='application/javascript')
 | 
			
		||||
        else:
 | 
			
		||||
            return f(*args, **kwargs)
 | 
			
		||||
    return decorated_function
 | 
			
		||||
 | 
			
		||||
@ -3,51 +3,66 @@ from flask import request, abort
 | 
			
		||||
from flask_login import current_user, UserMixin
 | 
			
		||||
from functools import wraps
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class User(UserMixin):
 | 
			
		||||
	def __init__(self, id, admin=False):
 | 
			
		||||
		self.admin = admin
 | 
			
		||||
		self.id = id
 | 
			
		||||
    def __init__(self, id, admin=False):
 | 
			
		||||
        self.admin = admin
 | 
			
		||||
        self.id = id
 | 
			
		||||
 | 
			
		||||
photo_user = User("user")
 | 
			
		||||
admin_user = User("admin", True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_manager.user_loader
 | 
			
		||||
def load_user(id):
 | 
			
		||||
	if id == "user":
 | 
			
		||||
		return photo_user
 | 
			
		||||
	elif id == "admin":
 | 
			
		||||
		return admin_user
 | 
			
		||||
	return None
 | 
			
		||||
    if id == "user":
 | 
			
		||||
        return photo_user
 | 
			
		||||
    elif id == "admin":
 | 
			
		||||
        return admin_user
 | 
			
		||||
    return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_manager.unauthorized_handler
 | 
			
		||||
def unauthorized():
 | 
			
		||||
	return abort(403)
 | 
			
		||||
    return abort(403)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def login_required(fn):
 | 
			
		||||
	@wraps(fn)
 | 
			
		||||
	def decorated_view(*args, **kwargs):
 | 
			
		||||
		if query_is_admin_user(request.args) or query_is_photo_user(request.args) or current_user.is_authenticated():
 | 
			
		||||
			return fn(*args, **kwargs)
 | 
			
		||||
		return app.login_manager.unauthorized()
 | 
			
		||||
	return decorated_view
 | 
			
		||||
    @wraps(fn)
 | 
			
		||||
    def decorated_view(*args, **kwargs):
 | 
			
		||||
        if (query_is_admin_user(request.args) or
 | 
			
		||||
                query_is_photo_user(request.args) or
 | 
			
		||||
                current_user.is_authenticated):
 | 
			
		||||
            return fn(*args, **kwargs)
 | 
			
		||||
        return app.login_manager.unauthorized()
 | 
			
		||||
    return decorated_view
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def admin_required(fn):
 | 
			
		||||
	@wraps(fn)
 | 
			
		||||
	def decorated_view(*args, **kwargs):
 | 
			
		||||
		if query_is_admin_user(request.args) or (current_user.is_authenticated() and current_user.admin):
 | 
			
		||||
			return fn(*args, **kwargs)
 | 
			
		||||
		return app.login_manager.unauthorized()
 | 
			
		||||
	return decorated_view
 | 
			
		||||
    @wraps(fn)
 | 
			
		||||
    def decorated_view(*args, **kwargs):
 | 
			
		||||
        if (query_is_admin_user(request.args) or
 | 
			
		||||
                (current_user.is_authenticated and current_user.admin)):
 | 
			
		||||
            return fn(*args, **kwargs)
 | 
			
		||||
        return app.login_manager.unauthorized()
 | 
			
		||||
    return decorated_view
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def query_is_photo_user(query):
 | 
			
		||||
	username = query.get("username", None)
 | 
			
		||||
	password = query.get("password", None)
 | 
			
		||||
	return username == app.config["PHOTO_USERNAME"] and password == app.config["PHOTO_PASSWORD"]
 | 
			
		||||
    username = query.get("username", None)
 | 
			
		||||
    password = query.get("password", None)
 | 
			
		||||
    return username == (app.config["PHOTO_USERNAME"] and
 | 
			
		||||
                        password == app.config["PHOTO_PASSWORD"])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def query_is_admin_user(query):
 | 
			
		||||
	username = query.get("username", None)
 | 
			
		||||
	password = query.get("password", None)
 | 
			
		||||
	return username == app.config["ADMIN_USERNAME"] and password == app.config["ADMIN_PASSWORD"]
 | 
			
		||||
    username = query.get("username", None)
 | 
			
		||||
    password = query.get("password", None)
 | 
			
		||||
    return username == (app.config["ADMIN_USERNAME"] and
 | 
			
		||||
                        password == app.config["ADMIN_PASSWORD"])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def is_authenticated():
 | 
			
		||||
	return query_is_admin_user(request.args) or query_is_photo_user(request.args) or current_user.is_authenticated()
 | 
			
		||||
    return (query_is_admin_user(request.args) or
 | 
			
		||||
            query_is_photo_user(request.args) or
 | 
			
		||||
            current_user.is_authenticated)
 | 
			
		||||
 | 
			
		||||
@ -3,50 +3,61 @@ import subprocess
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProcessWrapper(object):
 | 
			
		||||
	def __init__(self, process, done):
 | 
			
		||||
		self.process = process
 | 
			
		||||
		self.done = done
 | 
			
		||||
	def close(self):
 | 
			
		||||
		self.done()
 | 
			
		||||
		if self.process.returncode is not None:
 | 
			
		||||
			return
 | 
			
		||||
		self.process.stdout.close()
 | 
			
		||||
		self.process.terminate()
 | 
			
		||||
		self.process.wait()
 | 
			
		||||
	def __iter__(self):
 | 
			
		||||
		return self
 | 
			
		||||
	def __del__(self):
 | 
			
		||||
		self.close()
 | 
			
		||||
	def next(self):
 | 
			
		||||
		try:
 | 
			
		||||
			data = self.process.stdout.readline()
 | 
			
		||||
		except:
 | 
			
		||||
			self.close()
 | 
			
		||||
			raise StopIteration()
 | 
			
		||||
		if data:
 | 
			
		||||
			return data
 | 
			
		||||
		self.close()
 | 
			
		||||
		raise StopIteration()
 | 
			
		||||
    def __init__(self, process, done):
 | 
			
		||||
        self.process = process
 | 
			
		||||
        self.done = done
 | 
			
		||||
 | 
			
		||||
    def close(self):
 | 
			
		||||
        self.done()
 | 
			
		||||
        if self.process.returncode is not None:
 | 
			
		||||
            return
 | 
			
		||||
        self.process.stdout.close()
 | 
			
		||||
        self.process.terminate()
 | 
			
		||||
        self.process.wait()
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    def __del__(self):
 | 
			
		||||
        self.close()
 | 
			
		||||
 | 
			
		||||
    def next(self):
 | 
			
		||||
        try:
 | 
			
		||||
            data = self.process.stdout.readline()
 | 
			
		||||
        except:
 | 
			
		||||
            self.close()
 | 
			
		||||
            raise StopIteration()
 | 
			
		||||
        if data:
 | 
			
		||||
            return data
 | 
			
		||||
        self.close()
 | 
			
		||||
        raise StopIteration()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def send_process(args, pid_file):
 | 
			
		||||
	def setup_proc():
 | 
			
		||||
		f = open(pid_file, "w")
 | 
			
		||||
		f.write(str(os.getpid()))
 | 
			
		||||
		f.close()
 | 
			
		||||
		os.close(0)
 | 
			
		||||
		os.dup2(1, 2)
 | 
			
		||||
	def tear_down_proc():
 | 
			
		||||
		try:
 | 
			
		||||
			os.unlink(pid_file)
 | 
			
		||||
		except:
 | 
			
		||||
			pass
 | 
			
		||||
	if os.path.exists(pid_file):
 | 
			
		||||
		f = open(pid_file, "r")
 | 
			
		||||
		pid = f.read()
 | 
			
		||||
		f.close()
 | 
			
		||||
		if os.path.exists("/proc/%s/status" % pid):
 | 
			
		||||
			return Response("Scanner is already running.\n", mimetype="text/plain")
 | 
			
		||||
	process = subprocess.Popen(args, close_fds=True, stdout=subprocess.PIPE, preexec_fn=setup_proc)
 | 
			
		||||
	response = ProcessWrapper(process, tear_down_proc)
 | 
			
		||||
	return Response(response, direct_passthrough=True, mimetype="text/plain")
 | 
			
		||||
    def setup_proc():
 | 
			
		||||
        f = open(pid_file, "w")
 | 
			
		||||
        f.write(str(os.getpid()))
 | 
			
		||||
        f.close()
 | 
			
		||||
        os.close(0)
 | 
			
		||||
        os.dup2(1, 2)
 | 
			
		||||
 | 
			
		||||
    def tear_down_proc():
 | 
			
		||||
        try:
 | 
			
		||||
            os.unlink(pid_file)
 | 
			
		||||
        except:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
    if os.path.exists(pid_file):
 | 
			
		||||
        f = open(pid_file, "r")
 | 
			
		||||
        pid = f.read()
 | 
			
		||||
        f.close()
 | 
			
		||||
        if os.path.exists("/proc/%s/status" % pid):
 | 
			
		||||
            return Response(
 | 
			
		||||
                "Scanner is already running.\n", mimetype="text/plain")
 | 
			
		||||
 | 
			
		||||
    process = subprocess.Popen(
 | 
			
		||||
        args, close_fds=True, stdout=subprocess.PIPE, preexec_fn=setup_proc)
 | 
			
		||||
    response = ProcessWrapper(process, tear_down_proc)
 | 
			
		||||
    return Response(response, direct_passthrough=True, mimetype="text/plain")
 | 
			
		||||
 | 
			
		||||
@ -5,19 +5,21 @@ from CachePath import message
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
	reload(sys)
 | 
			
		||||
	sys.setdefaultencoding("UTF-8")
 | 
			
		||||
 | 
			
		||||
	if len(sys.argv) != 3:
 | 
			
		||||
		print "usage: %s ALBUM_PATH CACHE_PATH" % sys.argv[0]
 | 
			
		||||
		return
 | 
			
		||||
	try:
 | 
			
		||||
		os.umask(022)
 | 
			
		||||
		TreeWalker(sys.argv[1], sys.argv[2])
 | 
			
		||||
	except KeyboardInterrupt:
 | 
			
		||||
		message("keyboard", "CTRL+C pressed, quitting.")
 | 
			
		||||
		sys.exit(-97)
 | 
			
		||||
def main():
 | 
			
		||||
    reload(sys)
 | 
			
		||||
    sys.setdefaultencoding("UTF-8")
 | 
			
		||||
 | 
			
		||||
    if len(sys.argv) != 3:
 | 
			
		||||
        print "usage: %s ALBUM_PATH CACHE_PATH" % sys.argv[0]
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        os.umask(022)
 | 
			
		||||
        TreeWalker(sys.argv[1], sys.argv[2])
 | 
			
		||||
    except KeyboardInterrupt:
 | 
			
		||||
        message("keyboard", "CTRL+C pressed, quitting.")
 | 
			
		||||
        sys.exit(-97)
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
	main()
 | 
			
		||||
    main()
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user