Skip to content

Commit

Permalink
Merge pull request #355 from HelloYeew/map-info
Browse files Browse the repository at this point in the history
Add beatmap info to beatmap card
  • Loading branch information
HelloYeew authored Jun 13, 2022
2 parents 28537c3 + 59281b8 commit 8442499
Show file tree
Hide file tree
Showing 16 changed files with 333 additions and 4 deletions.
8 changes: 8 additions & 0 deletions rurusetto/users/static/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,14 @@ a.dropdown-item {
#desktop-header {
opacity: 0;
}

.beatmap-stat-text {
text-align: left!important;
}

.beatmap-info-modal {
background-image: none!important;
}
}

@media (max-width: 991px) {
Expand Down
18 changes: 17 additions & 1 deletion rurusetto/wiki/action.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
"""File that contain all action command that can run from web interface."""

from django.core.exceptions import ObjectDoesNotExist
from django.utils import timezone
from django.db.models.functions import datetime
from .function import source_link_type
from .models import RecommendBeatmap, Ruleset, RulesetStatus
from rurusetto.settings import OSU_API_V1_KEY, GITHUB_TOKEN
from django.core.files.temp import NamedTemporaryFile
from django.core.files import File
from django.utils.timezone import make_aware
from django.utils import timezone
import requests
import os
import time
Expand Down Expand Up @@ -118,6 +120,20 @@ def update_all_beatmap_action(action):
beatmap.bpm = beatmap_json_data['bpm']
beatmap.version = beatmap_json_data['version']
beatmap.url = f"https://osu.ppy.sh/beatmapsets/{beatmap_json_data['beatmapset_id']}#osu/{beatmap.beatmap_id}"
beatmap.playcount = beatmap_json_data['playcount']
beatmap.favourite_count = beatmap_json_data['favourite_count']
beatmap.total_length = beatmap_json_data['total_length']
beatmap.creator_id = beatmap_json_data['creator_id']
beatmap.genre_id = beatmap_json_data['genre_id']
beatmap.language_id = beatmap_json_data['language_id']
beatmap.tags = beatmap_json_data['tags']
beatmap.submit_date = make_aware(
datetime.datetime.strptime(beatmap_json_data['submit_date'], '%Y-%m-%d %H:%M:%S'))
if beatmap_json_data['approved_date'] is not None:
beatmap.approved_date = make_aware(
datetime.datetime.strptime(beatmap_json_data['approved_date'], '%Y-%m-%d %H:%M:%S'))
beatmap.last_update = make_aware(
datetime.datetime.strptime(beatmap_json_data['last_update'], '%Y-%m-%d %H:%M:%S'))
beatmap.save()
success += 1
except ObjectDoesNotExist:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Generated by Django 4.0.5 on 2022-06-13 05:57

from django.db import migrations, models
import django.utils.timezone


class Migration(migrations.Migration):

dependencies = [
('wiki', '0057_alter_ruleset_direct_download_link'),
]

operations = [
migrations.AddField(
model_name='recommendbeatmap',
name='approved_date',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name='recommendbeatmap',
name='creator_id',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='recommendbeatmap',
name='favourite_count',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='recommendbeatmap',
name='genre_id',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='recommendbeatmap',
name='language_id',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='recommendbeatmap',
name='last_update',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name='recommendbeatmap',
name='playcount',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='recommendbeatmap',
name='submit_date',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name='recommendbeatmap',
name='tags',
field=models.CharField(blank=True, max_length=5000),
),
migrations.AddField(
model_name='recommendbeatmap',
name='total_length',
field=models.IntegerField(default=0),
),
]
13 changes: 13 additions & 0 deletions rurusetto/wiki/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.contrib.auth.models import User
from mdeditor.fields import MDTextField
from django.contrib.sitemaps import ping_google
from django.utils import timezone
from PIL import Image


Expand Down Expand Up @@ -221,6 +222,18 @@ class RecommendBeatmap(models.Model):
beatmap_list = models.ImageField(default='default_beatmap_thumbnail.jpeg', upload_to='beatmap_list', validators=[
FileExtensionValidator(allowed_extensions=['png', 'gif', 'jpg', 'jpeg', 'bmp', 'svg', 'webp'])])

playcount = models.IntegerField(default=0)
favourite_count = models.IntegerField(default=0)
total_length = models.IntegerField(default=0)
creator_id = models.IntegerField(default=0)
genre_id = models.IntegerField(default=0)
language_id = models.IntegerField(default=0)
tags = models.CharField(max_length=5000, blank=True)

submit_date = models.DateTimeField(default=timezone.now)
approved_date = models.DateTimeField(default=timezone.now)
last_update = models.DateTimeField(default=timezone.now)

comment = models.TextField(default=None, blank=True)

created_at = models.DateTimeField(auto_now_add=True)
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@
{% else %}
<p class="card-text text-muted" style="margin-top: -10px"><small>{% trans 'recommend_by' %} <a href="{% url "profile" beatmap.1.id %}" class="hvr-picture-bounce text-decoration-none spacing-hover"><img src="{{ beatmap.1.profile.image.url }}" alt="{{ beatmap.1.username }}" width="32" height="32" class="rounded-circle hvr-icon" style="transition: 0.2s"> {{ beatmap.1.username }}</a></small></p>
{% endif %}
<p class="card-text"><button type="button" class="btn btn-rurusetto btn-sm hvr-bounce-to-bottom" data-bs-toggle="modal" data-bs-target="#modal{{ beatmap.0.beatmap_id }}" style="margin-top: -10px"><i class="fas fa-info-circle color-white"></i> Beatmap Detail</button></p>
<p class="card-text"><a class="btn btn-success btn-sm" href="{% url 'approve_recommend_beatmap' ruleset.slug beatmap.0.id %}" role="button" style="margin-top: -10px"><i class="fas fa-check color-white"></i> {% trans 'approve' %}</a> <a class="btn btn-danger btn-sm" href="{% url 'deny_recommend_beatmap' ruleset.slug beatmap.0.id %}" role="button" style="margin-top: -10px"><i class="fas fa-times color-white"></i> {% trans 'deny' %}</a></p>
</div>
</div>
</div>
</div>
</div>

{% include "wiki/snippets/beatmap_info_modal.html" %}
9 changes: 6 additions & 3 deletions rurusetto/wiki/templates/wiki/snippets/beatmap_card.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% load convert_star_rating %}

