1
0
mirror of https://github.com/gryf/pygtktalog.git synced 2026-03-27 06:33:30 +01:00

4 Commits

5 changed files with 69 additions and 16 deletions

View File

@@ -34,6 +34,7 @@ pycatalog requires python and following libraries:
* `python 3.10`_ and up * `python 3.10`_ and up
* `sqlalchemy 1.4`_ * `sqlalchemy 1.4`_
* `exifread`_ for parse EXIF information * `exifread`_ for parse EXIF information
* `mutagen`_ for extracting tags from audio files
Pycatalog extensively uses external programs in unix spirit, however there is Pycatalog extensively uses external programs in unix spirit, however there is
small possibility of using it Windows (probably with limitations) and quite big small possibility of using it Windows (probably with limitations) and quite big
@@ -88,3 +89,4 @@ file in top-level directory.
.. _sqlalchemy 1.4: http://www.sqlalchemy.org .. _sqlalchemy 1.4: http://www.sqlalchemy.org
.. _tagging files: http://en.wikipedia.org/wiki/tag_%28metadata%29 .. _tagging files: http://en.wikipedia.org/wiki/tag_%28metadata%29
.. _tox: https://testrun.org/tox .. _tox: https://testrun.org/tox
.. _mutagen: https://github.com/quodlibet/mutagen

View File

