def _update_manifest(): logger.debug("Updating manifest.db") manifest_response = cgss_query.get_manifests() with storage.get_writer(MANIFEST_PATH, 'wb') as fwb: fwb.write(decompress(manifest_response.content)) logger.info("manifest.db updated")
def decorate(*args, **kwargs): res = f(*args, **kwargs) if not os.path.exists(TEMP_PATH): logger.info("Failed to run CGSS API") else: os.remove(TEMP_PATH) return res
def update_potential(chara_id, pots): assert len(pots) == 5 db.cachedb.execute( """ INSERT OR REPLACE INTO potential_cache (chara_id, vo, vi, da, li, sk) VALUES (?,?,?,?,?,?) """, [int(chara_id)] + list(map(int, pots))) copy_card_data_from_master(update_all=False, chara_id=chara_id) logger.info("Updated character ID {} to pots {}".format(chara_id, pots))
def main(): logger.info("Starting virtual Chihiro...") sys.excepthook = excepthook initializer.setup(True) from gui.main import setup_gui app, main = setup_gui(sys.argv) main.show() app.exec_()
def set_unit(self, cards, row=None): if row is None: row = self.widget.rowCount() - 1 for idx, card in enumerate(cards): if card is None: continue self.widget.cellWidget(row, 0).set_card(idx=idx, card=card) logger.info("Unit insert: {} - {} row {}".format( self.widget.cellWidget(row, 0).get_short_uuid(), " ".join(map(str, cards)), row))
def setup_ui(self): logger.info("Initializing UI") self.main.resize(1850, 1000) self.setup_base() self.setup_calculator_song_layout() self.setup_card_unit_layout() self.setup_tip_view() self.main.setCentralWidget(self.central_widget) self.retranslate_ui(self.main) QMetaObject.connectSlotsByName(self.main)
def setup_calculator_song_layout(self): logger.info("Setting up calculator and song layouts") self.calculator_song_layout = QHBoxLayout() self.calculator = QTabWidget(self.central_widget) self.calculator_view = MainView() self.calculator_model = MainModel(self.calculator_view) self.calculator_view.set_model(self.calculator_model) self.calculator_view.setup() self.potential_view = PotentialView() self.potential_model = PotentialModel(self.potential_view) self.potential_view.set_model(self.potential_model) self.potential_model.initialize_data() self.calculator.addTab(self.calculator_view.widget, "Simulator") self.calculator.addTab(self.potential_view.widget, "Potentials") self.calculator_song_layout.addWidget(self.calculator) self.song_layout = QVBoxLayout() self.import_layout = QHBoxLayout() self.import_text = QLineEdit(self.main) self.import_text.setPlaceholderText( "Input user ID (9 digits, e.g. 123456789)") self.import_text.setValidator(QIntValidator( 0, 999999999, None)) # Only number allowed self.import_button = QPushButton("Import from ID", self.main) self.import_button.pressed.connect( lambda: self.import_from_id(self.import_text.text())) self.import_layout.addWidget(self.import_text) self.import_layout.addWidget(self.import_button) self.song_layout.addLayout(self.import_layout) self.song_view = SongView(self.central_widget) self.song_model = SongModel(self.song_view) self.song_model.initialize_data() self.song_view.set_model(self.song_model) self.song_layout.addWidget(self.song_view.widget) self.songsearch_view = SongQuickSearchView(self.central_widget, self.song_model) self.songsearch_model = SongQuickSearchModel(self.songsearch_view, self.song_view) self.songsearch_view.set_model(self.songsearch_model) hl = QHBoxLayout() hl.addWidget(self.songsearch_view.widget) chart_viewer_button = QPushButton("Popup Chart Viewer") hl.addWidget(chart_viewer_button) chart_viewer_button.pressed.connect(lambda: eventbus.eventbus.post( PopupChartViewerEvent(look_for_chart=True))) self.song_layout.addLayout(hl) self.calculator_song_layout.addLayout(self.song_layout) self.calculator_song_layout.setStretch(0, 3) self.calculator_song_layout.setStretch(1, 2) self.main_layout.addLayout(self.calculator_song_layout) self.calculator.setCurrentIndex(0)
def __init__(self): if not PROFILE_PATH.exists(): PROFILE_PATH.mkdir() db.cachedb.execute(""" CREATE TABLE IF NOT EXISTS profiles ( "name" TEXT UNIQUE ) """) db.cachedb.commit() if not self.switch_profile('main'): logger.info("No profile found, creating default profile") self.add_profile('main') self.switch_profile('main') self.profile = 'main'
def update_all(sleep=0.1): logger.info("Updating images, please wait...") _try_extract_cache() if not IMAGE_PATH64.exists(): IMAGE_PATH64.mkdir() if not IMAGE_PATH32.exists(): IMAGE_PATH32.mkdir() card_data = _base_query("list/card_t")['result'] logger.debug("Getting icons for {} cards".format(len(card_data))) card_ids = [int(card['id']) for card in card_data] card_ids_plus = [_ + 1 for _ in card_ids] with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor: for card_id in card_ids + card_ids_plus: executor.submit(update_image, card_id, sleep)
def simulate(self, row=None): score_id, diff_id, live_detail_id, _, _ = eventbus.eventbus.post_and_get_first( GetSongDetailsEvent()) if diff_id is None: logger.info("No chart loaded") return times = self.get_times() all_cards: List[ CardsWithUnitUuid] = eventbus.eventbus.post_and_get_first( GetAllCardsEvent(self.get_current_model(), row), required_non_none=True) perfect_play = eventbus.eventbus.post_and_get_first( GetPerfectPlayFlagEvent()) custom_pots = eventbus.eventbus.post_and_get_first( GetCustomPotsEvent()) appeals = eventbus.eventbus.post_and_get_first(GetAppealsEvent()) support = eventbus.eventbus.post_and_get_first(GetSupportEvent()) mirror = eventbus.eventbus.post_and_get_first(GetMirrorFlagEvent()) doublelife = eventbus.eventbus.post_and_get_first( GetDoublelifeFlagEvent()) autoplay = eventbus.eventbus.post_and_get_first(GetAutoplayFlagEvent()) autoplay_offset = eventbus.eventbus.post_and_get_first( GetAutoplayOffsetEvent()) extra_bonus, special_option, special_value = eventbus.eventbus.post_and_get_first( GetCustomBonusEvent()) left_inclusive, right_inclusive = eventbus.eventbus.post_and_get_first( GetSkillBoundaryEvent()) theoretical_simulation = eventbus.eventbus.post_and_get_first( GetTheoreticalMaxFlagEvent()) self.model.simulate_internal( perfect_play=perfect_play, left_inclusive=left_inclusive, right_inclusive=right_inclusive, theoretical_simulation=theoretical_simulation, score_id=score_id, diff_id=diff_id, times=times, all_cards=all_cards, custom_pots=custom_pots, appeals=appeals, support=support, extra_bonus=extra_bonus, special_option=special_option, special_value=special_value, mirror=mirror, autoplay=autoplay, autoplay_offset=autoplay_offset, doublelife=doublelife, row=row)
def _update_masterdb(): logger.debug("Updating master.db") manifest_conn = sqlite3.connect(get_manifestdb_path()) manifest_c = manifest_conn.cursor() manifest_c.execute('SELECT hash FROM manifests WHERE name="master.mdb"') master_hash = manifest_c.fetchone()[0] master_response = cgss_query.get_db(master_hash) with storage.get_writer(MASTERDB_PATH, 'wb') as fwb: fwb.write(decompress(master_response.content)) manifest_c.close() manifest_conn.close() logger.info("master.db updated")
def keyPressEvent(self, event): key = event.key() if QApplication.keyboardModifiers( ) == Qt.ControlModifier and key == Qt.Key_F: self.ui.quicksearch_view.focus() if QApplication.keyboardModifiers( ) == Qt.ControlModifier and key == Qt.Key_S: logger.info("User data backed up") unit_storage.clean_all_units(grand=False) for r_idx in range(self.ui.unit_view.widget.count()): widget = self.ui.unit_view.widget.itemWidget( self.ui.unit_view.widget.item(r_idx)) widget.update_unit() profile_manager.cleanup()
def push_card(self, idx, skip_guest_push=False): count = 0 cell_widget = None for row in range(self.view.widget.rowCount()): if self.view.widget.isRowHidden(row): continue if count == idx: cell_widget = self.view.widget.item(row, 2) break else: count += 1 if cell_widget is None: logger.info("No card at index {}".format(idx)) return eventbus.eventbus.post(PushCardEvent(int(cell_widget.text()), skip_guest_push))
def setup_gui(*args): app = QApplication(*args) app.setApplicationName("Chihiro") icon = QIcon(str(ROOT_DIR / 'icon.png')) app.setWindowIcon(icon) app.lastWindowClosed.connect(lambda: cleanup()) import ctypes myappid = 'mycompany.myproduct.subproduct.version' # arbitrary string ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid) MainWindow = CustomMainWindow() ui = UiMainWindow(MainWindow) MainWindow.setui(ui) ui.setup_ui() ui.disable_auto_resize() logger.info("GUI setup successfully") return app, MainWindow
def update_owned_cards(card_ids, numbers): logger.info("Updating cards: {}".format(card_ids)) if not isinstance(card_ids, list) or not isinstance(numbers, list): card_ids = [card_ids] numbers = [numbers] assert len(card_ids) == len(numbers) for card_id, number in zip(card_ids, numbers): db.cachedb.execute( """ INSERT OR REPLACE INTO owned_card (card_id, number) VALUES (?,?) """, [card_id, number]) db.cachedb.commit() from logic.search import indexer, search_engine indexer.im.initialize_index_db(card_ids) indexer.im.reindex(card_ids) search_engine.engine.refresh_searcher()
def load_data(self, data, card_list=None): if card_list is None: self.widget.setColumnCount(len(data[0]) + 2) self.widget.horizontalHeader().setSectionResizeMode(1, 2) # Not allow change icon column size self.widget.setRowCount(len(data)) self.widget.setHorizontalHeaderLabels(['#', ''] + list(data[0].keys())) rows = range(len(data)) else: data_dict = {int(_['ID']): _ for _ in data} rows = dict() for r_idx in range(self.widget.rowCount()): card_id = int(self.widget.item(r_idx, 2).text()) if card_id not in data_dict: continue else: rows[card_id] = r_idx rows = [rows[card_id] for card_id in map(int, card_list)] data = [data_dict[card_id] for card_id in map(int, card_list)] # Turn off sorting to avoid indices changing mid-update self.widget.setSortingEnabled(False) for r_idx, card_data in zip(rows, data): row_count_item = NumericalTableWidgetItem(r_idx + 1) row_count_item.setFlags(row_count_item.flags() & ~Qt.ItemIsEditable) self.widget.setItem(r_idx, 0, row_count_item) for c_idx, (key, value) in enumerate(card_data.items()): if isinstance(value, int): item = NumericalTableWidgetItem(value) elif value is None: item = QTableWidgetItem("") else: item = QTableWidgetItem(str(value)) if c_idx != 1: item.setFlags(item.flags() & ~Qt.ItemIsEditable) else: item = QTableWidgetItem() item.setData(Qt.EditRole, value) if key == 'Skill' and value is not None: item.setBackground(QColor(*SKILL_COLOR_BY_NAME[value], 135)) if key == 'Color' and value is not None: item.setBackground(QColor(*CARD_GUI_COLORS[value], 100)) self.widget.setItem(r_idx, c_idx + 2, item) logger.info("Loaded {} cards".format(len(data))) self.widget.setSortingEnabled(True) # Turn on auto fit once to make it look better then turn it off to render faster during resize self.toggle_auto_resize(card_list is None)
def load_images(self, size=None): logger.info("Card list thumbnail size: {}".format(size)) if size is None: self.images = dict() self.view.draw_icons(None, size) return if size is not None: assert size == 32 or size == 64 or size == 124 if size == 32: path = IMAGE_PATH32 elif size == 64: path = IMAGE_PATH64 elif size == 124: path = IMAGE_PATH for image_path in path.iterdir(): self.images[image_path.name.split(".")[0]] = image_path self.view.draw_icons(self.images, size)
def update_musicscores(): logger.debug("Updating all musicscores") if not storage.exists(MANIFEST_PATH): logger.debug("manifest.db not found, updating metadata") meta_updater.update_database() with db.CustomDB(meta_updater.get_manifestdb_path()) as manifest_conn: all_musicscores = manifest_conn.execute_and_fetchall(""" SELECT name,hash FROM manifests WHERE (name LIKE "musicscores\_m___.bdb" ESCAPE '\\') """) all_musicscores = {_[0].split(".")[0]: _[1] for _ in all_musicscores} if not _score_cache_db_exists(): _initialize_score_cache_db() new_scores = all_musicscores.keys() updated_scores = set() else: scores_meta = db.cachedb.execute_and_fetchall( "SELECT score_id, score_hash FROM score_cache") scores_meta = {_: __ for _, __ in scores_meta} deleted_scores = set(scores_meta.keys()).difference( all_musicscores.keys()) if len(deleted_scores) > 0: logger.info( "Found {} defunct musicscores, removing them...".format( len(deleted_scores))) for deleted_score in deleted_scores: path = MUSICSCORES_PATH / "{}.db".format(deleted_score) path.unlink() new_scores = set(all_musicscores.keys()).difference(scores_meta.keys()) updated_scores = [ _ for _ in set(all_musicscores.keys()).intersection( scores_meta.keys()) if scores_meta[_] != all_musicscores[_] ] logger.info( "Found {} musicscores, {} of them are new, {} are updated...".format( len(all_musicscores), len(new_scores), len(updated_scores))) if len(new_scores) + len(updated_scores) > 50: logger.info("It will take some time to download, please wait...") for musicscore_name in set(new_scores).union(set(updated_scores)): musicscore_hash = all_musicscores[musicscore_name] musicscore_response = cgss_query.get_db(musicscore_hash) with storage.get_writer( MUSICSCORES_PATH / "{}.db".format(musicscore_name), 'wb') as fwb: fwb.write(decompress(musicscore_response.content)) db.cachedb.execute( """ INSERT OR REPLACE INTO score_cache (score_id, score_hash) VALUES (?,?) """, [musicscore_name, musicscore_hash]) db.cachedb.commit() logger.info("All musicscores updated")
def get_all_cards(self, event): if event.model is not self: return res = list() rows_to_search = range( self.view.widget.rowCount()) if event.row is None else [event.row] for r_idx in rows_to_search: unit_widget = self.view.widget.cellWidget(r_idx, 0) if unit_widget.running_simulation: logger.info("Simulation already running: {}".format( unit_widget.get_uuid())) continue unit_widget.toggle_running_simulation(True) res.append( CardsWithUnitUuid( self.view.widget.cellWidget(r_idx, 0).get_uuid(), self.view.widget.cellWidget(r_idx, 0).get_short_uuid(), self.view.widget.cellWidget(r_idx, 0).cards_internal)) return res
def create_support_team(self, r): if not eventbus.eventbus.post_and_get_first( SetSupportCardsEvent( self.widget.cellWidget(r, 0).cards_internal)): logger.info("Invalid unit to evaluate support team") return appeals, support, life = eventbus.eventbus.post_and_get_first( RequestSupportTeamEvent()) self.widget.setItem(r, 2, NumericalTableWidgetItem(int(life))) total_appeals = eventbus.eventbus.post_and_get_first(GetAppealsEvent()) if total_appeals is not None: self.widget.setItem(r, 1, NumericalTableWidgetItem(total_appeals)) return custom_support = eventbus.eventbus.post_and_get_first( GetSupportEvent()) if custom_support is not None: support = custom_support self.widget.setItem(r, 1, NumericalTableWidgetItem(int(appeals + support)))
def import_from_gameid(game_id): try: assert len(str(game_id)) == 9 z = int(game_id) assert 0 <= z <= 999999999 logger.info( "Trying to import from ID {}, this might take a while".format( game_id)) cards = list(map(int, get_cards(game_id))) for idx, card in enumerate(cards): if card % 2 == 1: cards[idx] += 1 card_dict = defaultdict(int) for card in cards: card_dict[card] += 1 for card_id, number in card_dict.items(): z = list( zip(*db.cachedb.execute_and_fetchall( "SELECT number FROM owned_card WHERE card_id = ? OR card_id = ?", [card_id, card_id - 1])))[0] if z[0] + z[1] < number: db.cachedb.execute( """ INSERT OR REPLACE INTO owned_card (card_id, number) VALUES (?,?) """, [card_id, number - z[0]]) db.cachedb.commit() logger.info("Imported {} cards successfully".format(len(card_dict))) return list(card_dict.keys()) except: logger.debug(traceback.print_exc()) logger.info("Failed to import cards")
def load_data(self, data): DATA_COLS = ["LDID", "LiveID", "DifficultyInt", "ID", "Name", "Color", "Difficulty", "Level", "Duration (s)", "Note Count", "Tap", "Long", "Flick", "Slide", "Tap %", "Long %", "Flick %", "Slide %"] self.widget.setColumnCount(len(DATA_COLS)) self.widget.setRowCount(len(data)) self.widget.setHorizontalHeaderLabels(DATA_COLS) self.widget.setSortingEnabled(True) for r_idx, card_data in enumerate(data): for c_idx, (key, value) in enumerate(card_data.items()): if isinstance(value, int) and 13 >= c_idx >= 7 or c_idx == 1: item = NumericalTableWidgetItem(value) elif value is None: item = QTableWidgetItem("") else: item = QTableWidgetItem(str(value)) self.widget.setItem(r_idx, c_idx, item) logger.info("Loaded {} charts".format(len(data))) self.widget.setColumnHidden(0, True) self.widget.setColumnHidden(2, True) self.widget.setSortingEnabled(True) self.widget.sortItems(3, Qt.AscendingOrder) self.toggle_percentage(change=False) self.toggle_auto_resize(True)
def handle_simulation_request(self, event: SimulationEvent): event.live.set_unit(event.unit) if event.autoplay: logger.info("Simulation mode: Autoplay - {} - {}".format( event.short_uuid, event.unit)) sim = Simulator(event.live, special_offset=0.075) result = sim.simulate_auto(appeals=event.appeals, extra_bonus=event.extra_bonus, support=event.support, special_option=event.special_option, special_value=event.special_value, time_offset=event.autoplay_offset, mirror=event.mirror, doublelife=event.doublelife) else: if event.perfect_play: logger.info("Simulation mode: Perfect - {} - {}".format( event.short_uuid, event.unit)) else: logger.info("Simulation mode: Normal - {} - {}".format( event.short_uuid, event.unit)) sim = Simulator(event.live, left_inclusive=event.left_inclusive, right_inclusive=event.right_inclusive) result = sim.simulate(perfect_play=event.perfect_play, times=event.times, appeals=event.appeals, extra_bonus=event.extra_bonus, support=event.support, special_option=event.special_option, special_value=event.special_value, doublelife=event.doublelife) if event.theoretical_simulation: result.max_theoretical_result = sim.simulate_theoretical_max( appeals=event.appeals, extra_bonus=event.extra_bonus, support=event.support, special_option=event.special_option, special_value=event.special_value, doublelife=event.doublelife) self.process_simulation_results_signal.emit( BaseSimulationResultWithUuid(event.uuid, result, event.abuse_load))
def setup_card_unit_layout(self): logger.info("Setting up card and unit layouts") self.card_unit_layout = QHBoxLayout() self.card_layout = QVBoxLayout() self.card_quicksearch_layout = QHBoxLayout() self.quicksearch_layout = QHBoxLayout() # Set up card MV first self.card_view = CardView(self.central_widget) self.card_model = CardModel(self.card_view) self.card_view.set_model(self.card_model) self.card_model.initialize_cards() self.card_view.initialize_pics() self.card_view.connect_cell_change() self.card_layout.addWidget(self.card_view.widget) # Need card view self.quicksearch_view = QuickSearchView(self.central_widget, self.card_model) self.quicksearch_model = QuickSearchModel(self.quicksearch_view, self.card_view) self.quicksearch_view.set_model(self.quicksearch_model) self.card_quicksearch_layout.addLayout(self.quicksearch_layout) self.quicksearch_layout.addWidget(self.quicksearch_view.widget) self.highlight_checkbox = QCheckBox(self.central_widget) self.highlight_checkbox.setText("Highlight Carnival Idols") self.highlight_checkbox.clicked.connect( lambda _: self.card_model.highlight_event_cards(_)) self.quicksearch_layout.addWidget(self.highlight_checkbox) self.quicksearch_model.add_options(self.quicksearch_layout, self.central_widget) # Then icon loader MV since it makes use of the card model self.icon_loader_view = IconLoaderView(self.central_widget) self.icon_loader_model = IconLoaderModel(self.icon_loader_view, self.card_model) self.icon_loader_view.set_model(self.icon_loader_model) self.icon_loader_view.widget.setToolTip( "Larger icons require more RAM to run.") self.icon_loader_model.load_image(0) self.card_quicksearch_layout.addWidget(self.icon_loader_view.widget) self.card_layout.addLayout(self.card_quicksearch_layout) self.card_layout.setStretch(1, 1) self.unit_layout = QVBoxLayout() self.unit_view = UnitView(self.central_widget) self.unit_model = UnitModel(self.unit_view) self.unit_view.set_model(self.unit_model) self.unit_model.initialize_units() self.unit_layout.addWidget(self.unit_view.widget) self.card_unit_layout.addLayout(self.unit_layout) self.card_unit_layout.addLayout(self.card_layout) self.add_unit_button = QPushButton() self.add_unit_button.setText("Add unit") self.add_unit_button.setToolTip( "Add an untitled unit. Untitled units are not saved upon exit!\n" "Make sure to give your units a name. Unit names must be different.\n" "First/Red card is the leader, last/blue card is the guest.") self.add_unit_button.clicked.connect( lambda: self.unit_view.add_empty_widget()) self.unit_layout.addWidget(self.add_unit_button) self.card_unit_layout.setStretch(0, 1) self.card_unit_layout.setStretch(1, 2) self.main_layout.addLayout(self.card_unit_layout) self.grid_layout.addLayout(self.main_layout, 0, 0, 1, 1)
def setup_base(self): logger.info("Setting up UI base") self.central_widget = QWidget(self.main) self.grid_layout = QGridLayout(self.central_widget) self.main_layout = QVBoxLayout()
def simulate_internal(self, perfect_play, left_inclusive, right_inclusive, theoretical_simulation, score_id, diff_id, times, all_cards, custom_pots, appeals, support, extra_bonus, special_option, special_value, mirror, autoplay, autoplay_offset, doublelife, row=None): """ :type all_cards: List[CardsWithUnitUuid] """ results = list() if len(all_cards) == 0: logger.info("Nothing to simulate") return extra_return = None # Initialize song first because SQLite DB thread lock # Live objects are mutable so create one for each simulation # TODO: Minor optimize by calling set_music only once then clone, but set_music shouldn't take too long to run so this is on low priority live_objects = list() for card_with_uuid in all_cards: cards = card_with_uuid.cards if len(cards) == 15: live = GrandLive() else: live = Live() live.set_music(score_id=score_id, difficulty=diff_id) groove_song_color = eventbus.eventbus.post_and_get_first( GetGrooveSongColor()) if groove_song_color is not None: live.color = groove_song_color live_objects.append(live) # Load cards for live, card_with_uuid in zip(live_objects, all_cards): cards = card_with_uuid.cards try: if len(cards) == 15: unit = GrandUnit.from_list(cards, custom_pots) else: if cards[5] is None: cards = cards[:5] unit = Unit.from_list(cards, custom_pots) except InvalidUnit: logger.info("Invalid unit: {}".format(cards)) results.append(None) continue eventbus.eventbus.post(SimulationEvent( card_with_uuid.uuid, card_with_uuid.short_uuid, row is not None and theoretical_simulation, appeals, autoplay, autoplay_offset, doublelife, extra_bonus, extra_return, live, mirror, perfect_play, results, special_option, special_value, support, times, unit, left_inclusive, right_inclusive, theoretical_simulation), high_priority=True, asynchronous=True)
def initialize_index_db(self, card_list=None): logger.info("Building quicksearch index, please wait...") carnival_idols = ",".join( map(str, Live.static_get_chara_bonus_set(get_name=False))) db.cachedb.execute("""ATTACH DATABASE "{}" AS masterdb""".format( get_masterdb_path())) query = """ SELECT cdc.id, LOWER(cnc.card_short_name) as short, oc.number as owned, LOWER(cc.full_name) as chara, LOWER(rt.text) as rarity, LOWER(ct.text) as color, CASE WHEN cdc.rarity % 2 == 0 THEN 1 ELSE 0 END idolized, CASE WHEN pk.id IS NOT NULL THEN sd.condition || pk.short ELSE '' END time_prob_key, IFNULL(LOWER(sk.keywords), "") as skill, IFNULL(LOWER(lk.keywords), "") as leader, CASE WHEN cdc.leader_skill_id IN (70,71,72,73,81,82,83,84,104,105,106,113,117,118) AND cdc.rarity > 6 THEN "fes" ELSE "" END fes, CASE WHEN cdc.leader_skill_id IN (70,71,72,73,81,82,83,84,104,105,106,113,117) AND cdc.rarity > 6 THEN "blanc" ELSE "" END blanc, CASE WHEN cdc.leader_skill_id IN (118) AND cdc.rarity > 6 THEN "noir" ELSE "" END noir, CASE WHEN cdc.chara_id IN ({}) THEN "carnival" ELSE "" END carnival, CASE WHEN 1.0 * cdc.vocal_min / (cdc.vocal_min + cdc.visual_min + cdc.dance_min) > 0.39 THEN "vocal" WHEN 1.0 * cdc.visual_min / (cdc.vocal_min + cdc.visual_min + cdc.dance_min) > 0.39 THEN "visual" WHEN 1.0 * cdc.dance_min / (cdc.vocal_min + cdc.visual_min + cdc.dance_min) > 0.39 THEN "dance" ELSE "balance" END main_attribute FROM card_data_cache as cdc INNER JOIN card_name_cache cnc on cdc.id = cnc.card_id INNER JOIN owned_card oc on oc.card_id = cnc.card_id INNER JOIN chara_cache cc on cdc.chara_id = cc.chara_id INNER JOIN rarity_text rt on cdc.rarity = rt.id INNER JOIN color_text ct on cdc.attribute = ct.id LEFT JOIN masterdb.skill_data sd on cdc.skill_id = sd.id LEFT JOIN probability_keywords pk on pk.id = sd.probability_type LEFT JOIN skill_keywords sk on sd.skill_type = sk.id LEFT JOIN leader_keywords lk on cdc.leader_skill_id = lk.id """.format(carnival_idols) if card_list is not None: query += "WHERE cdc.id IN ({})".format(','.join(['?'] * len(card_list))) data = db.cachedb.execute_and_fetchall(query, card_list, out_dict=True) else: data = db.cachedb.execute_and_fetchall(query, out_dict=True) db.cachedb.execute("DROP TABLE IF EXISTS card_index_keywords") db.cachedb.execute(""" CREATE TABLE IF NOT EXISTS card_index_keywords ( "card_id" INTEGER UNIQUE PRIMARY KEY, "fields" BLOB ) """) logger.debug("Initializing quicksearch db for {} cards".format( len(data))) for card in data: card_id = card['id'] fields = {_: card[_] for _ in KEYWORD_KEYS} db.cachedb.execute( """ INSERT OR REPLACE INTO card_index_keywords ("card_id", "fields") VALUES (?,?) """, [card_id, str(fields)]) db.cachedb.commit() logger.debug( "Quicksearch db transaction for {} cards completed".format( len(data))) db.cachedb.execute("DETACH DATABASE masterdb")
def main_cleanup(): logger.info("Virtual Chihiro going back to sleep...")
def cleanup(): logger.info("Waiting for all threads to finish...") kill_tip_refresher_service()