1
0
mirror of https://github.com/gryf/pygtktalog.git synced 2025-12-17 19:40:21 +01:00

Legacy, working version. Several patches included to conform new format of the DB

This commit is contained in:
2012-02-18 18:49:45 +01:00
parent c2926c96d6
commit 1424ce9c86
6 changed files with 156 additions and 61 deletions

31
README
View File

@@ -1,5 +1,5 @@
pyGTKtalog 1.0 pyGTKtalog 1.0
================== ==============
pyGTKtalog is Linux/FreeBSD program for indexing CD/DVD or directories on pyGTKtalog is Linux/FreeBSD program for indexing CD/DVD or directories on
filesystem. It is similar to gtktalog <http://www.nongnu.org/gtktalog/> or filesystem. It is similar to gtktalog <http://www.nongnu.org/gtktalog/> or
@@ -75,6 +75,7 @@ There are still minor aims for versions 1.x to be done:
- implement advanced search - implement advanced search
For version 2.0: For version 2.0:
- Export/Import
- Icon grid in files view - Icon grid in files view
- command line support: query, adding media to collection etc - command line support: query, adding media to collection etc
- internationalization - internationalization
@@ -82,7 +83,8 @@ For version 2.0:
- user definied group of tags (represented by color in cloud tag) - user definied group of tags (represented by color in cloud tag)
- hiding specified files - configurable, like dot prefixed, cfg and manualy - hiding specified files - configurable, like dot prefixed, cfg and manualy
selected selected
- tests
- warning about existing image in media directory
Removed: Removed:
- filetypes handling (movies, images, archives, documents etc). Now it have - filetypes handling (movies, images, archives, documents etc). Now it have
common, unified external "plugin" system - simple text output from command common, unified external "plugin" system - simple text output from command
@@ -103,17 +105,22 @@ Removed:
NOTES NOTES
===== =====
Catalog file is tared and gziped sqlite database and directories with images and Catalog file is plain sqlite database (optionally compressed with bzip2). All
thumbnails. If there are more images, the size of catalog file will grow. So be images are stored in ~/.pygtktalog/images directory. Names for images are
carefull with adding big images in your catalog file! generated sha512 hash from image file itself. There is small possibility for two
identical hash for different image files. However, no images are overwritten.
Thumbnail filename for each image is simply concatenation of image filename in
images directory and '_t' string.
There is also converter form old database to new. In fact no image are stored in There is also converter from old database to new for internal use only. In
archive with katalog. All thumnails will be lost. All images without big image public release there will be no other formats so it will be useless, and
will be lost. There ar serious changes with application design, and I decided, deleted. There are some issues with converting. All thumbnails will be lost. All
that is better to keep media unpacked on disk, instead of pack it every time images without big image will be lost. There are serious changes with
with save and unpack with open methods. New design prevent from deleting eny application design, and I decided, that is better to keep media unpacked on
file from media directory (placed in ~/.pygtktalog/images). Functionality for disk, instead of pack it every time with save and unpack with open methods. New
exporting images and corresponding db file is planned. design prevent from deleting any file from media directory (placed in
~/.pygtktalog/images). Functionality for exporting images and corresponding db
file is planned.
BUGS BUGS
==== ====

View File

@@ -64,13 +64,17 @@ def check_requirements():
pass pass
try: try:
from pysqlite2 import dbapi2 as sqlite import sqlite3 as sqlite
except ImportError: except ImportError:
print "pyGTKtalog uses SQLite DB.\nYou'll need to get it and the", try:
print "python bindings as well.", from pysqlite2 import dbapi2 as sqlite
print "http://www.sqlite.org" except ImportError:
print "http://initd.org/tracker/pysqlite" print "pyGTKtalog uses SQLite DB.\nYou'll need to get it and the",
sys.exit(1) print "python bindings as well.",
print "http://www.sqlite.org"
print "http://initd.org/tracker/pysqlite"
print "Alternatively install python 2.5 or higher"
sys.exit(1)
if conf.confd['exportxls']: if conf.confd['exportxls']:
try: try:

