Beispiel #1
0
    def setUp(self):
        user = get_user_model().objects.create_user(username='******',
                                                    password='******')
        otaku = get_user_model().objects.create_user(username='******',
                                                     password='******')
        otaku2 = get_user_model().objects.create_user(username='******',
                                                      password='******')
        self.anime_category = Category.objects.get(slug='anime')
        manga = Category.objects.get(slug='manga')

        works = [
            Work(title='Anime B', nb_episodes=0, category=self.anime_category),
            Work(title='Anime A', nb_episodes=1, category=self.anime_category),
            Work(title='Manga B', category=manga),
            Work(title='Manga A', category=manga),
        ]
        works = Work.objects.bulk_create(works)

        # This will work as long as mangaki.algo.dataset.RATED_BY_AT_LEAST <= 2
        ratings = (
            [Rating(user=otaku, work=work, choice='like')
             for work in works] + [
                 Rating(user=otaku2, work=work, choice='dislike')
                 for work in works
             ] + [Rating(user=user, work=works[0], choice='dislike')])
        Rating.objects.bulk_create(ratings)

        if not os.path.exists(SNAPSHOT_DIR_TEST):
            os.makedirs(SNAPSHOT_DIR_TEST)
Beispiel #2
0
    def setUp(self):
        self.user = get_user_model().objects.create_user(username='******',
                                                         password='******')
        otaku = get_user_model().objects.create_user(username='******',
                                                     password='******')
        otaku2 = get_user_model().objects.create_user(username='******',
                                                      password='******')
        self.anime_category = Category.objects.get(slug='anime')
        manga = Category.objects.get(slug='manga')

        works = [
            Work(title='Anime B', nb_episodes=0, category=self.anime_category),
            Work(title='Anime A', nb_episodes=1, category=self.anime_category),
            Work(title='Manga B', category=manga),
            Work(title='Manga A', category=manga),
        ]
        works = Work.objects.bulk_create(works)
        self.work = works[0]

        # This will work as long as zero.dataset.RATED_BY_AT_LEAST <= 2
        ratings = (
            [Rating(user=otaku, work=work, choice='like')
             for work in works] + [
                 Rating(user=otaku2, work=work, choice='dislike')
                 for work in works
             ] + [Rating(user=self.user, work=works[0], choice='dislike')])
        Rating.objects.bulk_create(ratings)

        if not os.path.exists(ML_SNAPSHOT_ROOT_TEST):
            os.makedirs(ML_SNAPSHOT_ROOT_TEST)
            for key in {'svd', 'als', 'knn', 'knn-anonymous'}:
                path = get_path(key)
                if not os.path.exists(path):
                    os.makedirs(path)
Beispiel #3
0
 def signup(self, request, user):
     if self.cleaned_data['import_ratings']:
         ratings = get_anonymous_ratings(request.session)
         clear_anonymous_ratings(request.session)
         Rating.objects.bulk_create([
             Rating(user=user, work_id=work_id, choice=choice)
             for work_id, choice in ratings.items()
         ])
Beispiel #4
0
def get_profile_ratings(request,
                        category: str,
                        already_seen: bool,
                        can_see: bool,
                        is_anonymous: bool,
                        user: User) -> Tuple[List[Rating], Counter]:
    counts = Counter()
    if is_anonymous:
        ratings = []
        anon_ratings = get_anonymous_ratings(request.session)
        works_per_pk = Work.objects.select_related('category').in_bulk(anon_ratings.keys())
        for pk, choice in anon_ratings.items():
            rating = Rating()
            rating.work = works_per_pk[pk]
            rating.choice = choice

            seen_work = rating.choice not in SEE_CHOICES['unseen']
            count_key = 'seen_{}' if seen_work else 'unseen_{}'
            counts[count_key.format(rating.work.category.slug)] += 1

            if already_seen == seen_work and rating.work.category.slug == category:
                ratings.append(rating)
    elif can_see:
        ratings = list(
            Rating.objects
                .filter(user=user,
                        work__category__slug=category,
                        choice__in=SEE_CHOICES['seen'] if already_seen else SEE_CHOICES['unseen'])
                .select_related('work', 'work__category')
        )

        categories = Category.objects.all()
        for category in categories:
            qs = Rating.objects.filter(user=user,
                                       work__category=category)

            seen = qs.filter(choice__in=SEE_CHOICES['seen']).count()
            unseen = qs.count() - seen

            counts['seen_{}'.format(category.slug)] = seen
            counts['unseen_{}'.format(category.slug)] = unseen
    else:
        ratings = []

    return ratings, counts