@@ -19,13 +19,14 @@ TYPE_MAP = {0: 'd', 1: 'd', 2: 'f', 3: 'l'}
class Iface(object): class Iface(object):
"""Main class which interacts with the pyGTKtalog modules""" """Main class which interacts with the pyGTKtalog modules"""
def __init__(self, dbname, pretend=False, debug=False): def __init__(self, dbname, pretend=False, debug=False, use_color=True):
"""Init""" """Init"""
self.engine = dbcommon.connect(dbname) self.engine = dbcommon.connect(dbname)
self.sess = dbcommon.Session() self.sess = dbcommon.Session()
self.dry_run = pretend self.dry_run = pretend
self.root = None self.root = None
self._dbname = dbname self._dbname = dbname
self.use_color = use_color
if debug: if debug:
scan.LOG.setLevel('DEBUG') scan.LOG.setLevel('DEBUG')
LOG.setLevel('DEBUG') LOG.setLevel('DEBUG')
@@ -64,10 +65,10 @@ class Iface(object):
"""Make the path to the item in the DB""" """Make the path to the item in the DB"""
orig_node = node orig_node = node
if node.parent == node: if node.parent == node:
return {u'/': (u' ', 0, u' ')} return {'/': (u' ', 0, u' ')}
ext = '' ext = ''
if node.parent.type == dbo.TYPE['root']: if node.parent.type == dbo.TYPE['root'] and self.use_color:
ext = misc.colorize(' (%s)' % node.filepath, 'white') ext = misc.colorize(' (%s)' % node.filepath, 'white')
path = [] path = []
@@ -108,8 +109,11 @@ class Iface(object):
self.sess.commit() self.sess.commit()
self.sess.close() self.sess.close()
def list(self, path=None, recursive=False, long_=False): def list(self, path=None, recursive=False, long_=False, mode='plain'):
"""Simulate ls command for the provided item path""" """Simulate ls command for the provided item path"""
if mode == 'mc':
self.use_color = False
self.root = self.sess.query(dbo.File) self.root = self.sess.query(dbo.File)
self.root = self.root.filter(dbo.File.type == dbo.TYPE['root']).first() self.root = self.root.filter(dbo.File.type == dbo.TYPE['root']).first()
if path: if path:
@@ -119,16 +123,37 @@ class Iface(object):
node = self.root node = self.root
msg = "Content of path `/':" msg = "Content of path `/':"
print(misc.colorize(msg, 'white')) if mode != 'mc':
print(misc.colorize(msg, 'white'))
if recursive: if recursive:
items = self._walk(node) items = self._walk(node)
else: else:
items = self._list(node) items = self._list(node)
if long_: if mode == 'mc':
filenames = [] filenames = []
format_str = (u'{} {:>%d,} {} {}' % format_str = ('{} 1 {} {} {:>%d} {} {}' %
len(str(sorted([i[1] for i in
items.values()])[-1])))
for fname in sorted(items.keys()):
type_, size, date = items[fname]
if type_ == 'd':
perms = 'drwxrwxrwx'
elif type_ == 'l':
perms = 'lrw-rw-rw-'
elif type_ == 'f':
perms = '-rw-rw-rw-'
else:
continue
filenames.append(format_str
.format(perms, os.getuid(),
os.getgid(), size,
date.strftime('%d/%m/%Y %H:%M:%S'),
fname))
elif long_:
filenames = []
format_str = ('{} {:>%d,} {} {}' %
_get_highest_size_length(items)) _get_highest_size_length(items))
for fname in sorted(items.keys()): for fname in sorted(items.keys()):
type_, size, date = items[fname] type_, size, date = items[fname]
@@ -254,8 +279,12 @@ def _get_highest_size_length(item_dict):
@misc.asserdb @misc.asserdb
def list_db(args): def list_db(args):
"""List""" """List"""
if args.mode == 'mc':
LOG.setLevel(100) # supress logging
obj = Iface(args.db, False, args.debug) obj = Iface(args.db, False, args.debug)
obj.list(path=args.path, recursive=args.recursive, long_=args.long) obj.list(path=args.path, recursive=args.recursive, long_=args.long,
mode=args.mode)
obj.close() obj.close()
@@ -298,6 +327,12 @@ def main():
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('-m', '--mode', help='List items using mode. By '
'default is simply plain mode, other possibility is to '
'use "mc" mode, which is suitable to use with extfs '
'plugin', default='plain')
list_.add_argument('-c', '--color', help='Use colors for listing',
action='store_true', default=False)
list_.add_argument('-l', '--long', help='Show size, date and type', list_.add_argument('-l', '--long', help='Show size, date and type',
action='store_true', default=False) action='store_true', default=False)
list_.add_argument('-r', '--recursive', help='list items in ' list_.add_argument('-r', '--recursive', help='list items in '

View File

@@ -10,6 +10,9 @@ import re
from datetime import datetime from datetime import datetime
import mimetypes import mimetypes
import exifread
import mutagen
from pycatalog.dbobjects import File, TYPE from pycatalog.dbobjects import File, TYPE
from pycatalog import dbcommon from pycatalog import dbcommon
from pycatalog.logger import get_logger from pycatalog.logger import get_logger
@@ -212,12 +215,27 @@ class Scan(object):
pass pass
def _audio(self, fobj, filepath): def _audio(self, fobj, filepath):
# tags, depending on the format? tags = mutagen.File(filepath)
return if not tags:
return
fobj.description = tags.pprint()
def _image(self, fobj, filepath): def _image(self, fobj, filepath):
# exif? """Read exif if exists, add it to description"""
return with open(filepath, 'rb') as obj:
exif = exifread.process_file(obj)
if not exif:
return
data = []
# longest key + 2, since we need a colon and a space after it
longest_key = max([len(k) for k in exif]) + 2
for key in exif:
if 'thumbnail' in key.lower() and isinstance(exif[key], bytes):
data.append(f"{key + ':' :<{longest_key}}thumbnail present")
continue
data.append(f"{key + ':' :<{longest_key}}{exif[key]}")
fobj.description = "\n".join(data)
def _video(self, fobj, filepath): def _video(self, fobj, filepath):
""" """

View File

@@ -1,3 +0,0 @@
Pillow
exifread
sqlalchemy

View File

@@ -34,8 +34,9 @@ packages =
[options] [options]
install_requires = install_requires =
pillow exifread
sqlalchemy sqlalchemy
mutagen
[bdist_wheel] [bdist_wheel]
universal = 1 universal = 1