#!/usr/bin/env python

# Authors:
#   Jason Gerard DeRose <jderose@novacut.com>
#   David Green <david4dev@gmail.com>
#
# dmedia: distributed media library
# Copyright (C) 2010 Jason Gerard DeRose <jderose@novacut.com>
#
# This file is part of `dmedia`.
#
# `dmedia` is free software: you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# `dmedia` is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with `dmedia`.  If not, see <http://www.gnu.org/licenses/>.


"""
WARNING: the dmedia content-hash and schema are *not* yet stable, may change
wildly and without warning!

This will eventually be turned into a VCS-style script with several commands.
For now it has a single function, to recursively import media files from a
directory.  At this point, is is a quick-and-dirty demo of how media files might
be stored and how their meta-data might be stored.

For example, say we scan all the JPEG images in the '/usr/share/backgrounds'
directory:

    dmedia /usr/share/backgrounds jpg

Media files are identified by their unique Id which is generated by their
base32-encoded sha1 content-hash.  In the above example, the
'Life_by_Paco_Espinoza.jpg' file happens to have a sha1 content-hash of
'6BRRXCGRM2GKVPTREJPGRNGUR2GF2L4K'.  As such, this file will be stored at:

    ~/.dmedia/6B/RRXCGRM2GKVPTREJPGRNGUR2GF2L4K.jpg

Meta-data for the media files is stored in CouchDB using desktopcouch.  Each
media file has its own document.  The sha1 content-hash is used as the document
'_id'.  For example, the 'Life_by_Paco_Espinoza.jpg' file has a document that
looks like this:

    {
       "_id": "6BRRXCGRM2GKVPTREJPGRNGUR2GF2L4K",
       "_rev": "1-c19ea015eb53ede147d63d55f3967d13",
       "name": "Life_by_Paco_Espinoza.jpg",
       "record_type": "http://example.com/dmedia",
       "bytes": 360889,
       "height": 1500,
       "shutter": "1/400",
       "width": 2000,
       "ext": "jpg",
       "camera": "DSC-H5",
       "iso": 125,
       "focal_length": "6.0 mm",
       "mtime": 1284394022,
       "aperture": 4
    }

All media files will have the following fields:

    bytes - File size in bytes
    mtime - Value of path.getmtime() at time of import
    name - The path.basename() part of the original source file
    ext - The extension of the original source file, normalized to lower-case

Additional fields depend upon the type of media file.  For example, image and
video files will always have 'width' and 'height', whereas video and audio files
will always have a 'duration'.

You can browse through the dmedia database using a standard web-browser, like
this:

  xdg-open ~/.local/share/desktop-couch/couchdb.html

Note that the sha1 hash is only being used as a stop-gap.  dmedia will use the
Skein hash after its final constant tweaks are made.  See:

  http://blog.novacut.com/2010/09/how-about-that-skein-hash.html
"""

from __future__ import print_function

import sys
import os
from os import path
import optparse
import xdg.BaseDirectory
import gobject
import dmedia
from dmedia.client import Client

script = path.basename(sys.argv[0])

parser = optparse.OptionParser(
    version=dmedia.__version__,
    usage='Usage: %s DIRECTORY [EXTENSIONS...]' % script,
    epilog='Example: %s /media/EOS_DIGITAL jpg cr2 mov' % script,
)
parser.add_option('--kill',
    action='store_true',
    default=False,
    help='shutdown dmedia-service daemon and exit',
)
parser.add_option('--quick',
    dest='extract',
    action='store_false',
    default=True,
    help='import without metadata extraction or thumbnail generation',
)
parser.add_option('--type',
    action='append',
    default=[],
    help='import all files of TYPE ("video", "audio", or "image")'
)
(options, args) = parser.parse_args()


# Check if they just want us to kill the daemon
if options.kill:
    print('Telling dmedia-service daemon to shutdown...')
    Client().kill()
    print('Shutdown.')
    sys.exit()


if len(args) < 1:
    parser.print_usage()
    sys.exit('ERROR: must provide DIRECTORY')
base = path.abspath(args[0])
if not path.isdir(base):
    parser.print_usage()
    sys.exit('ERROR: not a directory: %r' % base)


extensions = list(a.lower().strip('.') for a in args[1:])


class CLI(object):
    def __init__(self, base):
        self.base = base
        self.mainloop = gobject.MainLoop()
        self.client = Client()
        self.client.connect('import_started', self.on_import_started)
        self.client.connect('import_count', self.on_import_count)
        self.client.connect('import_progress', self.on_import_progress)
        self.client.connect('import_finished', self.on_import_finished)

    def on_import_started(self, client, base, import_id):
        if base != self.base:
            return
        print('Started import of %s' % base)
        print ('  import_id = %s' % import_id)

    def on_import_count(self, client, base, import_id, total):
        if base != self.base:
            return
        print('Found %d files' % total)

    def on_import_progress(self, c, base, import_id, completed, total, info):
        if base != self.base:
            return
        print('  %(action)s %(src)s' % info)

    def on_import_finished(self, c, base, import_id, stats):
        if base != self.base:
            return
        print('-' * 80)
        for key in sorted(stats):
            print('%s=%d' % (key, stats[key]))
        self.mainloop.quit()

    def run(self, options):
        try:
            self.client.start_import(self.base, options.extract)
            self.mainloop.run()
        except KeyboardInterrupt:
            self.client.stop_import(self.base)
            print('\nImport stopped')

        couchdb_data_path = xdg.BaseDirectory.save_data_path('desktop-couch')
        dc = path.join(couchdb_data_path, 'couchdb.html')
        print('\nBrowse the `dmedia` database in CouchDB:')
        print('  file://%s\n' % dc)


cli = CLI(base)
cli.run(options)