Beispiel #5
0
def import_mal(mal_username, mangaki_username):
    """
    Import myAnimeList by username
    """

    MAL_URL = 'http://myanimelist.net/malappinfo.php?u=%s&status=all&type=anime' % mal_username
    HEADERS = {'X-Real-IP': random_ip(), 'User-Agent': MAL_USER_AGENT}
    r = requests.get(MAL_URL, headers=HEADERS)
    xml = ET.fromstring(r.text)
    user = User.objects.get(username=mangaki_username)
    nb_added = 0
    fails = []
    for entry in xml:
        if entry.tag == 'anime':
            title = entry.find('series_title').text
            poster = entry.find('series_image').text
            score = int(entry.find('my_score').text)
            mal_id = entry.find('series_animedb_id').text
            try:
                animes = Work.objects.filter(category__slug='anime')
                try:
                    anime = animes.get(title=title)
                except Work.DoesNotExist:
                    if animes.filter(poster=poster).count() == 1:
                        anime = Work.objects.get(poster=poster)
                    elif animes.filter(poster=poster).count() >= 2:
                        raise Exception(
                            'Integrity violation: found two or more works with the same poster, do you come from the past?'
                        )
                    else:
                        entries = lookup_mal_api(title)
                        retrieve_anime(entries)
                        anime = animes.get(poster=poster)
                if anime:
                    if not Rating.objects.filter(user=user,
                                                 work=anime).count():
                        if 7 <= score <= 10:
                            choice = 'like'
                        elif 5 <= score <= 6:
                            choice = 'neutral'
                        elif score > 0:
                            choice = 'dislike'
                        else:
                            continue
                        Rating(user=user, work=anime, choice=choice).save()
                        nb_added += 1
            except Exception as e:
                print(e)
                SearchIssue(user=user,
                            title=title,
                            poster=poster,
                            mal_id=mal_id,
                            score=score).save()
                fails.append(title)
    return nb_added, fails
Beispiel #6
0
    def signup(self, request, user):
        if self.cleaned_data['import_ratings']:
            ratings = get_anonymous_ratings(request.session)
            clear_anonymous_ratings(request.session)
            Rating.objects.bulk_create([
                Rating(user=user, work_id=work_id, choice=choice)
                for work_id, choice in ratings.items()
            ])

        Profile.objects.filter(id=user.profile.pk).update(
            newsletter_ok=self.cleaned_data['newsletter_ok'],
            research_ok=self.cleaned_data['research_ok'])