{% load i18n %}
{% load static %}

Expand Down Expand Up @@ -36,7 +36,7 @@
<span class="badge rounded-pill round-font-bold" style="background-color: rgb(0, 0, 0); color: rgb(83, 94, 101); margin-top: -2px">{% trans 'graveyard' %}</span>
{% endif %}

</p>
<p></p>
<p class="card-text text-muted" style="margin-top: -5px"><small>{% trans 'mapped_by' %} <a href="https://osu.ppy.sh/u/{{ beatmap.0.creator }}" class="text-decoration-none spacing-hover-short">{{ beatmap.0.creator }}</a></small></p>
<p class="card-text beatmap-comment" style="margin-top: -5px"><small>{{ beatmap.0.comment }}</small></p>
{% if beatmap.1 == None %}
Expand All @@ -45,8 +45,11 @@
<p class="card-text text-muted" style="margin-top: -10px"><small>{% trans 'recommend_by' %} <a href="{% url "profile" beatmap.1.id %}" class="hvr-picture-bounce text-decoration-none spacing-hover"><img src="{{ beatmap.1.profile.image.url }}" alt="{{ beatmap.1.username }}" width="32" height="32" class="rounded-circle hvr-icon" style="transition: 0.2s"> {{ beatmap.1.username }}</a></small></p>
{% endif %}
<a class="btn btn-rurusetto btn-sm hvr-bounce-to-bottom" href="osu://b/{{ beatmap.0.beatmap_id }}" role="button" style="margin-top: -10px"><i class="fas fa-download color-white"></i> osu!direct</a>
<button type="button" class="btn btn-rurusetto btn-sm hvr-bounce-to-bottom" data-bs-toggle="modal" data-bs-target="#modal{{ beatmap.0.beatmap_id }}" style="margin-top: -10px"><i class="fas fa-info-circle color-white"></i> Beatmap Detail</button>
</div>
</div>
</div>
</div>
</div>
</div>

