2
# Jason Gerard DeRose <jderose@novacut.com>
4
# dmedia: distributed media library
5
# Copyright (C) 2010 Jason Gerard DeRose <jderose@novacut.com>
7
# This file is part of `dmedia`.
9
# `dmedia` is free software: you can redistribute it and/or modify it under the
10
# terms of the GNU Affero General Public License as published by the Free
11
# Software Foundation, either version 3 of the License, or (at your option) any
14
# `dmedia` is distributed in the hope that it will be useful, but WITHOUT ANY
15
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19
# You should have received a copy of the GNU Affero General Public License along
20
# with `dmedia`. If not, see <http://www.gnu.org/licenses/>.
23
Store meta-data in desktop-couch.
31
from couchdb import ResourceNotFound, ResourceConflict
33
from desktopcouch.records.server import CouchDatabase
34
from desktopcouch.records.record import Record
35
from desktopcouch.local_files import DEFAULT_CONTEXT, Context
36
from .util import random_id
52
if (doc.type == 'dmedia/batch') {
60
if (doc.type == 'dmedia/import') {
68
if (doc.type == 'dmedia/file' && typeof(doc.bytes) == 'number') {
69
emit(doc.bytes, doc.bytes);
76
if (doc.type == 'dmedia/file') {
82
file_content_type = """
84
if (doc.type == 'dmedia/file') {
85
emit(doc.content_type, null);
92
if (doc.type == 'dmedia/file') {
93
emit(doc.mtime, null);
100
if (doc.type == 'dmedia/file' && doc.tags) {
101
doc.tags.forEach(function(tag) {
110
if (doc.type == 'dmedia/file' && doc.qid) {
118
if (doc.type == 'dmedia/file' && doc.import_id) {
119
emit(doc.import_id, null);
125
def dc_context(couchdir):
127
Create a desktopcouch Context for testing purposes.
129
assert path.isdir(couchdir)
131
path.join(couchdir, 'cache'),
132
path.join(couchdir, 'data'),
133
path.join(couchdir, 'config'),
137
def build_design_doc(design, views):
138
_id = '_design/' + design
140
for (view, map_, reduce_) in views:
141
d[view] = {'map': map_}
142
if reduce_ is not None:
143
d[view]['reduce'] = reduce_
146
'language': 'javascript',
152
def create_machine():
154
'_id': '_local/machine',
155
'machine_id': random_id(),
156
'type': 'dmedia/machine',
158
'hostname': socket.gethostname(),
159
'distribution': platform.linux_distribution(),
163
class MetaStore(object):
166
('type', type_type, _count),
170
('time', batch_time, None),
174
('time', import_time, None),
178
('qid', file_qid, None),
179
('import_id', file_import_id, None),
180
('bytes', file_bytes, _sum),
181
('ext', file_ext, _count),
182
('content_type', file_content_type, _count),
183
('mtime', file_mtime, None),
184
('tags', file_tags, _count),
188
def __init__(self, dbname='dmedia', couchdir=None):
190
# FIXME: once lp:672481 is fixed, this wont be needed. See:
191
# https://bugs.launchpad.net/desktopcouch/+bug/672481
192
self.ctx = (DEFAULT_CONTEXT if couchdir is None else dc_context(couchdir))
194
self.desktop = CouchDatabase(self.dbname, create=True, ctx=self.ctx)
195
self.server = self.desktop._server
196
self.db = self.server[self.dbname]
198
self._machine_id = None
200
def get_basic_auth(self):
201
data = gnomekeyring.find_items_sync(
202
gnomekeyring.ITEM_GENERIC_SECRET,
203
{'desktopcouch': 'basic'}
205
(user, password) = data[0].secret.split(':')
206
return (user, password)
209
return desktopcouch.find_port()
212
return 'http://localhost:%s' % self.get_port()
214
def get_auth_uri(self):
215
(user, password) = self.get_basic_auth()
216
return 'http://%s:%s@localhost:%s' % (
217
user, password, self.get_port()
220
def create_machine(self):
222
loc = self.db['_local/machine']
223
except ResourceNotFound:
224
loc = self.sync(create_machine())
226
doc['_id'] = doc['machine_id']
228
self.db[doc['_id']] = doc
229
except ResourceConflict:
231
return loc['machine_id']
234
def machine_id(self):
235
if self._machine_id is None:
236
self._machine_id = self.create_machine()
237
return self._machine_id
239
def update(self, doc):
241
Create *doc* if it doesn't exists, update doc only if different.
246
doc['_rev'] = old['_rev']
249
except ResourceNotFound:
257
def create_views(self):
258
for (name, views) in self.designs:
259
(_id, doc) = build_design_doc(name, views)
262
def by_quickid(self, qid):
263
for row in self.db.view('_design/file/_view/qid', key=qid):
266
def total_bytes(self):
267
for row in self.db.view('_design/file/_view/bytes'):
271
def extensions(self):
272
for row in self.db.view('_design/file/_view/ext', group=True):
273
yield (row.key, row.value)