Beispiel #7
0
def import_mal(mal_username: str, mangaki_username: str):
    """
    Import myAnimeList by username
    """

    user = User.objects.get(username=mangaki_username)
    fails = []
    mangaki_lists = {
        MALWorks.animes: Work.objects.filter(category__slug='anime'),
        MALWorks.mangas: Work.objects.filter(category__slug='manga')
    }
    scores = {}
    willsee = set()
    wontsee = set()

    for work_type in SUPPORTED_MANGAKI_WORKS:
        user_works = set(client.list_works_from_a_user(work_type,
                                                       mal_username))
        logger.info('Fetching {} works from {}\'s MAL.'.format(
            len(user_works), mal_username))
        for user_work in user_works:
            try:
                work = get_or_create_from_mal(mangaki_lists[work_type],
                                              work_type, user_work.title,
                                              user_work.synonyms,
                                              user_work.poster)

                if (work and
                        not any(work.id in container
                                for container in (scores, wontsee, willsee))):
                    if user_work.status == MALStatus.completed:
                        scores[work.id] = user_work.score
                    elif user_work.status == MALStatus.dropped:
                        wontsee.add(work.id)
                    elif user_work.status == MALStatus.plan_to_watch:
                        willsee.add(work.id)
            except Exception:
                logger.exception(
                    'Failure to fetch the work from MAL and import it into the Mangaki database.'
                )
                SearchIssue(user=user,
                            title=user_work.title,
                            poster=user_work.poster,
                            mal_id=user_work.mal_id,
                            score=user_work.score).save()
                fails.append(user_work.title)

    existing_ratings = (Rating.objects.filter(
        user=user, work__in=scores.keys()).values_list('work',
                                                       flat=True).all())

    for related_work_id in existing_ratings:
        del scores[related_work_id]

    ratings = []
    for work_id, score in scores.items():
        choice = compute_rating_choice_from_mal_score(score)
        if not choice:
            raise RuntimeError('No choice was deduced from MAL score!')

        rating = Rating(user=user, choice=choice, work_id=work_id)
        ratings.append(rating)

    for work_id in willsee:
        rating = Rating(user=user, choice='willsee', work_id=work_id)
        ratings.append(rating)

    for work_id in wontsee:
        rating = Rating(user=user, choice='wontsee', work_id=work_id)
        ratings.append(rating)

    Rating.objects.bulk_create(ratings)

    return len(ratings), fails
Beispiel #8
0
    def setUp(self):
        self.user = get_user_model().objects.create_superuser(
            username='******', password='******', email='*****@*****.**')
        self.users = []
        for username in 'ABCD':
            self.users.append(get_user_model().objects.create_user(
                username=username, password='******'))

        today = datetime.now()
        yesterday = datetime.now() - timedelta(1)
        tomorrow = datetime.now() + timedelta(1)

        anime = Category.objects.get(slug='anime')

        Work.objects.bulk_create([
            Work(title='Sangatsu no Lion', category=anime) for _ in range(10)
        ])
        Work.objects.create(title='Sangatsu no Lion',
                            category=anime,
                            nb_episodes=22)

        self.work_ids = Work.objects.values_list('id', flat=True)
        # Admin rated every movie
        Rating.objects.bulk_create([
            Rating(work_id=work_id, user=self.user, choice='like')
            for work_id in self.work_ids
        ])

        the_artist = Artist.objects.create(name='Yoko Kanno')

        references = []
        for work_id in self.work_ids:
            references.extend(
                Reference.objects.bulk_create([
                    Reference(work_id=work_id,
                              source='MAL',
                              identifier=31646,
                              url='https://myanimelist.net/anime/31646'),
                    Reference(
                        work_id=work_id,
                        source='AniDB',
                        identifier=11606,
                        url=
                        'https://anidb.net/perl-bin/animedb.pl?show=anime&aid=11606'
                    )
                ]))

        roles = Role.objects.bulk_create([
            Role(name='Director', slug='xxx'),
            Role(name='Composer', slug='yyy')
        ])

        Staff.objects.bulk_create([
            Staff(work_id=self.work_ids[0], artist=the_artist, role=roles[0]),
            Staff(work_id=self.work_ids[1], artist=the_artist, role=roles[0]),
            Staff(work_id=self.work_ids[1], artist=the_artist, role=roles[1])
        ])

        genres = Genre.objects.bulk_create(
            [Genre(title='SF'),
             Genre(title='Slice of life')])
        Work.objects.get(id=self.work_ids[0]).genre.add(genres[0])
        Work.objects.get(id=self.work_ids[1]).genre.add(genres[0])
        Work.objects.get(id=self.work_ids[1]).genre.add(genres[1])

        # Rating are built so that after merge, only the favorites should be kept
        Rating.objects.bulk_create([
            Rating(work_id=self.work_ids[0],
                   user=self.users[0],
                   choice='like',
                   date=today),
            Rating(work_id=self.work_ids[1],
                   user=self.users[0],
                   choice='favorite',
                   date=tomorrow),
            Rating(work_id=self.work_ids[2],
                   user=self.users[0],
                   choice='dislike',
                   date=yesterday),
            Rating(work_id=self.work_ids[1],
                   user=self.users[1],
                   choice='favorite',
                   date=today),
            Rating(work_id=self.work_ids[0],
                   user=self.users[2],
                   choice='favorite',
                   date=today),
            Rating(work_id=self.work_ids[2],
                   user=self.users[2],
                   choice='like',
                   date=yesterday),
            Rating(work_id=self.work_ids[0],
                   user=self.users[3],
                   choice='favorite',
                   date=yesterday)
        ])
        Rating.objects.filter(work_id=self.work_ids[1],
                              user=self.users[0]).update(date=tomorrow)
        Rating.objects.filter(work_id=self.work_ids[2],
                              user=self.users[0]).update(date=yesterday)
        Rating.objects.filter(work_id=self.work_ids[2],
                              user=self.users[2]).update(date=yesterday),
        Rating.objects.filter(work_id=self.work_ids[0],
                              user=self.users[3]).update(date=yesterday)