{% include "wiki/snippets/beatmap_info_modal.html" %}
75 changes: 75 additions & 0 deletions rurusetto/wiki/templates/wiki/snippets/beatmap_info_modal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{% load convert_star_rating %}
{% load thousand_seperator %}
{% load length_format %}
{% load round_up %}
{% load get_genre_name %}
{% load get_language_name %}

<div class="modal fade" id="modal{{ beatmap.0.beatmap_id }}" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Beatmap Detail</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body beatmap-info-modal" style="background-image: linear-gradient(to bottom, transparent, #4a4a4a 140px), url({{ beatmap.0.beatmap_cover.url }}); background-size:100%; background-repeat: no-repeat;">
<h4 class="beatmap-title fw-bold">{{ beatmap.0.title }}</h4>
<h6 class="fw-bold">{{ beatmap.0.artist }}</h6>
<h6 class="fw-bold" style="color: #a5a5a5">{{ beatmap.0.version }}</h6>
{% if beatmap.0.approved == "4" %}
<span class="badge rounded-pill bold-font" style="background-color: rgb(241, 101, 160); color: rgb(51, 58, 61); margin-top: -2px">LOVED</span>
{% elif beatmap.0.approved == "3" %}
<span class="badge rounded-pill bold-font" style="background-color: rgb(106, 196, 254); color: rgb(51, 58, 61); margin-top: -2px">QUALIFIED</span>
{% elif beatmap.0.approved == "2" %}
<span class="badge rounded-pill bold-font" style="background-color: rgb(210, 208, 85); color: rgb(51, 58, 61); margin-top: -2px">APPROVED</span>
{% elif beatmap.0.approved == "1" %}
<span class="badge rounded-pill bold-font" style="background-color: rgb(185, 251, 98); color: rgb(51, 58, 61); margin-top: -2px">RANKED</span>
{% elif beatmap.0.approved == "0" %}
<span class="badge rounded-pill bold-font" style="background-color: rgb(252, 212, 96); color: rgb(51, 58, 61); margin-top: -2px">PENDING</span>
{% elif beatmap.0.approved == "-1" %}
<span class="badge rounded-pill bold-font" style="background-color: rgb(245, 146, 93); color: rgb(51, 58, 61); margin-top: -2px">WIP</span>
{% elif beatmap.0.approved == "-2" %}
<span class="badge rounded-pill bold-font" style="background-color: rgb(0, 0, 0); color: rgb(83, 94, 101); margin-top: -2px">GRAVEYARD</span>
{% endif %}
<i class="fas fa-play-circle"></i> {{ beatmap.0.playcount | thousand_seperator }}
<i class="fas fa-heart"></i> {{ beatmap.0.favourite_count | thousand_seperator }}
<p></p>
<div class="row">
<div class="col-sm-2">
<img src="https://s.ppy.sh/a/{{ beatmap.0.creator_id }}" width="120px" height="120px" alt="{{ beatmap.0.creator }}'s profile" class="rounded-3">
</div>
<div class="col-sm-10">
<p class="beatmap-infobox-date">mapped by <a href="https://osu.ppy.sh/users/{{ beatmap.0.creator_id }}" class="text-decoration-none spacing-hover">{{ beatmap.0.creator }}</a></p>
<p class="beatmap-infobox-date">submitted {{ beatmap.0.submit_date | date:"j F Y H:i:s" }} UTC</p>
{% if beatmap.0.approved == '1' %}
<p class="beatmap-infobox-date">ranked {{ beatmap.0.approved_date | date:"j F Y H:i:s" }} UTC</p>
{% elif beatmap.0.approved == '3' %}
<p class="beatmap-infobox-date">qualified {{ beatmap.0.approved_date | date:"j F Y H:i:s" }} UTC</p>
{% else %}
<p class="beatmap-infobox-date">last updated {{ beatmap.0.last_update | date:"j F Y H:i:s" }} UTC</p>
{% endif %}
</div>
</div>
{% if beatmap.0.source %}
<p class="fw-bold">Source</p>
<p>{{ beatmap.0.source }}</p>
{% endif %}
<div class="row">
<div class="col-sm-6">
<p class="fw-bold">Genre</p>
<p>{{ beatmap.0.genre_id|get_genre_name }}</p>
</div>
<div class="col-sm-6">
<p class="fw-bold">Language</p>
<p>{{ beatmap.0.language_id|get_language_name }}</p>
</div>

</div>
{% if beatmap.0.tags %}
<p class="fw-bold">Tags</p>
<p>{{ beatmap.0.tags }}</p>
{% endif %}
</div>
</div>
</div>
</div>
42 changes: 42 additions & 0 deletions rurusetto/wiki/templatetags/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Constants of osu! api.
It is not really constant because osu! API may change.
"""

languages = {
0: "Any",
1: "Unspecified",
2: "English",
3: "Japanese",
4: "Chinese",
5: "Instrumental",
6: "Korean",
7: "French",
8: "German",
9: "Swedish",
10: "Spanish",
11: "Italian",
12: "Russian",
13: "Polish",
14: "Other"
# Default value is Unknown.
}

genres = {
0: "Any",
1: "Unspecified",
2: "Video Game",
3: "Anime",
4: "Rock",
5: "Pop",
6: "Other",
7: "Novelty",
# 8 is missing.
9: "Hip-hop",
10: "Electronic",
11: "Metal",
12: "Classical",
13: "Folk",
14: "Jazz",
# Default is unknown.
}
13 changes: 13 additions & 0 deletions rurusetto/wiki/templatetags/get_genre_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import Union
from django import template
from . import constants

register = template.Library()


def get_genre_name(genre_id: Union[str, int]):
"""Get genre name from osu! genre id."""
genre_id = int(genre_id)
return constants.genres.get(genre_id, "Unknown")

register.filter('get_genre_name', get_genre_name)
13 changes: 13 additions & 0 deletions rurusetto/wiki/templatetags/get_language_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import Union
from django import template
from . import constants

register = template.Library()


def get_language_name(language_id: Union[str, int]):
"""Get language from osu! language id."""
language_id = int(language_id)
return constants.languages.get(language_id, "Unknown")

register.filter('get_language_name', get_language_name)
24 changes: 24 additions & 0 deletions rurusetto/wiki/templatetags/length_format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django import template
from time import strftime, gmtime

register = template.Library()


def length_format(length):
"""Convert second to minutes and second. Mainly use in beatmap time length.
Args:
length (int): Length of the beatmap in second.
Returns:
str: Formatted length of the beatmap.
"""
if type(length) is not int:
try:
length = int(length)
except ValueError:
return "0:00"
if length >= 3600:
return strftime("%H:%M:%S", gmtime(length))
return strftime("%M:%S", gmtime(int(length)))


register.filter('length_format', length_format)
21 changes: 21 additions & 0 deletions rurusetto/wiki/templatetags/round_up.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django import template
import math

register = template.Library()


def round_up(value):
"""
Rounds up a value to the nearest integer.
Arguments:
value (float): The value to round up.
Returns:
int: The rounded up value.
"""
try:
return int(math.ceil(float(value)))
except ValueError:
return value


register.filter('round_up', round_up)
Loading

0 comments on commit 8442499

Please sign in to comment.