# -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 from __future__ import division from datetime import datetime import os import shutil import time import ox from changelog import Changelog from item.models import File from user.models import List from utils import remove_empty_folders from websocket import trigger_event import db import media import settings import state import logging logger = logging.getLogger('oml.item.scan') extensions = ['epub', 'pdf', 'txt'] def remove_missing(): dirty = False with db.session(): prefs = settings.preferences prefix = os.path.join(os.path.expanduser(prefs['libraryPath']), 'Books/') if os.path.exists(prefix): for f in File.query: path = f.item.get_path() if not os.path.exists(path): dirty = True f.item.remove_file() if dirty: state.db.session.commit() def add_file(id, f, prefix, from_=None): user = state.user() path = f[len(prefix):] data = media.metadata(f, from_) file = File.get_or_create(id, data, path) item = file.item if 'primaryid' in file.info: del file.info['primaryid'] state.db.session.add(file) if 'primaryid' in item.info: item.meta['primaryid'] = item.info.pop('primaryid') state.db.session.add(item) item.users.append(user) Changelog.record(user, 'additem', item.id, file.info) if item.meta.get('primaryid'): Changelog.record(user, 'edititem', item.id, dict([item.meta['primaryid']])) item.added = datetime.utcnow() item.scrape() item.update_icons() item.save() return file def run_scan(): remove_missing() with db.session(): prefs = settings.preferences prefix = os.path.join(os.path.expanduser(prefs['libraryPath']), 'Books/') if not prefix[-1] == '/': prefix += '/' assert isinstance(prefix, unicode) books = [] for root, folders, files in os.walk(prefix): for f in files: #if f.startswith('._') or f == '.DS_Store': if f.startswith('.'): continue f = os.path.join(root, f) ext = f.split('.')[-1] if ext in extensions: books.append(f) position = 0 added = 0 for f in ox.sorted_strings(books): position += 1 id = media.get_id(f) file = File.get(id) if not file: file = add_file(id, f, prefix, f) added += 1 trigger_event('change', {}) def run_import(options=None): options = options or {} with db.session(): prefs = settings.preferences prefix = os.path.expanduser(options.get('path', prefs['importPath'])) if os.path.islink(prefix): prefix = os.path.realpath(prefix) if not prefix[-1] == '/': prefix += '/' prefix_books = os.path.join(os.path.expanduser(prefs['libraryPath']), 'Books/') prefix_imported = os.path.join(prefix_books, 'Imported/') if prefix_books.startswith(prefix) or prefix.startswith(prefix_books): error = 'invalid path' elif not os.path.exists(prefix): error = 'path not found' elif not os.path.isdir(prefix): error = 'path must be a folder' else: error = None if error: trigger_event('activity', { 'activity': 'import', 'progress': [0, 0], 'status': {'code': 404, 'text': error} }) state.activity = {} return listname = options.get('list') if listname: listitems = [] assert isinstance(prefix, unicode) books = [] count = 0 for root, folders, files in os.walk(prefix): for f in files: #if f.startswith('._') or f == '.DS_Store': if f.startswith('.'): continue f = os.path.join(root, f) ext = f.split('.')[-1] if ext in extensions: books.append(f) count += 1 if state.activity.get('cancel'): state.activity = {} return if count % 1000 == 0: state.activity = { 'activity': 'import', 'path': prefix, 'progress': [0, count], } trigger_event('activity', state.activity) state.activity = { 'activity': 'import', 'path': prefix, 'progress': [0, len(books)], } trigger_event('activity', state.activity) position = 0 added = 0 last = 0 for f in ox.sorted_strings(books): position += 1 if not os.path.exists(f): continue id = media.get_id(f) file = File.get(id) if not file: f_import = f f = f.replace(prefix, prefix_imported) ox.makedirs(os.path.dirname(f)) if options.get('mode') == 'move': shutil.move(f_import, f) else: shutil.copy(f_import, f) file = add_file(id, f, prefix_books, f_import) file.move() added += 1 if listname: listitems.append(file.item.id) if time.time() - last > 5: last = time.time() state.activity = { 'activity': 'import', 'progress': [position, len(books)], 'path': prefix, 'added': added, } trigger_event('activity', state.activity) if state.activity.get('cancel'): state.activity = {} return if listname and listitems: l = List.get(settings.USER_ID, listname) if l: l.add_items(listitems) trigger_event('activity', { 'activity': 'import', 'progress': [position, len(books)], 'path': prefix, 'status': {'code': 200, 'text': ''}, 'added': added, }) state.activity = {} remove_empty_folders(prefix_books) if options.get('mode') == 'move': remove_empty_folders(prefix)