from typing import List from projects.services.project_history_service import ProjectHistoryService from shared.schemas import ArtistSchema, ArtistImageSchema from db import db from utils.list_utils import exists from models.artists import Artist from models.projects import ProjectEntityType, ProjectEntityAddType, ProjectTargetItem from projects.repositories.projects_repository import ProjectsRepository from projects.services.projects_service import artists_diff from services.artists_repository import ArtistsRepository from workers.base_worker import BaseWorker from utils.snowflake.models import GRASProjectModel, GRASArtist from config import ARTIST_IMAGE_SERVICE_URL class GRASProjectWorker(BaseWorker): artists_repository: ArtistsRepository = ArtistsRepository() projects_repository: ProjectsRepository = ProjectsRepository() history_service: ProjectHistoryService = ProjectHistoryService() def execute(self, projects: List[GRASProjectModel]): for project in projects: self.process(project) db.session.close() def process(self, project: GRASProjectModel): project_models = self.projects_repository.get_projects_by_GRAS_id(project.id) if not project_models: return for decibel_project in project_models: if decibel_project.is_deleted: return primary_artists_schemas = [self.__artist_schema_from(artist) for artist in project.primary_artists] featured_artists_schemas = [self.__artist_schema_from(artist) for artist in project.featured_artists] primary = self.artists_repository.get_or_create_artists(primary_artists_schemas) featured = self.artists_repository.get_or_create_artists(featured_artists_schemas) self.__update_project_artists(decibel_project, primary, featured) def __update_project_artists(self, decibel_project, primary, featured): if decibel_project.target_items[0].is_playlist(): return if len(primary) == 0: return target_items = decibel_project.target_items old_state = self.history_service.get_project_state(decibel_project) old_primary = list(map(lambda x: x.entity, filter(self.__primary_filter, target_items))) prs_target_items = list(filter(self.__prs_filter, target_items)) old_featured = list(map(lambda x: x.entity, filter(self.__featured_filter, target_items))) added_primary_artists, removed_primary_artists = artists_diff(old_primary, primary) added_featured_artists, removed_featured_artists = artists_diff(old_featured, featured) # Filter resulting items if they are in the new list or added manually by user target_items = list(filter(lambda x: self.__items_filter(x, primary + featured), target_items)) for item in target_items: if item.is_locked(): added_primary_artists = list(filter(lambda x: x.id != item.entity.id, added_primary_artists)) added_featured_artists = list(filter(lambda x: x.id != item.entity.id, added_featured_artists)) continue # Exclude artist from new primary if already added but update type if exists(added_primary_artists, lambda x: x.id == item.entity.id): item.entity_type = ProjectEntityType.PRIMARY_ARTIST.value added_primary_artists = list(filter(lambda x: x.id != item.entity.id, added_primary_artists)) # Exclude artist from new featured if already added but update type if exists(added_featured_artists, lambda x: x.id == item.entity.id): item.entity_type = ProjectEntityType.FEATURED_ARTIST.value added_featured_artists = list(filter(lambda x: x.id != item.entity.id, added_featured_artists)) target_items.extend(self.__project_target_items(added_primary_artists, ProjectEntityType.PRIMARY_ARTIST)) target_items.extend(self.__project_target_items(added_featured_artists, ProjectEntityType.FEATURED_ARTIST)) # Slice artists count to match limits primary_artists = list(filter(lambda x: x.is_primary_artist(), target_items)) sorted_primary_artists = sorted(primary_artists, key=lambda x: x.is_added_manually(), reverse=True) featured_artists = filter(lambda x: x.is_featured_artist(), target_items) sorted_featured_artists = sorted(featured_artists, key=lambda x: x.is_added_manually(), reverse=True) decibel_project.target_items = (prs_target_items + sorted_primary_artists)[:3] + sorted_featured_artists[:20] self.projects_repository.add_or_update_project(decibel_project) self.projects_repository.refresh_project(decibel_project) self.history_service.log_project_changes(decibel_project, old_state, None) def __items_filter(self, target_item: ProjectTargetItem, new_items: List[ProjectTargetItem]): is_manually_added = target_item.is_added_manually() exists_in_new_list = exists(new_items, lambda x: x.id == target_item.entity.id) return is_manually_added or exists_in_new_list def __primary_filter(self, item: ProjectTargetItem): return item.is_primary_artist() and not item.is_added_manually() def __prs_filter(self, item: ProjectTargetItem): return item.is_primary_artist() and item.is_locked() def __featured_filter(self, item: ProjectTargetItem): return item.is_featured_artist() and not item.is_added_manually() def __project_target_items(self, artists: List[Artist], type: ProjectEntityType): return [ProjectTargetItem(artist, type, ProjectEntityAddType.GRAS) for artist in artists] def __artist_schema_from(self, artist: GRASArtist): gras_id = f"GRAS_{artist.id}" image = ArtistImageSchema(ARTIST_IMAGE_SERVICE_URL.format(id=artist.id)) return ArtistSchema(id=gras_id, name=artist.name, isUnknown=False, image=image)