View File

@@ -62,6 +62,27 @@
<property name="visible">True</property> <property name="visible">True</property>
</widget> </widget>
</child> </child>
<child>
<widget class="GtkMenuItem" id="import">
<property name="visible">True</property>
<property name="label" translatable="yes">Import</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_import_activate"/>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="export">
<property name="visible">True</property>
<property name="label" translatable="yes">Export</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_export_activate"/>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separator13">
<property name="visible">True</property>
</widget>
</child>
<child> <child>
<widget class="GtkMenuItem" id="recent_files1"> <widget class="GtkMenuItem" id="recent_files1">
<property name="visible">True</property> <property name="visible">True</property>

View File

@@ -22,9 +22,9 @@
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
__version__ = "1.0 RC2" __version__ = "1.0.1"
LICENCE = open('LICENCE').read() #LICENCE = open('LICENCE').read()
LICENCE = ''
import os.path import os.path
from os import popen from os import popen
from utils import deviceHelper from utils import deviceHelper
@@ -871,6 +871,25 @@ class MainController(Controller):
self.view['discs'].expand_all() self.view['discs'].expand_all()
return return
def on_export_activate(self, menu_item):
"""export db file and coressponding images to tar.bz2 archive"""
dialog = Dialogs.ChooseFilename(None, "Choose export file")
filepath = dialog.run()
if not filepath:
return
list_of_paths = self.view['images'].get_selected_items()
model = self.view['images'].get_model()
count = 0
if len(list_of_paths) == 0:
# no picture was selected. default to save all of them
for image in model:
if self.model.save_image(image[0], filepath):
count += 1
def on_collapse_all1_activate(self, menu_item): def on_collapse_all1_activate(self, menu_item):
self.view['discs'].collapse_all() self.view['discs'].collapse_all()
return return
@@ -1579,7 +1598,10 @@ class MainController(Controller):
buf.insert_with_tags(buf.get_end_iter(), "Filename: ", tag) buf.insert_with_tags(buf.get_end_iter(), "Filename: ", tag)
buf.insert(buf.get_end_iter(), set['filename'] + "\n") buf.insert(buf.get_end_iter(), set['filename'] + "\n")
buf.insert_with_tags(buf.get_end_iter(), "Date: ", tag) buf.insert_with_tags(buf.get_end_iter(), "Date: ", tag)
buf.insert(buf.get_end_iter(), str(set['fileinfo']['date']) + "\n") try:
buf.insert(buf.get_end_iter(), str(set['fileinfo']['date']) + "\n")
except:
import ipdb; ipdb.set_trace()
buf.insert_with_tags(buf.get_end_iter(), "Size: ", tag) buf.insert_with_tags(buf.get_end_iter(), "Size: ", tag)
buf.insert(buf.get_end_iter(), str(set['fileinfo']['size']) + "\n") buf.insert(buf.get_end_iter(), str(set['fileinfo']['size']) + "\n")

View File

@@ -23,11 +23,9 @@
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
from shutil import copy from shutil import copy
from os import path, mkdir from os import path
from hashlib import sha512 from hashlib import sha512
from tempfile import mkstemp
from utils import EXIF
import Image import Image
class Img(object): class Img(object):
@@ -53,7 +51,8 @@ class Img(object):
# check wheter image already exists # check wheter image already exists
if path.exists(image_filename) and path.exists(thumbnail): if path.exists(image_filename) and path.exists(thumbnail):
if __debug__: if __debug__:
print "image", self.filename, "with hash", self.sha512, "already exist" print "image", self.filename, "with hash",
print self.sha512, "already exist"
return self.sha512 return self.sha512
if not path.exists(thumbnail): if not path.exists(thumbnail):

View File

