class MyAnimeListAPI(object): def __init__(self, username): self._instance = Jikan() self._user = username def search(self, title): search_results = self._instance.search('anime', title)['results'] entries = [] for result in search_results: entries.append(AnimeEntry(result)) return entries def currently_watching(self): response = self._instance.user(username=self._user, request="animelist", argument="watching") anime_list = [] for anime in response['anime']: anime_list.append(AnimeEntry(anime)) return anime_list def plan_to_watch(self): response = self._instance.user(username=self._user, request="animelist", argument="plantowatch") anime_list = [] for anime in response['anime']: anime_list.append(AnimeEntry(anime)) return anime_list
class AnimeList(object): def __init__(self, username): self.user = username self._api = Jikan() self.update() def update(self): _list = self._api.user(username=self.user, request='animelist')['anime'] self._list = [AnimeListEntry(i) for i in _list] def __len__(self): return len(self._list) def __iter__(self): self._iter = 0 return self def __next__(self): if self._iter < len(self._list): self._iter += 1 return self._list[self._iter - 1] else: raise StopIteration def __repr__(self): return f'<AnimeList: {self.user} [{len(self)}]>' def __contains__(self, obj): return obj in self._list def __getitem__(self, index): return self._list[index] @property def PTW(self): return [ i for i in self._list if i.status.watching is WatchStatus.PlanToWatch ] @property def Watching(self): return [ i for i in self._list if i.status.watching is WatchStatus.Watching ] @property def Completed(self): return [ i for i in self._list if i.status.watching is WatchStatus.Completed ]
class CachedJikan(): def __init__(self, username): self._jikan = Jikan() self._last_request_time = time.time() self._REQUEST_DELAY = 2 self._mal_username = username self._animelist_watching = None self._animelist_watching_time = None self._animes = dict() def _request_wait_time(self): return max(0, (self._last_request_time + self._REQUEST_DELAY) - time.time()) def _delay_request(self, request_func): time.sleep(self._request_wait_time()) result = request_func() self._last_request_time = time.time() return result def animelist_watching(self): if self._animelist_watching is None or time.time( ) - self._animelist_watching_time > 5 * 60: try: def do_request(): return self._jikan.user(username=self._mal_username, request='animelist', argument='watching') self._animelist_watching = self._delay_request(do_request) self._animelist_watching_time = time.time() except APIException as e: LOG.error('exception getting watchlist') LOG.error(e) return self._animelist_watching def anime(self, anime_id): if anime_id not in self._animes: try: def do_request(): return self._jikan.anime(anime_id) anime = self._delay_request(do_request) self._animes[anime_id] = anime except APIException as e: LOG.error(str.format('exception getting anime id:{}', anime_id)) LOG.error(e) return None return self._animes[anime_id]
def main(): fields = ['Username', 'Location', 'Gender', 'Episodes_watched', 'Favorites_anime_id'] jikan = Jikan() with open(csv_file_name, 'a') as csv_file: writer = csv.DictWriter(csv_file, fieldnames=fields) if csv_file.tell() == 0: writer.writeheader() for username in usernames: if username in parsed_dict_previous or username in parsed_dict: continue try: #2 seconds per request time.sleep(2) #write anime info to csv file user = jikan.user(username) content = {} content['Username'] = username content['Location'] = user['location'] content['Gender'] = user['gender'] content['Episodes_watched'] = user['anime_stats']['episodes_watched'] content['Favorites_anime_id'] = extract_list_info(user['favorites']['anime'], 'mal_id') print(content) writer.writerow(content) parsed_dict[username] = 1 except exceptions.APIException: print("Username: "******" does not exist") parsed_dict[username] = 1 except: print("failure at " + str(username)) for key, val in parsed_dict_previous.items(): parsed_dict[key] = val pickle.dump(parsed_dict, open(parsed_dict_location, "wb")) raise for key, val in parsed_dict_previous.items(): parsed_dict[key] = val pickle.dump(parsed_dict, open(parsed_dict_location, "wb"))
def update_mal_rss(user : str, Activity, db : SQLAlchemy): any_added = False jikan = Jikan() sleep(0.5) history = jikan.user(username=user, request = 'history') for entry in history['history']: name = entry['meta']['name'] number = entry['increment'] id = f'mal_{name}_ep_{number}' if not Activity.query.get(id): if entry['meta']['type'] == 'anime': action = 'Watched' increment = 'episode' else: action = 'Read' increment = 'chapter' title = f"{action} {name} {increment} {number}" link = entry['meta']['url'] date = datetime.datetime.fromisoformat(entry['date']) new_activity = Activity(id = id, title=title, link = link, date = date, website = 'My Anime List') db.session.add(new_activity) any_added = True print(f'entry added - {title}') if not any_added: print('no new MAL entires') db.session.commit()
results = {} resultsmanga = {} topaff = [] topaffmanga = [] names = [] namesmanga = [] var = [] varsmanga = [] #user_name = 'Guts__' now = datetime.now() dt_string = now.strftime("%d/%m/%Y %H:%M") jikan = Jikan() # friends get data ufriends = jikan.user( username=AffinityScraperMAL.spiders.credentials.user_name, request='friends') ufriends2 = jikan.user( username=AffinityScraperMAL.spiders.credentials.user_name, request='friends', argument=2) # merge all users for i in range(len(ufriends['friends'])): userlist.append(ufriends['friends'][int(i)]) for i in range(len(ufriends2['friends'])): userlist.append(ufriends2['friends'][int(i)]) # create a list of friend names friend_names = [f["username"] for f in userlist] for i in range(0, len(friend_names)): e.append(str('https://myanimelist.net/profile/') + str(friend_names[i]))
class Recomender: def __init__(self, user_name): self.user_name: str = user_name # MAL username self.jikan = Jikan() # API object self.anime_dic = {} # dic of anime id and it's score self.genre_dic = defaultdict( list) # dic of genres and a list of user scores for them self.studio_dic = defaultdict( list) # dic of studios and a list of user scores for them self.source_material_dic = defaultdict( list) # dic of source materials and a list of user scores for them self.type_dic = defaultdict( list) # dic of types and a list of user scores for them self.episodes_amount_dic = defaultdict( list ) # dic of episode amount enums and a list of user scores for them self.staff_dic = defaultdict( list) # dic of staff people and a list of user scores for them self.analyzed_anime_dic = { } # dic of analyzed seasonal anime and their scores self.anime_name_dic = {} # dic of MAL anime ids and names self.staff_name_dic = {} # dic of MAL staff ids and names """ Fills the anime_dic with the users rated anime """ def fill_anime_dic(self): print("Started filling anime dic.") last_page: bool = False page_num: int = 1 while not last_page: # the API only returns 300 anime so we may need to request multiple pages animelist = self.jikan.user(username=self.user_name, request='animelist', argument="all", page=page_num) if animelist["request_cached"] is False: time.sleep( SLEEP_TIME ) # if the request was uncached we need to add a delay or we get a 429 for anime in animelist["anime"]: if anime["score"] > 0: # only add the anime if the user set a score self.anime_dic[anime["mal_id"]] = anime["score"] if len(animelist["anime"] ) < 300: # each page contains max 300 anime last_page = True page_num += 1 """ Gathers data like genre or studio scores based upon the anime in the anime dic """ def gather_anime_data_from_anime_dic(self): print("Started gathering anime data from anime dic.") progress_counter = 1 for animeID in self.anime_dic.keys(): # go though every anime if progress_counter % 10 == 1: print("Gathered " + str(progress_counter) + " anime.") progress_counter += 1 anime = self.jikan.anime(animeID) if anime["request_cached"] is False: time.sleep(SLEEP_TIME) # sleep to prevent 429 anime_staff_full = self.jikan.anime( animeID, extension='characters_staff') # get staff data anime_staff = anime_staff_full["staff"] if anime_staff_full["request_cached"] is False: time.sleep(SLEEP_TIME) score = self.anime_dic[animeID] for genre in anime["genres"]: # add score for every genre self.genre_dic[genre["mal_id"]].append(score) for studio in anime["studios"]: # add score for every studio self.studio_dic[studio["mal_id"]].append(score) self.source_material_dic[anime["source"]].append( score) # add score for source material self.type_dic[anime["type"]].append(score) # add score for type episodes = anime["episodes"] if episodes is None: # if episodes are unset set the to zero episodes = 0 if episodes > 0: # only add score if episodes are set episodes_enum = self.get_episode_amount_enum(episodes) self.episodes_amount_dic[episodes_enum].append(score) for staff_member in anime_staff: for position in staff_member["positions"]: # only add the staff member if their position is relevant according to my own decision if position in POSITION_SET: self.staff_dic[staff_member["mal_id"]].append(score) self.staff_name_dic[ staff_member["mal_id"]] = staff_member["name"] """ analyzes the anime of a specific season with the data gathered from the user year = int, year of the season season = string, season of the year (either winter, spring, summer or fall) kids = boolean, if you want to analyze kids shows r18 = if you want to analyze r18 (hentai) shows """ def analyze_seasonal_anime(self, year, season, kids, r18): seasonal_anime_full = self.jikan.season(year=year, season=season) if seasonal_anime_full["request_cached"] is False: time.sleep(SLEEP_TIME) seasonal_anime = seasonal_anime_full["anime"] print("Started analyzing seasonal anime.") progress_counter = 1 for anime in seasonal_anime: if progress_counter % 10 == 1: print("Analyzed " + str(progress_counter) + " anime.") progress_counter += 1 if anime[ "continuing"]: # if the anime is actually from a previous season, don't analyze it continue if not r18 and anime["r18"]: continue if not kids and anime["kids"]: continue self.analyze_anime(anime) """ analyzes an anime and puts it and the score to the analyzed anime dic anime = either an anime object or the MAL ID as an int """ def analyze_anime(self, anime): if isinstance(anime, int): # if anime is an int get the anime object of it anime = self.jikan.anime(anime) score_divisor = 0 # variable through which the score in the end will be divided so that we get one that goes from 1 to 10 by adding the FACTOR of a value anime_staff_full = self.jikan.anime(anime["mal_id"], extension='characters_staff') if anime_staff_full["request_cached"] is False: time.sleep(SLEEP_TIME) anime_staff = anime_staff_full["staff"] score = 0.0 score_addition_counter = 0 # count how many scores were actually added to the score genre_amount = 0 genre_score = 0.0 for genre in anime["genres"]: if genre["mal_id"] in self.genre_dic.keys(): genre_amount += 1 # get the average of the scores in the list genre_score += sum(self.genre_dic[genre["mal_id"]]) / len( self.genre_dic[genre["mal_id"]]) if genre_amount > 0: # only add if there was atleast one genre score += genre_score / genre_amount * GENRE_FACTOR score_addition_counter += 1 score_divisor += GENRE_FACTOR studio_amount = 0 studio_score = 0.0 for studio in anime["producers"]: if studio["mal_id"] in self.studio_dic.keys(): studio_amount += 1 studio_score += sum(self.studio_dic[studio["mal_id"]]) / len( self.studio_dic[studio["mal_id"]]) if studio_amount > 0: score += studio_score / studio_amount * STUDIO_FACTOR score_addition_counter += 1 score_divisor += STUDIO_FACTOR if anime["source"] in self.source_material_dic: source_score = sum( self.source_material_dic[anime["source"]]) / len( self.source_material_dic[anime["source"]]) if source_score > 0: score += source_score * SOURCE_MATERIAL_FACTOR score_addition_counter += 1 score_divisor += SOURCE_MATERIAL_FACTOR if anime["type"] in self.type_dic: type_score = sum(self.type_dic[anime["type"]]) / len( self.type_dic[anime["type"]]) if type_score > 0: score += type_score * TYPE_FACTOR score_addition_counter += 1 score_divisor += TYPE_FACTOR episode_amount = anime["episodes"] if episode_amount is None: # check if episodes are set and if they are not set them to 0 episode_amount = 0 if episode_amount > 0: episode_enum = self.get_episode_amount_enum(episode_amount) if episode_enum in self.episodes_amount_dic: episode_amount_score = sum( self.episodes_amount_dic[episode_enum]) / len( self.episodes_amount_dic[episode_enum]) if episode_amount_score > 0: score += episode_amount_score * EPISODE_AMOUNT_FACTOR score_addition_counter += 1 score_divisor += EPISODE_AMOUNT_FACTOR staff_score = 0.0 staff_amount = 0 for staff_member in anime_staff: if staff_member["mal_id"] in self.staff_dic: staff_amount += 1 staff_score += sum( self.staff_dic[staff_member["mal_id"]]) / len( self.staff_dic[staff_member["mal_id"]]) if staff_amount > 0: staff_score /= staff_amount score += staff_score * STAFF_FACTOR score_addition_counter += 1 score_divisor += STAFF_FACTOR if score_addition_counter > 0: self.anime_name_dic[anime["mal_id"]] = anime["title"] self.analyzed_anime_dic[anime["mal_id"]] = ( (score / score_addition_counter) * (0.4 + 0.1 * score_addition_counter)) / ( score_divisor / score_addition_counter ) # calculate the score and add the anime to the dic """ writes a comma seperated value file with the result of the analyzed seasonal anime """ def write_analyzed_anime_to_file(self): with open("analyzed_anime.txt", mode="w", encoding="utf8") as text_file: text_file.write("Name^MAL ID^Score\n") for anime in self.analyzed_anime_dic.keys(): text_file.write( str(self.anime_name_dic[anime]) + "^" + str(anime) + "^" + str(self.analyzed_anime_dic[anime]) + "\n") print("Done writing anime file!") """ writes a comma seperated value file with staff members and their score """ def write_analyzed_staff_to_file(self): with open("analyzed_staff.txt", mode="w", encoding="utf8") as text_file: text_file.write("Name^MAL ID^Average^Amount^Score\n") max_len = -1 for staff in self.staff_dic.keys(): if len(self.staff_dic[staff]) > max_len: max_len = len(self.staff_dic[staff]) for staff in self.staff_dic.keys(): FACTOR = 0.866 length = len(self.staff_dic[staff]) scores_list = self.staff_dic[staff] average = sum(scores_list) / length text_file.write( str(self.staff_name_dic[staff]) + "^" + str(staff) + "^" + str(average) + "^" + str(length) + "^" + str(average * FACTOR + ((length / max_len) * (1.0 - FACTOR) * 10.0)) + "\n") print("Done writing staff file!") """ A Function that returns an Enum for summarizing episode amounts """ @staticmethod def get_episode_amount_enum(amount) -> EpisodesAmount: if amount < 1: return None elif amount == 1: return EpisodesAmount.One elif 2 <= amount <= 8: return EpisodesAmount.TwoEight elif 9 <= amount <= 19: return EpisodesAmount.NineNineteen elif 20 <= amount <= 30: return EpisodesAmount.TwentyThirty elif 31 <= amount <= 50: return EpisodesAmount.ThirtyoneFifty elif 51 <= amount <= 100: return EpisodesAmount.FiftyoneOnehundred else: return EpisodesAmount.OnehundredonePlus
root_folder_path = os.environ.get('ROOT_FOLDER_PATH','/downloads/Anime') monitored = os.environ.get('MONITORED',True) all_missing = os.environ.get('ALL_MISSING',False) # create jikan object to call to jikan-MAL API jikan = Jikan() page = 1 params = { 'page':page, 'sort':'desc', 'order_by':'last_updated' } # get initial list from MAL plan_to_watch = jikan.user(username=user, request='animelist',argument=target_list, parameters=params)['anime'] # get all pages if really long tmp_plan_to_watch = plan_to_watch while len(tmp_plan_to_watch) >= 300: page+=1 params['page']=page tmp_plan_to_watch = jikan.user(username=user, request='animelist',argument=target_list, parameters=params)['anime'] plan_to_watch.extend(tmp_plan_to_watch) titles=[x['title'] for x in plan_to_watch] mal_ids=[x['mal_id'] for x in plan_to_watch] print(titles) print(mal_ids) # ################ exit() # Load mal-tvdb mappings
archive = jikan.season_archive() pprint(archive) later = jikan.season_later() pprint(later) monday = jikan.schedule(day='monday') pprint(monday) top_anime = jikan.top(type='anime') pprint(top_anime) action = jikan.genre(type='anime', genre_id=1) pprint(action) deen = jikan.producer(producer_id=37) pprint(deen) jump = jikan.magazine(magazine_id=83) pprint(jump) nekomata1037 = jikan.user(username='******') pprint(nekomata1037) fantasy_anime_league = jikan.club(379) pprint(fantasy_anime_league) meta = jikan.meta(request='requests', type='anime', period='today') pprint(meta)
#display only 10 animes if count == 10: break print("\nTitle: ", items['title']) print("Episodes: ", items['episodes']) print("Score: ", items['score']) print("Synopsis: ", items['synopsis']) count+=1 #anime list elif choice == 4: user = input("\nEnter Username: "******"\nTitle: ", items['title']) print("Your Score: ", items['score']) print("Total Episodes: ", items['total_episodes']) print("Watched Episodes: ", items['watched_episodes']) elif choice == 100: break else: print("\nInvalid choice, please enter again.") #congratulations for making it all the way to the end print("\nDeveloped with <3 by Sankalp")
class Container: def __init__(self, id: str, shared_info): self.shared_info = shared_info self.shared_info.pending_updates_main = True self.names_list = [] self.graphs_list = [] self.jikan = Jikan() self.div = html.Div(id="graphcontainer") self.status_children = "Status: No issues. Feel free to add graphs" self.max_graphs = False self.app = DjangoDash(id, external_stylesheets=external_stylesheets) self.genre_options = [ {'label': 'Any', 'value': '1'}, {'label': 'Action', 'value': '2'}, {'label': 'Adventure', 'value': '3'}, {'label': 'Cars', 'value': '4'}, {'label': 'Comedy', 'value': '5'}, {'label': 'Dementia', 'value': '6'}, {'label': 'Demons', 'value': '7'}, {'label': 'Mystery', 'value': '8'}, {'label': 'Drama', 'value': '9'}, {'label': 'Ecchi', 'value': '10'}, {'label': 'Fantasy', 'value': '11'}, {'label': 'Game', 'value': '12'}, {'label': 'Hentai', 'value': '13'}, {'label': 'Historical', 'value': '14'}, {'label': 'Horror', 'value': '15'}, {'label': 'Kids', 'value': '16'}, {'label': 'Magic', 'value': '17'}, {'label': 'Martial Arts', 'value': '18'}, {'label': 'Mecha', 'value': '19'}, {'label': 'Music', 'value': '20'}, {'label': 'Parody', 'value': '21'}, {'label': 'Samurai', 'value': '22'}, {'label': 'Romance', 'value': '23'}, {'label': 'School', 'value': '24'}, {'label': 'Sci Fi', 'value': '25'}, {'label': 'Shoujo', 'value': '26'}, {'label': 'Shoujo Ai', 'value': '27'}, {'label': 'Shounen', 'value': '28'}, {'label': 'Shounen Ai', 'value': '29'}, {'label': 'Space', 'value': '30'}, {'label': 'Sports', 'value': '31'}, {'label': 'Super Power', 'value': '32'}, {'label': 'Vampire', 'value': '33'}, {'label': 'Yaoi', 'value': '34'}, {'label': 'Yuri', 'value': '35'}, {'label': 'Harem', 'value': '36'}, {'label': 'Slice Of Life', 'value': '37'}, {'label': 'Supernatural', 'value': '38'}, {'label': 'Military', 'value': '39'}, {'label': 'Police', 'value': '40'}, {'label': 'Psychological', 'value': '41'}, {'label': 'Thriller', 'value': '42'}, {'label': 'Seinen', 'value': '43'}, {'label': 'Josei', 'value': '44'}, ] self.category_options = [ {'label': 'Any', 'value': '1'}, {'label': 'TV', 'value': '2'}, {'label': 'OVA', 'value': '3'}, {'label': 'Movie', 'value': '4'}, {'label': 'Special', 'value': '5'}, {'label': 'ONA', 'value': '6'}, {'label': 'Music', 'value': '7'}, ] self.app.layout = self.serve_layout # @self.app.callback( # Output('graphcontainer', 'children'), # [Input('search_button', 'n_clicks'), # State('searchname', 'value')] # ) @self.app.callback( [Output('table', 'data'), Output('table', 'dropdown')], [Input('search_button', 'n_clicks'), Input("searchname", 'n_submit'), State("searchname", "value"), State('genre_dropdown', 'value'), State('category_dropdown', 'value'), State('date_picker_range', 'start_date'), State('date_picker_range', 'end_date')] ) def update_table(n_clicks, n_submit, searchname, genre_dropdown, category_dropdown, start_date, end_date): data = [{'Name': "", 'Add Graph(s)': ""}, {'Name': "", 'Add Graph(s)': ""}, {'Name': "", 'Add Graph(s)': ""}, {'Name': "", 'Add Graph(s)': ""}, {'Name': "", 'Add Graph(s)': ""}] dropdown = {} if searchname is not None: data = [] selected_genre = int(genre_dropdown) - 1 selected_category = (self.category_options[int(category_dropdown) - 1]['label']) results = self.search_anime(searchname, selected_genre, selected_category, start_date, end_date) for x in range(0, len(results) - 1): data.append({'Name': results[x]["title"], 'Add Graph(s)': "Don't add Graph"}) dropdown = { 'Add Graph(s)': { 'options': [ {'label': "No", 'value': "Don't add Graph"}, {'label': "Yes", 'value': "Add Graph"} ], 'searchable': False, 'clearable': False } } return data, dropdown @self.app.callback( [Output('graphcontainer', 'children'), Output('status_message', 'children'), Output('add_graphs', 'disabled')], [Input('add_graphs', 'n_clicks'), State('table', 'data')] ) def add_graph(n_clicks, data): id = 'graph-{}'.format(n_clicks) disable_add_button = self.max_graphs children = self.status_children names_added = [] names_no_data = [] names_duplicate = [] names_above_max = [] num_graphs = Anime.objects.count() if n_clicks > 0: for i in data: if i['Add Graph(s)'] == 'Add Graph': if num_graphs < 5: if i['Name'] not in self.names_list: try: test = graphs.Graphs(i['Name'] + 'app', i['Name'], i['Name'], i['Name'] + 'slider', False, [Input(i['Name'] + 'slider', 'value')], self.shared_info.color_graphs, self.shared_info.time_scale, i['Name']) self.graphs_list.append(test.return_layout()) # Potentially causes exception self.names_list.append(i['Name']) names_added.append(i['Name']) num_graphs = num_graphs + 1 a = Anime(anime_name=i['Name'], anime_order=num_graphs) a.save() except exceptions.ResponseError: names_no_data.append(i['Name']) else: names_duplicate.append(i['Name']) else: names_above_max.append(i['Name']) str_names = "" str_no_data = "" str_duplicates = "" str_above = "" if num_graphs == 5: disable_add_button = True self.max_graphs = True if len(names_added) > 0: self.shared_info.pending_updates_edit = True self.shared_info.pending_updates_export = True str_names = "Added (" + str(num_graphs) + "/5 total limit): " for i in names_added: str_names = str_names + i + "; " if len(names_no_data) > 0: str_no_data = "Not added (no search data or rate limit exceeded): " for i in names_no_data: str_no_data = str_no_data + i + "; " if len(names_duplicate) > 0: str_duplicates = "Not added (duplicate graph): " for i in names_duplicate: str_duplicates = str_duplicates + i + "; " if len(names_above_max) > 0: str_above = "Not added (exceeded 5-graph limit): " for i in names_above_max: str_above = str_above + i + "; " if len(str_names) > 0 or len(str_no_data) > 0 or len(str_duplicates) > 0 or len(str_above) > 0: children = "Status - " if len(str_names) > 0: children = children + str_names if len(str_no_data) > 0: children = children + str_no_data if len(str_duplicates) > 0: children = children + str_duplicates if len(str_above) > 0: children = children + str_above return html.Div(self.graphs_list), children, disable_add_button def serve_layout(self): if self.shared_info.pending_updates_main: self.shared_info.pending_updates_main = False self.div = html.Div(children=self.init_graph(), id="graphcontainer") num_graphs = Anime.objects.count() if num_graphs == 5: self.status_children = "Status: Max graphs (5) limit reached. Graphs may be removed via 'Settings' page." self.max_graphs = True else: self.status_children = "Status: No changes made yet. Feel free to add graphs (" + str( num_graphs) + "/5 total limit)" self.max_graphs = False graph_area = self.div return html.Div([ html.Div( id='searchtablearea', children=[ html.Div( id='searcharea', children=[ dcc.Input( id='searchname', type='text', placeholder='Enter Show Name', debounce=True, n_submit=0 ), html.Button(id="search_button", n_clicks=0, children="Search"), html.P('Genre:'), dcc.Dropdown(id='genre_dropdown', options=self.genre_options, value='1', clearable=False ), html.P('Category:'), dcc.Dropdown(id='category_dropdown', options=self.category_options, value='1', clearable=False ), html.P('Select search range:'), dcc.DatePickerRange( id='date_picker_range', start_date_placeholder_text='Select start date', end_date_placeholder_text='Select end date', clearable=True, ), ]), html.Div( id='tablearea', children= [self.init_table(), html.P(id='status_message', children=self.status_children, style={'font-style': 'italic'}), html.Button(id="add_graphs", n_clicks=0, children="Add selected graphs", disabled=self.max_graphs), ]) ]), graph_area, ]) def init_graph(self): initial_graphs = [] self.graphs_list = [] self.names_list = [] for a in Anime.objects.raw('SELECT anime_name FROM home_anime ORDER BY anime_order ASC'): p = str(a) self.names_list.append(p) initial_graphs.append( graphs.Graphs(p.replace(" ", ""), p, p.replace(" ", ""), p.replace(" ", "") + 'slider', False, [Input(p.replace(" ", "") + 'slider', 'value')], self.shared_info.color_graphs, self.shared_info.time_scale, p)) if len(initial_graphs) != 0: for i in initial_graphs: self.graphs_list.append(i.return_layout()) return html.Div(self.graphs_list) def search_anime_gender_birthday(self, anime_id): data = [sub['username'] for sub in self.jikan.anime(anime_id, extension='userupdates', page=1)["users"]] user = [self.jikan.user(username=name) for name in data] print(name['birthday'] for name in user) print(name['gender'] for name in user) def search_anime(self, anime_name, genre_number, category_name, start_date, end_date): search_params = {} if genre_number > 0: search_params['genre'] = genre_number if category_name != "Any": search_params['type'] = category_name if start_date is not None: search_params['start_date'] = start_date if end_date is not None: search_params['end_date'] = end_date search = self.jikan.search('anime', anime_name, parameters=search_params) # user = self.jikan.user_list(38000) # print(user) # print(user['birthday']) # print(user['gender']) return search["results"] def init_table(self, type: str = 'Add', pg_size: int = 5): layout = dash_table.DataTable( id='table', style_cell={'textAlign': 'left'}, style_data_conditional=[ { "if": {"state": "active"}, # 'active' | 'selected' "backgroundColor": "#FFFFFF", "border": "1px solid #3CCFCF", }, { "if": {"state": "selected"}, "backgroundColor": "##FFFFFF", "border": "1px solid #3CCFCF", }, ], style_header={ 'backgroundColor': 'rgb(230, 230, 230)', 'fontWeight': 'bold' }, columns=[{"name": "Name", "id": "Name", "editable": False }, {"name": type + ' Graph(s)', "id": type + ' Graph(s)', "presentation": "dropdown", "editable": True, } ], dropdown={}, data=[{'Name': "", 'Add Graph(s)': ""}, {'Name': "", 'Add Graph(s)': ""}, {'Name': "", 'Add Graph(s)': ""}, {'Name': "", 'Add Graph(s)': ""}, {'Name': "", 'Add Graph(s)': ""}], page_size=pg_size, ) return layout
print("I expected a username but you didn't give me one!") print('Example: python3 anifinity.py "Guts__"') sys.exit(1) username = sys.argv[1].strip() if len(sys.argv) <= 2: usr = username else: usr = sys.argv[2].strip() jikan = Jikan() print("Downloading your friends from MyAnimeList...") # friends info ufriends = jikan.user(username=usr, request='friends') ufriends2 = jikan.user(username=usr, request='friends', argument=2) # merge all users userlist = [] #userlist.append(ufriends['friends']) #userlist.append(ufriends2['friends']) for i in range(len(ufriends['friends'])): userlist.append(ufriends['friends'][int(i)]) for i in range(len(ufriends2['friends'])): userlist.append(ufriends2['friends'][int(i)]) print("Downloaded {} friends".format(len(userlist)))
def prep_data(username): global id_2_title, title_2_id, username_2_id, id_2_username # print("Loading data...") start = time.time() # Read in anime database: contains all animes along with its associated integer id anime_id_map = pd.read_csv('./data/anime_id_title.csv') id_2_title = {id: title for id, title in zip(anime_id_map.anime_id, anime_id_map.title)} title_2_id = {title: id for id, title in zip(anime_id_map.anime_id, anime_id_map.title)} # Read in user rating database: contains all user's and their associated rating to a specific anime df = pd.read_csv('./data/user_ratings.csv') df = df[['username','anime_id','my_score']] username_2_id = {username: id for id, username in enumerate(df.username.unique())} id_2_username = {id: username for id, username in enumerate(df.username.unique())} # Reduce the size of our dataset: # 1. Remove anime that have less than or equal to 5000 ratings. # 2. Remove user's that have less than or equal to 10 reviews. # 3. Randomly select 5000 users to be part of the recommendation system. #anime with less than 10 ratings reviews_per_anime = df.groupby('anime_id').count() anime_few_reviews = reviews_per_anime[reviews_per_anime.username <= 5000].index.to_list() #user's with less than 10 reviews review_per_user = df.groupby('username').count() users_few_reviews = review_per_user[review_per_user.anime_id <= 10].index.to_list() #Remove anime with less than 5000 ratings df = df[~df['anime_id'].isin(anime_few_reviews)] #Remove user's with less than 10 reviews df = df[~df['username'].isin(users_few_reviews)] # Map username to integer df['username'] = df['username'].map(username_2_id) #Randomly sample 5000 users from the dataframe index = np.random.randint(low=0, high=len(df.username.unique()), size=5000) df = df[df.username.isin(index)] df = df.rename(columns={'username':'******', 'anime_id':'itemID', 'my_score':'rating'}) # Get data of user's profile, use jikanpy and it's API call to myanimelist.net jikan = Jikan() user_profile = jikan.user(username=username, request='animelist') # Parse data such that it is in the form: (user_id, anime_id, rating) user_id = len(username_2_id) + 1 user_data = [(user_id, title_2_id[anime['title']], anime['score']) for anime in user_profile['anime'] if anime['title'] in title_2_id] # Append the new data gotten from API to our original dataset tmp = pd.DataFrame(user_data, columns=['userID','itemID','rating']) df = df.append(tmp,ignore_index = True) # Get list of animes that need to be rated anime_watched = df[df.userID == user_id].itemID.values testset = [item_id for item_id in df.itemID.unique() if item_id not in anime_watched] end = time.time() # print("Time Elapsed: {}".format(end - start)) return df, user_id, testset
print("I expected a username but you didn't give me one!") print('Example: python3 anifinity.py "Guts__"') sys.exit(1) username = sys.argv[1].strip() if len(sys.argv) <= 2: usr = username else: usr = sys.argv[2].strip() jikan = Jikan() print("Downloading your friends from MyAnimeList...") # friends info ufriends = jikan.user(username=usr, request='friends') print("Downloaded {} friends".format(len(ufriends["friends"]))) # Download the users myanimelist print("Downloading {}'s animelist...".format(username)) af = Aniffinity(username, base_service="MyAnimeList", wait_time=2) # e.g. results = {"some_user": affinity_val} results = {} # create a list of friend names friend_names = [f["username"] for f in ufriends["friends"]] while len(friend_names) > 0: # while the list isn't empty friend = friend_names[0] # get the first name
archive = jikan.season_archive() pprint(archive) later = jikan.season_later() pprint(later) monday = jikan.schedule(day="monday") pprint(monday) top_anime = jikan.top(type="anime") pprint(top_anime) action = jikan.genre(type="anime", genre_id=1) pprint(action) deen = jikan.producer(producer_id=37) pprint(deen) jump = jikan.magazine(magazine_id=83) pprint(jump) nekomata1037 = jikan.user(username="******") pprint(nekomata1037) fantasy_anime_league = jikan.club(379) pprint(fantasy_anime_league) meta = jikan.meta(request="requests", type="anime", period="today") pprint(meta)
lists = args.lists_include if args.lists_include is not None else default_lists page_lim = args.debug_page_lim # for simpleler debugging page_lim_enable = page_lim > 0 move_to_other_fold = args.m # where music will be stored and other data music_folder = args.dir # music_folder = r'C:\Users\Host\Music\Mal' username = args.username main_fold = path.join(music_folder, username) cprint('[I] Starting program', 'green') # check if profile exist or some other error like lacking internet occurs try: jikan.user(username, 'profile') except jikanpy.exceptions.APIException as api_err: cprint( '[E] Error occured, maybe lacking internet connection or username provided doesn\'t exists', 'red') exit() # find all already downloaded files in user's music folder downloaded_files = dict() for list in lists: p = path.join(main_fold, list) if path.isdir(p): downloaded_files.update({file: list for file in os.listdir(p)}) # loop over all types of lists for idx_type, list_type in enumerate(lists):
class UserCog(commands.Cog): """ UserCog: handles all the user-related logic. """ def __init__(self, bot): """ Constructor: initialize the cog. :param bot: The Discord bot. """ self.bot = bot self.discordUser = None self.malUser = None self.channel = None self.jikan = Jikan() @commands.command(brief='Ping the bot') async def ping(self, ctx): """ Ping the bot. :param ctx: The context. """ await ctx.send(f'Pong: {round(self.bot.latency*1000)}ms') def start(self): """ Start the UserCog: - retrieves the user from the database, if possible - start the updateMalProfileLoop """ user = self.bot.get_cog('DatabaseCog').getUser() if user: try: self.malUser = self._getMALProfile(user['mal']) except jikanpy.exceptions.APIException: pass self.discordUser = self._getMember(user['discord']) self.channel = self._getChannel(user['channel']) self.bot.command_prefix = user['prefix'] self.updateMalProfileLoop.start() def _getMALProfile(self, username): """ Get the MyAnimeList user object, given the username. :param username: The username of the MAL account. :return: The MAL user. """ return self.jikan.user(username=username) def _updateMALProfile(self, profile): """ Update the internal MAL user, i.e. updating the watching/reading list. :param profile: The username of the MAL account. """ try: newAnimeList = [] watching = self.jikan.user(username=profile, request='animelist', argument='watching')['anime'] ptw = self.jikan.user(username=profile, request='animelist', argument='ptw')['anime'] for anime in watching + ptw: anime['title_english'] = self.jikan.anime(anime['mal_id'])['title_english'] newAnimeList.append(anime) newMangaList = [] reading = self.jikan.user(username=profile, request='mangalist', argument='reading')['manga'] ptr = self.jikan.user(username=profile, request='mangalist', argument='ptr')['manga'] for manga in reading + ptr: manga['title_english'] = self.jikan.manga(manga['mal_id'])['title_english'] newMangaList.append(manga) # If for some reason, we cannot retrieve the new lists (e.g. API error), keep the old ones if newAnimeList: self.bot.get_cog('AnimeCog').list = newAnimeList if newMangaList: self.bot.get_cog('MangaCog').list = newMangaList except Exception as e: # There's nothing we can do :'( print(str(e)) def _getMember(self, user): """ Get the Discord member object, give its name and tag. :param user: The user (name + tag). :return: The member object, if none can be found, return None. """ for member in self.bot.get_all_members(): if str(member) == user: return member return None def _getChannel(self, channelName): """ Get the Discord channel object, give the name of the channel. :param channelName: The name of the channel. :return: The channel object, if none can be found, return None. """ for channel in self.bot.get_all_channels(): if str(channel) == channelName: return channel return None @commands.command(brief='Set your MAL profile') async def setProfile(self, ctx, profile: str): """ Set the internal MAL account, as well as the discord account and bot channel. :param ctx: The context. :param profile: Name of the MAL account. """ try: self.malUser = self._getMALProfile(profile) except jikanpy.exceptions.APIException: await ctx.send(f'Unable to find user {profile}, make sure the profile is public.') return await ctx.send( 'Successfully set profile, you\'ll now receive notifications for new anime episodes and manga chapters!') self.discordUser = ctx.author if self.channel is None: self.channel = ctx.channel # Store data in database self.bot.get_cog('DatabaseCog').addUser(profile, str(self.discordUser), str(self.channel)) self._updateMALProfile(profile) @commands.command(brief='Remove your MAL profile from the bot') async def removeProfile(self, ctx): self.bot.get_cog('DatabaseCog').truncateUsers() self.discordUser = None self.malUser = None self.channel = None self.bot.get_cog('AnimeCog').list = [] self.bot.get_cog('MangaCog').list = [] await ctx.send('Successfully removed you from the bot!') @commands.command(brief='Get a brief overview of your MAL profile') async def getProfile(self, ctx): """ Get the MAL profile in form of an embed :param ctx: The context. """ if self.malUser: embed = discord.Embed(title=self.malUser['username'], color=discord.Color.green()) embed.add_field(name="Watching/Plan-to-Watch", value=str(len(self.bot.get_cog('AnimeCog').list))) embed.add_field(name="Reading/Plan-to-Read", value=str(len(self.bot.get_cog('MangaCog').list))) embed.add_field(name="Link", value=self.malUser['url']) embed.set_thumbnail(url=self.malUser['image_url']) await ctx.send(embed=embed) else: await ctx.send("Profile is not set, please use `!setProfile <USERNAME>` first.") @commands.command(brief='Set the bot channel (where it will ping you)') async def setChannel(self, ctx, channel: discord.TextChannel): """ Set the bot channel. :param ctx: The context. :param channel: Name of the bot channel. """ self.channel = channel self.bot.get_cog('DatabaseCog').addUser(self.malUser['username'], str(self.discordUser), str(channel)) await ctx.send(f'Successfully set bot channel to {channel.mention}.') @commands.command(brief='Set the prefix of the bot') async def setPrefix(self, ctx, prefix: str): """ Set the prefix of the bot :param ctx: The context. :param prefix: The new prefix for the bot. """ self.bot.command_prefix = prefix self.bot.get_cog('DatabaseCog').addUser(self.malUser['username'], str(self.discordUser), str(self.channel), prefix) await ctx.send(f'Successfully set the prefix to `{prefix}`.') @setChannel.error async def setChannelError(self, ctx, error): """ Error Handler for setChannel. :param ctx: The context. :param error: The error raised. """ await ctx.send(error.args[0]) @tasks.loop(hours=1) async def updateMalProfileLoop(self): """ Loop that periodically updates the MAL account, i.e. update watching/reading list. """ if self.malUser: await self._updateMALProfile(self.malUser['username'])