mirror of
https://github.com/gryf/pygtktalog.git
synced 2025-12-17 11:30:19 +01:00
Corrections to db converter, some improvements to commandline version of client
This commit is contained in:
192
cmdcatalog.py
192
cmdcatalog.py
@@ -1,20 +1,26 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
Fast and ugly CLI interface for pyGTKtalog
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import errno
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
from pygtktalog import scan
|
from pygtktalog import scan
|
||||||
from pygtktalog.dbobjects import File
|
from pygtktalog import misc
|
||||||
|
from pygtktalog.dbobjects import File, Config
|
||||||
from pygtktalog.dbcommon import connect, Session
|
from pygtktalog.dbcommon import connect, Session
|
||||||
|
|
||||||
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
|
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(30, 38)
|
||||||
|
|
||||||
RESET_SEQ = "\033[0m"
|
RESET_SEQ = "\033[0m"
|
||||||
COLOR_SEQ = "\033[1;%dm"
|
COLOR_SEQ = "\033[1;%dm"
|
||||||
BOLD_SEQ = "\033[1m"
|
BOLD_SEQ = "\033[1m"
|
||||||
|
|
||||||
|
|
||||||
def cprint(txt, color):
|
def colorize(txt, color):
|
||||||
|
"""Pretty print with colors to console."""
|
||||||
color_map = {"black": BLACK,
|
color_map = {"black": BLACK,
|
||||||
"red": RED,
|
"red": RED,
|
||||||
"green": GREEN,
|
"green": GREEN,
|
||||||
@@ -23,27 +29,23 @@ def cprint(txt, color):
|
|||||||
"magenta": MAGENTA,
|
"magenta": MAGENTA,
|
||||||
"cyan": CYAN,
|
"cyan": CYAN,
|
||||||
"white": WHITE}
|
"white": WHITE}
|
||||||
print COLOR_SEQ % (30 + color_map[color]) + txt + RESET_SEQ
|
return COLOR_SEQ % color_map[color] + txt + RESET_SEQ
|
||||||
|
|
||||||
|
|
||||||
class Iface(object):
|
class Iface(object):
|
||||||
|
"""Main class which interacts with the pyGTKtalog modules"""
|
||||||
def __init__(self, dbname, pretend=False, debug=False):
|
def __init__(self, dbname, pretend=False, debug=False):
|
||||||
|
"""Init"""
|
||||||
self.engine = connect(dbname)
|
self.engine = connect(dbname)
|
||||||
self.sess = Session()
|
self.sess = Session()
|
||||||
self.dry_run = pretend
|
self.dry_run = pretend
|
||||||
self.root = None
|
self.root = None
|
||||||
|
self._dbname = dbname
|
||||||
if debug:
|
if debug:
|
||||||
scan.LOG.setLevel("DEBUG")
|
scan.LOG.setLevel("DEBUG")
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.sess.commit()
|
|
||||||
self.sess.close()
|
|
||||||
|
|
||||||
# def create(self):
|
|
||||||
# self.sess.commit()
|
|
||||||
# self.sess.close()
|
|
||||||
|
|
||||||
def _resolve_path(self, path):
|
def _resolve_path(self, path):
|
||||||
|
"""Identify path in the DB"""
|
||||||
if not path.startswith("/"):
|
if not path.startswith("/"):
|
||||||
raise AttributeError("Path have to start with slash (/)")
|
raise AttributeError("Path have to start with slash (/)")
|
||||||
|
|
||||||
@@ -62,18 +64,51 @@ class Iface(object):
|
|||||||
return last_node
|
return last_node
|
||||||
|
|
||||||
def _make_path(self, node):
|
def _make_path(self, node):
|
||||||
|
"""Make the path to the item in the DB"""
|
||||||
if node.parent == node:
|
if node.parent == node:
|
||||||
return "/"
|
return "/"
|
||||||
|
|
||||||
|
ext = ""
|
||||||
|
if node.parent.type == 0:
|
||||||
|
ext = colorize(" (%s)" % node.filepath, "white")
|
||||||
|
|
||||||
path = []
|
path = []
|
||||||
path.append(node.filename)
|
path.append(node.filename)
|
||||||
while node.parent != self.root:
|
while node.parent != self.root:
|
||||||
path.append(node.parent.filename)
|
path.append(node.parent.filename)
|
||||||
node = node.parent
|
node = node.parent
|
||||||
|
|
||||||
return "/".join([""] + path[::-1])
|
return "/".join([""] + path[::-1]) + ext
|
||||||
|
|
||||||
def list(self, path=None):
|
def _walk(self, dirnode):
|
||||||
|
"""Recursively go through the leaves of the node"""
|
||||||
|
items = []
|
||||||
|
for node in dirnode.children:
|
||||||
|
if node.type == 1:
|
||||||
|
items += self._walk(node)
|
||||||
|
|
||||||
|
items.append(" " + self._make_path(node))
|
||||||
|
|
||||||
|
items.sort()
|
||||||
|
return items
|
||||||
|
|
||||||
|
def _list(self, node):
|
||||||
|
"""List only current node content"""
|
||||||
|
items = []
|
||||||
|
for node in node.children:
|
||||||
|
if node != self.root:
|
||||||
|
items.append(" " + self._make_path(node))
|
||||||
|
|
||||||
|
items.sort()
|
||||||
|
return items
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Close the session"""
|
||||||
|
self.sess.commit()
|
||||||
|
self.sess.close()
|
||||||
|
|
||||||
|
def list(self, path=None, recursive=False):
|
||||||
|
"""Simulate ls command for the provided item path"""
|
||||||
self.root = self.sess.query(File).filter(File.type==0).first()
|
self.root = self.sess.query(File).filter(File.type==0).first()
|
||||||
if path:
|
if path:
|
||||||
node = self._resolve_path(path)
|
node = self._resolve_path(path)
|
||||||
@@ -82,20 +117,25 @@ class Iface(object):
|
|||||||
node = self.root
|
node = self.root
|
||||||
msg = "Content of path `/':"
|
msg = "Content of path `/':"
|
||||||
|
|
||||||
cprint(msg, "white")
|
print colorize(msg, "white")
|
||||||
for node in node.children:
|
|
||||||
if node != self.root:
|
if recursive:
|
||||||
#if __debug__:
|
items = self._walk(node)
|
||||||
# print " %d:" % node.id, self._make_path(node)
|
else:
|
||||||
#else:
|
items = self._list(node)
|
||||||
print " ", self._make_path(node)
|
|
||||||
|
print "\n".join(items)
|
||||||
|
|
||||||
def update(self, path, dir_to_update=None):
|
def update(self, path, dir_to_update=None):
|
||||||
|
"""
|
||||||
|
Update the DB against provided path and optionally directory on the
|
||||||
|
real filesystem
|
||||||
|
"""
|
||||||
self.root = self.sess.query(File).filter(File.type==0).first()
|
self.root = self.sess.query(File).filter(File.type==0).first()
|
||||||
node = self._resolve_path(path)
|
node = self._resolve_path(path)
|
||||||
if node == self.root:
|
if node == self.root:
|
||||||
cprint("Cannot update entire db, since root was provided as path.",
|
print colorize("Cannot update entire db, since root was provided "
|
||||||
"red")
|
"as path.", "red")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not dir_to_update:
|
if not dir_to_update:
|
||||||
@@ -104,14 +144,15 @@ class Iface(object):
|
|||||||
if not os.path.exists(dir_to_update):
|
if not os.path.exists(dir_to_update):
|
||||||
raise OSError("Path to updtate doesn't exists: %s", dir_to_update)
|
raise OSError("Path to updtate doesn't exists: %s", dir_to_update)
|
||||||
|
|
||||||
cprint("Updating node `%s' against directory "
|
print colorize("Updating node `%s' against directory "
|
||||||
"`%s'" % (path, dir_to_update), "white")
|
"`%s'" % (path, dir_to_update), "white")
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
scanob = scan.Scan(dir_to_update)
|
scanob = scan.Scan(dir_to_update)
|
||||||
# scanob.update_files(node.id)
|
# scanob.update_files(node.id)
|
||||||
scanob.update_files(node.id, self.engine)
|
scanob.update_files(node.id, self.engine)
|
||||||
|
|
||||||
def create(self, dir_to_add):
|
def create(self, dir_to_add, data_dir):
|
||||||
|
"""Create new database"""
|
||||||
self.root = File()
|
self.root = File()
|
||||||
self.root.id = 1
|
self.root.id = 1
|
||||||
self.root.filename = 'root'
|
self.root.filename = 'root'
|
||||||
@@ -119,51 +160,93 @@ class Iface(object):
|
|||||||
self.root.source = 0
|
self.root.source = 0
|
||||||
self.root.type = 0
|
self.root.type = 0
|
||||||
self.root.parent_id = 1
|
self.root.parent_id = 1
|
||||||
|
|
||||||
|
config = Config()
|
||||||
|
config.key = "image_path"
|
||||||
|
config.value = data_dir
|
||||||
|
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
self.sess.add(self.root)
|
self.sess.add(self.root)
|
||||||
|
self.sess.add(config)
|
||||||
self.sess.commit()
|
self.sess.commit()
|
||||||
|
|
||||||
cprint("Creating new db against directory `%s'" % dir_to_add, "white")
|
print colorize("Creating new db against directory `%s'" % dir_to_add,
|
||||||
|
"white")
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
|
if data_dir == ":same_as_db:":
|
||||||
|
misc.calculate_image_path(None, True)
|
||||||
|
else:
|
||||||
|
misc.calculate_image_path(data_dir, True)
|
||||||
|
|
||||||
scanob = scan.Scan(dir_to_add)
|
scanob = scan.Scan(dir_to_add)
|
||||||
scanob.add_files(self.engine)
|
scanob.add_files(self.engine)
|
||||||
|
|
||||||
|
def add(self, dir_to_add):
|
||||||
|
"""Add new directory to the db"""
|
||||||
|
self.root = self.sess.query(File).filter(File.type==0).first()
|
||||||
|
|
||||||
|
if not os.path.exists(dir_to_add):
|
||||||
|
raise OSError("Path to add doesn't exists: %s", dir_to_add)
|
||||||
|
|
||||||
|
print colorize("Adding directory `%s'" % dir_to_add, "white")
|
||||||
|
if not self.dry_run:
|
||||||
|
scanob = scan.Scan(dir_to_add)
|
||||||
|
scanob.add_files()
|
||||||
|
|
||||||
|
|
||||||
def list_db(args):
|
def list_db(args):
|
||||||
|
"""List"""
|
||||||
if not os.path.exists(args.db):
|
if not os.path.exists(args.db):
|
||||||
cprint("File `%s' does not exists!" % args.db, "red")
|
print colorize("File `%s' does not exists!" % args.db, "red")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
obj = Iface(args.db, False, args.debug)
|
obj = Iface(args.db, False, args.debug)
|
||||||
obj.list(path=args.path)
|
obj.list(path=args.path, recursive=args.recursive)
|
||||||
obj.close()
|
obj.close()
|
||||||
|
|
||||||
|
|
||||||
def update_db(args):
|
def update_db(args):
|
||||||
|
"""Update"""
|
||||||
if not os.path.exists(args.db):
|
if not os.path.exists(args.db):
|
||||||
cprint("File `%s' does not exists!" % args.db, "red")
|
print colorize("File `%s' does not exists!" % args.db, "red")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
obj = Iface(args.db, args.pretend, args.debug)
|
obj = Iface(args.db, args.pretend, args.debug)
|
||||||
obj.update(args.path, dir_to_update=args.dir_to_update)
|
obj.update(args.path, dir_to_update=args.dir_to_update)
|
||||||
obj.close()
|
obj.close()
|
||||||
|
|
||||||
def create_db(args):
|
|
||||||
if os.path.exists(args.db):
|
def add_dir(args):
|
||||||
cprint("File `%s' exists!" % args.db, "yellow")
|
"""Add"""
|
||||||
|
if not os.path.exists(args.db):
|
||||||
|
print colorize("File `%s' does not exists!" % args.db, "red")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
obj = Iface(args.db, args.pretend, args.debug)
|
obj = Iface(args.db, args.pretend, args.debug)
|
||||||
obj.create(args.dir_to_add)
|
obj.add(args.dir_to_add)
|
||||||
obj.close()
|
obj.close()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def create_db(args):
|
||||||
|
"""List"""
|
||||||
|
if os.path.exists(args.db):
|
||||||
|
print colorize("File `%s' exists!" % args.db, "yellow")
|
||||||
|
|
||||||
|
obj = Iface(args.db, args.pretend, args.debug)
|
||||||
|
obj.create(args.dir_to_add, args.imagedir)
|
||||||
|
obj.close()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main"""
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
|
|
||||||
subparser = parser.add_subparsers()
|
subparser = parser.add_subparsers()
|
||||||
list_ = subparser.add_parser("list")
|
list_ = subparser.add_parser("list")
|
||||||
list_.add_argument("db")
|
list_.add_argument("db")
|
||||||
list_.add_argument("path", nargs="?")
|
list_.add_argument("path", nargs="?")
|
||||||
|
list_.add_argument("-r", "--recursive", help="list items in "
|
||||||
|
"subdirectories", action="store_true", default=False)
|
||||||
list_.add_argument("-d", "--debug", help="Turn on debug",
|
list_.add_argument("-d", "--debug", help="Turn on debug",
|
||||||
action="store_true", default=False)
|
action="store_true", default=False)
|
||||||
list_.set_defaults(func=list_db)
|
list_.set_defaults(func=list_db)
|
||||||
@@ -182,6 +265,12 @@ if __name__ == "__main__":
|
|||||||
create = subparser.add_parser("create")
|
create = subparser.add_parser("create")
|
||||||
create.add_argument("db")
|
create.add_argument("db")
|
||||||
create.add_argument("dir_to_add")
|
create.add_argument("dir_to_add")
|
||||||
|
create.add_argument("-i", "--imagedir", help="Directory where to put "
|
||||||
|
"images for the database. Popular, but deprecated "
|
||||||
|
"choice is `~/.pygtktalog/images'. Currnet default "
|
||||||
|
"is special string `:same_as_db:' which will try to "
|
||||||
|
"create directory with the same name as the db with "
|
||||||
|
"data suffix", default=":same_as_db:")
|
||||||
create.add_argument("-p", "--pretend", help="Don't do the action, just "
|
create.add_argument("-p", "--pretend", help="Don't do the action, just "
|
||||||
"give the info what would gonna to happen.",
|
"give the info what would gonna to happen.",
|
||||||
action="store_true", default=False)
|
action="store_true", default=False)
|
||||||
@@ -189,27 +278,18 @@ if __name__ == "__main__":
|
|||||||
action="store_true", default=False)
|
action="store_true", default=False)
|
||||||
create.set_defaults(func=create_db)
|
create.set_defaults(func=create_db)
|
||||||
|
|
||||||
|
add = subparser.add_parser("add")
|
||||||
|
add.add_argument("db")
|
||||||
|
add.add_argument("dir_to_add")
|
||||||
|
add.add_argument("-p", "--pretend", help="Don't do the action, just "
|
||||||
|
"give the info what would gonna to happen.",
|
||||||
|
action="store_true", default=False)
|
||||||
|
add.add_argument("-d", "--debug", help="Turn on debug",
|
||||||
|
action="store_true", default=False)
|
||||||
|
add.set_defaults(func=add_dir)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
args.func(args)
|
args.func(args)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
"""
|
main()
|
||||||
db_file = "/home/gryf/spisy/xxx.sqlite"
|
|
||||||
connect(db_file)
|
|
||||||
sess = Session()
|
|
||||||
|
|
||||||
#if not sess.query(File).get(1):
|
|
||||||
# root = File()
|
|
||||||
# root.id = 1
|
|
||||||
# root.filename = 'root'
|
|
||||||
# root.size = 0
|
|
||||||
# root.source = 0
|
|
||||||
# t.type = 0
|
|
||||||
# root.parent_id = 1
|
|
||||||
# sess.add(root)
|
|
||||||
# sess.commit()
|
|
||||||
|
|
||||||
f = "/mnt/hardtwo/XXX/"
|
|
||||||
scanob = scan.Scan(f)
|
|
||||||
scanob.update_files(2)
|
|
||||||
"""
|
|
||||||
|
|||||||
@@ -6,39 +6,177 @@
|
|||||||
Author: Roman 'gryf' Dobosz, gryf73@gmail.com
|
Author: Roman 'gryf' Dobosz, gryf73@gmail.com
|
||||||
Created: 2009-08-14
|
Created: 2009-08-14
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import bz2
|
|
||||||
import shutil
|
|
||||||
from tempfile import mkstemp
|
|
||||||
from sqlite3 import dbapi2 as sqlite
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from sqlite3 import dbapi2 as sqlite
|
||||||
|
from sqlite3 import OperationalError
|
||||||
|
from tempfile import mkstemp
|
||||||
|
import bz2
|
||||||
|
import errno
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
# import db objects just to create schema
|
from sqlalchemy.dialects.sqlite import DATETIME
|
||||||
from pygtktalog.dbobjects import File, Exif, Group, Gthumb
|
|
||||||
from pygtktalog.dbobjects import Image, Tag, Thumbnail
|
|
||||||
from pygtktalog.dbcommon import connect
|
|
||||||
|
|
||||||
def create_schema(cur):
|
from pygtktalog.misc import mk_paths, calculate_image_path
|
||||||
pass
|
|
||||||
|
|
||||||
|
PATH1 = os.path.expanduser("~/.pygtktalog/images")
|
||||||
|
PATH2 = os.path.expanduser("~/.pygtktalog/imgs2")
|
||||||
|
|
||||||
|
|
||||||
|
def mkdir_p(path):
|
||||||
|
"""Make directories recurively, like 'mkdir -p' command"""
|
||||||
|
try:
|
||||||
|
os.makedirs(path)
|
||||||
|
except OSError as exc:
|
||||||
|
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
return path
|
||||||
|
|
||||||
|
def get_images_path(cur):
|
||||||
|
"""
|
||||||
|
Calculate the data dir in order:
|
||||||
|
- config table
|
||||||
|
- old default path
|
||||||
|
- new default path
|
||||||
|
return first, which contain provided image filename
|
||||||
|
"""
|
||||||
|
|
||||||
|
image = cur.execute("select filename from images limit 1").fetchone()
|
||||||
|
if image and image[0]:
|
||||||
|
image = image[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = cur.execute("select value from config where "
|
||||||
|
"key='image_path'").fetchone()
|
||||||
|
if (result and result[0] and
|
||||||
|
os.path.exists(os.path.join(result[0].encode("utf-8"),
|
||||||
|
image.encode("utf-8")))):
|
||||||
|
return result[0]
|
||||||
|
except OperationalError:
|
||||||
|
# no such table like config. proceed.
|
||||||
|
pass
|
||||||
|
|
||||||
|
for path in (PATH1, PATH2):
|
||||||
|
if os.path.exists(os.path.join(path, image)):
|
||||||
|
return path
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_path(cur, image):
|
||||||
|
"""
|
||||||
|
Calculate the data dir in order:
|
||||||
|
- config table
|
||||||
|
- old default path
|
||||||
|
- new default path
|
||||||
|
return first, which contain provided image filename
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
result = cur.execute("select value from config where "
|
||||||
|
"key='image_path'").fetchone()
|
||||||
|
if (result and result[0] and
|
||||||
|
os.path.exists(os.path.join(result[0].encode("utf-8"),
|
||||||
|
image.encode("utf-8")))):
|
||||||
|
return result[0]
|
||||||
|
except OperationalError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for path in (PATH1, PATH2):
|
||||||
|
if os.path.exists(os.path.join(path, image)):
|
||||||
|
return path
|
||||||
|
return None
|
||||||
|
|
||||||
|
def old_style_image_handle(fname, source_dir, dest_dir):
|
||||||
|
"""
|
||||||
|
Deal with old-style images in DB. There is a flat list under
|
||||||
|
~/.pygtktalog/images/ directory, which should be converted to nested
|
||||||
|
structure.
|
||||||
|
"""
|
||||||
|
|
||||||
|
partial_path = mk_paths(os.path.join(source_dir, fname), dest_dir)
|
||||||
|
|
||||||
|
dest_file = os.path.join(dest_dir, *partial_path)
|
||||||
|
dest_thumb = os.path.join(dest_dir, *partial_path) + "_t"
|
||||||
|
|
||||||
|
shutil.copy(os.path.join(source_dir, fname), dest_file)
|
||||||
|
shutil.copy(os.path.join(source_dir, fname + "_t"), dest_thumb)
|
||||||
|
with open("log.txt", "a") as fobj:
|
||||||
|
fobj.write(os.path.join(fname) + "\n")
|
||||||
|
fobj.write(os.path.join(fname + "_t\n"))
|
||||||
|
|
||||||
|
return os.path.join(*partial_path), os.path.join(*partial_path) + "_t"
|
||||||
|
|
||||||
|
|
||||||
|
def new_style_image_handle(partial_path, source_dir, dest_dir):
|
||||||
|
"""
|
||||||
|
Deal with old-style images in DB. In the early version directory was
|
||||||
|
hardcoded to ~/.pygtktalog/imgs2/, and all the needed files (with the
|
||||||
|
paths) should be copied to the new place.
|
||||||
|
params:
|
||||||
|
partial_path: string holding the relative path to file, for example
|
||||||
|
`de/ad/be/ef.jpg'
|
||||||
|
source_dir: path, where at the moment image file resides. Might be the
|
||||||
|
full path, like `/home/user/.pygtktalog/imgs2`
|
||||||
|
dest_dir: path (might be relative or absolute), where we want to put
|
||||||
|
the images (i.e. `../foo-images')
|
||||||
|
"""
|
||||||
|
dest_dir = mkdir_p(os.path.join(dest_dir, os.path.dirname(partial_path)))
|
||||||
|
base, ext = os.path.splitext(partial_path)
|
||||||
|
thumb = os.path.join(source_dir, "".join([base, "_t", ext]))
|
||||||
|
filename = os.path.join(source_dir, partial_path)
|
||||||
|
|
||||||
|
shutil.copy(filename, dest_dir)
|
||||||
|
shutil.copy(thumb, dest_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_images_to_destination(cursor, image_path, dest):
|
||||||
|
"""Copy images to dest directory and correct the db entry, if needed"""
|
||||||
|
|
||||||
|
sql = "select id, filename from images"
|
||||||
|
update = "update images set filename=? where id=?"
|
||||||
|
t_select = "select id from thumbnails where filename=?"
|
||||||
|
t_update = "update thumbnails set filename=? where id=?"
|
||||||
|
|
||||||
|
count = -1
|
||||||
|
for count, (id_, filename) in enumerate(cursor.execute(sql).fetchall()):
|
||||||
|
if not image_path:
|
||||||
|
image_path = get_path(cursor, filename)
|
||||||
|
if not image_path:
|
||||||
|
raise OSError("Image file '%s' not found under data "
|
||||||
|
"directory, aborting" % filename)
|
||||||
|
|
||||||
|
if image_path == PATH1:
|
||||||
|
# old style filenames. Flat list.
|
||||||
|
fname, tname = old_style_image_handle(filename, image_path, dest)
|
||||||
|
cursor.execute(update, (fname, id_))
|
||||||
|
for (thumb_id,) in cursor.execute(t_select,
|
||||||
|
(filename,)).fetchall():
|
||||||
|
cursor.execute(t_update, (tname, thumb_id))
|
||||||
|
else:
|
||||||
|
# new style filenames. nested dirs
|
||||||
|
new_style_image_handle(filename, image_path, dest)
|
||||||
|
|
||||||
|
if count > 0:
|
||||||
|
print "copied %d files" % (count + 1)
|
||||||
|
|
||||||
def create_temporary_db_file():
|
def create_temporary_db_file():
|
||||||
"""create temporary db file"""
|
"""create temporary db file"""
|
||||||
fd, fname = mkstemp()
|
file_descriptor, fname = mkstemp()
|
||||||
os.close(fd)
|
os.close(file_descriptor)
|
||||||
return fname
|
return fname
|
||||||
|
|
||||||
def connect_to_db(filename):
|
def connect_to_db(filename):
|
||||||
"""initialize db connection and store it in class attributes"""
|
"""initialize db connection and store it in class attributes"""
|
||||||
db_connection = sqlite.connect(filename, detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES)
|
db_connection = sqlite.connect(filename, detect_types=
|
||||||
|
sqlite.PARSE_DECLTYPES |
|
||||||
|
sqlite.PARSE_COLNAMES)
|
||||||
db_cursor = db_connection.cursor()
|
db_cursor = db_connection.cursor()
|
||||||
return db_connection, db_cursor
|
return db_connection, db_cursor
|
||||||
|
|
||||||
def opendb(filename=None):
|
def opendb(filename=None):
|
||||||
"""try to open db file"""
|
"""try to open db file"""
|
||||||
db_tmp_path = create_temporary_db_file()
|
db_tmp_path = create_temporary_db_file()
|
||||||
compressed = False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
test_file = open(filename).read(15)
|
test_file = open(filename).read(15)
|
||||||
@@ -57,7 +195,6 @@ def opendb(filename=None):
|
|||||||
curdb.write(open_file.read())
|
curdb.write(open_file.read())
|
||||||
curdb.close()
|
curdb.close()
|
||||||
open_file.close()
|
open_file.close()
|
||||||
compressed = True
|
|
||||||
except IOError:
|
except IOError:
|
||||||
# file is not bz2
|
# file is not bz2
|
||||||
os.unlink(db_tmp_path)
|
os.unlink(db_tmp_path)
|
||||||
@@ -68,52 +205,95 @@ def opendb(filename=None):
|
|||||||
|
|
||||||
return connect_to_db(db_tmp_path), db_tmp_path
|
return connect_to_db(db_tmp_path), db_tmp_path
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def _update_dates(cursor, select_sql, update_sql):
|
||||||
if len(sys.argv) != 3:
|
"""update date format - worker function"""
|
||||||
print "usage: %s src_base dst_base" % sys.argv[0]
|
for id_, date in cursor.execute(select_sql).fetchall():
|
||||||
exit()
|
|
||||||
|
|
||||||
result = opendb(sys.argv[1])
|
|
||||||
if not result:
|
|
||||||
print "unable to open src db file"
|
|
||||||
exit()
|
|
||||||
|
|
||||||
(src_con, src_c), src_tmpf = result
|
|
||||||
|
|
||||||
shutil.copy(src_tmpf, sys.argv[2])
|
|
||||||
|
|
||||||
# close src db.
|
|
||||||
src_c.close()
|
|
||||||
src_con.close()
|
|
||||||
os.unlink(src_tmpf)
|
|
||||||
|
|
||||||
# create or update shema
|
|
||||||
connect(sys.argv[2])
|
|
||||||
|
|
||||||
dst_con = sqlite.connect(sys.argv[2])
|
|
||||||
dst_c = dst_con.cursor()
|
|
||||||
|
|
||||||
sql = "select id, date from files"
|
|
||||||
|
|
||||||
for id, date in dst_c.execute(sql).fetchall():
|
|
||||||
sql = "update files set date=? where id=?"
|
|
||||||
if date and int(date) > 0:
|
|
||||||
dst_c.execute(sql, (datetime.fromtimestamp(int(date)), id))
|
|
||||||
else:
|
|
||||||
dst_c.execute(sql, (None, id))
|
|
||||||
|
|
||||||
sql = "select id, date from gthumb"
|
|
||||||
|
|
||||||
for id, date in dst_c.execute(sql).fetchall():
|
|
||||||
sql = "update gthumb set date=? where id=?"
|
|
||||||
try:
|
try:
|
||||||
if int(date) > 0:
|
date = int(date)
|
||||||
dst_c.execute(sql, (datetime.fromtimestamp(int(date)), id))
|
except ValueError:
|
||||||
else:
|
# most probably there is no need for updating this record.
|
||||||
dst_c.execute(sql, (None, id))
|
continue
|
||||||
except:
|
except TypeError:
|
||||||
print id, date
|
date = 0
|
||||||
|
|
||||||
dst_con.commit()
|
if date > 0:
|
||||||
dst_c.close()
|
val = DATETIME().bind_processor(None)(datetime.fromtimestamp(date))
|
||||||
dst_con.close()
|
else:
|
||||||
|
val = None
|
||||||
|
cursor.execute(update_sql, (val, id_))
|
||||||
|
|
||||||
|
def update_dates(cursor):
|
||||||
|
"""Update date format from plain int to datetime object"""
|
||||||
|
|
||||||
|
_update_dates(cursor,
|
||||||
|
"select id, date from files",
|
||||||
|
"update files set date=? where id=?")
|
||||||
|
_update_dates(cursor,
|
||||||
|
"select id, date from gthumb",
|
||||||
|
"update gthumb set date=? where id=?")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main logic"""
|
||||||
|
if len(sys.argv) not in (4, 3):
|
||||||
|
print("usage: %s source_dbfile destination_dbfile [image_dir]\n"
|
||||||
|
"where image dir is a name where to put images. same name with"
|
||||||
|
"'_images' suffix by default"
|
||||||
|
% sys.argv[0])
|
||||||
|
exit()
|
||||||
|
|
||||||
|
if len(sys.argv) == 4:
|
||||||
|
source_dbfile, destination_dbfile, image_dir = sys.argv[1:]
|
||||||
|
else:
|
||||||
|
source_dbfile, destination_dbfile = sys.argv[1:]
|
||||||
|
image_dir = ":same_as_db:"
|
||||||
|
|
||||||
|
result = opendb(source_dbfile)
|
||||||
|
if not result:
|
||||||
|
print("unable to open src db file")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
(connection, cursor), temporary_database_filename = result
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
||||||
|
shutil.copy(temporary_database_filename, destination_dbfile)
|
||||||
|
os.unlink(temporary_database_filename)
|
||||||
|
|
||||||
|
connection = sqlite.connect(destination_dbfile)
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
if cursor.execute("select name from sqlite_master where type='table' "
|
||||||
|
"and name='table_name'").fetchone() is None:
|
||||||
|
cursor.execute("CREATE TABLE 'config' (\n\t'id'\tINTEGER NOT NULL,\n"
|
||||||
|
"\t'key'\tTEXT,\n\t'value'\tTEXT,\n\tPRIMARY "
|
||||||
|
"KEY(id)\n)")
|
||||||
|
|
||||||
|
if cursor.execute("select value from config where "
|
||||||
|
"key='image_path'").fetchone() is None:
|
||||||
|
cursor.execute("insert into config(key, value) "
|
||||||
|
"values('image_path', ?)", (image_dir,))
|
||||||
|
else:
|
||||||
|
cursor.execute("update config set value=? where key='image_path'",
|
||||||
|
(image_dir,))
|
||||||
|
|
||||||
|
if image_dir == ":same_as_db:":
|
||||||
|
db_fname = os.path.basename(destination_dbfile)
|
||||||
|
base, dummy = os.path.splitext(db_fname)
|
||||||
|
image_dir_path = os.path.join(os.path.dirname(destination_dbfile),
|
||||||
|
base + "_images")
|
||||||
|
else:
|
||||||
|
image_dir_path = image_dir
|
||||||
|
|
||||||
|
calculate_image_path(image_dir_path, True)
|
||||||
|
|
||||||
|
update_dates(cursor)
|
||||||
|
old_image_path = get_images_path(cursor)
|
||||||
|
copy_images_to_destination(cursor, old_image_path, image_dir_path)
|
||||||
|
|
||||||
|
connection.commit()
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|||||||
64
project.vim
64
project.vim
@@ -1,64 +0,0 @@
|
|||||||
"All your bases are belong to us."
|
|
||||||
"
|
|
||||||
" Author: Roman.Dobosz at gmail.com
|
|
||||||
" Date: 2011-12-09 12:11:00
|
|
||||||
|
|
||||||
if !has("python")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
let g:project_dir = expand("%:p:h")
|
|
||||||
|
|
||||||
python << EOF
|
|
||||||
import os
|
|
||||||
import vim
|
|
||||||
|
|
||||||
PROJECT_DIR = vim.eval('project_dir')
|
|
||||||
TAGS_FILE = os.path.join(PROJECT_DIR, "tags")
|
|
||||||
|
|
||||||
if not PROJECT_DIR.endswith("/"):
|
|
||||||
PROJECT_DIR += "/"
|
|
||||||
PYFILES= []
|
|
||||||
|
|
||||||
if os.path.exists(PROJECT_DIR + "tmp"):
|
|
||||||
os.system('rm -fr ' + PROJECT_DIR + "tmp")
|
|
||||||
|
|
||||||
## icard specific
|
|
||||||
#for dir_ in os.listdir(os.path.join(PROJECT_DIR, "..", "externals")):
|
|
||||||
# if dir_ != 'mako':
|
|
||||||
# PYFILES.append(dir_)
|
|
||||||
|
|
||||||
vim.command("set tags+=" + TAGS_FILE)
|
|
||||||
|
|
||||||
# make all directories accessible by gf command
|
|
||||||
def req(path):
|
|
||||||
root, dirs, files = os.walk(path).next()
|
|
||||||
for dir_ in dirs:
|
|
||||||
newroot = os.path.join(root, dir_)
|
|
||||||
# all but the dot dirs
|
|
||||||
if dir_ in (".svn", ".hg", "locale", "tmp"):
|
|
||||||
continue
|
|
||||||
if "static" in root and dir_ != "js":
|
|
||||||
continue
|
|
||||||
|
|
||||||
vim.command("set path+=" + newroot)
|
|
||||||
req(newroot)
|
|
||||||
|
|
||||||
req(PROJECT_DIR)
|
|
||||||
|
|
||||||
# generate tags
|
|
||||||
def update_tags(path):
|
|
||||||
assert os.path.exists(path)
|
|
||||||
|
|
||||||
pylib_path = os.path.normpath(path)
|
|
||||||
pylib_path += " " + os.path.normpath('/usr/lib/python2.7/site-packages')
|
|
||||||
|
|
||||||
# find tags for all files
|
|
||||||
cmd = 'ctags -R --python-kinds=-i'
|
|
||||||
cmd += ' -f ' + TAGS_FILE + ' ' + pylib_path
|
|
||||||
print cmd
|
|
||||||
os.system(cmd)
|
|
||||||
EOF
|
|
||||||
|
|
||||||
"
|
|
||||||
command UpdateTags python update_tags(PROJECT_DIR)
|
|
||||||
@@ -21,6 +21,7 @@ from pygtktalog.logger import get_logger
|
|||||||
Meta = MetaData()
|
Meta = MetaData()
|
||||||
Base = declarative_base(metadata=Meta)
|
Base = declarative_base(metadata=Meta)
|
||||||
Session = sessionmaker()
|
Session = sessionmaker()
|
||||||
|
DbFilename = None
|
||||||
|
|
||||||
LOG = get_logger("dbcommon")
|
LOG = get_logger("dbcommon")
|
||||||
|
|
||||||
@@ -32,11 +33,13 @@ def connect(filename=None):
|
|||||||
@filename - string with absolute or relative path to sqlite database
|
@filename - string with absolute or relative path to sqlite database
|
||||||
file. If None, db in-memory will be created
|
file. If None, db in-memory will be created
|
||||||
"""
|
"""
|
||||||
|
global DbFilename
|
||||||
|
|
||||||
if not filename:
|
if not filename:
|
||||||
filename = ':memory:'
|
filename = ':memory:'
|
||||||
|
|
||||||
LOG.info("db filename: %s" % filename)
|
LOG.info("db filename: %s" % filename)
|
||||||
|
DbFilename = filename
|
||||||
|
|
||||||
connect_string = "sqlite:///%s" % filename
|
connect_string = "sqlite:///%s" % filename
|
||||||
engine = create_engine(connect_string)
|
engine = create_engine(connect_string)
|
||||||
|
|||||||
@@ -6,10 +6,7 @@
|
|||||||
Created: 2009-08-07
|
Created: 2009-08-07
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import errno
|
|
||||||
import shutil
|
import shutil
|
||||||
from hashlib import sha256
|
|
||||||
from zlib import crc32
|
|
||||||
|
|
||||||
from sqlalchemy import Column, Table, Integer, Text
|
from sqlalchemy import Column, Table, Integer, Text
|
||||||
from sqlalchemy import DateTime, ForeignKey, Sequence
|
from sqlalchemy import DateTime, ForeignKey, Sequence
|
||||||
@@ -18,12 +15,11 @@ from sqlalchemy.orm import relation, backref
|
|||||||
from pygtktalog.dbcommon import Base
|
from pygtktalog.dbcommon import Base
|
||||||
from pygtktalog.thumbnail import ThumbCreator
|
from pygtktalog.thumbnail import ThumbCreator
|
||||||
from pygtktalog.logger import get_logger
|
from pygtktalog.logger import get_logger
|
||||||
|
from pygtktalog.misc import mk_paths
|
||||||
|
|
||||||
|
|
||||||
LOG = get_logger(__name__)
|
LOG = get_logger(__name__)
|
||||||
|
|
||||||
IMG_PATH = "/home/gryf/.pygtktalog/imgs2/" # FIXME: should be configurable
|
|
||||||
|
|
||||||
tags_files = Table("tags_files", Base.metadata,
|
tags_files = Table("tags_files", Base.metadata,
|
||||||
Column("file_id", Integer, ForeignKey("files.id")),
|
Column("file_id", Integer, ForeignKey("files.id")),
|
||||||
Column("tag_id", Integer, ForeignKey("tags.id")))
|
Column("tag_id", Integer, ForeignKey("tags.id")))
|
||||||
@@ -31,25 +27,11 @@ tags_files = Table("tags_files", Base.metadata,
|
|||||||
TYPE = {'root': 0, 'dir': 1, 'file': 2, 'link': 3}
|
TYPE = {'root': 0, 'dir': 1, 'file': 2, 'link': 3}
|
||||||
|
|
||||||
|
|
||||||
def mk_paths(fname):
|
|
||||||
#new_name = str(uuid.uuid1()).split("-")
|
|
||||||
fd = open(fname)
|
|
||||||
new_path = "%x" % (crc32(fd.read(10*1024*1024)) & 0xffffffff)
|
|
||||||
fd.close()
|
|
||||||
|
|
||||||
new_path = [new_path[i:i + 2] for i in range(0, len(new_path), 2)]
|
|
||||||
full_path = os.path.join(IMG_PATH, *new_path[:-1])
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.makedirs(full_path)
|
|
||||||
except OSError as exc:
|
|
||||||
if exc.errno != errno.EEXIST:
|
|
||||||
LOG.debug("Directory %s already exists." % full_path)
|
|
||||||
|
|
||||||
return new_path
|
|
||||||
|
|
||||||
|
|
||||||
class File(Base):
|
class File(Base):
|
||||||
|
"""
|
||||||
|
File mapping. Instances of this object can reference other File object
|
||||||
|
which make the structure to be tree-like
|
||||||
|
"""
|
||||||
__tablename__ = "files"
|
__tablename__ = "files"
|
||||||
id = Column(Integer, Sequence("file_id_seq"), primary_key=True)
|
id = Column(Integer, Sequence("file_id_seq"), primary_key=True)
|
||||||
parent_id = Column(Integer, ForeignKey("files.id"), index=True)
|
parent_id = Column(Integer, ForeignKey("files.id"), index=True)
|
||||||
@@ -102,19 +84,9 @@ class File(Base):
|
|||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# def mk_checksum(self):
|
|
||||||
# if not (self.filename and self.filepath):
|
|
||||||
# return
|
|
||||||
|
|
||||||
# full_name = os.path.join(self.filepath, self.filename)
|
|
||||||
|
|
||||||
# SLOW!
|
|
||||||
# if os.path.isfile(full_name):
|
|
||||||
# fd = open(full_name)
|
|
||||||
# self.checksum = sha256(fd.read(10*1024*1024)).hexdigest()
|
|
||||||
# fd.close()
|
|
||||||
|
|
||||||
class Group(Base):
|
class Group(Base):
|
||||||
|
"""TODO: what is this class for?"""
|
||||||
__tablename__ = "groups"
|
__tablename__ = "groups"
|
||||||
id = Column(Integer, Sequence("group_id_seq"), primary_key=True)
|
id = Column(Integer, Sequence("group_id_seq"), primary_key=True)
|
||||||
name = Column(Text)
|
name = Column(Text)
|
||||||
@@ -129,6 +101,7 @@ class Group(Base):
|
|||||||
|
|
||||||
|
|
||||||
class Tag(Base):
|
class Tag(Base):
|
||||||
|
"""Tag mapping"""
|
||||||
__tablename__ = "tags"
|
__tablename__ = "tags"
|
||||||
id = Column(Integer, Sequence("tags_id_seq"), primary_key=True)
|
id = Column(Integer, Sequence("tags_id_seq"), primary_key=True)
|
||||||
group_id = Column(Integer, ForeignKey("groups.id"), index=True)
|
group_id = Column(Integer, ForeignKey("groups.id"), index=True)
|
||||||
@@ -146,22 +119,24 @@ class Tag(Base):
|
|||||||
|
|
||||||
|
|
||||||
class Thumbnail(Base):
|
class Thumbnail(Base):
|
||||||
|
"""Thumbnail for the file"""
|
||||||
__tablename__ = "thumbnails"
|
__tablename__ = "thumbnails"
|
||||||
id = Column(Integer, Sequence("thumbnail_id_seq"), primary_key=True)
|
id = Column(Integer, Sequence("thumbnail_id_seq"), primary_key=True)
|
||||||
file_id = Column(Integer, ForeignKey("files.id"), index=True)
|
file_id = Column(Integer, ForeignKey("files.id"), index=True)
|
||||||
filename = Column(Text)
|
filename = Column(Text)
|
||||||
|
|
||||||
def __init__(self, filename=None, file_obj=None):
|
def __init__(self, filename=None, img_path=None, file_obj=None):
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.file = file_obj
|
self.file = file_obj
|
||||||
if filename and file_obj:
|
self.img_path = img_path
|
||||||
self.save(self.filename)
|
if filename and file_obj and img_path:
|
||||||
|
self.save(self.filename, img_path)
|
||||||
|
|
||||||
def save(self, fname):
|
def save(self, fname, img_path):
|
||||||
"""
|
"""
|
||||||
Create file related thumbnail, add it to the file object.
|
Create file related thumbnail, add it to the file object.
|
||||||
"""
|
"""
|
||||||
new_name = mk_paths(fname)
|
new_name = mk_paths(fname, img_path)
|
||||||
ext = os.path.splitext(self.filename)[1]
|
ext = os.path.splitext(self.filename)[1]
|
||||||
if ext:
|
if ext:
|
||||||
new_name.append("".join([new_name.pop(), ext]))
|
new_name.append("".join([new_name.pop(), ext]))
|
||||||
@@ -170,8 +145,8 @@ class Thumbnail(Base):
|
|||||||
name, ext = os.path.splitext(new_name.pop())
|
name, ext = os.path.splitext(new_name.pop())
|
||||||
new_name.append("".join([name, "_t", ext]))
|
new_name.append("".join([name, "_t", ext]))
|
||||||
self.filename = os.path.sep.join(new_name)
|
self.filename = os.path.sep.join(new_name)
|
||||||
if not os.path.exists(os.path.join(IMG_PATH, *new_name)):
|
if not os.path.exists(os.path.join(img_path, *new_name)):
|
||||||
shutil.move(thumb, os.path.join(IMG_PATH, *new_name))
|
shutil.move(thumb, os.path.join(img_path, *new_name))
|
||||||
else:
|
else:
|
||||||
LOG.info("Thumbnail already exists (%s: %s)" % \
|
LOG.info("Thumbnail already exists (%s: %s)" % \
|
||||||
(fname, "/".join(new_name)))
|
(fname, "/".join(new_name)))
|
||||||
@@ -182,34 +157,36 @@ class Thumbnail(Base):
|
|||||||
|
|
||||||
|
|
||||||
class Image(Base):
|
class Image(Base):
|
||||||
|
"""Images and their thumbnails"""
|
||||||
__tablename__ = "images"
|
__tablename__ = "images"
|
||||||
id = Column(Integer, Sequence("images_id_seq"), primary_key=True)
|
id = Column(Integer, Sequence("images_id_seq"), primary_key=True)
|
||||||
file_id = Column(Integer, ForeignKey("files.id"), index=True)
|
file_id = Column(Integer, ForeignKey("files.id"), index=True)
|
||||||
filename = Column(Text)
|
filename = Column(Text)
|
||||||
|
|
||||||
def __init__(self, filename=None, file_obj=None, move=True):
|
def __init__(self, filename=None, img_path=None, file_obj=None, move=True):
|
||||||
self.filename = None
|
self.filename = None
|
||||||
self.file = file_obj
|
self.file = file_obj
|
||||||
if filename:
|
self.img_path = img_path
|
||||||
|
if filename and img_path:
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.save(filename, move)
|
self.save(filename, img_path, move)
|
||||||
|
|
||||||
def save(self, fname, move=True):
|
def save(self, fname, img_path, move=True):
|
||||||
"""
|
"""
|
||||||
Save and create coressponding thumbnail (note: it differs from file
|
Save and create coressponding thumbnail (note: it differs from file
|
||||||
related thumbnail!)
|
related thumbnail!)
|
||||||
"""
|
"""
|
||||||
new_name = mk_paths(fname)
|
new_name = mk_paths(fname, img_path)
|
||||||
ext = os.path.splitext(self.filename)[1]
|
ext = os.path.splitext(self.filename)[1]
|
||||||
|
|
||||||
if ext:
|
if ext:
|
||||||
new_name.append("".join([new_name.pop(), ext]))
|
new_name.append("".join([new_name.pop(), ext]))
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(IMG_PATH, *new_name)):
|
if not os.path.exists(os.path.join(img_path, *new_name)):
|
||||||
if move:
|
if move:
|
||||||
shutil.move(self.filename, os.path.join(IMG_PATH, *new_name))
|
shutil.move(self.filename, os.path.join(img_path, *new_name))
|
||||||
else:
|
else:
|
||||||
shutil.copy(self.filename, os.path.join(IMG_PATH, *new_name))
|
shutil.copy(self.filename, os.path.join(img_path, *new_name))
|
||||||
else:
|
else:
|
||||||
LOG.warning("Image with same CRC already exists "
|
LOG.warning("Image with same CRC already exists "
|
||||||
"('%s', '%s')" % (self.filename, "/".join(new_name)))
|
"('%s', '%s')" % (self.filename, "/".join(new_name)))
|
||||||
@@ -219,9 +196,9 @@ class Image(Base):
|
|||||||
name, ext = os.path.splitext(new_name.pop())
|
name, ext = os.path.splitext(new_name.pop())
|
||||||
new_name.append("".join([name, "_t", ext]))
|
new_name.append("".join([name, "_t", ext]))
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(IMG_PATH, *new_name)):
|
if not os.path.exists(os.path.join(img_path, *new_name)):
|
||||||
thumb = ThumbCreator(os.path.join(IMG_PATH, self.filename))
|
thumb = ThumbCreator(os.path.join(img_path, self.filename))
|
||||||
shutil.move(thumb.generate(), os.path.join(IMG_PATH, *new_name))
|
shutil.move(thumb.generate(), os.path.join(img_path, *new_name))
|
||||||
else:
|
else:
|
||||||
LOG.info("Thumbnail already generated %s" % "/".join(new_name))
|
LOG.info("Thumbnail already generated %s" % "/".join(new_name))
|
||||||
|
|
||||||
@@ -241,20 +218,21 @@ class Image(Base):
|
|||||||
"""
|
"""
|
||||||
path, fname = os.path.split(self.filename)
|
path, fname = os.path.split(self.filename)
|
||||||
base, ext = os.path.splitext(fname)
|
base, ext = os.path.splitext(fname)
|
||||||
return os.path.join(IMG_PATH, path, base + "_t" + ext)
|
return os.path.join(self.img_path, path, base + "_t" + ext)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def imagepath(self):
|
def imagepath(self):
|
||||||
"""
|
"""
|
||||||
Return full path to image
|
Return full path to image
|
||||||
"""
|
"""
|
||||||
return os.path.join(IMG_PATH, self.filename)
|
return os.path.join(self.img_path, self.filename)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Image('%s', %s)>" % (str(self.filename), str(self.id))
|
return "<Image('%s', %s)>" % (str(self.filename), str(self.id))
|
||||||
|
|
||||||
|
|
||||||
class Exif(Base):
|
class Exif(Base):
|
||||||
|
"""Selected EXIF information"""
|
||||||
__tablename__ = "exif"
|
__tablename__ = "exif"
|
||||||
id = Column(Integer, Sequence("exif_id_seq"), primary_key=True)
|
id = Column(Integer, Sequence("exif_id_seq"), primary_key=True)
|
||||||
file_id = Column(Integer, ForeignKey("files.id"), index=True)
|
file_id = Column(Integer, ForeignKey("files.id"), index=True)
|
||||||
@@ -292,6 +270,7 @@ class Exif(Base):
|
|||||||
|
|
||||||
|
|
||||||
class Gthumb(Base):
|
class Gthumb(Base):
|
||||||
|
"""Gthumb information"""
|
||||||
__tablename__ = "gthumb"
|
__tablename__ = "gthumb"
|
||||||
id = Column(Integer, Sequence("gthumb_id_seq"), primary_key=True)
|
id = Column(Integer, Sequence("gthumb_id_seq"), primary_key=True)
|
||||||
file_id = Column(Integer, ForeignKey("files.id"), index=True)
|
file_id = Column(Integer, ForeignKey("files.id"), index=True)
|
||||||
@@ -307,3 +286,18 @@ class Gthumb(Base):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Gthumb('%s', '%s', %s)>" % (str(self.date), str(self.place),
|
return "<Gthumb('%s', '%s', %s)>" % (str(self.date), str(self.place),
|
||||||
str(self.id))
|
str(self.id))
|
||||||
|
|
||||||
|
|
||||||
|
class Config(Base):
|
||||||
|
"""Per-database configuration"""
|
||||||
|
__tablename__ = "config"
|
||||||
|
id = Column(Integer, Sequence("config_id_seq"), primary_key=True)
|
||||||
|
key = Column(Text)
|
||||||
|
value = Column(Text)
|
||||||
|
|
||||||
|
def __init__(self, key=None, value=None):
|
||||||
|
self.key = key
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Config('%s', '%s')>" % (str(self.key), str(self.value))
|
||||||
|
|||||||
@@ -5,6 +5,15 @@
|
|||||||
Author: Roman 'gryf' Dobosz, gryf73@gmail.com
|
Author: Roman 'gryf' Dobosz, gryf73@gmail.com
|
||||||
Created: 2009-04-05
|
Created: 2009-04-05
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
|
import errno
|
||||||
|
from zlib import crc32
|
||||||
|
|
||||||
|
import pygtktalog.dbcommon
|
||||||
|
from pygtktalog.logger import get_logger
|
||||||
|
|
||||||
|
LOG = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def float_to_string(float_length):
|
def float_to_string(float_length):
|
||||||
"""
|
"""
|
||||||
@@ -20,3 +29,47 @@ def float_to_string(float_length):
|
|||||||
sec = int(float_length)
|
sec = int(float_length)
|
||||||
return "%02d:%02d:%02d" % (hour, minutes, sec)
|
return "%02d:%02d:%02d" % (hour, minutes, sec)
|
||||||
|
|
||||||
|
def calculate_image_path(dbpath=None, create=False):
|
||||||
|
"""Calculate image path out of provided path or using current connection"""
|
||||||
|
if not dbpath:
|
||||||
|
dbpath = pygtktalog.dbcommon.DbFilename
|
||||||
|
if dbpath == ":memory:":
|
||||||
|
raise OSError("Cannot create image path out of in-memory db!")
|
||||||
|
|
||||||
|
dir_, file_ = (os.path.dirname(dbpath), os.path.basename(dbpath))
|
||||||
|
file_base, dummy = os.path.splitext(file_)
|
||||||
|
images_dir = os.path.join(dir_, file_base + "_images")
|
||||||
|
else:
|
||||||
|
if dbpath and "~" in dbpath:
|
||||||
|
dbpath = os.path.expanduser(dbpath)
|
||||||
|
if dbpath and "$" in dbpath:
|
||||||
|
dbpath = os.path.expandvars(dbpath)
|
||||||
|
images_dir = dbpath
|
||||||
|
|
||||||
|
if create:
|
||||||
|
if not os.path.exists(images_dir):
|
||||||
|
try:
|
||||||
|
os.mkdir(images_dir)
|
||||||
|
except OSError, err:
|
||||||
|
if err.errno != errno.EEXIST:
|
||||||
|
raise
|
||||||
|
elif not os.path.exists(images_dir):
|
||||||
|
raise OSError("%s: No such directory" % images_dir)
|
||||||
|
|
||||||
|
return os.path.abspath(images_dir)
|
||||||
|
|
||||||
|
def mk_paths(fname, img_path):
|
||||||
|
"""Make path for provided pathname by calculating crc32 out of file"""
|
||||||
|
with open(fname) as fobj:
|
||||||
|
new_path = "%x" % (crc32(fobj.read(10*1024*1024)) & 0xffffffff)
|
||||||
|
|
||||||
|
new_path = [new_path[i:i + 2] for i in range(0, len(new_path), 2)]
|
||||||
|
full_path = os.path.join(img_path, *new_path[:-1])
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.makedirs(full_path)
|
||||||
|
except OSError as exc:
|
||||||
|
if exc.errno != errno.EEXIST:
|
||||||
|
LOG.debug("Directory %s already exists." % full_path)
|
||||||
|
|
||||||
|
return new_path
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import re
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
|
||||||
from pygtktalog.dbobjects import File, Image, Thumbnail, TYPE
|
import pygtktalog.misc
|
||||||
|
from pygtktalog.dbobjects import File, Image, Thumbnail, Config, TYPE
|
||||||
from pygtktalog.dbcommon import Session
|
from pygtktalog.dbcommon import Session
|
||||||
from pygtktalog.logger import get_logger
|
from pygtktalog.logger import get_logger
|
||||||
from pygtktalog.video import Video
|
from pygtktalog.video import Video
|
||||||
@@ -44,7 +45,7 @@ class Scan(object):
|
|||||||
"""
|
"""
|
||||||
Initialize
|
Initialize
|
||||||
@Arguments:
|
@Arguments:
|
||||||
@path - string with initial root directory to scan
|
@path - string with path to be added to topmost node (root)
|
||||||
"""
|
"""
|
||||||
self.abort = False
|
self.abort = False
|
||||||
self.path = path.rstrip(os.path.sep)
|
self.path = path.rstrip(os.path.sep)
|
||||||
@@ -55,6 +56,8 @@ class Scan(object):
|
|||||||
self.files_count = self._get_files_count()
|
self.files_count = self._get_files_count()
|
||||||
self.current_count = 0
|
self.current_count = 0
|
||||||
|
|
||||||
|
self._set_image_path()
|
||||||
|
|
||||||
def add_files(self, engine=None):
|
def add_files(self, engine=None):
|
||||||
"""
|
"""
|
||||||
Returns list, which contain object, modification date and file
|
Returns list, which contain object, modification date and file
|
||||||
@@ -106,15 +109,21 @@ class Scan(object):
|
|||||||
req(row)
|
req(row)
|
||||||
|
|
||||||
sql = SQL2 % ",".join("?" * len(all_ids))
|
sql = SQL2 % ",".join("?" * len(all_ids))
|
||||||
res = engine.execute(sql, tuple(all_ids)).fetchall()
|
all_ids = [row_[0] for row_ in engine
|
||||||
|
.execute(sql, tuple(all_ids))
|
||||||
|
.fetchall()]
|
||||||
|
|
||||||
all_obj = []
|
all_obj = []
|
||||||
for row in res:
|
# number of objects to retrieve at once. Limit is 999. Let's do a
|
||||||
all_obj.append(self._session
|
# little bit below.
|
||||||
|
no = 900
|
||||||
|
steps = len(all_ids) / no + 1
|
||||||
|
for step in range(steps):
|
||||||
|
all_obj.extend(self._session
|
||||||
.query(File)
|
.query(File)
|
||||||
.filter(File.id == row[0])
|
.filter(File.id
|
||||||
.first())
|
.in_(all_ids[step * no:step * no + no]))
|
||||||
|
.all())
|
||||||
return all_obj
|
return all_obj
|
||||||
|
|
||||||
def update_files(self, node_id, engine=None):
|
def update_files(self, node_id, engine=None):
|
||||||
@@ -248,7 +257,7 @@ class Scan(object):
|
|||||||
|
|
||||||
preview_fn = vid.capture()
|
preview_fn = vid.capture()
|
||||||
if preview_fn:
|
if preview_fn:
|
||||||
Image(preview_fn, fobj)
|
Image(preview_fn, self.img_path, fobj)
|
||||||
|
|
||||||
def _check_related(self, fobj, pattern):
|
def _check_related(self, fobj, pattern):
|
||||||
"""
|
"""
|
||||||
@@ -261,10 +270,10 @@ class Scan(object):
|
|||||||
full_fname = os.path.join(fobj.filepath, filen)
|
full_fname = os.path.join(fobj.filepath, filen)
|
||||||
LOG.debug('found cover file: %s' % full_fname)
|
LOG.debug('found cover file: %s' % full_fname)
|
||||||
|
|
||||||
Image(full_fname, fobj, False)
|
Image(full_fname, self.img_path, fobj, False)
|
||||||
|
|
||||||
if not fobj.thumbnail:
|
if not fobj.thumbnail:
|
||||||
Thumbnail(full_fname, fobj)
|
Thumbnail(full_fname, self.img_path, fobj)
|
||||||
|
|
||||||
def _name_matcher(self, fpath, fname, media=False):
|
def _name_matcher(self, fpath, fname, media=False):
|
||||||
"""
|
"""
|
||||||
@@ -326,7 +335,7 @@ class Scan(object):
|
|||||||
fobj.type = fob['ftype']
|
fobj.type = fob['ftype']
|
||||||
else:
|
else:
|
||||||
fobj = File(**fob)
|
fobj = File(**fob)
|
||||||
# SLOW. Don;t do this. Checksums has no value eventually
|
# SLOW. Don't do this. Checksums has no value eventually
|
||||||
# fobj.mk_checksum()
|
# fobj.mk_checksum()
|
||||||
|
|
||||||
if parent is None:
|
if parent is None:
|
||||||
@@ -482,12 +491,24 @@ class Scan(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def _get_files_count(self):
|
def _get_files_count(self):
|
||||||
|
"""return size in bytes"""
|
||||||
count = 0
|
count = 0
|
||||||
for root, dirs, files in os.walk(str(self.path)):
|
for _, _, files in os.walk(str(self.path)):
|
||||||
count += len(files)
|
count += len(files)
|
||||||
LOG.debug("count of files: %s", count)
|
LOG.debug("count of files: %s", count)
|
||||||
return count
|
return count
|
||||||
|
|
||||||
|
def _set_image_path(self):
|
||||||
|
"""Get or calculate the images path"""
|
||||||
|
image_path = self._session.query(Config) \
|
||||||
|
.filter(Config.key=="image_path").one()
|
||||||
|
if image_path.value == ":same_as_db:":
|
||||||
|
image_path = pygtktalog.misc.calculate_image_path()
|
||||||
|
else:
|
||||||
|
image_path = pygtktalog.misc.calculate_image_path(image_path.value)
|
||||||
|
|
||||||
|
self.img_path = image_path
|
||||||
|
|
||||||
|
|
||||||
class asdScan(object):
|
class asdScan(object):
|
||||||
"""
|
"""
|
||||||
@@ -561,7 +582,7 @@ class asdScan(object):
|
|||||||
current_dir = os.path.join(root, i)
|
current_dir = os.path.join(root, i)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
st = os.stat(current_dir)
|
st = os.lstat(current_dir)
|
||||||
st_mtime = st.st_mtime
|
st_mtime = st.st_mtime
|
||||||
except OSError:
|
except OSError:
|
||||||
st_mtime = 0
|
st_mtime = 0
|
||||||
@@ -597,7 +618,7 @@ class asdScan(object):
|
|||||||
current_file = os.path.join(root, i)
|
current_file = os.path.join(root, i)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
st = os.stat(current_file)
|
st = os.lstat(current_file)
|
||||||
st_mtime = st.st_mtime
|
st_mtime = st.st_mtime
|
||||||
st_size = st.st_size
|
st_size = st.st_size
|
||||||
except OSError:
|
except OSError:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from tempfile import mkstemp
|
from tempfile import mkstemp
|
||||||
|
import shutil
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
@@ -56,14 +57,17 @@ class ThumbCreator(object):
|
|||||||
thumb.close()
|
thumb.close()
|
||||||
else:
|
else:
|
||||||
LOG.debug("no exif thumb")
|
LOG.debug("no exif thumb")
|
||||||
thumb = self._scale_image()
|
if self.is_image_smaller():
|
||||||
if thumb:
|
shutil.copyfile(self.filename, thumb_fn)
|
||||||
thumb.save(thumb_fn, "JPEG")
|
else:
|
||||||
|
thumb = self._scale_image()
|
||||||
|
if thumb:
|
||||||
|
thumb.save(thumb_fn, "JPEG")
|
||||||
|
|
||||||
if exif and 'Image Orientation' in exif:
|
if exif and 'Image Orientation' in exif:
|
||||||
orient = exif['Image Orientation'].values[0]
|
orient = exif['Image Orientation'].values[0]
|
||||||
if orient > 1 and orient in orientations:
|
if orient > 1 and orient in orientations:
|
||||||
thumb_image = Image.open(self.thumb_fn)
|
thumb_image = Image.open(thumb_fn)
|
||||||
tmp_thumb_img = thumb_image.transpose(orientations[orient])
|
tmp_thumb_img = thumb_image.transpose(orientations[orient])
|
||||||
|
|
||||||
if orient in flips:
|
if orient in flips:
|
||||||
@@ -73,6 +77,13 @@ class ThumbCreator(object):
|
|||||||
|
|
||||||
return thumb_fn
|
return thumb_fn
|
||||||
|
|
||||||
|
def is_image_smaller(self):
|
||||||
|
"""Check if image is smaller than desired dimention, return boolean"""
|
||||||
|
image = Image.open(self.filename)
|
||||||
|
im_x, im_y = image.size
|
||||||
|
image.close()
|
||||||
|
return im_x <= self.thumb_x and im_y <= self.thumb_y
|
||||||
|
|
||||||
def _get_exif(self):
|
def _get_exif(self):
|
||||||
"""
|
"""
|
||||||
Get exif (if available), return as a dict
|
Get exif (if available), return as a dict
|
||||||
|
|||||||
Reference in New Issue
Block a user