class ExportService(object): name = 'export' def __init__(self, provider_class): self.abort = False self._system_monitor = KodiUtils.get_system_monitor() self.provider = provider_class() self.addonid = KodiUtils.get_addon_info('id') self._addon_name = KodiUtils.get_addon_info('name') self._common_addon_id = 'script.module.clouddrive.common' self._common_addon = KodiUtils.get_addon(self._common_addon_id) self._profile_path = Utils.unicode( KodiUtils.translate_path(KodiUtils.get_addon_info('profile'))) self._startup_type = Utils.str(ExportScheduleDialog._startup_type) self.export_manager = ExportManager(self._profile_path) self._account_manager = AccountManager(self._profile_path) self._video_file_extensions = [ x for x in KodiUtils.get_supported_media("video") if x not in ('', 'zip') ] self._audio_file_extensions = KodiUtils.get_supported_media("music") self._artwork_file_extensions = [ 'back', 'banner', 'characterart', 'clearart', 'clearlogo', 'discart', 'fanart', 'keyart', 'landscape', 'poster', 'spine', 'thumb', 'folder', 'cover', 'animatedposter', 'animatedfanart' ] self._export_progress_dialog_bg = DialogProgressBG(self._addon_name) def __del__(self): del self._system_monitor del self.export_manager del self._account_manager del self._common_addon del self._export_progress_dialog_bg def cleanup_export_map(self): exports = self.export_manager.get_exports() for exportid in exports: export = exports[exportid] export['exporting'] = False self.export_manager.save_export(export) def get_scheduled_export_map(self): exports = self.export_manager.get_exports() export_map = {} for exportid in exports: export = exports[exportid] schedules = Utils.get_safe_value(export, 'schedules', []) exporting = Utils.get_safe_value(export, 'exporting', False) if not exporting: if Utils.get_safe_value(export, 'schedule', False) and schedules: for schedule in schedules: key = Utils.str( Utils.get_safe_value(schedule, 'type', '')) if key != self._startup_type: key += Utils.get_safe_value(schedule, 'at', '') export_map[key] = Utils.get_safe_value( export_map, key, []) export_map[key].append(export) key = 'run_immediately' if Utils.get_safe_value(export, key, False): export_map[key] = Utils.get_safe_value(export_map, key, []) export_map[key].append(export) export[key] = False self.export_manager.save_export(export) Logger.debug('scheduled export_map: %s' % Utils.str(export_map)) return export_map def start(self): Logger.notice('Service \'%s\' started.' % self.name) self.cleanup_export_map() monitor = KodiUtils.get_system_monitor() startup = True while not self.abort: try: now = datetime.datetime.now() export_map = self.get_scheduled_export_map() if export_map: self.process_schedules(export_map, now, startup) self.process_watch() except Exception as e: ErrorReport.handle_exception(e) startup = False if monitor.waitForAbort(60): break del monitor del self.provider Logger.notice('Service stopped.') def process_schedules(self, export_map, now, startup=False): Logger.debug('now: %s, startup: %s' % (Utils.str(now), Utils.str(startup))) export_list = [] if startup: export_list.extend( Utils.get_safe_value(export_map, self._startup_type, [])) else: key = 'run_immediately' run_immediately_list = Utils.get_safe_value(export_map, key, []) export_list.extend(run_immediately_list) at = '%02d:%02d' % ( now.hour, now.minute, ) Logger.debug('at: %s' % Utils.str(at)) daily_list = Utils.get_safe_value( export_map, Utils.str(ExportScheduleDialog._daily_type) + at, []) export_list.extend(daily_list) Logger.debug('daily_list: %s' % Utils.str(daily_list)) weekday = now.weekday() + 11 weekday_list = Utils.get_safe_value(export_map, Utils.str(weekday) + at, []) export_list.extend(weekday_list) Logger.debug('weekday_list: %s' % Utils.str(weekday_list)) Logger.debug('export_list: %s' % Utils.str(export_list)) for export in export_list: self.run_export(export) def _get_progress_header(self, export): sid = 32024 if Utils.get_safe_value(export, 'origin', '') == 'watch': sid = 32088 return self._common_addon.getLocalizedString( sid) + ': ' + Utils.unicode(export['name']) def _get_percent(self, completed, target): if target > 0: return completed * 100 / target return 0 def _show_progress_before_change(self, change, pending_changes, changes_done, retry_changes, ignored, export): completed = len(changes_done) + len(retry_changes) + ignored target = len(pending_changes) + completed + 1 self._export_progress_dialog_bg.update( self._get_percent(completed, target), self._addon_name + ' ' + self._get_progress_header(export), Utils.get_safe_value(change, 'name', 'n/a')) def _show_progress_after_change(self, change, change_type, pending_changes, changes_done, retry_changes, ignored, export): completed = len(changes_done) + len(retry_changes) + ignored target = len(pending_changes) + completed msg = self._common_addon.getLocalizedString(32041) if change_type: msg = Utils.get_safe_value(change, 'name', 'n/a') self._export_progress_dialog_bg.update( self._get_percent(completed, target), self._addon_name + ' ' + self._get_progress_header(export), msg) def run_export(self, export): exporting = Utils.get_safe_value(export, 'exporting', False) Logger.debug('Run export requested. Exporting = %s' % (exporting, )) if not exporting: export['exporting'] = True export['origin'] = 'schedule' self.export_manager.save_export(export) try: show_export_progress = KodiUtils.get_addon_setting( 'hide_export_progress') != 'true' if show_export_progress: self._export_progress_dialog_bg.create( self._addon_name + ' ' + self._common_addon.getLocalizedString(32024), self._common_addon.getLocalizedString(32025)) export_folder = export['destination_folder'] if not KodiUtils.file_exists(export_folder): Logger.debug('creating folder: %s' % (export_folder, )) if not KodiUtils.mkdirs(export_folder): Logger.debug('unable to create folder %s' % (export_folder, )) if KodiUtils.file_exists(export_folder): driveid = export['driveid'] self.provider.configure(self._account_manager, driveid) exportid = export['id'] items_info = {} ExportManager.add_item_info(items_info, 'root-folder', None, export_folder, None, 'folder') self.export_manager.save_items_info(exportid, items_info) item = self.provider.get_item(export['item_driveid'], exportid) item.update({ 'parent': 'root-folder', 'origin': 'schedule' }) self.export_manager.save_pending_changes( exportid, deque([item])) self.export_manager.save_retry_changes(exportid, deque([])) if show_export_progress: progress_listener = self._show_progress_before_change else: progress_listener = None changes_done = self.process_pending_changes( exportid, on_before_change=progress_listener) if changes_done: if Utils.get_safe_value(export, 'update_library', False): if Utils.get_safe_value(export, 'content_type', '') == 'audio': KodiUtils.update_library('music') else: KodiUtils.update_library('video') except Exception as e: ErrorReport.handle_exception(e) KodiUtils.show_notification( self._common_addon.getLocalizedString(32027) + ' ' + Utils.unicode(e)) finally: export['exporting'] = False del export['origin'] self.export_manager.save_export(export) self._export_progress_dialog_bg.close() else: KodiUtils.show_notification( self._common_addon.getLocalizedString(32059) + ' ' + self._common_addon.getLocalizedString(32038)) def get_folder_changes(self, driveid, folder, on_before_add_item=None): return self.provider.get_folder_items( Utils.default(Utils.get_safe_value(folder, 'drive_id'), driveid), folder['id'], include_download_info=True, on_before_add_item=on_before_add_item) def on_before_add_item(self, export, item): item['origin'] = Utils.get_safe_value(export, 'origin', '') def process_pending_changes(self, exportid, on_after_change=None, on_before_change=None): changes_done = [] pending_changes = self.export_manager.get_pending_changes(exportid) if pending_changes: export = self.export_manager.get_exports()[exportid] Logger.debug('*** Processing all changes for export id: %s' % exportid) try: Logger.debug(' Exporting "%s" in %s' % (Utils.unicode(export['name']), Utils.unicode(export['destination_folder']))) except Exception: Logger.debug(' Export name: %s' % Utils.str(export['name'])) Logger.debug(' Export destination_folder: %s' % Utils.str(export['destination_folder'])) items_info = Utils.default( self.export_manager.get_items_info(exportid), {}) retry_changes = [] processed_changes = set() ignored = 0 while len(pending_changes) > 0: change = pending_changes.popleft() change_id = change['id'] if change_id in processed_changes: continue processed_changes.add(change_id) if on_before_change: on_before_change(change, pending_changes, changes_done, retry_changes, ignored, export) change_type = self.process_change(change, items_info, export) self.export_manager.save_items_info(exportid, items_info) self.export_manager.save_pending_changes( exportid, pending_changes) is_retry = False if change_type: if change_type[-6:] == "_retry": is_retry = True retry_changes.append(change) Logger.debug('change marked for retry') else: changes_done.append(change) if change_type == 'create_folder' or ( change_type == 'create_folder_ignored' and Utils.get_safe_value(change, 'origin', '') == 'schedule'): before_add_item = lambda item: self.on_before_add_item( change, item) pending_changes.extendleft( self.get_folder_changes( export['driveid'], change, before_add_item)) self.export_manager.save_pending_changes( exportid, pending_changes) else: ignored += 1 if on_after_change: on_after_change(change, change_type, pending_changes, changes_done, retry_changes, ignored, export) if is_retry: self.export_manager.save_retry_changes( exportid, deque(retry_changes)) return changes_done def process_watch(self): exports = self.export_manager.get_exports() update_library = {} changes_by_drive = {} for exportid in exports: export = exports[exportid] watch = Utils.get_safe_value(export, 'watch', False) exporting = Utils.get_safe_value(export, 'exporting', False) retry_changes = self.export_manager.get_retry_changes(exportid) if (watch or len(retry_changes) > 0) and not exporting: items_info = self.export_manager.get_items_info(exportid) if items_info: export['exporting'] = True export['origin'] = 'watch' self.export_manager.save_export(export) try: driveid = export['driveid'] if driveid in changes_by_drive: changes = changes_by_drive[driveid] else: self.provider.configure(self._account_manager, export['driveid']) changes = self.provider.changes() changes_by_drive[driveid] = [] changes_by_drive[driveid].extend(changes) pending_changes = self.export_manager.get_pending_changes( exportid) pending_changes.extend(retry_changes) pending_changes.extend(changes) if len(changes) > 0 or len(retry_changes) > 0: self.export_manager.save_pending_changes( exportid, pending_changes) if len(retry_changes) > 0: self.export_manager.save_retry_changes( exportid, deque([])) show_export_progress = KodiUtils.get_addon_setting( 'hide_export_progress') != 'true' if pending_changes and show_export_progress: self._export_progress_dialog_bg.update( 0, self._addon_name + ' ' + self._common_addon.getLocalizedString(32088), self._common_addon.getLocalizedString(32025)) if show_export_progress: progress_listener = self._show_progress_after_change else: progress_listener = None changes_done = self.process_pending_changes( exportid, on_after_change=progress_listener) if changes_done: if Utils.get_safe_value(export, 'update_library', False): update_library[Utils.get_safe_value( export, 'content_type', 'None')] = True for change in changes_done: if change in changes_by_drive[driveid]: changes_by_drive[driveid].remove(change) except Exception as e: ErrorReport.handle_exception(e) KodiUtils.show_notification( self._common_addon.getLocalizedString(32027) + ' ' + Utils.unicode(e)) finally: export['exporting'] = False del export['origin'] self.export_manager.save_export(export) else: self.run_export(export) self._export_progress_dialog_bg.close() if update_library: if Utils.get_safe_value(update_library, 'video', False): KodiUtils.update_library('video') if Utils.get_safe_value(update_library, 'audio', False): KodiUtils.update_library('music') @timeit def process_change(self, change, items_info, export): change_type = None changed_item_id = change['id'] Logger.debug('change_object: %s' % Utils.str(change)) changed_item_name = Utils.get_safe_value(change, 'name', '') deleted = Utils.get_safe_value( change, 'deleted') or Utils.get_safe_value(change, 'removed') parent_id = Utils.get_safe_value(change, 'parent', '') if changed_item_id in items_info: item_info = items_info[changed_item_id] item_info_path = item_info['full_local_path'] if KodiUtils.file_exists(item_info_path): if deleted: change_type = self.process_change_delete( change, items_info) elif parent_id != item_info[ 'parent'] or changed_item_name != item_info['name']: if parent_id in items_info: change_type = self.process_change_move( change, items_info) elif changed_item_id != export['id']: Logger.debug( 'change is move to a parent not in item list. deleting from current export info and ignoring (could be moved to another export info)' ) self.process_change_delete(change, items_info) else: change_type = self.process_change_create( change, items_info, export) elif not deleted: Logger.debug( 'changed item not found in its location: %s. creating...' % item_info_path) change_type = self.process_change_create( change, items_info, export) elif parent_id in items_info and not deleted: change_type = self.process_change_create(change, items_info, export) Logger.debug('change_type: %s ' % Utils.str(change_type)) return change_type def process_change_delete(self, change, items_info): change_type = 'delete' changed_item_id = change['id'] item_info = items_info[changed_item_id] item_info_path = item_info['full_local_path'] item_type = item_info['type'] is_folder = item_type == 'folder' Logger.debug('deleting: %s' % item_info_path) if KodiUtils.file_exists(item_info_path): if is_folder: change_type += '_folder' if not Utils.remove_folder(item_info_path, self._system_monitor): change_type += '_retry' else: change_type += '_file' if not KodiUtils.file_delete(item_info_path): change_type += '_retry' else: Logger.debug('file already deleted: %s' % item_info_path) change_type += '_ignored' ExportManager.remove_item_info(items_info, changed_item_id) return change_type def process_change_move(self, change, items_info): change_type = 'move' parent_id = Utils.get_safe_value(change, 'parent', '') parent_item_info = items_info[parent_id] parent_item_path = parent_item_info['full_local_path'] changed_item_id = change['id'] changed_item_name = Utils.get_safe_value(change, 'name', '') changed_item_extension = Utils.get_safe_value(change, 'name_extension', '') changed_item_mimetype = Utils.get_safe_value(change, 'mimetype', '') item_info = items_info[changed_item_id] item_type = item_info['type'] is_folder = item_type == 'folder' item_info_path = item_info['full_local_path'] new_path = os.path.join(Utils.unicode(parent_item_path), Utils.unicode(changed_item_name)) if is_folder: change_type += '_folder' new_path = os.path.join(new_path, '') else: change_type += '_file' if changed_item_extension in self._video_file_extensions or 'video' in changed_item_mimetype or 'video' in change: new_path += '.strm' Logger.debug('%s from: %s to: %s' % ( change_type, item_info_path, new_path, )) if KodiUtils.file_exists(new_path): Logger.debug('location already exists: %s. removing...' % (new_path, )) if is_folder: Utils.remove_folder(item_info_path, self._system_monitor) else: KodiUtils.file_delete(item_info_path) if not KodiUtils.file_rename(item_info_path, new_path): change_type += '_retry' ExportManager.add_item_info(items_info, changed_item_id, Utils.unicode(changed_item_name), new_path, parent_id, item_type) return change_type def process_change_create(self, change, items_info, export): content_type = export['content_type'] changed_item_id = change['id'] changed_item_name = Utils.get_safe_value(change, 'name', '') changed_item_extension = Utils.get_safe_value(change, 'name_extension', '') parent_id = Utils.get_safe_value(change, 'parent', '') is_folder = 'folder' in change item_type = 'folder' if is_folder else 'file' parent_item_info = Utils.get_safe_value(items_info, parent_id) if parent_item_info: parent_item_path = parent_item_info['full_local_path'] new_path = os.path.join(Utils.unicode(parent_item_path), Utils.unicode(changed_item_name)) change_type = 'create' if is_folder: change_type += '_folder' new_path = os.path.join(new_path, '') if parent_id == 'root-folder' and KodiUtils.get_addon_setting( 'clean_folder') == 'true' and KodiUtils.file_exists( new_path): if not Utils.remove_folder(new_path): error = self._common_addon.getLocalizedString( 32066) % new_path KodiUtils.show_notification(error) Logger.debug(error) if not KodiUtils.file_exists(new_path): Logger.debug('creating folder: %s' % (new_path, )) if not KodiUtils.mkdir(new_path): change_type += '_retry' Logger.debug('unable to create folder %s' % (new_path, )) else: change_type += '_ignored' Logger.debug('folder %s already exists' % (new_path, )) else: download_artwork = 'download_artwork' in export and export[ 'download_artwork'] is_download = changed_item_extension \ and ( changed_item_extension in ['strm', 'nomedia'] or ( download_artwork and ( changed_item_extension in ['nfo'] or ( changed_item_extension in ['jpg', 'png'] and ( any(s in changed_item_name for s in self._artwork_file_extensions) or parent_item_info['name'] in ['.actors', 'extrafanart'] ) ) ) ) ) if is_download: Logger.debug('downloading file: %s' % (new_path, )) change_type = 'download_file' cloud_size = Utils.get_safe_value(change, 'size', 0) local_size = KodiUtils.file(new_path).size() if cloud_size != local_size: Logger.debug( 'Download requested. File changed: Local file size (%s) - cloud file size (%s)' % ( Utils.str(local_size), Utils.str(cloud_size), )) if not ExportManager.download(change, new_path, self.provider): change_type += "_retry" Logger.debug('Unable to download file: %s' % (new_path, )) else: change_type += '_ignored' Logger.debug( 'Download ignored: Local file size (%s) is equal to cloud file size (%s)' % ( Utils.str(local_size), Utils.str(cloud_size), )) else: is_stream_file = (('video' in change or (changed_item_extension and changed_item_extension in self._video_file_extensions)) and content_type == 'video') \ or (('audio' in change or (changed_item_extension and changed_item_extension in self._audio_file_extensions)) and content_type == 'audio') if is_stream_file: change_type += '_file' if KodiUtils.get_addon_setting( 'no_extension_strm') == 'true': new_path = Utils.remove_extension(new_path) new_path += ExportManager._strm_extension strm_content = ExportManager.get_strm_link( export['driveid'], change, content_type, 'plugin://%s/' % self.addonid) Logger.debug('creating strm file: %s' % (new_path, )) if not KodiUtils.file_exists( new_path) or KodiUtils.file( new_path).size() != len(strm_content): if not ExportManager.create_text_file( new_path, strm_content): change_type += '_retry' else: change_type += '_ignored' Logger.debug( 'ignoring strm creation: %s, strm file already exists. same expected size.' % (new_path, )) else: change_type = None Logger.debug('ignoring file: %s' % (new_path, )) if change_type: ExportManager.add_item_info(items_info, changed_item_id, Utils.unicode(changed_item_name), new_path, parent_id, item_type) else: Logger.debug('invalid state. no parent info found') change_type = None return change_type def stop(self): self.abort = True
class ExportService(object): name = 'export' def __init__(self, provider_class): self.abort = False self._system_monitor = KodiUtils.get_system_monitor() self.provider = provider_class() self.addonid = KodiUtils.get_addon_info('id') self._profile_path = Utils.unicode( KodiUtils.translate_path(KodiUtils.get_addon_info('profile'))) self._startup_type = Utils.str(ExportScheduleDialog._startup_type) self.export_manager = ExportManager(self._profile_path) self._account_manager = AccountManager(self._profile_path) self._video_file_extensions = KodiUtils.get_supported_media("video") self._audio_file_extensions = KodiUtils.get_supported_media("music") def __del__(self): del self._system_monitor del self.export_manager del self._account_manager def cleanup_export_map(self): exports = self.export_manager.load() for exportid in exports: export = exports[exportid] export['exporting'] = False self.export_manager.save() def get_export_map(self): exports = self.export_manager.load() export_map = {} for exportid in exports: export = exports[exportid] schedules = Utils.get_safe_value(export, 'schedules', []) exporting = Utils.get_safe_value(export, 'exporting', False) if not exporting: if Utils.get_safe_value(export, 'schedule', False) and schedules: for schedule in schedules: key = Utils.str( Utils.get_safe_value(schedule, 'type', '')) if key != self._startup_type: key += Utils.get_safe_value(schedule, 'at', '') export_map[key] = Utils.get_safe_value( export_map, key, []) export_map[key].append(export) if Utils.get_safe_value(export, 'watch', False): export_map['watch'] = Utils.get_safe_value( export_map, 'watch', []) export_map['watch'].append(export) Logger.debug('export_map: %s' % Utils.str(export_map)) return export_map def start(self): Logger.notice('Service \'%s\' started.' % self.name) self.cleanup_export_map() monitor = KodiUtils.get_system_monitor() startup = True while not self.abort: try: now = datetime.datetime.now() export_map = self.get_export_map() if export_map: self.process_schedules(export_map, now, startup) self.process_watch(export_map) except Exception as e: ErrorReport.handle_exception(e) startup = False if monitor.waitForAbort(60): break del monitor del self.provider Logger.notice('Service stopped.') def process_schedules(self, export_map, now, startup=False): Logger.debug('now: %s, startup: %s' % (Utils.str(now), Utils.str(startup))) export_list = [] if startup: export_list.extend( Utils.get_safe_value(export_map, self._startup_type, [])) else: at = '%02d:%02d' % ( now.hour, now.minute, ) Logger.debug('at: %s' % Utils.str(at)) daily_list = Utils.get_safe_value( export_map, Utils.str(ExportScheduleDialog._daily_type) + at, []) export_list.extend(daily_list) Logger.debug('daily_list: %s' % Utils.str(daily_list)) weekday = now.weekday() + 11 weekday_list = Utils.get_safe_value(export_map, Utils.str(weekday) + at, []) export_list.extend(weekday_list) Logger.debug('weekday_list: %s' % Utils.str(weekday_list)) Logger.debug('export_list: %s' % Utils.str(export_list)) for export in export_list: self.run_export(export) def run_export(self, export): export['exporting'] = True params = { 'action': '_run_export', 'content_type': Utils.get_safe_value(export, 'content_type', ''), 'driveid': Utils.get_safe_value(export, 'driveid', ''), 'item_id': export['id'] } KodiUtils.run_plugin(self.addonid, params, False) def process_watch(self, export_map): exports = Utils.get_safe_value(export_map, 'watch', []) update_library = {} changes_by_drive = {} for export in exports: item_id = export['id'] driveid = export['driveid'] if driveid in changes_by_drive: changes = changes_by_drive[driveid] else: self.provider.configure(self._account_manager, export['driveid']) changes = self.provider.changes() changes_by_drive[driveid] = changes items_info = self.export_manager.get_items_info(item_id) if items_info: if changes and not Utils.get_safe_value( export, 'exporting', False): Logger.debug( '*** Processing changes for export "%s" in %s' % (export['name'], export['destination_folder'])) while True: changes_retry = [] changes_done = [] for change in changes: change_type = self.process_change( change, items_info, export) if change_type and change_type != 'retry': changes_done.append(change) self.export_manager.save_items_info( item_id, items_info) if Utils.get_safe_value( export, 'update_library', False): update_library[Utils.get_safe_value( export, 'content_type', 'None')] = True elif change_type and change_type == 'retry': changes_retry.append(change) for change in changes_done: changes_by_drive[driveid].remove(change) if changes_done and changes_retry: changes = changes_retry Logger.debug('Retrying pending changes...') else: break else: self.run_export(export) if update_library: if Utils.get_safe_value(update_library, 'video', False): KodiUtils.update_library('video') if Utils.get_safe_value(update_library, 'audio', False): KodiUtils.update_library('music') def process_change_delete(self, items_info, item_id, is_folder): change_type = 'delete' item_info = items_info[item_id] item_info_path = item_info['full_local_path'] if KodiUtils.file_exists(item_info_path): if is_folder: Logger.debug('Change is delete folder: %s' % item_info_path) if not self.remove_folder(item_info_path): change_type = 'retry' else: Logger.debug('Change is delete file') if not KodiUtils.file_delete(item_info_path): change_type = 'retry' if change_type != 'retry': ExportManager.remove_item_info(items_info, item_id) return change_type def remove_folder(self, folder_path): if not KodiUtils.rmdir(folder_path, True): if self._system_monitor.waitForAbort(3): return False return KodiUtils.rmdir(folder_path, True) return True def process_change(self, change, items_info, export): change_type = None changed_item_id = change['id'] Logger.debug('Change: %s' % Utils.str(change)) if changed_item_id != export['id']: changed_item_name = change['name'] deleted = Utils.get_safe_value(change, 'deleted') parent_id = change['parent'] is_folder = 'folder' in change if not is_folder: changed_item_name += ExportManager._strm_extension if changed_item_id in items_info: item_info = items_info[changed_item_id] Logger.debug('item_info: %s' % Utils.str(item_info)) item_info_path = item_info['full_local_path'] if KodiUtils.file_exists(item_info_path): if deleted: change_type = self.process_change_delete( items_info, changed_item_id, is_folder) elif parent_id != item_info[ 'parent'] or changed_item_name != item_info['name']: if parent_id in items_info: change_type = 'move' Logger.debug('Change is move') parent_item_info = items_info[parent_id] parent_item_path = parent_item_info[ 'full_local_path'] new_path = os.path.join(parent_item_path, changed_item_name) if is_folder: new_path = os.path.join(new_path, '') if KodiUtils.file_rename(item_info_path, new_path): ExportManager.remove_item_info( items_info, changed_item_id) ExportManager.add_item_info( items_info, changed_item_id, changed_item_name, new_path, parent_id) else: change_type = 'retry' else: Logger.debug( 'Change is move but parent not in item list. Change is delete' ) change_type = self.process_change_delete( items_info, changed_item_id, is_folder) else: Logger.debug( 'Invalid state. Changed item not found: %s. Deleting from item list.' % item_info_path) change_type = self.process_change_delete( items_info, changed_item_id, is_folder) elif parent_id in items_info and not deleted: content_type = export['content_type'] item_name_extension = change['name_extension'] if is_folder or ( ('video' in change or item_name_extension in self._video_file_extensions) and content_type == 'video') or ( 'audio' in change and content_type == 'audio'): change_type = 'add' Logger.debug('Change is new item') parent_item_info = items_info[parent_id] parent_item_path = parent_item_info['full_local_path'] new_path = os.path.join(parent_item_path, changed_item_name) if is_folder: new_path = os.path.join(new_path, '') if not KodiUtils.mkdirs(new_path): change_type = 'retry' else: ExportManager.create_strm( export['driveid'], change, new_path, content_type, 'plugin://%s/' % self.addonid) if change_type != 'retry': ExportManager.add_item_info(items_info, changed_item_id, changed_item_name, new_path, parent_id) Logger.debug('change type: %s ' % Utils.str(change_type)) return change_type def stop(self): self.abort = True