diff --git a/.build/main.yml b/.build/main.yml index 73ba9b22..b2b407f3 100644 --- a/.build/main.yml +++ b/.build/main.yml @@ -75,9 +75,13 @@ stages: artifactFeeds: AKL/akl_libs - bash: | + python -m venv .venv + source .venv/bin/activate python -m pip install --upgrade pip + pip install setup pip install -r requirements.txt - displayName: pip install + workingDirectory: $(workingDirectory) + displayName: 'Install application dependencies' - task: RegExMatchReplace@2 displayName: 'Set addon version' @@ -86,14 +90,24 @@ stages: RegEx: 'version="\d+\.\d+\.\d+.*" provider' ValueToReplace: 'version="$(addonVersion)" provider' - - bash: update_addon_news $(workingDirectory)/addon.xml $(workingDirectory)/changelog.md + - bash: | + source .venv/bin/activate + update_addon_news $(workingDirectory)/addon.xml $(workingDirectory)/changelog.md displayName: 'Add changelog in addon.xml' workingDirectory: '$(workingDirectory)' - - bash: 'python -m pytest --junitxml=$(build.artifactstagingdirectory)/$(addonName)_$(addonVersion)_testresults.xml' + # - script: | + # source .venv/bin/activate + # python -m flake8 . + # workingDirectory: '$(workingDirectory)' + # displayName: 'Run lint tests' + + - bash: | + source .venv/bin/activate + python -m pytest --junitxml=$(build.artifactstagingdirectory)/$(addonName)_$(addonVersion)_testresults.xml workingDirectory: '$(workingDirectory)' - displayName: 'Run tests' - + displayName: 'Run unit tests' + - task: CopyFiles@2 displayName: 'Copy addon files for package' inputs: @@ -112,6 +126,12 @@ stages: flattenFolders: false OverWrite: true + - bash: | + source .venv/bin/activate + kodi-addon-checker --branch matrix $(build.artifactstagingdirectory)/$(addonName)/ + workingDirectory: '$(workingDirectory)' + displayName: 'Run Kodi addon checker' + - task: ArchiveFiles@2 inputs: rootFolderOrFile: '$(build.artifactstagingdirectory)/$(addonName)' diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..d148452b --- /dev/null +++ b/.flake8 @@ -0,0 +1,10 @@ +[flake8] +max-line-length = 140 +exclude = + .git, + tests/*, + __pycache__, + .build, + .vscode, + .venv +ignore = W293 \ No newline at end of file diff --git a/addon.py b/addon.py index 7c8d536a..41bb58bb 100644 --- a/addon.py +++ b/addon.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # # Advanced Kodi Launcher main script file # @@ -18,6 +18,7 @@ # Advanced Emulator Launcher main script file. +# --- Python standard library --- import sys import logging @@ -28,13 +29,10 @@ kodilogging.config() logger = logging.getLogger(__name__) -# --- Python standard library --- -import sys # ------------------------------------------------------------------------------------------------- # Entrypoint of the Frontend/UI application # ------------------------------------------------------------------------------------------------- - try: views.run_plugin(sys.argv) except Exception as ex: diff --git a/addon.xml b/addon.xml index 8ec74142..ccb99205 100644 --- a/addon.xml +++ b/addon.xml @@ -3,7 +3,7 @@ - + executable game @@ -15,7 +15,7 @@ android freebsd ios linux osx windows GNU General Public License version 2 crizzz@gmail.com - http://forum.kodi.tv/showthread.php?tid=366351 + https://forum.kodi.tv/showthread.php?tid=366351 https://github.com/chrisism/plugin.program.akl https://github.com/chrisism/plugin.program.akl diff --git a/changelog.md b/changelog.md index cdffb984..0eb59a8a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,14 +1,14 @@ ## Current +- Added support for PEGI rating +- Fixed bug deleting collections +- Proper icon/thumb mapping for virtual collections + +## Previous - Virtual categories now render items from database - Add and execute single instance ROMs or Games - Added an overview option with installed plugins - Fix adding tags to ROMs - Minor bugfixes - Updated dependency - -## Bugfixes - Fixed virtual collections (Favs, Most recent ..) -- Fixed scraping ROM assets only - -## Previous: v1.0.0 -- The initial release of the new AKL fork. \ No newline at end of file +- Fixed scraping ROM assets only \ No newline at end of file diff --git a/media/fanart.jpg b/media/fanart.jpg index bed87969..dcdd1fdb 100644 Binary files a/media/fanart.jpg and b/media/fanart.jpg differ diff --git a/media/theme/Browse_by_PEGI_icon.png b/media/theme/Browse_by_PEGI_icon.png new file mode 100644 index 00000000..28918dc9 Binary files /dev/null and b/media/theme/Browse_by_PEGI_icon.png differ diff --git a/media/theme/Browse_by_PEGI_poster.png b/media/theme/Browse_by_PEGI_poster.png new file mode 100644 index 00000000..0c3bd5e5 Binary files /dev/null and b/media/theme/Browse_by_PEGI_poster.png differ diff --git a/requirements.txt b/requirements.txt index 1c51462c..5cfa50fd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,5 +3,6 @@ kodi-addon-checker==0.0.26 Kodistubs==19.0.3 routing==0.2.3 pytest==6.2.5 -script.module.akl==1.0.7 -requests==2.22.0 \ No newline at end of file +script.module.akl==1.0.9 +requests==2.22.0 +flake8==5.0.4 diff --git a/resources/lib/commands/rom_commands.py b/resources/lib/commands/rom_commands.py index 6826c04f..f1868862 100644 --- a/resources/lib/commands/rom_commands.py +++ b/resources/lib/commands/rom_commands.py @@ -96,6 +96,7 @@ def cmd_rom_metadata(args): options['ROM_EDIT_METADATA_NPLAYERS'] = "Edit NPlayers: '{}'".format(rom.get_number_of_players()) options['ROM_EDIT_METADATA_NPLAYERS_ONL']= "Edit NPlayers online: '{}'".format(rom.get_number_of_players_online()) options['ROM_EDIT_METADATA_ESRB'] = "Edit ESRB rating: '{}'".format(rom.get_esrb_rating()) + options['ROM_EDIT_METADATA_PEGI'] = "Edit PEGI rating: '{}'".format(rom.get_pegi_rating()) options['ROM_EDIT_METADATA_RATING'] = "Edit Rating: '{}'".format(rating) options['ROM_EDIT_METADATA_PLOT'] = "Edit Plot: '{}'".format(plot_str) options['ROM_EDIT_METADATA_TAGS'] = "Edit Tags" @@ -215,7 +216,7 @@ def cmd_rom_metadata_title(args): AppMediator.sync_cmd('ROM_EDIT_METADATA', args) @AppMediator.register('ROM_EDIT_METADATA_ESRB') -def cmd_rom_metadata_platform(args): +def cmd_rom_metadata_esrb(args): rom_id = args['rom_id'] if 'rom_id' in args else None uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) with uow: @@ -230,6 +231,23 @@ def cmd_rom_metadata_platform(args): AppMediator.async_cmd('RENDER_VCATEGORY_VIEW', {'vcategory_id': constants.VCATEGORY_ESRB_ID}) AppMediator.sync_cmd('ROM_EDIT_METADATA', args) + +@AppMediator.register('ROM_EDIT_METADATA_PEGI') +def cmd_rom_metadata_pegi(args): + rom_id = 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) + + if editors.edit_field_by_list(rom, 'PEGI rating', constants.PEGI_LIST, + rom.get_pegi_rating, rom.set_pegi_rating): + repository.update_rom(rom) + uow.commit() + AppMediator.async_cmd('RENDER_ROM_VIEWS', {'rom_id': rom.get_id()}) + AppMediator.async_cmd('RENDER_VCATEGORY_VIEW', {'vcategory_id': constants.VCATEGORY_PEGI_ID}) + + AppMediator.sync_cmd('ROM_EDIT_METADATA', args) @AppMediator.register('ROM_EDIT_METADATA_RELEASEYEAR') def cmd_rom_metadata_releaseyear(args): diff --git a/resources/lib/commands/stats_commands.py b/resources/lib/commands/stats_commands.py index f50fd1e6..09c0c5cf 100644 --- a/resources/lib/commands/stats_commands.py +++ b/resources/lib/commands/stats_commands.py @@ -18,19 +18,17 @@ from __future__ import division import logging -import collections -import typing from akl import constants -from akl.utils import kodi, io +from akl.utils import kodi from resources.lib.commands.mediator import AppMediator from resources.lib import globals -from resources.lib.repositories import UnitOfWork, ROMCollectionRepository, ROMsRepository, ROMsJsonFileRepository -from resources.lib.domain import ROM, AssetInfo, g_assetFactory +from resources.lib.repositories import UnitOfWork, ROMsRepository logger = logging.getLogger(__name__) + # ------------------------------------------------------------------------------------------------- # ROM stats # ------------------------------------------------------------------------------------------------- @@ -38,7 +36,7 @@ @AppMediator.register('ROM_WAS_LAUNCHED') def cmd_process_launching_of_rom(args): logger.debug('ROM_WAS_LAUNCHED: cmd_process_launching_of_rom() Processing that a ROM was launched') - rom_id:str = args['rom_id'] if 'rom_id' in args else None + rom_id: str = args['rom_id'] if 'rom_id' in args else None if rom_id is None: logger.warning('cmd_process_launching_of_rom(): No rom id supplied.') return @@ -55,12 +53,13 @@ def cmd_process_launching_of_rom(args): logger.debug('ROM_WAS_LAUNCHED: cmd_process_launching_of_rom() Processed stats for ROM {}'.format(rom.get_name())) AppMediator.async_cmd('RENDER_VCOLLECTION_VIEW', {'vcollection_id': constants.VCOLLECTION_RECENT_ID}) AppMediator.async_cmd('RENDER_VCOLLECTION_VIEW', {'vcollection_id': constants.VCOLLECTION_MOST_PLAYED_ID}) - + + @AppMediator.register('ADD_ROM_TO_FAVOURITES') def cmd_add_rom_to_favourites(args): - rom_id:str = args['rom_id'][0] if 'rom_id' in args else None + rom_id: str = args['rom_id'] if 'rom_id' in args else None if rom_id is None: - logger.warning('cmd_add_rom_to_favourites(): No rom id supplied.') + logger.warning('No rom id supplied.') kodi.notify_warn("Invalid parameters supplied.") return @@ -68,11 +67,9 @@ def cmd_add_rom_to_favourites(args): with uow: repository = ROMsRepository(uow) rom = repository.find_rom(rom_id) - rom.add_to_favourites() repository.update_rom(rom) uow.commit() - logger.debug('ADD_ROM_TO_FAVOURITES: cmd_add_rom_to_favourites() Added ROM {} to favourites'.format(rom.get_name())) + logger.debug(f'Added ROM {rom.get_rom_identifier()} to favourites') AppMediator.async_cmd('RENDER_VCOLLECTION_VIEW', {'vcollection_id': constants.VCOLLECTION_FAVOURITES_ID}) - \ No newline at end of file diff --git a/resources/lib/commands/view_rendering_commands.py b/resources/lib/commands/view_rendering_commands.py index ad72b18c..433d55fc 100644 --- a/resources/lib/commands/view_rendering_commands.py +++ b/resources/lib/commands/view_rendering_commands.py @@ -2,7 +2,7 @@ # # Advanced Kodi Launcher: Commands (Precompiling the view data) # -# Copyright (c) Wintermute0110 / Chrisism +# Copyright (c) Chrisism # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -31,22 +31,24 @@ logger = logging.getLogger(__name__) + @AppMediator.register('RENDER_VIEWS') def cmd_render_views_data(args): kodi.notify('Rendering all views') uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) with uow: - categories_repository = CategoryRepository(uow) + categories_repository = CategoryRepository(uow) romcollections_repository = ROMCollectionRepository(uow) - roms_repository = ROMsRepository(uow) - views_repository = ViewRepository(globals.g_PATHS) + roms_repository = ROMsRepository(uow) + views_repository = ViewRepository(globals.g_PATHS) _render_root_view(categories_repository, romcollections_repository, roms_repository, views_repository, render_sub_views=True) kodi.notify('All views rendered') kodi.refresh_container() + @AppMediator.register('RENDER_CATEGORY_VIEW') def cmd_render_view_data(args): kodi.notify('Rendering views') @@ -55,10 +57,10 @@ def cmd_render_view_data(args): uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) with uow: - categories_repository = CategoryRepository(uow) + categories_repository = CategoryRepository(uow) romcollections_repository = ROMCollectionRepository(uow) - roms_repository = ROMsRepository(uow) - views_repository = ViewRepository(globals.g_PATHS) + roms_repository = ROMsRepository(uow) + views_repository = ViewRepository(globals.g_PATHS) if category_id is None or category_id == constants.VCATEGORY_ADDONROOT_ID: _render_root_view(categories_repository, romcollections_repository, roms_repository, views_repository, render_recursive) @@ -166,14 +168,15 @@ def cmd_render_romcollection_view_data(args): kodi.notify('Selected views rendered') kodi.refresh_container() + @AppMediator.register('RENDER_VCOLLECTION_VIEW') def cmd_render_vcollection(args): vcollection_id = args['vcollection_id'] if 'vcollection_id' in args else None uow = UnitOfWork(globals.g_PATHS.DATABASE_FILE_PATH) with uow: - roms_repository = ROMsRepository(uow) - views_repository = ViewRepository(globals.g_PATHS) + roms_repository = ROMsRepository(uow) + views_repository = ViewRepository(globals.g_PATHS) vcollection = VirtualCollectionFactory.create(vcollection_id) @@ -184,6 +187,7 @@ def cmd_render_vcollection(args): kodi.notify('{} view rendered'.format(vcollection.get_name())) kodi.refresh_container() + @AppMediator.register('RENDER_ROM_VIEWS') def cmd_render_rom_views(args): rom_id = args['rom_id'] if 'rom_id' in args else None @@ -236,12 +240,13 @@ def cmd_render_virtual_collection(vcategory_id: str, collection_value: str) -> d viewdata = _render_romcollection_view(vcollection, roms_repository) return viewdata + # ------------------------------------------------------------------------------------------------- # Rendering of views (containers) -# ------------------------------------------------------------------------------------------------- -def _render_root_view(categories_repository: CategoryRepository, romcollections_repository: ROMCollectionRepository, - roms_repository: ROMsRepository, views_repository: ViewRepository, - render_sub_views = False): +# ------------------------------------------------------------------------------------------------- +def _render_root_view(categories_repository: CategoryRepository, romcollections_repository: ROMCollectionRepository, + roms_repository: ROMsRepository, views_repository: ViewRepository, + render_sub_views=False): root_categories = categories_repository.find_root_categories() root_romcollections = romcollections_repository.find_root_romcollections() @@ -264,7 +269,7 @@ def _render_root_view(categories_repository: CategoryRepository, romcollections_ for root_romcollection in root_romcollections: logger.debug(f'Processing romcollection "{root_romcollection.get_name()}"') root_items.append(_render_romcollection_listitem(root_romcollection)) - if render_sub_views: + if render_sub_views: collection_view_data = _render_romcollection_view(root_romcollection, roms_repository) views_repository.store_view(root_romcollection.get_id(), root_romcollection.get_type(), collection_view_data) @@ -278,8 +283,8 @@ def _render_root_view(categories_repository: CategoryRepository, romcollections_ logger.debug('Processing root virtual category') root_items.append(_render_category_listitem(root_vcategory)) if render_sub_views: - _render_category_view(root_vcategory, categories_repository, romcollections_repository, - roms_repository, views_repository, render_sub_views) + _render_category_view(root_vcategory, categories_repository, romcollections_repository, + roms_repository, views_repository, render_sub_views) for vcollection_id in constants.VCOLLECTIONS: vcollection = VirtualCollectionFactory.create(vcollection_id) @@ -291,10 +296,11 @@ def _render_root_view(categories_repository: CategoryRepository, romcollections_ logger.debug('Storing {} items in root view.'.format(len(root_items))) root_data['items'] = root_items views_repository.store_root_view(root_data) - -def _render_category_view(category_obj: Category, categories_repository: CategoryRepository, - romcollections_repository: ROMCollectionRepository, roms_repository: ROMsRepository, - views_repository: ViewRepository, render_sub_views = False): + + +def _render_category_view(category_obj: Category, categories_repository: CategoryRepository, + romcollections_repository: ROMCollectionRepository, roms_repository: ROMsRepository, + views_repository: ViewRepository, render_sub_views=False): sub_categories = categories_repository.find_categories_by_parent(category_obj.get_id()) romcollections = romcollections_repository.find_romcollections_by_parent(category_obj.get_id()) @@ -309,10 +315,12 @@ def _render_category_view(category_obj: Category, categories_repository: Categor } view_items = [] for sub_category in sub_categories: - logger.debug('Processing category "{}", part of "{}"'.format(sub_category.get_name(), category_obj.get_name())) + if sub_category is None: + continue + logger.debug(f'Processing category "{sub_category.get_name()}", part of "{category_obj.get_name()}"') view_items.append(_render_category_listitem(sub_category)) if render_sub_views: - _render_category_view(sub_category, categories_repository, romcollections_repository, roms_repository, + _render_category_view(sub_category, categories_repository, romcollections_repository, roms_repository, views_repository, render_sub_views) for romcollection in romcollections: @@ -335,11 +343,10 @@ def _render_category_view(category_obj: Category, categories_repository: Categor logger.debug(f'Storing {len(view_items)} items for category "{category_obj.get_name()}" view.') view_data['items'] = view_items views_repository.store_view(category_obj.get_id(), category_obj.get_type(), view_data) - + + def _render_romcollection_view(romcollection_obj: ROMCollection, roms_repository: ROMsRepository) -> dict: - roms = roms_repository.find_roms_by_romcollection(romcollection_obj) - view_data = { 'id': romcollection_obj.get_id(), 'parent_id': romcollection_obj.get_parent_id(), @@ -356,13 +363,14 @@ def _render_romcollection_view(romcollection_obj: ROMCollection, roms_repository try: rom.apply_romcollection_asset_mapping(romcollection_obj) view_items.append(_render_rom_listitem(rom)) - except Exception as ex: - logger.error('Exception while rendering list item ROM "{}"'.format(rom.get_name()), exc_info=ex) + except Exception: + logger.exception(f'Exception while rendering list item ROM "{rom.get_name()}"') - logger.debug('Storing {} items for romcollection "{}" view.'.format(len(view_items), romcollection_obj.get_name())) + logger.debug(f'Storing {len(view_items)} items for romcollection "{romcollection_obj.get_name()}" view.') view_data['items'] = view_items return view_data + # ------------------------------------------------------------------------------------------------- # Rendering of list items per view # ------------------------------------------------------------------------------------------------- @@ -399,7 +407,8 @@ def _render_category_listitem(category_obj: Category) -> dict: 'num_romcollections': category_obj.num_romcollections() } } - + + def _render_romcollection_listitem(romcollection_obj: ROMCollection) -> dict: # --- Do not render row if romcollection finished --- if romcollection_obj.is_finished() and \ @@ -413,7 +422,7 @@ def _render_romcollection_listitem(romcollection_obj: ROMCollection) -> dict: if romcollection_obj.get_type() == constants.OBJ_COLLECTION_VIRTUAL: if romcollection_obj.get_parent_id() is None: url = globals.router.url_for_path(f'collection/virtual/{romcollection_obj.get_id()}') - else: + else: collection_value = romcollection_obj.get_custom_attribute("collection_value") url = globals.router.url_for_path(f'collection/virtual/{romcollection_obj.get_parent_id()}/items?value={collection_value}') else: @@ -447,78 +456,97 @@ def _render_romcollection_listitem(romcollection_obj: ROMCollection) -> dict: # --- Browse Offline Scraper database --- #if not settings.getSettingAsBool('display_hide_AKL_scraper'): render_vcategory_AKL_offline_scraper_row() #if not settings.getSettingAsBool('display_hide_LB_scraper'): render_vcategory_LB_offline_scraper_row() - + + def _render_rom_listitem(rom_obj: ROM) -> dict: # --- Do not render row if romcollection finished --- - if rom_obj.is_finished() and settings.getSettingAsBool('display_hide_finished'): return + if rom_obj.is_finished() and settings.getSettingAsBool('display_hide_finished'): + return ICON_OVERLAY = 5 if rom_obj.is_finished() else 4 assets = rom_obj.get_view_assets() # --- Default values for flags --- - AKL_InFav_bool_value = constants.AKL_INFAV_BOOL_VALUE_FALSE + AKL_InFav_bool_value = constants.AKL_INFAV_BOOL_VALUE_FALSE AKL_MultiDisc_bool_value = constants.AKL_MULTIDISC_BOOL_VALUE_FALSE - AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_NONE - AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_NONE - AKL_PClone_stat_value = constants.AKL_PCLONE_STAT_VALUE_NONE - - rom_status = rom_obj.get_rom_status() - if rom_status == 'OK': AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_OK - elif rom_status == 'Unlinked ROM': AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_UNLINKED_ROM - elif rom_status == 'Unlinked Launcher': AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_UNLINKED_LAUNCHER - elif rom_status == 'Broken': AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_BROKEN - else: AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_NONE + AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_NONE + AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_NONE + AKL_PClone_stat_value = constants.AKL_PCLONE_STAT_VALUE_NONE + + rom_status = rom_obj.get_rom_status() + if rom_status == 'OK': + AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_OK + elif rom_status == 'Unlinked ROM': + AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_UNLINKED_ROM + elif rom_status == 'Unlinked Launcher': + AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_UNLINKED_LAUNCHER + elif rom_status == 'Broken': + AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_BROKEN + else: + AKL_Fav_stat_value = constants.AKL_FAV_STAT_VALUE_NONE # --- NoIntro status flag --- nstat = rom_obj.get_nointro_status() - if nstat == constants.AUDIT_STATUS_HAVE: AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_HAVE - elif nstat == constants.AUDIT_STATUS_MISS: AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_MISS - elif nstat == constants.AUDIT_STATUS_UNKNOWN: AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_UNKNOWN - elif nstat == constants.AUDIT_STATUS_NONE: AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_NONE + if nstat == constants.AUDIT_STATUS_HAVE: + AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_HAVE + elif nstat == constants.AUDIT_STATUS_MISS: + AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_MISS + elif nstat == constants.AUDIT_STATUS_UNKNOWN: + AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_UNKNOWN + elif nstat == constants.AUDIT_STATUS_NONE: + AKL_NoIntro_stat_value = constants.AKL_NOINTRO_STAT_VALUE_NONE # --- Mark clone ROMs --- pclone_status = rom_obj.get_pclone_status() - if pclone_status == constants.PCLONE_STATUS_PARENT: AKL_PClone_stat_value = constants.AKL_PCLONE_STAT_VALUE_PARENT - elif pclone_status == constants.PCLONE_STATUS_CLONE: AKL_PClone_stat_value = constants.AKL_PCLONE_STAT_VALUE_CLONE + if pclone_status == constants.PCLONE_STATUS_PARENT: + AKL_PClone_stat_value = constants.AKL_PCLONE_STAT_VALUE_PARENT + elif pclone_status == constants.PCLONE_STATUS_CLONE: + AKL_PClone_stat_value = constants.AKL_PCLONE_STAT_VALUE_CLONE rom_in_fav = rom_obj.is_favourite() - if rom_in_fav: AKL_InFav_bool_value = constants.AKL_INFAV_BOOL_VALUE_TRUE + if rom_in_fav: + AKL_InFav_bool_value = constants.AKL_INFAV_BOOL_VALUE_TRUE - # --- Set common flags to all launchers--- - if rom_obj.has_multiple_disks(): AKL_MultiDisc_bool_value = constants.AKL_MULTIDISC_BOOL_VALUE_TRUE + # --- Set common flags to all launchers--- + if rom_obj.has_multiple_disks(): + AKL_MultiDisc_bool_value = constants.AKL_MULTIDISC_BOOL_VALUE_TRUE list_name = rom_obj.get_name() if list_name is None or list_name == '': list_name = rom_obj.get_rom_identifier() - return { + return { 'id': rom_obj.get_id(), 'name': list_name, 'url': globals.router.url_for_path(f'execute/rom/{rom_obj.get_id()}'), 'is_folder': False, 'type': 'video', 'info': { - 'title' : rom_obj.get_name(), 'year' : rom_obj.get_releaseyear(), - 'genre' : rom_obj.get_genre(), 'studio' : rom_obj.get_developer(), - 'rating' : rom_obj.get_rating(), 'plot' : rom_obj.get_plot(), - 'trailer' : rom_obj.get_trailer(), 'overlay' : ICON_OVERLAY + 'title': rom_obj.get_name(), + 'year': rom_obj.get_releaseyear(), + 'genre': rom_obj.get_genre(), + 'studio': rom_obj.get_developer(), + 'rating': rom_obj.get_rating(), + 'plot': rom_obj.get_plot(), + 'trailer': rom_obj.get_trailer(), + 'overlay': ICON_OVERLAY }, 'art': assets, - 'properties': { - 'platform': rom_obj.get_platform(), - 'nplayers': rom_obj.get_number_of_players(), - 'nplayers_online': rom_obj.get_number_of_players_online(), - 'esrb': rom_obj.get_esrb_rating(), - 'boxsize': rom_obj.get_box_sizing(), - 'tags': ','.join(rom_obj.get_tags()), - 'obj_type': constants.OBJ_ROM, + 'properties': { + 'platform': rom_obj.get_platform(), + 'nplayers': rom_obj.get_number_of_players(), + 'nplayers_online': rom_obj.get_number_of_players_online(), + 'esrb': rom_obj.get_esrb_rating(), + 'pegi': rom_obj.get_pegi_rating(), + 'boxsize': rom_obj.get_box_sizing(), + 'tags': ','.join(rom_obj.get_tags()), + 'obj_type': constants.OBJ_ROM, # --- ROM flags (Skins will use these flags to render icons) --- - constants.AKL_CONTENT_LABEL: constants.AKL_CONTENT_VALUE_ROM, - constants.AKL_INFAV_BOOL_LABEL: AKL_InFav_bool_value, + constants.AKL_CONTENT_LABEL: constants.AKL_CONTENT_VALUE_ROM, + constants.AKL_INFAV_BOOL_LABEL: AKL_InFav_bool_value, constants.AKL_MULTIDISC_BOOL_LABEL: AKL_MultiDisc_bool_value, - constants.AKL_FAV_STAT_LABEL: AKL_Fav_stat_value, - constants.AKL_NOINTRO_STAT_LABEL: AKL_NoIntro_stat_value, - constants.AKL_PCLONE_STAT_LABEL: AKL_PClone_stat_value + constants.AKL_FAV_STAT_LABEL: AKL_Fav_stat_value, + constants.AKL_NOINTRO_STAT_LABEL: AKL_NoIntro_stat_value, + constants.AKL_PCLONE_STAT_LABEL: AKL_PClone_stat_value } } - \ No newline at end of file diff --git a/resources/lib/domain.py b/resources/lib/domain.py index 9520c0b1..26bb8a26 100644 --- a/resources/lib/domain.py +++ b/resources/lib/domain.py @@ -76,6 +76,7 @@ def __hash__(self): def __str__(self): return self.name + # Abstract base class for all DB entities class EntityABC(object): __metaclass__ = abc.ABCMeta @@ -352,12 +353,13 @@ def configure_for_rom(self, rom:ROM): self.addon.get_addon_id(), self.get_configure_command_for_rom(rom)) + class RetroplayerLauncherAddon(ROMLauncherAddon): def get_launch_command(self, rom: ROM) -> dict: return None - def get_configure_command(self, romcollection: ROMCollection) -> dict: + def get_configure_command(self, romcollection: ROMCollection) -> dict: return None def launch(self, rom: ROM): @@ -545,10 +547,12 @@ def __init__(self, def get_object_name(self) -> str: pass @abc.abstractmethod - def get_assets_kind(self) -> int: pass + def get_assets_kind(self) -> int: + pass @abc.abstractmethod - def get_type(self) -> str: pass + def get_type(self) -> str: + pass # --- Metadata -------------------------------------------------------------------------------- def get_name(self): @@ -634,7 +638,7 @@ def get_asset(self, asset_id: str) -> Asset: return self.assets[asset_id] if asset_id in self.assets else None def get_assets(self) -> typing.List[Asset]: - return [*self.assets.values()] + return list(self.assets.values()) # # Returns a collection with the object assets, ready to be edited. @@ -685,7 +689,8 @@ def set_asset(self, asset_info: AssetInfo, path_FN: io.FileName): def clear_asset(self, asset_info: AssetInfo): asset = self.get_asset(asset_info.id) - if asset is None: self.assets[asset_info.id] = Asset.create(asset_info.id) + if asset is None: + self.assets[asset_info.id] = Asset.create(asset_info.id) asset.clear() def get_assets_root_path(self) -> io.FileName: @@ -705,7 +710,7 @@ def set_assets_root_path(self, path: io.FileName, asset_ids = [], create_default def get_asset_paths(self) -> typing.List[AssetPath]: - return self.asset_paths.values() + return list(self.asset_paths.values()) def get_asset_path(self, asset_info: AssetInfo, fallback_to_root = True) -> io.FileName: if not asset_info: return None @@ -725,13 +730,16 @@ def set_asset_path(self, asset_info: AssetInfo, path: str): self.asset_paths[asset_info.id] = asset_path @abc.abstractmethod - def get_asset_ids_list(self) -> typing.List[str]: pass + def get_asset_ids_list(self) -> typing.List[str]: + pass @abc.abstractmethod - def get_mappable_asset_ids_list(self) -> typing.List[str]: return [] + def get_mappable_asset_ids_list(self) -> typing.List[str]: + return [] @abc.abstractmethod - def get_default_icon(self) -> str: pass + def get_default_icon(self) -> str: + pass def is_mappable_asset(self, asset_info) -> bool: return asset_info.id in self.get_mappable_asset_ids_list() @@ -816,7 +824,7 @@ def set_mapped_asset_key(self, asset_info: AssetInfo, mapped_to_info: AssetInfo) self.entity_data[asset_info.default_key] = mapped_to_info.key def __str__(self): - return '{}}#{}: {}'.format(self.get_object_name(), self.get_id(), self.get_name()) + return '{}#{}: {}'.format(self.get_object_name(), self.get_id(), self.get_name()) # ------------------------------------------------------------------------------------------------- # Class representing an AKL Cateogry. @@ -1026,8 +1034,10 @@ def get_ROM_mappable_asset_list(self) -> typing.List[AssetInfo]: # the given (ROM) assetinfo for this particular MetaDataItem. # def get_mapped_ROM_asset_info(self, asset_info=None, asset_id=None) -> AssetInfo: - if asset_info is None and asset_id is None: return None - if asset_id is not None: asset_info = g_assetFactory.get_asset_info(asset_id) + if asset_info is None and asset_id is None: + return None + if asset_id is not None: + asset_info = g_assetFactory.get_asset_info(asset_id) mapped_key = self.get_mapped_ROM_asset_key(asset_info) mapped_asset_info = g_assetFactory.get_asset_info_by_key(mapped_key) @@ -1039,10 +1049,11 @@ def get_mapped_ROM_asset_info(self, asset_info=None, asset_id=None) -> AssetInfo # def get_mapped_ROM_asset_key(self, asset_info: AssetInfo) -> str: if asset_info.rom_default_key == '': - logger.error('Requested mapping for AssetInfo without default key. Type {}'.format(asset_info.id)) + logger.error(f'Requested mapping for AssetInfo without default key. Type {asset_info.id}') raise constants.AddonError('Not supported asset type used. This might be a bug!') - if asset_info.rom_default_key not in self.entity_data: return asset_info.key + if asset_info.rom_default_key not in self.entity_data: + return asset_info.key return self.entity_data[asset_info.rom_default_key] def set_mapped_ROM_asset_key(self, asset_info: AssetInfo, mapped_to_info: AssetInfo): @@ -1249,15 +1260,20 @@ def __init__(self, super(VirtualCollection, self).__init__(entity_data, assets_data) - def get_object_name(self): return 'Virtual Collection' + def get_object_name(self): + return 'Virtual Collection' - def get_assets_kind(self): return constants.KIND_ASSET_COLLECTION + def get_assets_kind(self): + return constants.KIND_ASSET_COLLECTION - def get_type(self): return constants.OBJ_COLLECTION_VIRTUAL + def get_type(self): + return constants.OBJ_COLLECTION_VIRTUAL - def get_asset_ids_list(self): return constants.COLLECTION_ASSET_ID_LIST + def get_asset_ids_list(self): + return constants.COLLECTION_ASSET_ID_LIST - def get_mappable_asset_ids_list(self): return constants.MAPPABLE_LAUNCHER_ASSET_ID_LIST + def get_mappable_asset_ids_list(self): + return constants.MAPPABLE_LAUNCHER_ASSET_ID_LIST def get_collection_value(self) -> str: return self.entity_data['collection_value'] if 'collection_value' in self.entity_data else None @@ -1298,11 +1314,13 @@ def get_rom_identifier(self) -> str: identifier = self.get_scanned_data_element('identifier') name = self.get_name() - if identifier: return identifier - if name: return name + if identifier: + return identifier + if name: + return name - return 'ROM_{}'.format(self.get_id()) - + return f'ROM_{self.get_id()}' + # inherited value from ROMCollection def get_platform(self): return self.entity_data['platform'] if 'platform' in self.entity_data else None @@ -1348,15 +1366,18 @@ def get_number_of_players_online(self): def get_esrb_rating(self): return self.entity_data['m_esrb'] + def get_pegi_rating(self): + return self.entity_data['m_pegi'] + def get_rom_status(self): return self.entity_data['rom_status'] if 'rom_status' in self.entity_data else None def is_favourite(self) -> bool: return self.entity_data['is_favourite'] if 'is_favourite' in self.entity_data else False - + def get_tags(self) -> typing.List[str]: if self.tags is not None: - return [tag for tag in self.tags.keys() if tag is not None] + return [tag for tag in list(self.tags.keys()) if tag is not None] return [] def get_tag_data(self) -> dict: @@ -1368,7 +1389,7 @@ def get_launch_count(self): 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'] + return self.entity_data['last_launch_timestamp'] if 'last_launch_timestamp' in self.entity_data else None def get_scanned_with(self) -> str: return self.entity_data['scanned_by_id'] if 'scanned_by_id' in self.entity_data else None @@ -1390,6 +1411,9 @@ def set_number_of_players_online(self, amount): def set_esrb_rating(self, esrb): self.entity_data['m_esrb'] = esrb + def set_pegi_rating(self, pegi): + self.entity_data['m_pegi'] = pegi + def set_platform(self, platform): self.entity_data['platform'] = platform @@ -1491,7 +1515,8 @@ def copy(self): data = self.copy_of_data_dic() return ROM(data) - def get_asset_ids_list(self): return constants.ROM_ASSET_ID_LIST + def get_asset_ids_list(self): + return constants.ROM_ASSET_ID_LIST def get_mappable_asset_ids_list(self): return constants.MAPPABLE_ROM_ASSET_ID_LIST @@ -1499,7 +1524,7 @@ def get_default_icon(self) -> str: return 'DefaultProgram.png' def create_dto(self) -> api.ROMObj: dto_data:dict = api.ROMObj.get_data_template() - for key in dto_data.keys(): + for key in list(dto_data.keys()): if key in self.entity_data: dto_data[key] = self.entity_data[key] dto_data['tags'] = self.get_tags() @@ -1548,6 +1573,7 @@ def update_with_nfo_file(self, nfo_file_path:io.FileName, verbose = True): item_developer = re.findall('(.*?)', nfo_str) item_nplayers = re.findall('(.*?)', nfo_str) item_esrb = re.findall('(.*?)', nfo_str) + item_pegi = re.findall('(.*?)', nfo_str) item_rating = re.findall('(.*?)', nfo_str) item_plot = re.findall('(.*?)', nfo_str) item_trailer = re.findall('(.*?)', nfo_str) @@ -1561,6 +1587,7 @@ def update_with_nfo_file(self, nfo_file_path:io.FileName, verbose = True): if len(item_plot) > 0: self.set_plot(text.unescape_XML(item_plot[0])) if len(item_nplayers) > 0: self.set_number_of_players(text.unescape_XML(item_nplayers[0])) if len(item_esrb) > 0: self.set_esrb_rating(text.unescape_XML(item_esrb[0])) + if len(item_pegi) > 0: self.set_pegi_rating(text.unescape_XML(item_pegi[0])) if len(item_trailer) > 0: self.set_trailer(text.unescape_XML(item_trailer[0])) if verbose: @@ -1583,6 +1610,7 @@ def export_to_NFO_file(self, nfo_FileName: io.FileName): nfo_content.append(text.XML_line('developer', self.get_developer())) nfo_content.append(text.XML_line('nplayers', self.get_number_of_players())) nfo_content.append(text.XML_line('esrb', self.get_esrb_rating())) + nfo_content.append(text.XML_line('pegi', self.get_pegi_rating())) nfo_content.append(text.XML_line('rating', self.get_rating())) nfo_content.append(text.XML_line('plot', self.get_plot())) nfo_content.append(text.XML_line('trailer', self.get_trailer())) @@ -1637,10 +1665,16 @@ def update_with(self, self.set_number_of_players_online(api_rom_obj.get_number_of_players_online()) if constants.META_ESRB_ID in metadata_to_update\ - and api_rom_obj.get_esrb_rating() \ - and (overwrite_existing or _is_empty(self.get_esrb_rating())): + and api_rom_obj.get_esrb_rating() \ + and (overwrite_existing or _is_empty(self.get_esrb_rating()) \ + or self.get_esrb_rating() == constants.ESRB_PENDING): self.set_esrb_rating(api_rom_obj.get_esrb_rating()) + if constants.META_PEGI_ID in metadata_to_update\ + and api_rom_obj.get_pegi_rating() \ + and (overwrite_existing or _is_empty(self.get_pegi_rating())): + self.set_pegi_rating(api_rom_obj.get_pegi_rating()) + if constants.META_RATING_ID in metadata_to_update \ and api_rom_obj.get_rating() \ and (overwrite_existing or _is_empty(self.get_rating())): @@ -1665,7 +1699,7 @@ def update_with(self, scanned_data = api_rom_obj.get_scanned_data() if scanned_name: self.set_name(scanned_name) - for scanned_entry in scanned_data.keys(): + for scanned_entry in list(scanned_data.keys()): self.set_scanned_data_element(scanned_entry, scanned_data[scanned_entry]) # if 'romcollection' in launcher_settings \ @@ -1722,7 +1756,7 @@ def get_asset_info(self, asset_ID) -> AssetInfo: # Returns the corresponding assetinfo object for the # given key (eg: 's_icon') def get_asset_info_by_key(self, asset_key): - asset_info = next((a for a in self.ASSET_INFO_ID_DICT.values() if a.key == asset_key), None) + asset_info = next((a for a in list(self.ASSET_INFO_ID_DICT.values()) if a.key == asset_key), None) if asset_info is None: logger.error('get_asset_info_by_key() Wrong asset_key = {0}'.format(asset_key)) @@ -1733,7 +1767,7 @@ def get_asset_info_by_key(self, asset_key): # Returns the corresponding assetinfo object for the # given path key (eg: 'path_icon') def get_asset_info_by_pathkey(self, path_key): - asset_info = next((a for a in self.ASSET_INFO_ID_DICT.values() if a.path_key == path_key), None) + asset_info = next((a for a in list(self.ASSET_INFO_ID_DICT.values()) if a.path_key == path_key), None) if asset_info is None: logger.error('get_asset_info_by_pathkey() Wrong path key = {0}'.format(path_key)) @@ -2177,38 +2211,39 @@ class VirtualCollectionFactory(object): @staticmethod def create(vcollection_id: str) -> VirtualCollection: - + + default_entity_data = _get_default_ROMCollection_data_model() if vcollection_id == constants.VCOLLECTION_FAVOURITES_ID: - return VirtualCollection({ + return VirtualCollection(dict(default_entity_data, **{ 'id' : vcollection_id, 'm_name' : '', 'plot': 'Browse AKL Favourite ROMs', 'finished': settings.getSettingAsBool('display_hide_favs') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Favourites_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Favourites_poster.png').getPath()}), ]) if vcollection_id == constants.VCOLLECTION_RECENT_ID: - return VirtualCollection({ + return VirtualCollection(dict(default_entity_data, **{ 'id' : vcollection_id, 'm_name' : '[Recently played ROMs]', 'plot': 'Browse the ROMs you played recently', 'finished': settings.getSettingAsBool('display_hide_recent') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Recently_played_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Recently_played_poster.png').getPath()}), ]) if vcollection_id == constants.VCOLLECTION_MOST_PLAYED_ID: - return VirtualCollection({ + return VirtualCollection(dict(default_entity_data, **{ 'id' : vcollection_id, 'm_name' : '[Most played ROMs]', 'plot': 'Browse the ROMs you play most', 'finished': settings.getSettingAsBool('display_hide_mostplayed') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Most_played_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Most_played_poster.png').getPath()}), @@ -2219,14 +2254,15 @@ def create(vcollection_id: str) -> VirtualCollection: @staticmethod def create_by_category(vcategory_id:str, collection_value:str) -> VirtualCollection: - return VirtualCollection({ + default_entity_data = _get_default_ROMCollection_data_model() + return VirtualCollection(dict(default_entity_data, **{ 'id' : f'{vcategory_id}_{collection_value}', 'parent_id': vcategory_id, 'm_name' : collection_value, 'plot': f"Browse ROMs filtered on '{collection_value}'", 'collection_value': collection_value, 'finished': settings.getSettingAsBool('display_hide_vcategories') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}) ]) @@ -2235,97 +2271,110 @@ class VirtualCategoryFactory(object): @staticmethod def create(vcategory_id: str) -> VirtualCategory: + default_entity_data = _get_default_category_data_model() if vcategory_id == constants.VCATEGORY_ROOT_ID: - return VirtualCategory({ + return VirtualCategory(dict(default_entity_data, **{ 'id' : vcategory_id, 'm_name' : 'Browse by...', 'plot': 'Browse the ROMs by specifics', 'finished': settings.getSettingAsBool('display_hide_vcategories') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_poster.png').getPath()}), ]) if vcategory_id == constants.VCATEGORY_TITLE_ID: - return VirtualCategory({ + return VirtualCategory(dict(default_entity_data, **{ 'id' : vcategory_id, 'm_name' : 'Browse by Title', 'plot': 'Browse the ROMs by title', 'finished': settings.getSettingAsBool('display_hide_vcategories') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_Title_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_Title_poster.png').getPath()}), ]) if vcategory_id == constants.VCATEGORY_YEARS_ID: - return VirtualCategory({ + return VirtualCategory(dict(default_entity_data, **{ 'id' : vcategory_id, 'm_name' : 'Browse by Year', 'plot': 'Browse the ROMs by year', 'finished': settings.getSettingAsBool('display_hide_vcategories') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_Year_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_Year_poster.png').getPath()}), ]) if vcategory_id == constants.VCATEGORY_GENRE_ID: - return VirtualCategory({ + return VirtualCategory(dict(default_entity_data, **{ 'id' : vcategory_id, 'm_name' : 'Browse by Genre', 'plot': 'Browse the ROMs by genre', 'finished': settings.getSettingAsBool('display_hide_vcategories') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_Genre_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_Genre_poster.png').getPath()}), ]) if vcategory_id == constants.VCATEGORY_DEVELOPER_ID: - return VirtualCategory({ + return VirtualCategory(dict(default_entity_data, **{ 'id' : vcategory_id, 'm_name' : 'Browse by Developer', 'plot': 'Browse the ROMs by developer', 'finished': settings.getSettingAsBool('display_hide_vcategories') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_Developer_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_Developer_poster.png').getPath()}), ]) if vcategory_id == constants.VCATEGORY_NPLAYERS_ID: - return VirtualCategory({ + return VirtualCategory(dict(default_entity_data, **{ 'id' : vcategory_id, 'm_name' : 'Browse by Number of Players', 'plot': 'Browse the ROMs by number of players', 'finished': settings.getSettingAsBool('display_hide_vcategories') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_NPlayers_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_NPlayers_poster.png').getPath()}), ]) if vcategory_id == constants.VCATEGORY_ESRB_ID: - return VirtualCategory({ + return VirtualCategory(dict(default_entity_data, **{ 'id' : vcategory_id, 'm_name' : 'Browse by ESRB Rating', 'plot': 'Browse the ROMs by ESRB rating', 'finished': settings.getSettingAsBool('display_hide_vcategories') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_ESRB_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_ESRB_poster.png').getPath()}), ]) - - if vcategory_id == constants.VCATEGORY_RATING_ID: + + if vcategory_id == constants.VCATEGORY_PEGI_ID: return VirtualCategory({ + 'id' : vcategory_id, + 'm_name' : 'Browse by PEGI Rating', + 'plot': 'Browse the ROMs by PEGI rating', + 'finished': settings.getSettingAsBool('display_hide_vcategories') + }, [ + Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), + Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_PEGI_icon.png').getPath()}), + Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_PEGI_poster.png').getPath()}), + ]) + + if vcategory_id == constants.VCATEGORY_RATING_ID: + return VirtualCategory(dict(default_entity_data, **{ 'id' : vcategory_id, 'm_name' : 'Browse by Rating', 'plot': 'Browse the ROMs by rating', 'finished': settings.getSettingAsBool('display_hide_vcategories') - }, [ + }), [ Asset({'id' : '', 'asset_type' : constants.ASSET_FANART_ID, 'filepath' : globals.g_PATHS.FANART_FILE_PATH.getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_ICON_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_User_Rating_icon.png').getPath()}), Asset({'id' : '', 'asset_type' : constants.ASSET_POSTER_ID, 'filepath' : globals.g_PATHS.ADDON_CODE_DIR.pjoin('media/theme/Browse_by_User_Rating_poster.png').getPath()}), @@ -2460,6 +2509,7 @@ def _get_default_ROM_data_model(): 'm_nplayers' : '', 'm_nplayers_online' : '', 'm_esrb' : constants.ESRB_PENDING, + 'm_pegi' : constants.DEFAULT_META_PEGI, 'm_rating' : '', 'm_plot' : '', 'platform': '', diff --git a/resources/lib/queries.py b/resources/lib/queries.py index 9e7bcb03..bd1f9edf 100644 --- a/resources/lib/queries.py +++ b/resources/lib/queries.py @@ -52,8 +52,9 @@ SELECT_VCOLLECTION_TITLES = "SELECT DISTINCT(SUBSTR(UPPER(m_name), 1,1)) AS option_value FROM vw_roms" SELECT_VCOLLECTION_GENRES = "SELECT DISTINCT(m_genre) AS option_value FROM vw_roms" SELECT_VCOLLECTION_DEVELOPER = "SELECT DISTINCT(m_developer) AS option_value FROM vw_roms" -SELECT_VCOLLECTION_ESRB = "SELECT DISTINCT(m_esrb) AS option_value FROM vw_roms" -SELECT_VCOLLECTION_YEAR = "SELECT DISTINCT(m_year) AS option_value FROM vw_roms" +SELECT_VCOLLECTION_ESRB = "SELECT DISTINCT(m_esrb) AS option_value FROM vw_roms" +SELECT_VCOLLECTION_PEGI = "SELECT DISTINCT(m_pegi) AS option_value FROM vw_roms" +SELECT_VCOLLECTION_YEAR = "SELECT DISTINCT(m_year) AS option_value FROM vw_roms" SELECT_VCOLLECTION_NPLAYERS = "SELECT DISTINCT(m_nplayers) AS option_value FROM vw_roms" SELECT_VCOLLECTION_RATING = "SELECT DISTINCT(m_rating) AS option_value FROM vw_roms" @@ -72,7 +73,7 @@ WHERE id =? """ UPDATE_ROMCOLLECTION_PARENT = "UPDATE romcollections SET parent_id = ? WHERE id =?" -DELETE_ROMCOLLECTION = "DELETE FROM romcollection WHERE id = ?" +DELETE_ROMCOLLECTION = "DELETE FROM romcollections WHERE id = ?" SELECT_ROMCOLLECTION_ASSETS_BY_SET = "SELECT * FROM vw_romcollection_assets WHERE romcollection_id = ?" SELECT_ROOT_ROMCOLLECTION_ASSETS = "SELECT * FROM vw_romcollection_assets WHERE parent_id IS NULL" @@ -135,9 +136,9 @@ INSERT_ROM = """ INSERT INTO roms ( - id, metadata_id, name, num_of_players, num_of_players_online, esrb_rating, + id, metadata_id, name, num_of_players, num_of_players_online, esrb_rating, pegi_rating, platform, box_size, nointro_status, cloneof, rom_status, scanned_by_id) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?) """ SELECT_MY_FAVOURITES = "SELECT * FROM vw_roms WHERE is_favourite = 1" @@ -153,13 +154,14 @@ WHERE r.launch_count > 0 ORDER BY launch_count DESC LIMIT 100 """ -SELECT_BY_TITLE = "SELECT * FROM vw_roms WHERE m_name LIKE ? || '%'" -SELECT_BY_GENRE = "SELECT * FROM vw_roms WHERE m_genre = ?" -SELECT_BY_DEVELOPER = "SELECT * FROM vw_roms WHERE m_developer = ?" -SELECT_BY_YEAR = "SELECT * FROM vw_roms WHERE m_year = ?" -SELECT_BY_NPLAYERS = "SELECT * FROM vw_roms WHERE m_nplayers = ?" -SELECT_BY_ESRB = "SELECT * FROM vw_roms WHERE m_esrb = ?" -SELECT_BY_RATING = "SELECT * FROM vw_roms WHERE m_rating = ?" +SELECT_BY_TITLE = "SELECT * FROM vw_roms WHERE m_name LIKE ? || '%'" +SELECT_BY_GENRE = "SELECT * FROM vw_roms WHERE m_genre = ?" +SELECT_BY_DEVELOPER = "SELECT * FROM vw_roms WHERE m_developer = ?" +SELECT_BY_YEAR = "SELECT * FROM vw_roms WHERE m_year = ?" +SELECT_BY_NPLAYERS = "SELECT * FROM vw_roms WHERE m_nplayers = ?" +SELECT_BY_ESRB = "SELECT * FROM vw_roms WHERE m_esrb = ?" +SELECT_BY_PEGI = "SELECT * FROM vw_roms WHERE m_pegi = ?" +SELECT_BY_RATING = "SELECT * FROM vw_roms WHERE m_rating = ?" SELECT_BY_TITLE_ASSETS = "SELECT ra.* FROM vw_rom_assets AS ra INNER JOIN vw_roms AS r ON r.id = ra.rom_id WHERE UPPER(r.m_name) LIKE ? || '%'" SELECT_BY_GENRE_ASSETS = "SELECT ra.* FROM vw_rom_assets AS ra INNER JOIN vw_roms AS r ON r.id = ra.rom_id WHERE r.m_genre = ?" @@ -167,6 +169,7 @@ SELECT_BY_YEAR_ASSETS = "SELECT ra.* FROM vw_rom_assets AS ra INNER JOIN vw_roms AS r ON r.id = ra.rom_id WHERE r.m_year = ?" SELECT_BY_NPLAYERS_ASSETS = "SELECT ra.* FROM vw_rom_assets AS ra INNER JOIN vw_roms AS r ON r.id = ra.rom_id WHERE r.m_nplayers = ?" SELECT_BY_ESRB_ASSETS = "SELECT ra.* FROM vw_rom_assets AS ra INNER JOIN vw_roms AS r ON r.id = ra.rom_id WHERE r.m_esrb = ?" +SELECT_BY_PEGI_ASSETS = "SELECT ra.* FROM vw_rom_assets AS ra INNER JOIN vw_roms AS r ON r.id = ra.rom_id WHERE r.m_pegi = ?" SELECT_BY_RATING_ASSETS = "SELECT ra.* FROM vw_rom_assets AS ra INNER JOIN vw_roms AS r ON r.id = ra.rom_id WHERE r.m_rating = ?" INSERT_ROM_ASSET = "INSERT INTO rom_assets (rom_id, asset_id) VALUES (?, ?)" @@ -175,7 +178,7 @@ UPDATE_ROM = """ UPDATE roms - SET name=?, num_of_players=?, num_of_players_online=?, esrb_rating=?, platform=?, box_size=?, + SET name=?, num_of_players=?, num_of_players_online=?, esrb_rating=?, pegi_rating=?, platform=?, box_size=?, nointro_status=?, cloneof=?, rom_status=?, launch_count=?, last_launch_timestamp=?, is_favourite=?, scanned_by_id=? WHERE id =? """ diff --git a/resources/lib/repositories.py b/resources/lib/repositories.py index c9a4ea88..1bf82f57 100644 --- a/resources/lib/repositories.py +++ b/resources/lib/repositories.py @@ -5,7 +5,6 @@ import sqlite3 from sqlite3.dbapi2 import Cursor -from akl.settings import * from akl.utils import text, io from akl import constants @@ -15,6 +14,7 @@ from resources.lib.domain import VirtualCategoryFactory, VirtualCollectionFactory, ROMLauncherAddonFactory, g_assetFactory from resources.lib.domain import ROMCollectionScanner, ROMLauncherAddon, AelAddon + # ################################################################################################# # ################################################################################################# # Data storage objects. @@ -52,7 +52,7 @@ def find_root_items(self): return item_data - def find_items(self, view_id, is_virtual = False) -> typing.Any: + def find_items(self, view_id, is_virtual=False) -> typing.Any: repository_file = self.paths.VIEWS_DIR.pjoin('view_{}.json'.format(view_id)) if is_virtual: repository_file = self.paths.GENERATED_VIEWS_DIR.pjoin('view_{}.json'.format(view_id)) @@ -281,6 +281,8 @@ def _get_scanned_data_from_romdata(self, rom_data: dict) -> dict: def _alter_dictionary_for_compatibility(self, rom_data: dict) -> dict: rom_data['rom_status'] = rom_data['fav_status'] if 'fav_status' in rom_data else None return rom_data + + # # UnitOfWork to be used with sqlite repositories. # Can be used to create database scopes/sessions (unit of work pattern). @@ -418,6 +420,7 @@ def dict_factory(cursor, row): d[col[0]] = row[idx] return d + # # CategoryRepository -> Category from SQLite DB # @@ -428,7 +431,8 @@ def __init__(self, uow: UnitOfWork): self.logger = logging.getLogger(__name__) def find_category(self, category_id: str) -> Category: - if category_id == constants.VCATEGORY_ADDONROOT_ID: return Category({'m_name': 'Root'}) + if category_id == constants.VCATEGORY_ADDONROOT_ID: + return Category({'m_name': 'Root'}) self._uow.execute(qry.SELECT_CATEGORY, category_id) category_data = self._uow.single_result() @@ -438,7 +442,7 @@ def find_category(self, category_id: str) -> Category: assets = [] for asset_data in assets_result_set: - assets.append(Asset(asset_data)) + assets.append(Asset(asset_data)) return Category(category_data, assets) @@ -452,17 +456,17 @@ def find_root_categories(self) -> typing.Iterator[Category]: 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)) + assets.append(Asset(asset_data)) yield Category(category_data, assets) - def find_categories_by_parent(self, category_id) -> typing.Iterator[Category]: - + def find_categories_by_parent(self, category_id) -> typing.Iterator[Category]: if category_id == constants.VCATEGORY_ROOT_ID: for vcategory_id in constants.VCATEGORIES: yield VirtualCategoryFactory.create(vcategory_id) - if category_id in constants.VCATEGORIES: return [] + if category_id in constants.VCATEGORIES: + return [] self._uow.execute(qry.SELECT_CATEGORIES_BY_PARENT, category_id) result_set = self._uow.result_set() @@ -915,6 +919,7 @@ def _get_collections_query_by_vcategory_id(self, vcategory_id:str) -> str: if vcategory_id == constants.VCATEGORY_GENRE_ID: return qry.SELECT_VCOLLECTION_GENRES if vcategory_id == constants.VCATEGORY_DEVELOPER_ID:return qry.SELECT_VCOLLECTION_DEVELOPER if vcategory_id == constants.VCATEGORY_ESRB_ID: return qry.SELECT_VCOLLECTION_ESRB + if vcategory_id == constants.VCATEGORY_PEGI_ID: return qry.SELECT_VCOLLECTION_PEGI if vcategory_id == constants.VCATEGORY_YEARS_ID: return qry.SELECT_VCOLLECTION_YEAR if vcategory_id == constants.VCATEGORY_NPLAYERS_ID: return qry.SELECT_VCOLLECTION_NPLAYERS if vcategory_id == constants.VCATEGORY_RATING_ID: return qry.SELECT_VCOLLECTION_RATING @@ -1084,7 +1089,7 @@ def find_rom(self, rom_id:str) -> ROM: tags = {} for tag_data in tags_data: tags[tag_data['tag']] = tag_data['id'] - + return ROM(rom_data, tags, assets, asset_paths, scanned_data, launchers) def find_all_tags(self) -> dict: @@ -1096,7 +1101,7 @@ def find_all_tags(self) -> dict: return tags def insert_rom(self, rom_obj: ROM): - self.logger.info(f"ROMsRepository.insert_rom(): Inserting new ROM '{rom_obj.get_name()}'") + self.logger.info(f"Inserting new ROM '{rom_obj.get_rom_identifier()}'") metadata_id = text.misc_generate_random_SID() assets_path = rom_obj.get_assets_root_path() @@ -1116,7 +1121,8 @@ def insert_rom(self, rom_obj: ROM): rom_obj.get_name(), rom_obj.get_number_of_players(), rom_obj.get_number_of_players_online(), - rom_obj.get_esrb_rating(), + rom_obj.get_esrb_rating(), + rom_obj.get_pegi_rating(), rom_obj.get_platform(), rom_obj.get_box_sizing(), rom_obj.get_nointro_status(), @@ -1139,7 +1145,7 @@ def insert_rom(self, rom_obj: ROM): self._update_launchers(rom_obj.get_id(), rom_obj.get_launchers()) def update_rom(self, rom_obj: ROM): - self.logger.info("ROMsRepository.update_rom(): Updating ROM '{}'".format(rom_obj.get_name())) + self.logger.info(f"Updating ROM '{rom_obj.get_rom_identifier()}'") assets_path = rom_obj.get_assets_root_path() self._uow.execute(qry.UPDATE_METADATA, @@ -1157,6 +1163,7 @@ def update_rom(self, rom_obj: ROM): rom_obj.get_number_of_players(), rom_obj.get_number_of_players_online(), rom_obj.get_esrb_rating(), + rom_obj.get_pegi_rating(), rom_obj.get_platform(), rom_obj.get_box_sizing(), rom_obj.get_nointro_status(), @@ -1263,17 +1270,29 @@ def _get_queries_by_vcollection_type(self, vcollection:VirtualCollection) -> typ vcategory_id = vcollection.get_parent_id() if vcategory_id is not None: - if vcategory_id == constants.VCATEGORY_TITLE_ID: return qry.SELECT_BY_TITLE, qry.SELECT_BY_TITLE_ASSETS - if vcategory_id == constants.VCATEGORY_GENRE_ID: return qry.SELECT_BY_GENRE, qry.SELECT_BY_GENRE_ASSETS - if vcategory_id == constants.VCATEGORY_DEVELOPER_ID: return qry.SELECT_BY_DEVELOPER, qry.SELECT_BY_DEVELOPER_ASSETS - if vcategory_id == constants.VCATEGORY_ESRB_ID: return qry.SELECT_BY_ESRB, qry.SELECT_BY_ESRB_ASSETS - if vcategory_id == constants.VCATEGORY_YEARS_ID: return qry.SELECT_BY_YEAR, qry.SELECT_BY_YEAR_ASSETS - if vcategory_id == constants.VCATEGORY_NPLAYERS_ID: return qry.SELECT_BY_NPLAYERS, qry.SELECT_BY_NPLAYERS_ASSETS - if vcategory_id == constants.VCATEGORY_RATING_ID: return qry.SELECT_BY_RATING, qry.SELECT_BY_RATING_ASSETS + if vcategory_id == constants.VCATEGORY_TITLE_ID: + return qry.SELECT_BY_TITLE, qry.SELECT_BY_TITLE_ASSETS + if vcategory_id == constants.VCATEGORY_GENRE_ID: + return qry.SELECT_BY_GENRE, qry.SELECT_BY_GENRE_ASSETS + if vcategory_id == constants.VCATEGORY_DEVELOPER_ID: + return qry.SELECT_BY_DEVELOPER, qry.SELECT_BY_DEVELOPER_ASSETS + if vcategory_id == constants.VCATEGORY_ESRB_ID: + return qry.SELECT_BY_ESRB, qry.SELECT_BY_ESRB_ASSETS + if vcategory_id == constants.VCATEGORY_PEGI_ID: + return qry.SELECT_BY_PEGI, qry.SELECT_BY_PEGI_ASSETS + if vcategory_id == constants.VCATEGORY_YEARS_ID: + return qry.SELECT_BY_YEAR, qry.SELECT_BY_YEAR_ASSETS + if vcategory_id == constants.VCATEGORY_NPLAYERS_ID: + return qry.SELECT_BY_NPLAYERS, qry.SELECT_BY_NPLAYERS_ASSETS + if vcategory_id == constants.VCATEGORY_RATING_ID: + return qry.SELECT_BY_RATING, qry.SELECT_BY_RATING_ASSETS else: - if vcollection_id == constants.VCOLLECTION_FAVOURITES_ID: return qry.SELECT_MY_FAVOURITES, qry.SELECT_FAVOURITES_ROM_ASSETS - if vcollection_id == constants.VCOLLECTION_RECENT_ID: return qry.SELECT_RECENTLY_PLAYED_ROMS,qry.SELECT_RECENTLY_PLAYED_ROM_ASSETS - if vcollection_id == constants.VCOLLECTION_MOST_PLAYED_ID: return qry.SELECT_MOST_PLAYED_ROMS, qry.SELECT_MOST_PLAYED_ROM_ASSETS + if vcollection_id == constants.VCOLLECTION_FAVOURITES_ID: + return qry.SELECT_MY_FAVOURITES, qry.SELECT_FAVOURITES_ROM_ASSETS + if vcollection_id == constants.VCOLLECTION_RECENT_ID: + return qry.SELECT_RECENTLY_PLAYED_ROMS,qry.SELECT_RECENTLY_PLAYED_ROM_ASSETS + if vcollection_id == constants.VCOLLECTION_MOST_PLAYED_ID: + return qry.SELECT_MOST_PLAYED_ROMS, qry.SELECT_MOST_PLAYED_ROM_ASSETS return None, None diff --git a/resources/lib/services.py b/resources/lib/services.py index 22fc93c3..f2cd279b 100644 --- a/resources/lib/services.py +++ b/resources/lib/services.py @@ -19,14 +19,15 @@ logger = logging.getLogger(__name__) + class AppService(object): def __init__(self): - + threading.Thread.name = 'akl' globals.g_bootstrap_instances() - + self.queue = [] self.monitor = AppMonitor(addon_id=globals.addon_id, action=self.queue.append) @@ -35,9 +36,9 @@ def _execute_service_actions(self, action_data): args = action_data['data'] AppMediator.sync_cmd(cmd, args) - def run(self): + def run(self): kodi.set_windowprop('akl_server_state', 'STARTING') - + # --- Some debug stuff for development --- logger.info('------------ Called Advanced Kodi Launcher : Service ------------') logger.debug(f'sys.platform "{sys.platform}"') diff --git a/resources/lib/views.py b/resources/lib/views.py index cc73b59a..6ec37d81 100644 --- a/resources/lib/views.py +++ b/resources/lib/views.py @@ -318,6 +318,7 @@ def vw_create_filter(filter_on_type:str, filter_on_value:str) -> ListFilter: if filter_on_type == constants.META_YEAR_ID: return OnReleaseYearFilter(filter_on_value) if filter_on_type == constants.META_RATING_ID: return OnRatingFilter(filter_on_value) if filter_on_type == constants.META_ESRB_ID: return OnESRBFilter(filter_on_value) + if filter_on_type == constants.META_PEGI_ID: return OnPEGIFilter(filter_on_value) if filter_on_type == constants.META_NPLAYERS_ID: return OnNumberOfPlayersFilter(filter_on_value) if filter_on_type == 'platform': return OnPlatformFilter(filter_on_value) @@ -357,6 +358,11 @@ def is_valid(self, subject: dict) -> bool: class OnESRBFilter(ListFilter): def is_valid(self, subject: dict) -> bool: return 'properties' in subject and 'esrb' in subject['properties'] and subject['properties']['esrb'] == self.filter_on_value + +class OnPEGIFilter(ListFilter): + def is_valid(self, subject: dict) -> bool: + return 'properties' in subject and 'pegi' in subject['properties'] and subject['properties']['pegi'] == self.filter_on_value + class OnNumberOfPlayersFilter(ListFilter): def is_valid(self, subject: dict) -> bool: return 'properties' in subject and 'nplayers' in subject['properties'] and subject['properties']['nplayers'] == self.filter_on_value diff --git a/resources/migrations/1.2.0.sql b/resources/migrations/1.2.0.sql new file mode 100644 index 00000000..95eb9ef3 --- /dev/null +++ b/resources/migrations/1.2.0.sql @@ -0,0 +1,38 @@ +DROP VIEW vw_roms; +ALTER TABLE roms + ADD pegi_rating TEXT; + +CREATE VIEW IF NOT EXISTS vw_roms AS SELECT + r.id AS id, + r.metadata_id, + r.name AS m_name, + r.num_of_players AS m_nplayers, + r.num_of_players_online AS m_nplayers_online, + r.esrb_rating AS m_esrb, + r.pegi_rating AS m_pegi, + r.nointro_status AS nointro_status, + r.pclone_status AS pclone_status, + r.cloneof AS cloneof, + r.platform AS platform, + r.box_size AS box_size, + r.scanned_by_id AS scanned_by_id, + m.year AS m_year, + m.genre AS m_genre, + m.developer AS m_developer, + m.rating AS m_rating, + m.plot AS m_plot, + m.finished, + r.rom_status, + r.is_favourite, + r.launch_count, + r.last_launch_timestamp, + m.assets_path AS assets_path, + ( + SELECT group_concat(t.tag) AS rom_tags + FROM tags AS t + INNER JOIN metatags AS mt ON t.id = mt.tag_id + WHERE mt.metadata_id = r.metadata_id + GROUP BY mt.metadata_id + ) AS rom_tags +FROM roms AS r + INNER JOIN metadata AS m ON r.metadata_id = m.id; \ No newline at end of file diff --git a/resources/schema.sql b/resources/schema.sql index 2ea7a310..8cc0d097 100644 --- a/resources/schema.sql +++ b/resources/schema.sql @@ -113,6 +113,7 @@ CREATE TABLE IF NOT EXISTS roms( num_of_players INTEGER DEFAULT 1 NOT NULL, num_of_players_online INTEGER DEFAULT 0 NOT NULL, esrb_rating TEXT, + pegi_rating TEXT, nointro_status TEXT, pclone_status TEXT, cloneof TEXT, @@ -276,6 +277,7 @@ CREATE VIEW IF NOT EXISTS vw_roms AS SELECT r.num_of_players AS m_nplayers, r.num_of_players_online AS m_nplayers_online, r.esrb_rating AS m_esrb, + r.pegi_rating AS m_pegi, r.nointro_status AS nointro_status, r.pclone_status AS pclone_status, r.cloneof AS cloneof, diff --git a/service.py b/service.py index ce74025c..8d5096c2 100644 --- a/service.py +++ b/service.py @@ -9,13 +9,13 @@ kodilogging.config() logger = logging.getLogger(__name__) -if __name__ == '__main__': +if __name__ == '__main__': logger.debug("Loading '%s' version '%s'" % (addon_id, addon_version)) - + try: AppService().run() except Exception as ex: logger.fatal('Exception in plugin', exc_info=ex) kodi.notify_error("General failure") - logger.debug("'%s' shutting down." % addon_id) \ No newline at end of file + logger.debug("'%s' shutting down." % addon_id)