@@ -45,10 +45,11 @@ class Qst(object):
def run(self): def run(self):
retval = self.dialog.run() retval = self.dialog.run()
self.dialog.destroy() retval = False
if retval == gtk.RESPONSE_OK: if retval == gtk.RESPONSE_OK:
return True retval = True
return False self.dialog.destroy()
return retval
class Inf(object): class Inf(object):
"""Show simple dialog for notices""" """Show simple dialog for notices"""
@@ -139,10 +140,11 @@ class InputDiskLabel(object):
entry = gladexml.get_widget("volname") entry = gladexml.get_widget("volname")
entry.set_text(self.label) entry.set_text(self.label)
result = dialog.run() result = dialog.run()
dialog.destroy() res = None
if result == gtk.RESPONSE_OK: if result == gtk.RESPONSE_OK:
return entry.get_text() res = entry.get_text()
return None dialog.destroy()
return res
class InputNewName(object): class InputNewName(object):
"""Sepcific dialog for quering user for a disc label""" """Sepcific dialog for quering user for a disc label"""
@@ -158,10 +160,11 @@ class InputNewName(object):
entry = gladexml.get_widget("name") entry = gladexml.get_widget("name")
entry.set_text(self.name) entry.set_text(self.name)
result = dialog.run() result = dialog.run()
dialog.destroy() res = None
if result == gtk.RESPONSE_OK: if result == gtk.RESPONSE_OK:
return entry.get_text() res = entry.get_text()
return None dialog.destroy()
return res
class PointDirectoryToAdd(object): class PointDirectoryToAdd(object):
"""Sepcific dialog for quering user for selecting directory to add""" """Sepcific dialog for quering user for selecting directory to add"""
@@ -206,7 +209,7 @@ class PointDirectoryToAdd(object):
ch = True ch = True
result = dialog.run() result = dialog.run()
while ch: while ch:
if result == gtk.RESPONSE_OK and (self.volname.get_text()=='' or \ if result == gtk.RESPONSE_OK and (self.volname.get_text() == '' or \
self.directory.get_text() == ''): self.directory.get_text() == ''):
a = Err("Error - pyGTKtalog", a = Err("Error - pyGTKtalog",
"There are fields needed to be filled.", "There are fields needed to be filled.",
@@ -215,11 +218,15 @@ class PointDirectoryToAdd(object):
result = dialog.run() result = dialog.run()
else: else:
ch = False ch = False
dialog.destroy()
volname = self.volname.get_text()
directory = self.directory.get_text()
res = (None,None)
if result == gtk.RESPONSE_OK: if result == gtk.RESPONSE_OK:
return self.volname.get_text(),self.directory.get_text() res = (volname, directory)
else: dialog.destroy()
return None,None return res
class SelectDirectory(object): class SelectDirectory(object):
"""Sepcific dialog for quering user for selecting directory to add""" """Sepcific dialog for quering user for selecting directory to add"""
@@ -257,15 +264,15 @@ class SelectDirectory(object):
dialog.destroy() dialog.destroy()
return retval return retval
class ChooseDBFilename(object): class ChooseFilename(object):
"""Sepcific dialog for quering user for selecting filename for database""" """Dialog for quering user for selecting filename"""
URI=None URI=None
def __init__(self, path=None): def __init__(self, path=None, title=''):
self.path = path self.path = path
self.dialog = gtk.FileChooserDialog( self.dialog = gtk.FileChooserDialog(
title="Save catalog as...", title="",
action=gtk.FILE_CHOOSER_ACTION_SAVE, action=gtk.FILE_CHOOSER_ACTION_SAVE,
buttons=( buttons=(
gtk.STOCK_CANCEL, gtk.STOCK_CANCEL,
@@ -276,7 +283,44 @@ class ChooseDBFilename(object):
self.dialog.set_action(gtk.FILE_CHOOSER_ACTION_SAVE) self.dialog.set_action(gtk.FILE_CHOOSER_ACTION_SAVE)
self.dialog.set_default_response(gtk.RESPONSE_OK) self.dialog.set_default_response(gtk.RESPONSE_OK)
self.dialog.set_do_overwrite_confirmation(True) self.dialog.set_do_overwrite_confirmation(True)
self.dialog.set_title('Save catalog to file...') self.dialog.set_title(title)
f = gtk.FileFilter()
f.set_name("Catalog files")
f.add_pattern("*.sqlite")
f.add_pattern("*.sqlite.bz2")
self.dialog.add_filter(f)
f = gtk.FileFilter()
f.set_name("All files")
f.add_pattern("*.*")
self.dialog.add_filter(f)
def run(self):
if self.URI:
self.dialog.set_current_folder_uri(self.URI)
elif self.path and os.path.exists(self.path):
self.path = "file://"+os.path.abspath(self.path)
self.dialog.set_current_folder_uri(self.path)
response = self.dialog.run()
if response == gtk.RESPONSE_OK:
filename = self.dialog.get_filename()
self.__class__.URI = self.dialog.get_current_folder_uri()
self.dialog.destroy()
return filename
else:
self.dialog.destroy()
return None
pass
class ChooseDBFilename(ChooseFilename):
"""Sepcific dialog for quering user for selecting filename for database"""
URI=None
def __init__(self, path=None):
ChooseFilename.__init__(self)
self.dialog.set_title('Save catalog as...')
f = gtk.FileFilter() f = gtk.FileFilter()
f.set_name("Catalog files") f.set_name("Catalog files")
@@ -298,11 +342,6 @@ class ChooseDBFilename(object):
response = self.dialog.run() response = self.dialog.run()
if response == gtk.RESPONSE_OK: if response == gtk.RESPONSE_OK:
filename = self.dialog.get_filename() filename = self.dialog.get_filename()
print filename, ' do ',
if filename[-11:].lower() != '.sqlite.bz2' and \
filename[-7:].lower() != '.sqlite':
filename = filename + '.sqlite.bz2'
print filename
self.__class__.URI = self.dialog.get_current_folder_uri() self.__class__.URI = self.dialog.get_current_folder_uri()
self.dialog.destroy() self.dialog.destroy()
return filename return filename
@@ -488,10 +527,11 @@ class StatsDialog(object):
entry.set_text(str(self.values['size'])) entry.set_text(str(self.values['size']))
result = dialog.run() result = dialog.run()
dialog.destroy() retval = None
if result == gtk.RESPONSE_OK: if result == gtk.RESPONSE_OK:
return entry.get_text() retval = entry.get_text()
return None dialog.destroy()
return retval
class TagsDialog(object): class TagsDialog(object):
"""Sepcific dialog for display stats""" """Sepcific dialog for display stats"""
@@ -507,10 +547,11 @@ class TagsDialog(object):
result = dialog.run() result = dialog.run()
dialog.destroy() retval = None
if result == gtk.RESPONSE_OK: if result == gtk.RESPONSE_OK:
return entry.get_text() retval = entry.get_text()
return None dialog.destroy()
return retval
class TagsRemoveDialog(object): class TagsRemoveDialog(object):
"""Sepcific dialog for display stats""" """Sepcific dialog for display stats"""
@@ -572,14 +613,15 @@ class TagsRemoveDialog(object):
result = dialog.run() result = dialog.run()
dialog.destroy() retval = (None, None)
if result == gtk.RESPONSE_OK: if result == gtk.RESPONSE_OK:
ids = [] ids = []
for i in model: for i in model:
if i[2]: if i[2]:
ids.append(i[0]) ids.append(i[0])
return "ok", ids retval = ("ok", ids)
return None, None dialog.destroy()
return retval
class EditDialog(object): class EditDialog(object):
"""Sepcific dialog for display stats""" """Sepcific dialog for display stats"""