Beispiel #9
0
def import_mal(mal_username: str, mangaki_username: str, update_callback=None):
    """
    Import myAnimeList by username
    """

    user = User.objects.get(username=mangaki_username)
    fails = []
    mangaki_lists = {
        MALWorks.animes: Work.objects.filter(category__slug='anime'),
        MALWorks.mangas: Work.objects.filter(category__slug='manga')
    }
    scores = {}
    willsee = set()
    wontsee = set()

    for work_type in SUPPORTED_MANGAKI_WORKS:
        user_works = set(client.list_works_from_a_user(work_type,
                                                       mal_username))
        logger.info('Fetching {} works from {}\'s MAL.'.format(
            len(user_works), mal_username))
        for current_index, user_work in enumerate(user_works):
            try:
                work = get_or_create_from_mal(mangaki_lists[work_type],
                                              work_type, user_work.title,
                                              user_work.synonyms,
                                              user_work.poster,
                                              user_work.mal_id)

                if (work and
                        not any(work.id in container
                                for container in (scores, wontsee, willsee))):
                    if user_work.status == MALStatus.completed:
                        scores[work.id] = user_work.score
                    elif user_work.status == MALStatus.dropped:
                        wontsee.add(work.id)
                    elif user_work.status == MALStatus.plan_to_watch:
                        willsee.add(work.id)

                if update_callback:
                    update_callback(len(user_works), current_index + 1,
                                    user_work.title)
            except Exception:
                logger.exception(
                    'Failure to fetch the work from MAL and import it into the Mangaki database.'
                )
                fails.append(user_work.title)

    # MAL is the source of truth for further imports, rather than our own database of ratings.
    Rating.objects.filter(user=user,
                          work__in=list(scores.keys()) +
                          list(willsee | wontsee)).delete()
    ratings = []
    for work_id, score in scores.items():
        choice = compute_rating_choice_from_mal_score(score)
        if not choice:
            raise RuntimeError('No choice was deduced from MAL score!')

        rating = Rating(user=user, choice=choice, work_id=work_id)
        ratings.append(rating)

    for work_id in willsee:
        rating = Rating(user=user, choice='willsee', work_id=work_id)
        ratings.append(rating)

    for work_id in wontsee:
        rating = Rating(user=user, choice='wontsee', work_id=work_id)
        ratings.append(rating)

    Rating.objects.bulk_create(ratings)

    return len(ratings), fails