Beispiel #1
0
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
Beispiel #2
0
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
        ]
Beispiel #3
0
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"))
Beispiel #5
0
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()
Beispiel #6
0
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
Beispiel #8
0
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
Beispiel #9
0
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")
Beispiel #11
0
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
Beispiel #15
0
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)
Beispiel #16
0
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):
Beispiel #17
0
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'])