From 0dd8a6f86195c8732c7721b8155454abc408d071 Mon Sep 17 00:00:00 2001 From: chrisism Date: Wed, 13 Jul 2022 14:35:22 +0200 Subject: [PATCH 1/3] New standalone rom action --- resources/lib/commands/rom_commands.py | 25 +++++++++++++++++++++++-- resources/lib/viewqueries.py | 7 ++++--- resources/lib/views.py | 4 ++++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/resources/lib/commands/rom_commands.py b/resources/lib/commands/rom_commands.py index aa834d07..ddd3db2b 100644 --- a/resources/lib/commands/rom_commands.py +++ b/resources/lib/commands/rom_commands.py @@ -315,7 +315,6 @@ def cmd_rom_metadata_nplayers_online(args): AppMediator.sync_cmd('ROM_EDIT_METADATA', args) - @AppMediator.register('ROM_EDIT_METADATA_RATING') def cmd_rom_metadata_rating(args): rom_id = args['rom_id'] if 'rom_id' in args else None @@ -606,4 +605,26 @@ def cmd_manage_rom_tags(args): repository.delete_tag(selected_option) if did_tag_change: - uow.commit() \ No newline at end of file + uow.commit() + +# ------------------------------------------------------------------------------------------------- +# ROM ADD +# ------------------------------------------------------------------------------------------------- +@AppMediator.register('ADD_STANDALONE_ROM') +def cmd_add_rom(args): + logger.debug('ADD_STANDALONE_ROM: cmd_add_rom() BEGIN') + category_id:str = args['category_id'] if 'category_id' in args else None + + if category_id is None: + logger.warning('cmd_add_rom(): No Category id supplied.') + kodi.notify_warn("Invalid parameters supplied.") + return + + rom_name = "" + is_file_based = kodi.dialog_yesno("Is it a file based ROM/executable?") + if is_file_based: + #kodi.dialog_get_directory get File, parse name as possible name + pass + # ask name input, prefill + # create, store, refresh view. Rest goes through context menu + \ No newline at end of file diff --git a/resources/lib/viewqueries.py b/resources/lib/viewqueries.py index e82fbcd8..9ee89538 100644 --- a/resources/lib/viewqueries.py +++ b/resources/lib/viewqueries.py @@ -426,7 +426,6 @@ def qry_listitem_context_menu_items(list_item_data, container_data)-> typing.Lis is_category: bool = item_type == constants.OBJ_CATEGORY is_romcollection: bool = item_type == constants.OBJ_ROMCOLLECTION is_virtual_category: bool = item_type == constants.OBJ_CATEGORY_VIRTUAL - is_virtual_collection: bool = item_type == constants.OBJ_COLLECTION_VIRTUAL is_rom: bool = item_type == constants.OBJ_ROM commands = [] @@ -435,11 +434,13 @@ def qry_listitem_context_menu_items(list_item_data, container_data)-> typing.Lis commands.append(('Edit ROM', _context_menu_url_for(f'/rom/edit/{item_id}'))) commands.append(('Link ROM in other collection', _context_menu_url_for('/execute/command/link_rom',{'rom_id':item_id}))) commands.append(('Add ROM to AKL Favourites', _context_menu_url_for('/execute/command/add_rom_to_favourites',{'rom_id':item_id}))) + if is_category: commands.append(('View Category', _context_menu_url_for(f'/categories/view/{item_id}'))) commands.append(('Edit Category', _context_menu_url_for(f'/categories/edit/{item_id}'))) commands.append(('Add new Category',_context_menu_url_for(f'/categories/add/{item_id}/in/{container_id}'))) commands.append(('Add new ROM Collection', _context_menu_url_for(f'/romcollection/add/{item_id}/in/{container_id}'))) + commands.append(('Add new ROM (Standalone)', _context_menu_url_for(f'/categories/addrom/{container_id}'))) if is_romcollection: commands.append(('View ROM Collection', _context_menu_url_for(f'/romcollection/view/{item_id}'))) @@ -448,10 +449,10 @@ def qry_listitem_context_menu_items(list_item_data, container_data)-> typing.Lis if not is_category and container_is_category: commands.append(('Add new Category',_context_menu_url_for(f'/categories/add/{container_id}'))) commands.append(('Add new ROM Collection', _context_menu_url_for(f'/romcollection/add/{container_id}'))) - + if is_virtual_category: commands.append((f'Rebuild {item_name} view', _context_menu_url_for('execute/command/render_vcategory_view',{'vcategory_id':item_id}))) - + return commands def _context_menu_url_for(url: str, params: dict = None) -> str: diff --git a/resources/lib/views.py b/resources/lib/views.py index 47004bed..3d10002a 100644 --- a/resources/lib/views.py +++ b/resources/lib/views.py @@ -192,6 +192,10 @@ def vw_add_category(category_id: str = None, parent_category_id: str = None): def vw_edit_category(category_id: str): AppMediator.async_cmd('EDIT_CATEGORY', {'category_id': category_id }) +@router.route('/categories/addrom/') +def vw_add_rom_to_category(category_id: str): + AppMediator.async_cmd('ADD_STANDALONE_ROM', {'category_id': category_id }) + @router.route('/romcollection/add') @router.route('/romcollection/add/') @router.route('/romcollection/add//in') From 5beba69f9698bedf3d9ca0b1f1bac611ed9c68e8 Mon Sep 17 00:00:00 2001 From: chrisism Date: Mon, 18 Jul 2022 16:39:49 +0200 Subject: [PATCH 2/3] Implemented single ROMs --- addon.xml | 2 +- changelog.md | 1 + requirements.txt | 2 +- resources/lib/commands/api_commands.py | 46 +++-- resources/lib/commands/rom_commands.py | 82 +++++++- .../lib/commands/rom_launcher_commands.py | 182 +++++++++++++++++- .../lib/commands/view_rendering_commands.py | 15 +- resources/lib/domain.py | 77 +++++++- resources/lib/editors.py | 61 +++--- resources/lib/repositories.py | 109 +++++++++-- resources/lib/viewqueries.py | 7 +- 11 files changed, 501 insertions(+), 83 deletions(-) diff --git a/addon.xml b/addon.xml index 3404e144..bced0a01 100644 --- a/addon.xml +++ b/addon.xml @@ -3,7 +3,7 @@ - + executable game diff --git a/changelog.md b/changelog.md index 375a504d..739d4b0f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,6 @@ ## Current - Virtual categories now render items from database +- Add and execute single instance ROMs or Games - Minor bugfixes - Updated dependency diff --git a/requirements.txt b/requirements.txt index e42aa62d..a71ed949 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,5 +3,5 @@ kodi-addon-checker==0.0.26 Kodistubs==19.0.3 routing==0.2.3 pytest==6.2.5 -script.module.akl==1.0.5 +script.module.akl==1.0.7rc5 requests==2.22.0 \ No newline at end of file diff --git a/resources/lib/commands/api_commands.py b/resources/lib/commands/api_commands.py index b066230d..360d22e3 100644 --- a/resources/lib/commands/api_commands.py +++ b/resources/lib/commands/api_commands.py @@ -37,6 +37,7 @@ # ------------------------------------------------------------------------------------------------- def cmd_set_launcher_args(args) -> bool: romcollection_id:str = args['romcollection_id'] if 'romcollection_id' in args else None + rom_id:str = args['rom_id'] if 'rom_id' in args else None launcher_id:str = args['akl_addon_id'] if 'akl_addon_id' in args else None addon_id:str = args['addon_id'] if 'addon_id' in args else None launcher_settings = args['settings'] if 'settings' in args else None @@ -47,27 +48,40 @@ def cmd_set_launcher_args(args) -> bool: with uow: addon_repository = AelAddonRepository(uow) romcollection_repository = ROMCollectionRepository(uow) + rom_repository = ROMsRepository(uow) addon = addon_repository.find_by_addon_id(addon_id, constants.AddonType.LAUNCHER) - romcollection = romcollection_repository.find_romcollection(romcollection_id) - if launcher_id is None: - romcollection.add_launcher(addon, launcher_settings, True) - else: - launcher = romcollection.get_launcher(launcher_id) - launcher.set_settings(launcher_settings) - - if 'romcollection' in launcher_settings \ - and kodi.dialog_yesno('Do you want to overwrite collection metadata properties with values from the launcher?'): - romcollection.import_data_dic(launcher_settings['romcollection']) - metadata_updated = True + if romcollection_id is not None: + romcollection = romcollection_repository.find_romcollection(romcollection_id) + if launcher_id is None: + romcollection.add_launcher(addon, launcher_settings, True) + else: + launcher = romcollection.get_launcher(launcher_id) + launcher.set_settings(launcher_settings) + + if 'romcollection' in launcher_settings \ + and kodi.dialog_yesno('Do you want to overwrite collection metadata properties with values from the launcher?'): + romcollection.import_data_dic(launcher_settings['romcollection']) + metadata_updated = True + + romcollection_repository.update_romcollection(romcollection) + uow.commit() - romcollection_repository.update_romcollection(romcollection) - uow.commit() + if metadata_updated: AppMediator.async_cmd('RENDER_CATEGORY_VIEW', {'category_id': romcollection.get_parent_id()}) + AppMediator.async_cmd('EDIT_ROMCOLLECTION', {'romcollection_id': romcollection_id}) + else: + rom = rom_repository.find_rom(rom_id) + if launcher_id is None: + rom.add_launcher(addon, launcher_settings, True) + else: + launcher = rom.get_launcher(launcher_id) + launcher.set_settings(launcher_settings) + + rom_repository.update_rom(rom) + uow.commit() - kodi.notify('Configured launcher {}'.format(addon.get_name())) - if metadata_updated: AppMediator.async_cmd('RENDER_CATEGORY_VIEW', {'category_id': romcollection.get_parent_id()}) - AppMediator.async_cmd('EDIT_ROMCOLLECTION', {'romcollection_id': romcollection_id}) + kodi.notify(f'Configured launcher {addon.get_name()}') return True # ------------------------------------------------------------------------------------------------- diff --git a/resources/lib/commands/rom_commands.py b/resources/lib/commands/rom_commands.py index ddd3db2b..a512a27e 100644 --- a/resources/lib/commands/rom_commands.py +++ b/resources/lib/commands/rom_commands.py @@ -25,8 +25,8 @@ from resources.lib.commands.mediator import AppMediator from resources.lib import globals, editors -from resources.lib.repositories import ROMsRepository, ROMCollectionRepository, UnitOfWork -from resources.lib.domain import g_assetFactory +from resources.lib.repositories import CategoryRepository, ROMsRepository, ROMCollectionRepository, UnitOfWork +from resources.lib.domain import g_assetFactory, ROM logger = logging.getLogger(__name__) @@ -54,11 +54,14 @@ def cmd_edit_rom(args): options = collections.OrderedDict() options['ROM_EDIT_METADATA'] = 'Edit Metadata ...' options['ROM_EDIT_ASSETS'] = 'Edit Assets/Artwork ...' - options['EDIT_ROM_STATUS'] = 'ROM status: {0}'.format(rom.get_finished_str()) + options['EDIT_ROM_STATUS'] = f'ROM status: {rom.get_finished_str()}' + if rom.has_launchers(): + options['EDIT_ROM_LAUNCHERS'] = 'Manage associated launchers' + else: options['ADD_ROM_LAUNCHER'] = 'Add new launcher to ROM' options['DELETE_ROM'] = 'Delete ROM' options['SCRAPE_ROM'] = 'Scrape ROM' - s = 'Edit ROM "{}"'.format(rom.get_name()) + s = f'Edit ROM "{rom.get_name()}"' selected_option = kodi.OrdDictionaryDialog().select(s, options) if selected_option is None: # >> Exits context menu @@ -66,7 +69,7 @@ def cmd_edit_rom(args): return # >> Execute subcommand. May be atomic, maybe a submenu. - logger.debug('EDIT_ROM: cmd_edit_rom() Selected {}'.format(selected_option)) + logger.debug(f'EDIT_ROM: cmd_edit_rom() Selected {selected_option}') AppMediator.sync_cmd(selected_option, args) # --- Submenu commands --- @@ -156,6 +159,43 @@ def cmd_rom_assets(args): AppMediator.async_cmd('RENDER_ROMCOLLECTION_VIEW', {'romcollection_id': romcollection_id}) AppMediator.sync_cmd('ROM_EDIT_ASSETS', {'rom_id': rom_id, 'selected_asset': asset.id}) + +# +# Remove ROMCollection +# +@AppMediator.register('DELETE_ROM') +def cmd_rom_delete(args): + rom_id:str = args['rom_id'] if 'rom_id' in args else None + romcollections = [] + categories = [] + uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) + with uow: + roms_repository = ROMsRepository(uow) + romcollections_repository = ROMCollectionRepository(uow) + category_repository = CategoryRepository(uow) + + rom = roms_repository.find_rom(rom_id) + + question = f'Are you sure you want to delete "{rom.get_name()}"?\nThis will delete the ROM from all views.' + ret = kodi.dialog_yesno(question) + if not ret: + AppMediator.sync_cmd('EDIT_ROM', args) + return + + romcollections = list(romcollections_repository.find_romcollections_by_rom(rom_id)) + categories = list(category_repository.find_categories_by_rom(rom_id)) + + logger.info(f'Deleting ROM "{rom.get_name()}" ID {rom.get_id()}') + roms_repository.delete_rom(rom.get_id()) + uow.commit() + + for romcollection in romcollections: + AppMediator.async_cmd('RENDER_ROMCOLLECTION_VIEW', {'romcollection_id': romcollection.get_id()}) + for category in categories: + AppMediator.async_cmd('RENDER_CATEGORY_VIEW', {'category_id': category.get_id()}) + AppMediator.async_cmd('RENDER_VIRTUAL_VIEWS') + + kodi.notify(f'Deleted ROM {rom.get_name()}') # --- Atomic commands --- @AppMediator.register('ROM_EDIT_METADATA_TITLE') @@ -612,6 +652,7 @@ def cmd_manage_rom_tags(args): # ------------------------------------------------------------------------------------------------- @AppMediator.register('ADD_STANDALONE_ROM') def cmd_add_rom(args): + import xbmcgui logger.debug('ADD_STANDALONE_ROM: cmd_add_rom() BEGIN') category_id:str = args['category_id'] if 'category_id' in args else None @@ -623,8 +664,31 @@ def cmd_add_rom(args): rom_name = "" is_file_based = kodi.dialog_yesno("Is it a file based ROM/executable?") if is_file_based: - #kodi.dialog_get_directory get File, parse name as possible name - pass - # ask name input, prefill - # create, store, refresh view. Rest goes through context menu + #TODO: change to file_path = kodi.dialog_get_file("Select file") - remove xmbcgui import + file_path = xbmcgui.Dialog().browse(1, "Select file", "") + if file_path is not None: + path = io.FileName(file_path) + rom_name = path.getBaseNoExt() + + rom_name = kodi.dialog_keyboard("Name", rom_name) + if rom_name is None: + return + + rom_obj = ROM() + rom_obj.set_name(rom_name) + rom_obj.set_scanned_data_element("file", file_path) + + uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) + with uow: + category_repository = CategoryRepository(uow) + roms_repository = ROMsRepository(uow) + + roms_repository.insert_rom(rom_obj) + category_repository.add_rom_to_category(category_id, rom_obj.get_id()) + uow.commit() + + AppMediator.async_cmd('RENDER_CATEGORY_VIEW', args) + AppMediator.async_cmd('RENDER_VCATEGORY_VIEW', {'vcategory_id': constants.VCATEGORY_TITLE_ID}) + kodi.notify(f"Created new standalone ROM '{rom_name}'") + kodi.refresh_container() \ No newline at end of file diff --git a/resources/lib/commands/rom_launcher_commands.py b/resources/lib/commands/rom_launcher_commands.py index c2a34176..0e53c534 100644 --- a/resources/lib/commands/rom_launcher_commands.py +++ b/resources/lib/commands/rom_launcher_commands.py @@ -34,7 +34,6 @@ # ROMCollection launcher management. # ------------------------------------------------------------------------------------------------- -# --- Submenu menu command --- @AppMediator.register('EDIT_ROMCOLLECTION_LAUNCHERS') def cmd_manage_romcollection_launchers(args): logger.debug('EDIT_ROMCOLLECTION_LAUNCHERS: cmd_manage_romcollection_launchers() SHOW MENU') @@ -68,7 +67,71 @@ def cmd_manage_romcollection_launchers(args): logger.debug('EDIT_ROMCOLLECTION_LAUNCHERS: cmd_manage_romcollection_launchers() Selected {}'.format(selected_option)) AppMediator.sync_cmd(selected_option, args) +@AppMediator.register('EDIT_ROM_LAUNCHERS') +def cmd_manage_rom_launchers(args): + logger.debug('EDIT_ROM_LAUNCHERS: cmd_manage_rom_launchers() SHOW MENU') + rom_id:str = args['rom_id'] if 'rom_id' in args else None + + selected_option = None + uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) + with uow: + repository = ROMsRepository(uow) + rom = repository.find_rom(rom_id) + + launchers = rom.get_launchers() + default_launcher = next((l for l in launchers if l.is_default()), launchers[0]) if len(launchers) > 0 else None + default_launcher_name = default_launcher.get_name() if default_launcher is not None else 'None' + + options = collections.OrderedDict() + options['ADD_ROM_LAUNCHER'] = 'Add new launcher' + options['EDIT_ROM_LAUNCHER'] = 'Edit launcher' + options['REMOVE_ROM_LAUNCHER'] = 'Remove launcher' + options['SET_DEFAULT_ROM_LAUNCHER'] = f'Set default launcher: "{default_launcher_name}"' + + s = f'Manage Launchers for "{rom.get_name()}"' + selected_option = kodi.OrdDictionaryDialog().select(s, options) + if selected_option is None: + # >> Exits context menu + logger.debug('Selected None. Closing context menu') + AppMediator.sync_cmd('EDIT_ROM', args) + return + + # >> Execute subcommand. May be atomic, maybe a submenu. + logger.debug(f'Selected {selected_option}') + AppMediator.sync_cmd(selected_option, args) + # --- Sub commands --- +@AppMediator.register('ADD_ROM_LAUNCHER') +def cmd_add_rom_launchers(args): + rom_id:str = args['rom_id'] if 'rom_id' in args else None + + options = collections.OrderedDict() + uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) + with uow: + repository = AelAddonRepository(uow) + rom_repository = ROMsRepository(uow) + + addons = repository.find_all_launchers() + rom = rom_repository.find_rom(rom_id) + + for addon in addons: + options[addon] = addon.get_name() + + s = 'Choose launcher to associate' + selected_option:AelAddon = kodi.OrdDictionaryDialog().select(s, options) + + if selected_option is None: + # >> Exits context menu + logger.debug('Selected None. Closing context menu') + AppMediator.sync_cmd('EDIT_ROM_LAUNCHERS', args) + return + + # >> Execute subcommand. May be atomic, maybe a submenu. + logger.debug(f'Selected {selected_option.get_id()}') + + selected_launcher = ROMLauncherAddonFactory.create(selected_option, {}) + selected_launcher.configure_for_rom(rom) + @AppMediator.register('ADD_LAUNCHER') def cmd_add_romcollection_launchers(args): romcollection_id:str = args['romcollection_id'] if 'romcollection_id' in args else None @@ -131,7 +194,39 @@ def cmd_edit_romcollection_launchers(args): # >> Execute subcommand. May be atomic, maybe a submenu. logger.debug('EDIT_LAUNCHER: cmd_edit_romcollection_launchers() Selected {}'.format(selected_option.get_id())) selected_option.configure(romcollection) - + +@AppMediator.register('EDIT_ROM_LAUNCHER') +def cmd_edit_rom_launcher(args): + rom_id:str = args['rom_id'] if 'rom_id' in args else None + + uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) + with uow: + repository = ROMsRepository(uow) + rom = repository.find_rom(rom_id) + + launchers = rom.get_launchers() + if len(launchers) == 0: + kodi.notify('No launchers configured for this ROM!') + AppMediator.async_cmd('EDIT_ROM_LAUNCHERS', args) + return + + options = collections.OrderedDict() + for launcher in launchers: + options[launcher] = launcher.get_name() + + s = 'Choose launcher to edit' + selected_option:ROMLauncherAddon = kodi.OrdDictionaryDialog().select(s, options) + + if selected_option is None: + # >> Exits context menu + logger.debug('Selected None. Closing context menu') + AppMediator.async_cmd('EDIT_ROM_LAUNCHERS', args) + return + + # >> Execute subcommand. May be atomic, maybe a submenu. + logger.debug(f'Selected {selected_option.get_id()}') + selected_option.configure_for_rom(rom) + @AppMediator.register('REMOVE_LAUNCHER') def cmd_remove_romcollection_launchers(args): romcollection_id:str = args['romcollection_id'] if 'romcollection_id' in args else None @@ -168,11 +263,54 @@ def cmd_remove_romcollection_launchers(args): return romcollection_repository.remove_launcher(romcollection.get_id(), selected_option.get_id()) - logger.info('REMOVE_LAUNCHER: cmd_remove_romcollection_launchers() Removed launcher#{}'.format(selected_option.get_id())) + logger.info(f'Removed launcher#{selected_option.get_id()}') uow.commit() + kodi.notify(f'Removed launcher "{selected_option.get_name()}"') AppMediator.sync_cmd('EDIT_ROMCOLLECTION_LAUNCHERS', args) + +@AppMediator.register('REMOVE_ROM_LAUNCHER') +def cmd_remove_rom_launchers(args): + rom_id:str = args['rom_id'] if 'rom_id' in args else None + uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) + with uow: + repository = ROMsRepository(uow) + rom = repository.find_rom(rom_id) + + launchers = rom.get_launchers() + if len(launchers) == 0: + kodi.notify('No launchers configured for this ROM!') + AppMediator.sync_cmd('EDIT_ROM_LAUNCHERS', args) + return + + options = collections.OrderedDict() + for launcher in launchers: + options[launcher] = launcher.get_name() + + s = 'Choose launcher to remove' + selected_option:ROMLauncherAddon = kodi.OrdDictionaryDialog().select(s, options) + + if selected_option is None: + # >> Exits context menu + logger.debug('Selected None. Closing context menu') + AppMediator.sync_cmd('EDIT_ROM_LAUNCHERS', args) + return + + # >> Execute subcommand. May be atomic, maybe a submenu. + logger.debug(f'Selected {selected_option.get_id()}') + if not kodi.dialog_yesno(f'Are you sure to delete launcher "{selected_option.get_name()}"'): + logger.debug('Cancelled operation.') + AppMediator.async_cmd('EDIT_ROM_LAUNCHERS', args) + return + + repository.remove_launcher(rom.get_id(), selected_option.get_id()) + logger.info(f'Removed launcher#{selected_option.get_id()}') + uow.commit() + + kodi.notify(f'Removed launcher "{selected_option.get_name()}"') + AppMediator.sync_cmd('EDIT_ROM_LAUNCHERS', args) + @AppMediator.register('SET_DEFAULT_LAUNCHER') def cmd_set_default_romcollection_launchers(args): romcollection_id:str = args['romcollection_id'] if 'romcollection_id' in args else None @@ -203,11 +341,47 @@ def cmd_set_default_romcollection_launchers(args): # >> Execute subcommand. May be atomic, maybe a submenu. logger.debug('SET_DEFAULT_LAUNCHER: cmd_set_default_romcollection_launchers() Selected {}'.format(selected_option)) - #@romcollection.set_launcher_as_default(launc) + romcollection.set_launcher_as_default(selected_option) romcollection_repository.update_romcollection(romcollection) uow.commit() AppMediator.sync_cmd('EDIT_ROMCOLLECTION_LAUNCHERS', args) + +@AppMediator.register('SET_DEFAULT_ROM_LAUNCHER') +def cmd_set_default_rom_launchers(args): + rom_id:str = args['rom_id'] if 'rom_id' in args else None + + uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) + with uow: + repository = ROMsRepository(uow) + rom = repository.find_rom(rom_id) + + launchers = rom.get_launchers() + if len(launchers) == 0: + kodi.notify('No launchers configured for this ROM!') + AppMediator.sync_cmd('EDIT_ROM_LAUNCHERS', args) + return + + options = collections.OrderedDict() + for launcher in launchers: + options[launcher.get_id()] = launcher.get_name() + + s = 'Choose launcher to set as default' + selected_option = kodi.OrdDictionaryDialog().select(s, options) + + if selected_option is None: + # >> Exits context menu + logger.debug('Selected None. Closing context menu') + AppMediator.sync_cmd('EDIT_ROM_LAUNCHERS', args) + return + + # >> Execute subcommand. May be atomic, maybe a submenu. + logger.debug(f'Selected {selected_option}') + rom.set_launcher_as_default(selected_option) + repository.update_rom(rom) + uow.commit() + + AppMediator.sync_cmd('EDIT_ROM_LAUNCHERS', args) # ------------------------------------------------------------------------------------------------- # ROMCollection Launcher executing diff --git a/resources/lib/commands/view_rendering_commands.py b/resources/lib/commands/view_rendering_commands.py index 835944b4..e1484c95 100644 --- a/resources/lib/commands/view_rendering_commands.py +++ b/resources/lib/commands/view_rendering_commands.py @@ -291,6 +291,7 @@ def _render_category_view(category_obj: Category, categories_repository: Categor sub_categories = categories_repository.find_categories_by_parent(category_obj.get_id()) romcollections = romcollections_repository.find_romcollections_by_parent(category_obj.get_id()) + roms = roms_repository.find_roms_by_category(category_obj) view_data = { 'id': category_obj.get_id(), @@ -308,15 +309,21 @@ def _render_category_view(category_obj: Category, categories_repository: Categor views_repository, render_sub_views) for romcollection in romcollections: - logger.debug('Processing romcollection "{}"'.format(romcollection.get_name())) + logger.debug(f"Processing romcollection '{romcollection.get_name()}'") try: view_items.append(_render_romcollection_listitem(romcollection)) - except Exception as ex: - logger.error('Exception while rendering list item ROM Collection "{}"'.format(romcollection.get_name()), exc_info=ex) - kodi.notify_error("Failed to process ROM collection {}".format(romcollection.get_name())) + except Exception: + logger.exception(f"Exception while rendering list item ROM Collection '{romcollection.get_name()}'") + kodi.notify_error(f"Failed to process ROM collection {romcollection.get_name()}") if render_sub_views and not category_obj.get_type() == constants.OBJ_CATEGORY_VIRTUAL: collection_view_data = _render_romcollection_view(romcollection, roms_repository) views_repository.store_view(romcollection.get_id(), romcollection.get_type(), collection_view_data) + + for rom in roms: + try: + view_items.append(_render_rom_listitem(rom)) + except Exception: + logger.exception(f"Exception while rendering list item ROM '{rom.get_name()}'") logger.debug(f'Storing {len(view_items)} items for category "{category_obj.get_name()}" view.') view_data['items'] = view_items diff --git a/resources/lib/domain.py b/resources/lib/domain.py index 3ade86ff..0bacab5e 100644 --- a/resources/lib/domain.py +++ b/resources/lib/domain.py @@ -322,6 +322,16 @@ def get_configure_command(self, romcollection: ROMCollection) -> dict: '--akl_addon_id': self.get_id() } + def get_configure_command_for_rom(self, rom: ROM) -> dict: + return { + '--cmd': 'configure', + '--type': constants.AddonType.LAUNCHER.name, + '--server_host': globals.WEBSERVER_HOST, + '--server_port': globals.WEBSERVER_PORT, + '--rom_id': rom.get_id(), + '--akl_addon_id': self.get_id() + } + def launch(self, rom: ROM): kodi.run_script( self.addon.get_addon_id(), @@ -331,6 +341,11 @@ def configure(self, romcollection:ROMCollection): kodi.run_script( self.addon.get_addon_id(), self.get_configure_command(romcollection)) + + def configure_for_rom(self, rom:ROM): + kodi.run_script( + self.addon.get_addon_id(), + self.get_configure_command_for_rom(rom)) class RetroplayerLauncherAddon(ROMLauncherAddon): @@ -360,7 +375,7 @@ def launch(self, rom: ROM): kodi.play_item(rom.get_name(), rom_file_path.getPath(), 'game', game_info) logger.debug('Retroyplayer call finished') - def configure(self, romcollection:ROMCollection): + def configure(self, romcollection: ROMCollection): post_data = { 'romcollection_id': romcollection.get_id(), 'akl_addon_id': self.get_id(), @@ -370,6 +385,17 @@ def configure(self, romcollection:ROMCollection): is_stored = api.client_post_launcher_settings(globals.WEBSERVER_HOST, globals.WEBSERVER_PORT, post_data) if not is_stored: kodi.notify_error('Failed to store launchers settings') + + def configure_for_rom(self, rom: ROM): + post_data = { + 'rom_id': rom.get_id(), + 'akl_addon_id': self.get_id(), + 'addon_id': self.addon.get_addon_id(), + 'settings': {} + } + is_stored = api.client_post_launcher_settings(globals.WEBSERVER_HOST, globals.WEBSERVER_PORT, post_data) + if not is_stored: + kodi.notify_error('Failed to store launchers settings') class ROMCollectionScanner(ROMAddon): @@ -686,7 +712,7 @@ def get_asset_path(self, asset_info: AssetInfo, fallback_to_root = True) -> io.F return None def set_asset_path(self, asset_info: AssetInfo, path: str): - logger.debug('Setting "{}" to {}'.format(asset_info.id, path)) + logger.debug(f'Setting "{asset_info.id}" to {path}') asset_path = self.asset_paths[asset_info.id] if asset_info.id in self.asset_paths else AssetPath() asset_path.set_path(path) asset_path.set_asset_info(asset_info) @@ -1061,7 +1087,7 @@ def add_launcher(self, addon: AelAddon, settings: dict, is_non_blocking = True, if current_default_launcher: current_default_launcher.set_default(False) self.launchers_data.append(launcher) - logger.debug(f'Adding addon "{addon.get_addon_id()}" to launcher "{self.get_name()}"') + logger.debug(f'Adding addon "{addon.get_addon_id()}" to collection "{self.get_name()}"') def get_launchers(self) -> typing.List[ROMLauncherAddon]: return self.launchers_data @@ -1076,6 +1102,16 @@ def get_default_launcher(self) -> ROMLauncherAddon: return default_launcher + def set_launcher_as_default(self, launcher_id): + if len(self.launchers_data) == 0: return + + current_default_launcher = next((l for l in self.launchers_data if l.is_default()), None) + if current_default_launcher: current_default_launcher.set_default(False) + + launcher_to_be_default = next((l for l in self.launchers_data if l.get_id() == launcher_id), None) + if launcher_to_be_default: + launcher_to_be_default.set_default(True) + def has_scanners(self) -> bool: return len(self.scanners_data) > 0 @@ -1322,7 +1358,7 @@ def get_tag_data(self) -> dict: return self.tags if self.tags is None else {} def get_launch_count(self): - return self.entity_data['launch_count'] + return self.entity_data['launch_count'] if 'launch_count' in self.entity_data else 0 def get_last_launch_date(self): return self.entity_data['last_launch_timestamp'] @@ -1406,12 +1442,45 @@ def get_box_sizing(self): def set_box_sizing(self, box_size): self.entity_data['box_size'] = box_size + def has_launchers(self) -> bool: + return len(self.launchers_data) > 0 + + def add_launcher(self, addon: AelAddon, settings: dict, is_non_blocking = True, is_default: bool = False): + launcher = ROMLauncherAddonFactory.create(addon, { + 'settings': json.dumps(settings), + 'is_non_blocking': is_non_blocking, + 'is_default': is_default + }) + if is_default: + current_default_launcher = next((l for l in self.launchers_data if l.is_default()), None) + if current_default_launcher: current_default_launcher.set_default(False) + + self.launchers_data.append(launcher) + logger.debug(f'Adding addon "{addon.get_addon_id()}" to ROM "{self.get_name()}"') + def get_launchers(self) -> typing.List[ROMLauncherAddon]: return self.launchers_data def get_launcher(self, id:str) -> ROMLauncherAddon: return next((l for l in self.launchers_data if l.get_id() == id), None) + def get_default_launcher(self) -> ROMLauncherAddon: + if len(self.launchers_data) == 0: return None + default_launcher = next((l for l in self.launchers_data if l.is_default()), None) + if default_launcher is None: return self.launchers_data[0] + + return default_launcher + + def set_launcher_as_default(self, launcher_id): + if len(self.launchers_data) == 0: return + + current_default_launcher = next((l for l in self.launchers_data if l.is_default()), None) + if current_default_launcher: current_default_launcher.set_default(False) + + launcher_to_be_default = next((l for l in self.launchers_data if l.get_id() == launcher_id), None) + if launcher_to_be_default: + launcher_to_be_default.set_default(True) + def copy(self): data = self.copy_of_data_dic() return ROM(data) diff --git a/resources/lib/editors.py b/resources/lib/editors.py index a5d9cd03..0695ec69 100644 --- a/resources/lib/editors.py +++ b/resources/lib/editors.py @@ -222,20 +222,28 @@ def edit_asset(obj_instance: MetaDataItemABC, asset_info: AssetInfo) -> str: # Scraper additionaly requires: current_asset_path, scraper_obj, platform, rom_base_noext asset_directory = obj_instance.get_assets_root_path() - # --- New style code --- - if asset_directory is None: - if obj_instance.get_assets_kind() == constants.KIND_ASSET_CATEGORY: - asset_directory = io.FileName(settings.getSetting('categories_asset_dir'), isdir = True) - elif obj_instance.get_assets_kind() == constants.KIND_ASSET_COLLECTION: - asset_directory = io.FileName(settings.getSetting('collections_asset_dir'), isdir = True) - elif obj_instance.get_assets_kind() == constants.KIND_ASSET_LAUNCHER: - asset_directory = io.FileName(settings.getSetting('launchers_asset_dir'), isdir = True) - elif obj_instance.get_assets_kind() == constants.KIND_ASSET_ROM: - asset_directory = io.FileName(settings.getSetting('launchers_asset_dir'), isdir = True) + if not asset_directory: + if kodi.dialog_yesno("No local assets path configured. Configure now?\n Else we will use addon default directories."): + path_str = kodi.dialog_get_directory(f"Assets root path for entry '{obj_instance.get_name()}'") + asset_directory = io.FileName(path_str, True) + obj_instance.set_assets_root_path(asset_directory, None, create_default_subdirectories=True) else: - kodi.dialog_OK('Unknown obj_instance.get_assets_kind() {}. '.format(obj_instance.get_assets_kind()) + - 'This is a bug, please report it.') - return None + if obj_instance.get_assets_kind() == constants.KIND_ASSET_CATEGORY: + asset_directory = io.FileName(settings.getSetting('categories_asset_dir'), isdir = True) + obj_instance.set_assets_root_path(asset_directory, None, create_default_subdirectories=True) + elif obj_instance.get_assets_kind() == constants.KIND_ASSET_COLLECTION: + asset_directory = io.FileName(settings.getSetting('collections_asset_dir'), isdir = True) + obj_instance.set_assets_root_path(asset_directory, None, create_default_subdirectories=True) + elif obj_instance.get_assets_kind() == constants.KIND_ASSET_LAUNCHER: + asset_directory = io.FileName(settings.getSetting('launchers_asset_dir'), isdir = True) + obj_instance.set_assets_root_path(asset_directory, None, create_default_subdirectories=True) + elif obj_instance.get_assets_kind() == constants.KIND_ASSET_ROM: + asset_directory = io.FileName(settings.getSetting('launchers_asset_dir'), isdir = True) + obj_instance.set_assets_root_path(asset_directory, None, create_default_subdirectories=True) + else: + kodi.dialog_OK('Unknown obj_instance.get_assets_kind() {}. '.format(obj_instance.get_assets_kind()) + + 'This is a bug, please report it.') + return None asset_path_noext = g_assetFactory.assets_get_path_noext_SUFIX(asset_info.id, asset_directory, obj_instance.get_name(), obj_instance.get_id()) @@ -309,13 +317,11 @@ def edit_asset(obj_instance: MetaDataItemABC, asset_info: AssetInfo) -> str: # --- Import an image --- # >> Copy and rename a local image into asset directory elif selected_option == 'IMPORT_LOCAL': - # >> If assets exists start file dialog from current asset directory - current_image_file = obj_instance.get_asset_FN(asset_info) - current_image_dir = io.FileName(current_image_file.getDir(), isdir = True) - logger.debug('edit_asset() current_image_dir "{0}"'.format(current_image_dir.getPath())) - logger.debug('edit_asset() current_image_file "{0}"'.format(current_image_file.getPath())) - - title_str = 'Select {0} {1}'.format(obj_instance.get_object_name(), asset_info.name) + current_image_dir = obj_instance.get_asset_path(asset_info, fallback_to_root=False) + if not current_image_dir: + current_image_dir = obj_instance.get_assets_root_path() + + title_str = f'Select {obj_instance.get_object_name()} {asset_info.name}' ext_list = asset_info.exts_dialog if asset_info.id == constants.ASSET_MANUAL_ID or asset_info.id == constants.ASSET_TRAILER_ID: new_asset_file_str = kodi.browse(text=title_str, mask=ext_list, preselected_path=current_image_dir.getPath()) @@ -327,9 +333,9 @@ def edit_asset(obj_instance: MetaDataItemABC, asset_info: AssetInfo) -> str: # >> Determine image extension and dest filename. Check for errors. new_asset_file = io.FileName(new_asset_file_str) dest_asset_file = asset_path_noext.append(new_asset_file.getExt()) - logger.debug('m_gui_edit_asset() new_asset_file "{0}"'.format(new_asset_file.getPath())) - logger.debug('m_gui_edit_asset() new_asset_file ext "{0}"'.format(new_asset_file.getExt())) - logger.debug('m_gui_edit_asset() dest_asset_file "{0}"'.format(dest_asset_file.getPath())) + logger.debug(f'm_gui_edit_asset() new_asset_file "{new_asset_file.getPath()}"') + logger.debug(f'm_gui_edit_asset() new_asset_file ext "{new_asset_file.getExt()}"') + logger.debug(f'm_gui_edit_asset() dest_asset_file "{dest_asset_file.getPath()}"') if new_asset_file.getPath() == dest_asset_file.getPath(): logger.info('m_gui_edit_asset() new_asset_file and dest_asset_file are the same. Returning.') kodi.notify_warn('new_asset_file and dest_asset_file are the same. Returning') @@ -388,11 +394,14 @@ def edit_asset(obj_instance: MetaDataItemABC, asset_info: AssetInfo) -> str: # logger.debug('dest_asset_file ctime {0}'.format(time.ctime(os.path.getctime(dest_asset_file.getPath())))) # --- Delete cached image to force a cache update --- - kodi.delete_cache_texture(dest_asset_file.getPath()) - kodi.print_texture_info(dest_asset_file.getPath()) + try: + kodi.delete_cache_texture(dest_asset_file.getPath()) + kodi.print_texture_info(dest_asset_file.getPath()) + except Exception: + logging.exception("Failed to delete cache") # --- Notify user --- - kodi.notify('{0} {1} has been updated'.format(obj_instance.get_object_name(), asset_info.name)) + kodi.notify(f'{obj_instance.get_object_name()} {asset_info.name} has been updated') # --- Unset asset --- elif selected_option == 'UNSET': diff --git a/resources/lib/repositories.py b/resources/lib/repositories.py index f5e23314..6e9f166d 100644 --- a/resources/lib/repositories.py +++ b/resources/lib/repositories.py @@ -431,6 +431,10 @@ def dict_factory(cursor, row): QUERY_SELECT_CATEGORIES_BY_PARENT = "SELECT * FROM vw_categories WHERE parent_id = ? ORDER BY m_name" QUERY_SELECT_CATEGORY_ASSETS_BY_PARENT = "SELECT * FROM vw_category_assets WHERE parent_id = ?" +QUERY_SELECT_CATEGORIES_BY_ROM = "SELECT c.* FROM vw_categories AS c INNER JOIN roms_in_category AS rc ON rc.category_id = c.id WHERE rc.rom_id = ?" +QUERY_SELECT_CATEGORIES_ASSETS_BY_ROM = "SELECT ca.* FROM vw_category_assets AS ca INNER JOIN roms_in_category AS rc ON rc.category_id = ca.category_id WHERE rc.rom_id = ?" + + QUERY_INSERT_CATEGORY = """ INSERT INTO categories (id,name,parent_id,metadata_id,default_icon,default_fanart,default_banner,default_poster,default_clearlogo) VALUES (?,?,?,?,?,?,?,?,?) @@ -442,6 +446,11 @@ def dict_factory(cursor, row): """ QUERY_INSERT_CATEGORY_ASSET = "INSERT INTO category_assets (category_id, asset_id) VALUES (?, ?)" QUERY_DELETE_CATEGORY = "DELETE FROM category WHERE id = ?" + +QUERY_INSERT_ROM_IN_CATEGORY = "INSERT INTO roms_in_category (rom_id, category_id) VALUES (?,?)" +QUERY_REMOVE_ROM_FROM_CATEGORY = "DELETE FROM roms_in_category WHERE rom_id = ? AND category_id = ?" +QUERY_REMOVE_ROMS_FROM_CATEGORY = "DELETE FROM roms_in_category WHERE category_id = ?" + class CategoryRepository(object): def __init__(self, uow: UnitOfWork): @@ -510,7 +519,21 @@ def find_all_categories(self) -> typing.Iterator[Category]: assets.append(Asset(asset_data)) yield Category(category_data, assets) - + + def find_categories_by_rom(self, rom_id: str) -> typing.Iterator[Category]: + self._uow.execute(QUERY_SELECT_CATEGORIES_BY_ROM, rom_id) + result_set = self._uow.result_set() + + self._uow.execute(QUERY_SELECT_CATEGORIES_ASSETS_BY_ROM, rom_id) + assets_result_set = self._uow.result_set() + + for category_data in result_set: + assets = [] + for asset_data in filter(lambda a: a['category_id'] == category_data['id'], assets_result_set): + assets.append(Asset(asset_data)) + + yield Category(category_data, assets) + def insert_category(self, category_obj: Category, parent_obj: Category = None): logger.info("CategoryRepository.insert_category(): Inserting new category '{}'".format(category_obj.get_name())) metadata_id = text.misc_generate_random_SID() @@ -572,7 +595,16 @@ def update_category(self, category_obj: Category): def delete_category(self, category_id: str): logger.info("CategoryRepository.delete_category(): Deleting category '{}'".format(category_id)) self._uow.execute(QUERY_DELETE_CATEGORY, category_id) + + def add_rom_to_category(self, category_id: str, rom_id: str): + self._uow.execute(QUERY_INSERT_ROM_IN_CATEGORY, rom_id, category_id) + + def remove_rom_from_category(self, category_id: str, rom_id: str): + self._uow.execute(QUERY_REMOVE_ROM_FROM_CATEGORY, rom_id, category_id) + def remove_all_roms_in_category(self, category_id: str): + self._uow.execute(QUERY_REMOVE_ROMS_FROM_CATEGORY, category_id) + def _insert_asset(self, asset: Asset, category_obj: Category): asset_db_id = text.misc_generate_random_SID() self._uow.execute(QUERY_INSERT_ASSET, asset_db_id, asset.get_path(), asset.get_asset_info_id()) @@ -978,13 +1010,19 @@ def _get_collections_query_by_vcategory_id(self, vcategory_id:str) -> str: # ROMsRepository -> ROMs from SQLite DB # QUERY_SELECT_ROM = "SELECT * FROM vw_roms WHERE id = ?" -QUERY_SELECT_ROMS_BY_SET = "SELECT r.* FROM vw_roms AS r INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = r.id AND rs.romcollection_id = ?" QUERY_SELECT_ROM_ASSETS = "SELECT * FROM vw_rom_assets WHERE rom_id = ?" QUERY_SELECT_ROM_ASSETPATHS = "SELECT * FROM vw_rom_asset_paths WHERE rom_id = ?" +QUERY_SELECT_ROM_TAGS = "SELECT * FROM vw_rom_tags WHERE rom_id = ?" + +QUERY_SELECT_ROMS_BY_SET = "SELECT r.* FROM vw_roms AS r INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = r.id AND rs.romcollection_id = ?" QUERY_SELECT_ROM_ASSETS_BY_SET = "SELECT ra.* FROM vw_rom_assets AS ra INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = ra.rom_id AND rs.romcollection_id = ?" QUERY_SELECT_ROM_ASSETPATHS_BY_SET = "SELECT rap.* FROM vw_rom_asset_paths AS rap INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = rap.rom_id AND rs.romcollection_id = ?" QUERY_SELECT_ROM_TAGS_BY_SET = "SELECT rt.* FROM vw_rom_tags AS rt INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = rt.rom_id AND rs.romcollection_id = ?" -QUERY_SELECT_ROM_TAGS = "SELECT * FROM vw_rom_tags WHERE rom_id = ?" + +QUERY_SELECT_ROMS_BY_CATEGORY = "SELECT r.* FROM vw_roms AS r INNER JOIN roms_in_category AS rc ON rc.rom_id = r.id AND rc.category_id = ?" +QUERY_SELECT_ROM_ASSETS_BY_CATEGORY = "SELECT ra.* FROM vw_rom_assets AS ra INNER JOIN roms_in_category AS rc ON rc.rom_id = ra.rom_id AND rc.category_id = ?" +QUERY_SELECT_ROM_ASSETPATHS_BY_CATEGORY = "SELECT rap.* FROM vw_rom_asset_paths AS rap INNER JOIN roms_in_category AS rc ON rc.rom_id = rap.rom_id AND rc.category_id = ?" +QUERY_SELECT_ROM_TAGS_BY_CATEGORY = "SELECT rt.* FROM vw_rom_tags AS rt INNER JOIN roms_in_category AS rc ON rc.rom_id = rt.rom_id AND rc.category_id = ?" # Filter values QUERY_SELECT_GENRES_BY_COLLECTION = "SELECT DISTINCT(r.m_genre) AS genre FROM vw_roms AS r INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = r.id AND rs.romcollection_id = ? ORDER BY genre" @@ -992,12 +1030,12 @@ def _get_collections_query_by_vcategory_id(self, vcategory_id:str) -> str: QUERY_SELECT_DEVELOPER_BY_COLLECTION = "SELECT DISTINCT(r.m_developer) AS developer FROM vw_roms AS r INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = r.id AND rs.romcollection_id = ? ORDER BY developer" QUERY_SELECT_RATING_BY_COLLECTION = "SELECT DISTINCT(r.m_rating) AS rating FROM vw_roms AS r INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = r.id AND rs.romcollection_id = ? ORDER BY rating" -QUERY_INSERT_ROM = """ - INSERT INTO roms ( - id, metadata_id, name, num_of_players, num_of_players_online, esrb_rating, - platform, box_size, nointro_status, cloneof, rom_status, scanned_by_id) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?) - """ +QUERY_INSERT_ROM = """ + INSERT INTO roms ( + id, metadata_id, name, num_of_players, num_of_players_online, esrb_rating, + platform, box_size, nointro_status, cloneof, rom_status, scanned_by_id) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?) + """ QUERY_SELECT_MY_FAVOURITES = "SELECT * FROM vw_roms WHERE is_favourite = 1" QUERY_SELECT_RECENTLY_PLAYED_ROMS = "SELECT * FROM vw_roms WHERE last_launch_timestamp IS NOT NULL ORDER BY last_launch_timestamp DESC LIMIT 100" @@ -1041,15 +1079,16 @@ def _get_collections_query_by_vcategory_id(self, vcategory_id:str) -> str: QUERY_DELETE_ROM = "DELETE FROM roms WHERE id = ?" QUERY_DELETE_ROMS_BY_COLLECTION = "DELETE FROM roms WHERE id IN (SELECT rc.rom_id FROM roms_in_romcollection AS rc WHERE rc.romcollection_id = ?)" -QUERY_SELECT_ROM_SCANNED_DATA = "SELECT s.* FROM scanned_roms_data AS s WHERE s.rom_id = ?" -QUERY_SELECT_ROM_SCANNED_DATA_BY_SET = "SELECT s.* FROM scanned_roms_data AS s INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = s.rom_id AND rs.romcollection_id = ?" -QUERY_DELETE_SCANNED_DATA = "DELETE FROM scanned_roms_data WHERE rom_id = ?" +QUERY_SELECT_ROM_SCANNED_DATA = "SELECT s.* FROM scanned_roms_data AS s WHERE s.rom_id = ?" +QUERY_SELECT_ROM_SCANNED_DATA_BY_SET = "SELECT s.* FROM scanned_roms_data AS s INNER JOIN roms_in_romcollection AS rs ON rs.rom_id = s.rom_id AND rs.romcollection_id = ?" +QUERY_SELECT_ROM_SCANNED_DATA_BY_CATEGORY = "SELECT s.* FROM scanned_roms_data AS s INNER JOIN roms_in_category AS rc ON rc.rom_id = s.rom_id AND rc.category_id = ?" +QUERY_DELETE_SCANNED_DATA = "DELETE FROM scanned_roms_data WHERE rom_id = ?" QUERY_SELECT_ROM_LAUNCHERS = "SELECT * FROM vw_rom_launchers WHERE rom_id = ?" QUERY_INSERT_ROM_LAUNCHER = "INSERT INTO rom_launchers (id, rom_id, akl_addon_id, settings, is_default) VALUES (?,?,?,?,?)" QUERY_UPDATE_ROM_LAUNCHER = "UPDATE rom_launchers SET settings = ?, is_default = ? WHERE id = ?" QUERY_DELETE_ROM_LAUNCHERS = "DELETE FROM rom_launchers WHERE rom_id = ?" -QUERY_DELETE_ROM_LAUNCHER = "DELETE FROM rom_launchers WHERE romcollection_id = ? AND id = ?" +QUERY_DELETE_ROM_LAUNCHER = "DELETE FROM rom_launchers WHERE rom_id = ? AND id = ?" QUERY_SELECT_TAGS = "SELECT * FROM tags" QUERY_INSERT_TAG = "INSERT INTO tags (id, tag) VALUES (?,?)" @@ -1062,6 +1101,41 @@ class ROMsRepository(object): def __init__(self, uow: UnitOfWork): self._uow = uow + def find_roms_by_category(self, category: Category) -> typing.Iterator[ROM]: + category_id = category.get_id() + + self._uow.execute(QUERY_SELECT_ROMS_BY_CATEGORY, category_id) + result_set = self._uow.result_set() + + self._uow.execute(QUERY_SELECT_ROM_ASSETS_BY_CATEGORY, category_id) + assets_result_set = self._uow.result_set() + + self._uow.execute(QUERY_SELECT_ROM_ASSETPATHS_BY_CATEGORY, category_id) + asset_paths_result_set = self._uow.result_set() + + self._uow.execute(QUERY_SELECT_ROM_SCANNED_DATA_BY_CATEGORY, category_id) + scanned_data_result_set = self._uow.result_set() + + self._uow.execute(QUERY_SELECT_ROM_TAGS_BY_CATEGORY, category_id) + tags_data_set = self._uow.result_set() + + for rom_data in result_set: + assets = [] + asset_paths = [] + tags = {} + for asset_data in filter(lambda a: a['rom_id'] == rom_data['id'], assets_result_set): + assets.append(Asset(asset_data)) + for asset_paths_data in filter(lambda a: a['rom_id'] == rom_data['id'], asset_paths_result_set): + asset_paths.append(AssetPath(asset_paths_data)) + for tag in filter(lambda t: t['rom_id'] == rom_data['id'], tags_data_set): + tags[tag['tag']] = tag['id'] + + scanned_data = { + entry['data_key']: entry['data_value'] + for entry in filter(lambda s: s['rom_id'] == rom_data['id'], scanned_data_result_set) + } + yield ROM(rom_data, tags, assets, asset_paths, scanned_data) + def find_roms_by_romcollection(self, romcollection: ROMCollection) -> typing.Iterator[ROM]: is_virtual = romcollection.get_type() == constants.OBJ_COLLECTION_VIRTUAL romcollection_id = romcollection.get_id() @@ -1248,7 +1322,7 @@ def update_rom(self, rom_obj: ROM): self._update_scanned_data(rom_obj.get_id(),rom_obj.scanned_data) self._update_launchers(rom_obj.get_id(), rom_obj.get_launchers()) - + def delete_rom(self, rom_id: str): logger.info("ROMsRepository.delete_rom(): Deleting ROM '{}'".format(rom_id)) self._uow.execute(QUERY_DELETE_ROM, rom_id) @@ -1256,6 +1330,9 @@ def delete_rom(self, rom_id: str): def delete_roms_by_romcollection(self, romcollection_id:str): self._uow.execute(QUERY_DELETE_ROMS_BY_COLLECTION, romcollection_id) + def remove_launcher(self, rom_id: str, launcher_id:str): + self._uow.execute(QUERY_DELETE_ROM_LAUNCHER, rom_id, launcher_id) + def insert_tag(self, tag:str) -> str: db_id = text.misc_generate_random_SID() self._uow.execute(QUERY_INSERT_TAG, db_id, tag) @@ -1288,14 +1365,14 @@ def _update_launchers(self, rom_id:str, rom_launchers:typing.List[ROMLauncherAdd for rom_launcher in rom_launchers: if rom_launcher.get_id() is None: rom_launcher.set_id(text.misc_generate_random_SID()) - self._uow.execute(QUERY_INSERT_ROMCOLLECTION_LAUNCHER, + self._uow.execute(QUERY_INSERT_ROM_LAUNCHER, rom_launcher.get_id(), rom_id, rom_launcher.addon.get_id(), rom_launcher.get_settings_str(), rom_launcher.is_default()) else: - self._uow.execute(QUERY_UPDATE_ROMCOLLECTION_LAUNCHER, + self._uow.execute(QUERY_UPDATE_ROM_LAUNCHER, rom_launcher.get_settings_str(), rom_launcher.is_default(), rom_launcher.get_id()) diff --git a/resources/lib/viewqueries.py b/resources/lib/viewqueries.py index 9ee89538..3dae208b 100644 --- a/resources/lib/viewqueries.py +++ b/resources/lib/viewqueries.py @@ -387,7 +387,8 @@ def qry_container_context_menu_items(container_data) -> typing.List[typing.Tuple commands = [] if is_category: commands.append(('Rebuild {} view'.format(container_name), - _context_menu_url_for('execute/command/render_view',{'category_id':container_id}))) + _context_menu_url_for('execute/command/render_view',{'category_id':container_id}))) + if is_romcollection: commands.append(('Search ROM in collection', _context_menu_url_for(f'/collection/{container_id}/search'))) commands.append(('Rebuild {} view'.format(container_name), @@ -440,7 +441,6 @@ def qry_listitem_context_menu_items(list_item_data, container_data)-> typing.Lis commands.append(('Edit Category', _context_menu_url_for(f'/categories/edit/{item_id}'))) commands.append(('Add new Category',_context_menu_url_for(f'/categories/add/{item_id}/in/{container_id}'))) commands.append(('Add new ROM Collection', _context_menu_url_for(f'/romcollection/add/{item_id}/in/{container_id}'))) - commands.append(('Add new ROM (Standalone)', _context_menu_url_for(f'/categories/addrom/{container_id}'))) if is_romcollection: commands.append(('View ROM Collection', _context_menu_url_for(f'/romcollection/view/{item_id}'))) @@ -449,6 +449,9 @@ def qry_listitem_context_menu_items(list_item_data, container_data)-> typing.Lis if not is_category and container_is_category: commands.append(('Add new Category',_context_menu_url_for(f'/categories/add/{container_id}'))) commands.append(('Add new ROM Collection', _context_menu_url_for(f'/romcollection/add/{container_id}'))) + + if container_is_category: + commands.append(('Add new ROM (Standalone)', _context_menu_url_for(f'/categories/addrom/{container_id}'))) if is_virtual_category: commands.append((f'Rebuild {item_name} view', _context_menu_url_for('execute/command/render_vcategory_view',{'vcategory_id':item_id}))) From 5c3694fa13b378ea8d0b238818a497f88e6cff67 Mon Sep 17 00:00:00 2001 From: chrisism Date: Mon, 18 Jul 2022 16:42:34 +0200 Subject: [PATCH 3/3] updated ref dialog --- resources/lib/commands/rom_commands.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/resources/lib/commands/rom_commands.py b/resources/lib/commands/rom_commands.py index a512a27e..e71f75e3 100644 --- a/resources/lib/commands/rom_commands.py +++ b/resources/lib/commands/rom_commands.py @@ -652,20 +652,17 @@ def cmd_manage_rom_tags(args): # ------------------------------------------------------------------------------------------------- @AppMediator.register('ADD_STANDALONE_ROM') def cmd_add_rom(args): - import xbmcgui - logger.debug('ADD_STANDALONE_ROM: cmd_add_rom() BEGIN') category_id:str = args['category_id'] if 'category_id' in args else None if category_id is None: - logger.warning('cmd_add_rom(): No Category id supplied.') + logger.warning('No Category id supplied.') kodi.notify_warn("Invalid parameters supplied.") return rom_name = "" is_file_based = kodi.dialog_yesno("Is it a file based ROM/executable?") if is_file_based: - #TODO: change to file_path = kodi.dialog_get_file("Select file") - remove xmbcgui import - file_path = xbmcgui.Dialog().browse(1, "Select file", "") + file_path = kodi.dialog_get_file("Select file") if file_path is not None: path = io.FileName(file_path) rom_name = path.getBaseNoExt()