From f645530cb4c9b6edb7abe2ffb796f6607b53fb1d Mon Sep 17 00:00:00 2001 From: spellew Date: Sun, 16 Jun 2019 13:15:04 -0400 Subject: [PATCH 01/20] Changes made to SQL scripts in order to support the reviewal of recordings --- admin/schema_changes/16.sql | 1 + admin/sql/create_types.sql | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/admin/schema_changes/16.sql b/admin/schema_changes/16.sql index b1f4e5377..fd697495f 100644 --- a/admin/schema_changes/16.sql +++ b/admin/schema_changes/16.sql @@ -1 +1,2 @@ ALTER TYPE entity_types ADD VALUE 'artist' AFTER 'place'; +ALTER TYPE entity_types ADD VALUE 'recording' AFTER 'artist'; diff --git a/admin/sql/create_types.sql b/admin/sql/create_types.sql index ea9218c2d..4b6ed15b1 100644 --- a/admin/sql/create_types.sql +++ b/admin/sql/create_types.sql @@ -9,5 +9,6 @@ CREATE TYPE entity_types AS ENUM ( 'release_group', 'event', 'place', - 'artist' + 'artist', + 'recording' ); From 1f440a8fadcaa32385f9e992ef43f8a9810e7544 Mon Sep 17 00:00:00 2001 From: spellew Date: Sun, 16 Jun 2019 13:23:01 -0400 Subject: [PATCH 02/20] Implemented the retrieval of recordings through brainzutils --- .../external/musicbrainz_db/entities.py | 8 +++++++ .../external/musicbrainz_db/recording.py | 22 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 critiquebrainz/frontend/external/musicbrainz_db/recording.py diff --git a/critiquebrainz/frontend/external/musicbrainz_db/entities.py b/critiquebrainz/frontend/external/musicbrainz_db/entities.py index 7210e20ef..a1ed23bfe 100644 --- a/critiquebrainz/frontend/external/musicbrainz_db/entities.py +++ b/critiquebrainz/frontend/external/musicbrainz_db/entities.py @@ -1,3 +1,4 @@ +from brainzutils.musicbrainz_db.recording import fetch_multiple_recordings from brainzutils.musicbrainz_db.artist import fetch_multiple_artists from brainzutils.musicbrainz_db.place import fetch_multiple_places from brainzutils.musicbrainz_db.event import fetch_multiple_events @@ -6,6 +7,7 @@ from critiquebrainz.frontend.external.musicbrainz_db.place import get_place_by_id from critiquebrainz.frontend.external.musicbrainz_db.event import get_event_by_id from critiquebrainz.frontend.external.musicbrainz_db.artist import get_artist_by_id +from critiquebrainz.frontend.external.musicbrainz_db.recording import get_recording_by_id def get_multiple_entities(entities): @@ -26,6 +28,7 @@ def get_multiple_entities(entities): entities_info = {} release_group_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'release_group', entities)] artist_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'artist', entities)] + recording_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'recording', entities)] place_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'place', entities)] event_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'event', entities)] entities_info.update(fetch_multiple_release_groups( @@ -35,6 +38,9 @@ def get_multiple_entities(entities): entities_info.update(fetch_multiple_artists( artist_mbids, )) + entities_info.update(fetch_multiple_recordings( + recording_mbids, + )) entities_info.update(fetch_multiple_places( place_mbids, )) @@ -50,6 +56,8 @@ def get_entity_by_id(id, type='release_group'): entity = get_release_group_by_id(str(id)) elif type == 'artist': entity = get_artist_by_id(str(id)) + elif type == 'recording': + entity = get_recording_by_id(str(id)) elif type == 'place': entity = get_place_by_id(str(id)) elif type == 'event': diff --git a/critiquebrainz/frontend/external/musicbrainz_db/recording.py b/critiquebrainz/frontend/external/musicbrainz_db/recording.py new file mode 100644 index 000000000..4b33f0f6e --- /dev/null +++ b/critiquebrainz/frontend/external/musicbrainz_db/recording.py @@ -0,0 +1,22 @@ +from brainzutils import cache +from brainzutils.musicbrainz_db.recording import fetch_multiple_recordings +from critiquebrainz.frontend.external.musicbrainz_db import DEFAULT_CACHE_EXPIRATION + + +def get_recording_by_id(mbid): + """Get recording with MusicBrainz ID. + + Args: + mbid (uuid): MBID(gid) of the recording. + Returns: + Dictionary containing the recording information + """ + key = cache.gen_key(mbid) + recording = cache.get(key) + if not recording: + recording = fetch_multiple_recordings( + [mbid], + includes=['artist-rels', 'work-rels', 'url-rels'], + ).get(mbid) + cache.set(key=key, val=recording, time=DEFAULT_CACHE_EXPIRATION) + return recording From e4d1bc4d19a8d143b3eb86322fe479ba7117b5d4 Mon Sep 17 00:00:00 2001 From: spellew Date: Sun, 16 Jun 2019 13:35:11 -0400 Subject: [PATCH 03/20] Implemented the searching of recordings --- critiquebrainz/frontend/__init__.py | 2 + .../frontend/external/musicbrainz.py | 6 +++ critiquebrainz/frontend/templates/navbar.html | 3 +- .../frontend/templates/recording/entity.html | 1 + .../templates/release_group/entity.html | 2 +- .../frontend/templates/search/index.html | 8 ++++ .../frontend/templates/search/results.html | 24 +++++++++++ .../frontend/templates/search/selector.html | 31 ++++++++++++++ .../templates/search/selector_results.html | 31 +++++++++++++- critiquebrainz/frontend/views/recording.py | 41 +++++++++++++++++++ critiquebrainz/frontend/views/search.py | 10 ++++- 11 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 critiquebrainz/frontend/templates/recording/entity.html create mode 100644 critiquebrainz/frontend/views/recording.py diff --git a/critiquebrainz/frontend/__init__.py b/critiquebrainz/frontend/__init__.py index 6082ba867..5421acd4e 100644 --- a/critiquebrainz/frontend/__init__.py +++ b/critiquebrainz/frontend/__init__.py @@ -133,6 +133,7 @@ def create_app(debug=None, config_path=None): from critiquebrainz.frontend.views.artist import artist_bp from critiquebrainz.frontend.views.release_group import release_group_bp from critiquebrainz.frontend.views.release import release_bp + from critiquebrainz.frontend.views.recording import recording_bp from critiquebrainz.frontend.views.event import event_bp from critiquebrainz.frontend.views.mapping import mapping_bp from critiquebrainz.frontend.views.user import user_bp @@ -154,6 +155,7 @@ def create_app(debug=None, config_path=None): app.register_blueprint(artist_bp, url_prefix='/artist') app.register_blueprint(release_group_bp, url_prefix='/release-group') app.register_blueprint(release_bp, url_prefix='/release') + app.register_blueprint(recording_bp, url_prefix='/recording') app.register_blueprint(event_bp, url_prefix='/event') app.register_blueprint(place_bp, url_prefix='/place') app.register_blueprint(mapping_bp, url_prefix='/mapping') diff --git a/critiquebrainz/frontend/external/musicbrainz.py b/critiquebrainz/frontend/external/musicbrainz.py index f4711f69b..ab48e2157 100644 --- a/critiquebrainz/frontend/external/musicbrainz.py +++ b/critiquebrainz/frontend/external/musicbrainz.py @@ -44,3 +44,9 @@ def search_places(query='', limit=None, offset=None): """Search for places.""" api_resp = musicbrainzngs.search_places(query=query, limit=limit, offset=offset) return api_resp.get('place-count'), api_resp.get('place-list') + + +def search_recordings(query='', limit=None, offset=None): + """Search for recordings.""" + api_resp = musicbrainzngs.search_recordings(query=query, limit=limit, offset=offset) + return api_resp.get('recording-count'), api_resp.get('recording-list') diff --git a/critiquebrainz/frontend/templates/navbar.html b/critiquebrainz/frontend/templates/navbar.html index 980b69eda..4ec147380 100644 --- a/critiquebrainz/frontend/templates/navbar.html +++ b/critiquebrainz/frontend/templates/navbar.html @@ -95,9 +95,10 @@
diff --git a/critiquebrainz/frontend/templates/recording/entity.html b/critiquebrainz/frontend/templates/recording/entity.html new file mode 100644 index 000000000..21f5da261 --- /dev/null +++ b/critiquebrainz/frontend/templates/recording/entity.html @@ -0,0 +1 @@ +{% extends 'base.html' %} diff --git a/critiquebrainz/frontend/templates/release_group/entity.html b/critiquebrainz/frontend/templates/release_group/entity.html index 001cb3d27..17447a892 100644 --- a/critiquebrainz/frontend/templates/release_group/entity.html +++ b/critiquebrainz/frontend/templates/release_group/entity.html @@ -113,7 +113,7 @@

{{ _('Tracklist') }}

{{ track.number }} - + {{ track.recording_title }} diff --git a/critiquebrainz/frontend/templates/search/index.html b/critiquebrainz/frontend/templates/search/index.html index e4ba87a0f..fd367d26f 100644 --- a/critiquebrainz/frontend/templates/search/index.html +++ b/critiquebrainz/frontend/templates/search/index.html @@ -24,6 +24,7 @@

{{ _('Search') }}

+
+ +
+
+ +
+
+ + + + + @@ -109,6 +132,7 @@

{{ _('Place selection') }}

or request.args.get('release_group', default=False) or request.args.get('event', default=False) or request.args.get('place', default=False) + or request.args.get('recording', default=False) %}
{% if not results %} @@ -146,6 +170,13 @@

{{ _('Place selection') }}

{{ _('Location') }} + {% elif type=="recording" %} + + {{ _('Title') }} + {{ _('Length') }} + {{ _('Artist') }} + {{ _('Release group') }} + {% endif %} {% include 'search/selector_results.html' %} diff --git a/critiquebrainz/frontend/templates/search/selector_results.html b/critiquebrainz/frontend/templates/search/selector_results.html index e90be8090..974e10c0c 100644 --- a/critiquebrainz/frontend/templates/search/selector_results.html +++ b/critiquebrainz/frontend/templates/search/selector_results.html @@ -87,7 +87,36 @@ {% endif %} - + + + + +{% elif type=="recording" %} + + + {{ result['name'] }} + + + {% if result['length'] %} + {{ result['length'] | track_length }} + {% else %} + - + {% endif %} + + + {{ result['artist-credit'][0]['artist']['name'] or '-' }} + + + {% if result['release-list'] %} + + {{ result['release-list'][0].title or '-' }} + + {% else %} + - + {% endif %} + + + diff --git a/critiquebrainz/frontend/views/recording.py b/critiquebrainz/frontend/views/recording.py new file mode 100644 index 000000000..126963fec --- /dev/null +++ b/critiquebrainz/frontend/views/recording.py @@ -0,0 +1,41 @@ +# critiquebrainz - Repository for Creative Commons licensed reviews +# +# Copyright (C) 2018 MetaBrainz Foundation Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from flask import Blueprint, render_template, request +from flask_login import current_user +from flask_babel import gettext +from werkzeug.exceptions import NotFound +import critiquebrainz.frontend.external.musicbrainz_db.recording as mb_recording +import critiquebrainz.frontend.external.musicbrainz_db.exceptions as mb_exceptions +import critiquebrainz.db.review as db_review +from critiquebrainz.frontend.forms.rate import RatingEditForm +from critiquebrainz.frontend.views import get_avg_rating + + +recording_bp = Blueprint('recording', __name__) + + +@recording_bp.route('/') +def entity(id): + id = str(id) + try: + recording = mb_recording.get_recording_by_id(id) + except mb_exceptions.NoDataFoundException: + raise NotFound(gettext("Sorry, we couldn't find a release group with that MusicBrainz ID.")) + + return render_template('recording/entity.html', id=recording['id'], recording=recording) diff --git a/critiquebrainz/frontend/views/search.py b/critiquebrainz/frontend/views/search.py index 05dc6d176..fdc0dc681 100644 --- a/critiquebrainz/frontend/views/search.py +++ b/critiquebrainz/frontend/views/search.py @@ -16,6 +16,8 @@ def search_wrapper(query, type, offset=None): count, results = musicbrainz.search_places(query, limit=RESULTS_LIMIT, offset=offset) elif type == "release-group": count, results = musicbrainz.search_release_groups(query, limit=RESULTS_LIMIT, offset=offset) + elif type == "recording": + count, results = musicbrainz.search_recordings(query, limit=RESULTS_LIMIT, offset=offset) else: count, results = 0, [] else: @@ -46,6 +48,7 @@ def more(): def selector(): release_group = request.args.get('release_group') artist = request.args.get('artist') + recording = request.args.get('recording') event = request.args.get('event') place = request.args.get('place') type = request.args.get('type') @@ -56,6 +59,8 @@ def selector(): count, results = musicbrainz.search_release_groups(release_group, limit=RESULTS_LIMIT) elif artist: count, results = musicbrainz.search_artists(artist, limit=RESULTS_LIMIT) + elif recording: + count, results = musicbrainz.search_recordings(recording, limit=RESULTS_LIMIT) elif event: count, results = musicbrainz.search_events(event, limit=RESULTS_LIMIT) elif place: @@ -65,12 +70,13 @@ def selector(): return render_template('search/selector.html', next=next, type=type, results=results, count=count, limit=RESULTS_LIMIT, artist=artist, release_group=release_group, event=event, - place=place) + recording=recording, place=place) @search_bp.route('/selector/more') def selector_more(): artist = request.args.get('artist') + recording = request.args.get('recording') release_group = request.args.get('release_group') event = request.args.get('event') place = request.args.get('place') @@ -82,6 +88,8 @@ def selector_more(): limit=RESULTS_LIMIT, offset=offset) elif type == 'artist': count, results = musicbrainz.search_artists(artist, limit=RESULTS_LIMIT, offset=offset) + elif type == 'recording': + count, results = musicbrainz.search_recordings(recording, limit=RESULTS_LIMIT, offset=offset) elif type == 'event': count, results = musicbrainz.search_events(event, limit=RESULTS_LIMIT, offset=offset) elif type == 'place': From 37bd4219261a5f40933466e7f911fe7296c33267 Mon Sep 17 00:00:00 2001 From: spellew Date: Sun, 16 Jun 2019 13:43:52 -0400 Subject: [PATCH 04/20] Implemented the reviewal of recordings --- critiquebrainz/db/review.py | 1 + .../external/musicbrainz_db/recording.py | 5 ++-- .../frontend/static/styles/main.less | 5 ++++ .../frontend/templates/entity_review.html | 2 ++ critiquebrainz/frontend/templates/macros.html | 7 +++++ .../frontend/templates/recording/entity.html | 22 ++++++++++++++++ .../frontend/templates/review/browse.html | 2 ++ .../templates/review/entity/recording.html | 24 +++++++++++++++++ .../templates/review/modify/recording.html | 26 +++++++++++++++++++ .../frontend/templates/search/selector.html | 1 + .../templates/search/selector_results.html | 6 ++--- 11 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 critiquebrainz/frontend/templates/review/entity/recording.html create mode 100644 critiquebrainz/frontend/templates/review/modify/recording.html diff --git a/critiquebrainz/db/review.py b/critiquebrainz/db/review.py index fc92fc19d..7eddfe017 100644 --- a/critiquebrainz/db/review.py +++ b/critiquebrainz/db/review.py @@ -20,6 +20,7 @@ "place", "release_group", "artist", + "recording", ] diff --git a/critiquebrainz/frontend/external/musicbrainz_db/recording.py b/critiquebrainz/frontend/external/musicbrainz_db/recording.py index 4b33f0f6e..c43f58e07 100644 --- a/critiquebrainz/frontend/external/musicbrainz_db/recording.py +++ b/critiquebrainz/frontend/external/musicbrainz_db/recording.py @@ -12,11 +12,12 @@ def get_recording_by_id(mbid): Dictionary containing the recording information """ key = cache.gen_key(mbid) - recording = cache.get(key) + recording = False if not recording: recording = fetch_multiple_recordings( [mbid], - includes=['artist-rels', 'work-rels', 'url-rels'], + includes=['artist', 'work-rels', 'url-rels'], ).get(mbid) + recording.update({ 'length': recording['length'] * 1000.0 }) cache.set(key=key, val=recording, time=DEFAULT_CACHE_EXPIRATION) return recording diff --git a/critiquebrainz/frontend/static/styles/main.less b/critiquebrainz/frontend/static/styles/main.less index 47e333899..ce3267a3f 100644 --- a/critiquebrainz/frontend/static/styles/main.less +++ b/critiquebrainz/frontend/static/styles/main.less @@ -11,6 +11,7 @@ // Entity colors @rg-color: @blue; @artist-color: @blue; +@recording-color: @blue; @event-color: @green; @place-color: @yellow; @@ -127,6 +128,8 @@ ul.sharing { } &.artist { background-color: fade(@artist-color, 70%); + &.recording { + background-color: fade(@recording-color, 70%); } &.place { background-color: fade(@place-color, 70%); @@ -489,6 +492,8 @@ a#edit-review { margin-top: 20px; } } &.artist { background-color: fade(@artist-color, 70%); + &.recording { + background-color: fade(@recording-color, 70%); } &.place { background-color: fade(@place-color, 70%); diff --git a/critiquebrainz/frontend/templates/entity_review.html b/critiquebrainz/frontend/templates/entity_review.html index f5f26fa06..bbe996c2a 100644 --- a/critiquebrainz/frontend/templates/entity_review.html +++ b/critiquebrainz/frontend/templates/entity_review.html @@ -5,6 +5,8 @@ artist = entity['artist-credit-phrase'] | default(_('[Unknown artist]'))) }} {% elif review.entity_type == 'artist' %} {{ _('%(artist)s', artist = ''|safe + entity.name | default(_('[Unknown artist]')) + ''|safe) }} + {% elif review.entity_type == 'recording' %} + {{ _('%(recording)s', recording = ''|safe + entity.name | default(_('[Unknown recording]')) + ''|safe) }} {% elif review.entity_type == 'event' %} {{ _('%(event)s', event = ''|safe + entity.name | default(_('[Unknown event]')) + ''|safe) }} {% elif review.entity_type == 'place' %} diff --git a/critiquebrainz/frontend/templates/macros.html b/critiquebrainz/frontend/templates/macros.html index 1acee7d0b..b6a46ea07 100644 --- a/critiquebrainz/frontend/templates/macros.html +++ b/critiquebrainz/frontend/templates/macros.html @@ -53,6 +53,13 @@ {{ _('Artist') }} {% endif %} + {% elif entity_type == 'recording' %} + + {% if overlay_type %} + + {{ _('Recording') }} + + {% endif %} {% else %} {# release-group #} {% if overlay_type %} diff --git a/critiquebrainz/frontend/templates/recording/entity.html b/critiquebrainz/frontend/templates/recording/entity.html index 21f5da261..a0a752aa3 100644 --- a/critiquebrainz/frontend/templates/recording/entity.html +++ b/critiquebrainz/frontend/templates/recording/entity.html @@ -1 +1,23 @@ {% extends 'base.html' %} + +{# {% block title %}{{ event.name }} - CritiqueBrainz{% endblock %} #} + +{% block content %} +
+

+ {# {{ event.name }} #} +

+ + {% if not my_review %} + + {{ _('Write a review') }} + + {% else %} + + {{ _('Edit my review') }} + + {% endif %} +
+{% endblock %} diff --git a/critiquebrainz/frontend/templates/review/browse.html b/critiquebrainz/frontend/templates/review/browse.html index b50374e99..f007ae4b0 100644 --- a/critiquebrainz/frontend/templates/review/browse.html +++ b/critiquebrainz/frontend/templates/review/browse.html @@ -13,6 +13,8 @@

{{ _('Reviews') }}

{{ _('Release group') }}
  • {{ _('Artist') }}
  • +
  • + {{ _('Recording') }}
  • {{ _('Event') }}
  • diff --git a/critiquebrainz/frontend/templates/review/entity/recording.html b/critiquebrainz/frontend/templates/review/entity/recording.html new file mode 100644 index 000000000..31e2d87e2 --- /dev/null +++ b/critiquebrainz/frontend/templates/review/entity/recording.html @@ -0,0 +1,24 @@ +{% extends 'review/entity/base.html' %} + +{% set recording = review.entity_id | entity_details(type='recording') %} + +{% block title %} + {% set recording_title = recording.name | default(_('[Unknown recording]')) %} + {{ _('Review of "%(recording)s" by %(user)s', recording=recording_title, user=review.user.display_name) }} - CritiqueBrainz +{% endblock %} + +{% block entity_title %} +

    + {% if recording %} + {% set recording_name = '' | safe % url_for('recording.entity', id=review.entity_id) ~ recording.name ~ ''|safe %} + {% else %} + {% set recording_name = _('[Unknown recording]') %} + {% endif %} + + {{ _('%(recording)s', recording=recording_name) }} + + {% if recording['life-span'] %} + {{ recording['life-span']['begin'][:4] }} + {% endif %} +

    +{% endblock %} diff --git a/critiquebrainz/frontend/templates/review/modify/recording.html b/critiquebrainz/frontend/templates/review/modify/recording.html new file mode 100644 index 000000000..c888fc210 --- /dev/null +++ b/critiquebrainz/frontend/templates/review/modify/recording.html @@ -0,0 +1,26 @@ +{% if entity is not defined %} + {% set entity = review.entity_id | entity_details(type=entity_type) %} +{% endif %} +
    +
    +
    {{ _('Recording') }}
    +
    + {{ entity['name'] | default(_('[Unknown recording]')) }} +
    +
    {{ _('Length') }}
    +
    + {% if entity['length'] %} + {{ entity['length'] | track_length }} + {% else %} + - + {% endif %} +
    +
    {{ _('Artist') }}
    +
    + {{ entity['artist'] or '-' }} +
    + {% block more_info %} + {# Information like creation date, votes etc. #} + {% endblock %} +
    +
    diff --git a/critiquebrainz/frontend/templates/search/selector.html b/critiquebrainz/frontend/templates/search/selector.html index 35063ca43..3e882dd85 100644 --- a/critiquebrainz/frontend/templates/search/selector.html +++ b/critiquebrainz/frontend/templates/search/selector.html @@ -176,6 +176,7 @@

    {{ _('Recording selection') }}

    {{ _('Length') }} {{ _('Artist') }} {{ _('Release group') }} + {% endif %} diff --git a/critiquebrainz/frontend/templates/search/selector_results.html b/critiquebrainz/frontend/templates/search/selector_results.html index 974e10c0c..daa4b853a 100644 --- a/critiquebrainz/frontend/templates/search/selector_results.html +++ b/critiquebrainz/frontend/templates/search/selector_results.html @@ -94,7 +94,7 @@ {% elif type=="recording" %} - {{ result['name'] }} + {{ result['title'] }} {% if result['length'] %} @@ -108,9 +108,7 @@ {% if result['release-list'] %} - - {{ result['release-list'][0].title or '-' }} - + {{ result['release-list'][0].title or '-' }} {% else %} - {% endif %} From 9af57f60d51a3e524f0bc2de60f8482653241d77 Mon Sep 17 00:00:00 2001 From: spellew Date: Sat, 22 Jun 2019 19:29:42 -0400 Subject: [PATCH 05/20] Fixed bug in recording retrieval --- critiquebrainz/frontend/external/musicbrainz_db/recording.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/critiquebrainz/frontend/external/musicbrainz_db/recording.py b/critiquebrainz/frontend/external/musicbrainz_db/recording.py index c43f58e07..75bd178dd 100644 --- a/critiquebrainz/frontend/external/musicbrainz_db/recording.py +++ b/critiquebrainz/frontend/external/musicbrainz_db/recording.py @@ -12,7 +12,7 @@ def get_recording_by_id(mbid): Dictionary containing the recording information """ key = cache.gen_key(mbid) - recording = False + recording = cache.get(key) if not recording: recording = fetch_multiple_recordings( [mbid], From adbc6bc6ad05eb01f9a9e949464ec7e55bd814e3 Mon Sep 17 00:00:00 2001 From: spellew Date: Thu, 4 Jul 2019 20:32:19 -0400 Subject: [PATCH 06/20] Fixed tests --- .../frontend/external/musicbrainz_db/recording.py | 2 +- critiquebrainz/frontend/views/recording.py | 13 +++++++------ critiquebrainz/frontend/views/search.py | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/critiquebrainz/frontend/external/musicbrainz_db/recording.py b/critiquebrainz/frontend/external/musicbrainz_db/recording.py index 75bd178dd..96955727c 100644 --- a/critiquebrainz/frontend/external/musicbrainz_db/recording.py +++ b/critiquebrainz/frontend/external/musicbrainz_db/recording.py @@ -18,6 +18,6 @@ def get_recording_by_id(mbid): [mbid], includes=['artist', 'work-rels', 'url-rels'], ).get(mbid) - recording.update({ 'length': recording['length'] * 1000.0 }) + recording.update({'length': recording['length'] * 1000.0}) cache.set(key=key, val=recording, time=DEFAULT_CACHE_EXPIRATION) return recording diff --git a/critiquebrainz/frontend/views/recording.py b/critiquebrainz/frontend/views/recording.py index 126963fec..789749258 100644 --- a/critiquebrainz/frontend/views/recording.py +++ b/critiquebrainz/frontend/views/recording.py @@ -16,15 +16,16 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -from flask import Blueprint, render_template, request -from flask_login import current_user -from flask_babel import gettext +from flask import Blueprint, render_template +# from flask import request +# from flask_login import current_user from werkzeug.exceptions import NotFound +from flask_babel import gettext import critiquebrainz.frontend.external.musicbrainz_db.recording as mb_recording import critiquebrainz.frontend.external.musicbrainz_db.exceptions as mb_exceptions -import critiquebrainz.db.review as db_review -from critiquebrainz.frontend.forms.rate import RatingEditForm -from critiquebrainz.frontend.views import get_avg_rating +# import critiquebrainz.db.review as db_review +# from critiquebrainz.frontend.forms.rate import RatingEditForm +# from critiquebrainz.frontend.views import get_avg_rating recording_bp = Blueprint('recording', __name__) diff --git a/critiquebrainz/frontend/views/search.py b/critiquebrainz/frontend/views/search.py index fdc0dc681..fa2c3b22f 100644 --- a/critiquebrainz/frontend/views/search.py +++ b/critiquebrainz/frontend/views/search.py @@ -46,6 +46,7 @@ def more(): @search_bp.route('/selector') def selector(): + artist = request.args.get('artist') release_group = request.args.get('release_group') artist = request.args.get('artist') recording = request.args.get('recording') From 6465ff4695bb30f537640882a9cba0b17a807c3d Mon Sep 17 00:00:00 2001 From: spellew Date: Thu, 4 Jul 2019 21:51:19 -0400 Subject: [PATCH 07/20] Commented out AB link --- critiquebrainz/frontend/templates/release_group/entity.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/critiquebrainz/frontend/templates/release_group/entity.html b/critiquebrainz/frontend/templates/release_group/entity.html index 17447a892..30998d283 100644 --- a/critiquebrainz/frontend/templates/release_group/entity.html +++ b/critiquebrainz/frontend/templates/release_group/entity.html @@ -113,6 +113,9 @@

    {{ _('Tracklist') }}

    {{ track.number }} + {{ track.recording_title }} From 60512c94198f088dec823cfa0c2c5bd150338031 Mon Sep 17 00:00:00 2001 From: spellew Date: Mon, 5 Aug 2019 18:07:46 -0400 Subject: [PATCH 08/20] Removed comments and unused imports --- critiquebrainz/frontend/views/recording.py | 26 +--------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/critiquebrainz/frontend/views/recording.py b/critiquebrainz/frontend/views/recording.py index 789749258..ab25ca3c3 100644 --- a/critiquebrainz/frontend/views/recording.py +++ b/critiquebrainz/frontend/views/recording.py @@ -1,32 +1,8 @@ -# critiquebrainz - Repository for Creative Commons licensed reviews -# -# Copyright (C) 2018 MetaBrainz Foundation Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - from flask import Blueprint, render_template -# from flask import request -# from flask_login import current_user from werkzeug.exceptions import NotFound from flask_babel import gettext import critiquebrainz.frontend.external.musicbrainz_db.recording as mb_recording import critiquebrainz.frontend.external.musicbrainz_db.exceptions as mb_exceptions -# import critiquebrainz.db.review as db_review -# from critiquebrainz.frontend.forms.rate import RatingEditForm -# from critiquebrainz.frontend.views import get_avg_rating - recording_bp = Blueprint('recording', __name__) @@ -37,6 +13,6 @@ def entity(id): try: recording = mb_recording.get_recording_by_id(id) except mb_exceptions.NoDataFoundException: - raise NotFound(gettext("Sorry, we couldn't find a release group with that MusicBrainz ID.")) + raise NotFound(gettext("Sorry, we couldn't find a recording with that MusicBrainz ID.")) return render_template('recording/entity.html', id=recording['id'], recording=recording) From 00298fe12af245ca9c730288a8925f4330a39421 Mon Sep 17 00:00:00 2001 From: spellew Date: Thu, 15 Aug 2019 12:11:31 -0400 Subject: [PATCH 09/20] Moved alter type sql script to it's own file --- admin/schema_changes/16.sql | 1 - admin/schema_changes/18.sql | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 admin/schema_changes/18.sql diff --git a/admin/schema_changes/16.sql b/admin/schema_changes/16.sql index fd697495f..b1f4e5377 100644 --- a/admin/schema_changes/16.sql +++ b/admin/schema_changes/16.sql @@ -1,2 +1 @@ ALTER TYPE entity_types ADD VALUE 'artist' AFTER 'place'; -ALTER TYPE entity_types ADD VALUE 'recording' AFTER 'artist'; diff --git a/admin/schema_changes/18.sql b/admin/schema_changes/18.sql new file mode 100644 index 000000000..15a154731 --- /dev/null +++ b/admin/schema_changes/18.sql @@ -0,0 +1 @@ +ALTER TYPE entity_types ADD VALUE 'recording' AFTER 'label'; From 88332e21f51bbf1d9950989c3dd1e80023a0ffb4 Mon Sep 17 00:00:00 2001 From: spellew Date: Thu, 15 Aug 2019 14:33:59 -0400 Subject: [PATCH 10/20] Updated recording entity page to display relevant information --- .../external/musicbrainz_db/recording.py | 2 +- .../frontend/templates/recording/entity.html | 147 ++++++++++++++++-- critiquebrainz/frontend/views/recording.py | 39 ++++- 3 files changed, 170 insertions(+), 18 deletions(-) diff --git a/critiquebrainz/frontend/external/musicbrainz_db/recording.py b/critiquebrainz/frontend/external/musicbrainz_db/recording.py index 96955727c..4431948cf 100644 --- a/critiquebrainz/frontend/external/musicbrainz_db/recording.py +++ b/critiquebrainz/frontend/external/musicbrainz_db/recording.py @@ -16,7 +16,7 @@ def get_recording_by_id(mbid): if not recording: recording = fetch_multiple_recordings( [mbid], - includes=['artist', 'work-rels', 'url-rels'], + includes=['artists', 'work-rels', 'url-rels'], ).get(mbid) recording.update({'length': recording['length'] * 1000.0}) cache.set(key=key, val=recording, time=DEFAULT_CACHE_EXPIRATION) diff --git a/critiquebrainz/frontend/templates/recording/entity.html b/critiquebrainz/frontend/templates/recording/entity.html index a0a752aa3..824c9833a 100644 --- a/critiquebrainz/frontend/templates/recording/entity.html +++ b/critiquebrainz/frontend/templates/recording/entity.html @@ -1,23 +1,140 @@ {% extends 'base.html' %} +{% from 'macros.html' import show_avg_rating, entity_rate_form, show_external_reviews with context %} -{# {% block title %}{{ event.name }} - CritiqueBrainz{% endblock %} #} +{% block title %} + {{ _('Recording "%(name)s" by %(artist)s', name=recording.name, artist=recording['artist-credit-phrase']) }} + - CritiqueBrainz +{% endblock %} {% block content %} -
    -

    - {# {{ event.name }} #} -

    - - {% if not my_review %} - - {{ _('Write a review') }} - +
    +

    + {% set artist = [] %} + {% for credit in recording['artists'] %} + {% if credit.name %} + {% do artist.append(''|safe % url_for('artist.entity', mbid=credit.id) ~ credit.name ~ ''|safe) %} + {% if credit.join_phrase %} + {% do artist.append(credit.join_phrase) %} + {% endif %} + {% else %} + {% do artist.append(credit) %} + {% endif %} + {% endfor %} + + {{ _('%(recording)s by %(artist)s', recording = recording.name, artist = artist|join()) }} +

    + + {% if not my_review %} + + {{ _('Write a review') }} + + {% else %} + + {{ _('Edit my review') }} + + {% endif %} +
    + +
    +
    + {{ entity_rate_form('recording', 'recording') }} +

    +

    {{ _('Reviews') }}

    + {% if not reviews %} +

    {{ _('No reviews found') }}

    {% else %} - - {{ _('Edit my review') }} - + + + + + + + + + + {% for review in reviews %} + + + + + + {% endfor %} + +
    {{ _('Published on') }}{{ _('Votes (+/-)') }}
    + + {{ _('by %(reviewer)s', reviewer=' '|safe % review.user.avatar + review.user.display_name) }} + + {{ review.published_on | date }}{{ review.votes_positive_count }}/{{ review.votes_negative_count }}
    +
      + {% set pages = count//limit %} + {% if count%limit %} + {% set pages = pages+1 %} + {% endif %} + {% if pages>1 %} + {% for p in range(pages) %} + {% set p_offset = p*limit %} +
    • + {{ p+1 }} +
    • + {% endfor %} + {% endif %} +
    + {% endif %} +
    + +
    +

    {{ _('Recording information') }}

    + {% if avg_rating %} +
    + {{ show_avg_rating(avg_rating.rating, avg_rating.count) }} +
    + {% endif %} + {% if external_reviews %} + {{ _('External reviews') }} + + {% endif %} + {% if recording['external-urls'] %} + {{ _('External links') }} + {% endif %} + +
    +
    +{% endblock %} + +{% block scripts %} + + + {% endblock %} diff --git a/critiquebrainz/frontend/views/recording.py b/critiquebrainz/frontend/views/recording.py index ab25ca3c3..f7db58d74 100644 --- a/critiquebrainz/frontend/views/recording.py +++ b/critiquebrainz/frontend/views/recording.py @@ -1,8 +1,13 @@ -from flask import Blueprint, render_template +from flask import Blueprint, render_template, request +from flask_login import current_user from werkzeug.exceptions import NotFound from flask_babel import gettext +import critiquebrainz.db.review as db_review import critiquebrainz.frontend.external.musicbrainz_db.recording as mb_recording import critiquebrainz.frontend.external.musicbrainz_db.exceptions as mb_exceptions +from critiquebrainz.frontend.forms.rate import RatingEditForm +from critiquebrainz.frontend.views import get_avg_rating + recording_bp = Blueprint('recording', __name__) @@ -15,4 +20,34 @@ def entity(id): except mb_exceptions.NoDataFoundException: raise NotFound(gettext("Sorry, we couldn't find a recording with that MusicBrainz ID.")) - return render_template('recording/entity.html', id=recording['id'], recording=recording) + if 'url-rels' in recording: + external_reviews = list(filter(lambda rel: rel['type'] == 'review', recording['url-rels'])) + else: + external_reviews = [] + + limit = int(request.args.get('limit', default=10)) + offset = int(request.args.get('offset', default=0)) + if current_user.is_authenticated: + my_reviews, my_count = db_review.list_reviews( + entity_id=recording['id'], + entity_type='recording', + user_id=current_user.id, + ) + my_review = my_reviews[0] if my_count else None + else: + my_review = None + reviews, count = db_review.list_reviews( + entity_id=recording['id'], + entity_type='recording', + sort='popularity', + limit=limit, + offset=offset, + ) + avg_rating = get_avg_rating(recording['id'], "recording") + + rating_form = RatingEditForm(entity_id=id, entity_type='recording') + rating_form.rating.data = my_review['rating'] if my_review else None + + return render_template('recording/entity.html', id=recording['id'], recording=recording, reviews=reviews, + my_review=my_review, external_reviews=external_reviews, limit=limit, offset=offset, + count=count, avg_rating=avg_rating, rating_form=rating_form, current_user=current_user) From 625d03fa522f6eee4bb459b731e4aaeed48815ae Mon Sep 17 00:00:00 2001 From: spellew Date: Thu, 15 Aug 2019 14:46:02 -0400 Subject: [PATCH 11/20] Merged with master --- admin/sql/create_types.sql | 1 + critiquebrainz/db/review.py | 1 + critiquebrainz/frontend/__init__.py | 2 + .../frontend/external/musicbrainz.py | 6 + .../external/musicbrainz_db/entities.py | 8 ++ .../frontend/external/musicbrainz_db/label.py | 23 ++++ .../frontend/external/relationships/label.py | 76 +++++++++++ .../frontend/static/styles/main.less | 7 + .../frontend/templates/entity_review.html | 2 + .../frontend/templates/label/entity.html | 121 ++++++++++++++++++ critiquebrainz/frontend/templates/macros.html | 13 +- critiquebrainz/frontend/templates/navbar.html | 3 +- .../frontend/templates/review/browse.html | 2 + .../templates/review/entity/label.html | 24 ++++ .../templates/review/modify/label.html | 21 +++ .../templates/review/modify/write.html | 6 - .../frontend/templates/search/index.html | 7 + .../frontend/templates/search/results.html | 13 ++ .../frontend/templates/search/selector.html | 34 ++++- .../templates/search/selector_results.html | 16 +++ critiquebrainz/frontend/views/__init__.py | 1 + critiquebrainz/frontend/views/label.py | 54 ++++++++ critiquebrainz/frontend/views/review.py | 10 +- critiquebrainz/frontend/views/search.py | 13 +- docker/Dockerfile.test | 2 +- 25 files changed, 450 insertions(+), 16 deletions(-) create mode 100644 critiquebrainz/frontend/external/musicbrainz_db/label.py create mode 100644 critiquebrainz/frontend/external/relationships/label.py create mode 100644 critiquebrainz/frontend/templates/label/entity.html create mode 100644 critiquebrainz/frontend/templates/review/entity/label.html create mode 100644 critiquebrainz/frontend/templates/review/modify/label.html create mode 100644 critiquebrainz/frontend/views/label.py diff --git a/admin/sql/create_types.sql b/admin/sql/create_types.sql index 4b6ed15b1..7ac2243bb 100644 --- a/admin/sql/create_types.sql +++ b/admin/sql/create_types.sql @@ -10,5 +10,6 @@ CREATE TYPE entity_types AS ENUM ( 'event', 'place', 'artist', + 'label', 'recording' ); diff --git a/critiquebrainz/db/review.py b/critiquebrainz/db/review.py index 7eddfe017..0e38c20dd 100644 --- a/critiquebrainz/db/review.py +++ b/critiquebrainz/db/review.py @@ -21,6 +21,7 @@ "release_group", "artist", "recording", + "label", ] diff --git a/critiquebrainz/frontend/__init__.py b/critiquebrainz/frontend/__init__.py index 5421acd4e..4b6bdb716 100644 --- a/critiquebrainz/frontend/__init__.py +++ b/critiquebrainz/frontend/__init__.py @@ -131,6 +131,7 @@ def create_app(debug=None, config_path=None): from critiquebrainz.frontend.views.review import review_bp from critiquebrainz.frontend.views.search import search_bp from critiquebrainz.frontend.views.artist import artist_bp + from critiquebrainz.frontend.views.label import label_bp from critiquebrainz.frontend.views.release_group import release_group_bp from critiquebrainz.frontend.views.release import release_bp from critiquebrainz.frontend.views.recording import recording_bp @@ -153,6 +154,7 @@ def create_app(debug=None, config_path=None): app.register_blueprint(review_bp, url_prefix='/review') app.register_blueprint(search_bp, url_prefix='/search') app.register_blueprint(artist_bp, url_prefix='/artist') + app.register_blueprint(label_bp, url_prefix='/label') app.register_blueprint(release_group_bp, url_prefix='/release-group') app.register_blueprint(release_bp, url_prefix='/release') app.register_blueprint(recording_bp, url_prefix='/recording') diff --git a/critiquebrainz/frontend/external/musicbrainz.py b/critiquebrainz/frontend/external/musicbrainz.py index ab48e2157..45f07c452 100644 --- a/critiquebrainz/frontend/external/musicbrainz.py +++ b/critiquebrainz/frontend/external/musicbrainz.py @@ -50,3 +50,9 @@ def search_recordings(query='', limit=None, offset=None): """Search for recordings.""" api_resp = musicbrainzngs.search_recordings(query=query, limit=limit, offset=offset) return api_resp.get('recording-count'), api_resp.get('recording-list') + + +def search_labels(query='', limit=None, offset=None): + """Search for labels.""" + api_resp = musicbrainzngs.search_labels(query=query, limit=limit, offset=offset) + return api_resp.get('label-count'), api_resp.get('label-list') diff --git a/critiquebrainz/frontend/external/musicbrainz_db/entities.py b/critiquebrainz/frontend/external/musicbrainz_db/entities.py index a1ed23bfe..de5865cd4 100644 --- a/critiquebrainz/frontend/external/musicbrainz_db/entities.py +++ b/critiquebrainz/frontend/external/musicbrainz_db/entities.py @@ -1,11 +1,13 @@ from brainzutils.musicbrainz_db.recording import fetch_multiple_recordings from brainzutils.musicbrainz_db.artist import fetch_multiple_artists +from brainzutils.musicbrainz_db.label import fetch_multiple_labels from brainzutils.musicbrainz_db.place import fetch_multiple_places from brainzutils.musicbrainz_db.event import fetch_multiple_events from brainzutils.musicbrainz_db.release_group import fetch_multiple_release_groups from critiquebrainz.frontend.external.musicbrainz_db.release_group import get_release_group_by_id from critiquebrainz.frontend.external.musicbrainz_db.place import get_place_by_id from critiquebrainz.frontend.external.musicbrainz_db.event import get_event_by_id +from critiquebrainz.frontend.external.musicbrainz_db.label import get_label_by_id from critiquebrainz.frontend.external.musicbrainz_db.artist import get_artist_by_id from critiquebrainz.frontend.external.musicbrainz_db.recording import get_recording_by_id @@ -29,6 +31,7 @@ def get_multiple_entities(entities): release_group_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'release_group', entities)] artist_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'artist', entities)] recording_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'recording', entities)] + label_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'label', entities)] place_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'place', entities)] event_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'event', entities)] entities_info.update(fetch_multiple_release_groups( @@ -41,6 +44,9 @@ def get_multiple_entities(entities): entities_info.update(fetch_multiple_recordings( recording_mbids, )) + entities_info.update(fetch_multiple_labels( + label_mbids, + )) entities_info.update(fetch_multiple_places( place_mbids, )) @@ -58,6 +64,8 @@ def get_entity_by_id(id, type='release_group'): entity = get_artist_by_id(str(id)) elif type == 'recording': entity = get_recording_by_id(str(id)) + elif type == 'label': + entity = get_label_by_id(str(id)) elif type == 'place': entity = get_place_by_id(str(id)) elif type == 'event': diff --git a/critiquebrainz/frontend/external/musicbrainz_db/label.py b/critiquebrainz/frontend/external/musicbrainz_db/label.py new file mode 100644 index 000000000..0cb48995b --- /dev/null +++ b/critiquebrainz/frontend/external/musicbrainz_db/label.py @@ -0,0 +1,23 @@ +from brainzutils import cache +from brainzutils.musicbrainz_db.label import fetch_multiple_labels +from critiquebrainz.frontend.external.musicbrainz_db import DEFAULT_CACHE_EXPIRATION +from critiquebrainz.frontend.external.relationships import label as label_rel + + +def get_label_by_id(mbid): + """Get label with MusicBrainz ID. + + Args: + mbid (uuid): MBID(gid) of the label. + Returns: + Dictionary containing the label information + """ + key = cache.gen_key(mbid) + label = cache.get(key) + if not label: + label = fetch_multiple_labels( + [mbid], + includes=['artist-rels', 'url-rels'], + ).get(mbid) + cache.set(key=key, val=label, time=DEFAULT_CACHE_EXPIRATION) + return label_rel.process(label) diff --git a/critiquebrainz/frontend/external/relationships/label.py b/critiquebrainz/frontend/external/relationships/label.py new file mode 100644 index 000000000..150684f43 --- /dev/null +++ b/critiquebrainz/frontend/external/relationships/label.py @@ -0,0 +1,76 @@ +""" +Relationship processor for label entity. +""" +import urllib.parse +from flask_babel import lazy_gettext + + +def process(label): + """Handles processing supported relation lists.""" + if 'url-rels' in label and label['url-rels']: + label['external-urls'] = _url(label['url-rels']) + return label + + +def _url(url_list): + """Processor for Label-URL relationship.""" + basic_types = { + 'wikidata': {'name': lazy_gettext('Wikidata'), 'icon': 'wikidata-16.png', }, + 'discogs': {'name': lazy_gettext('Discogs'), 'icon': 'discogs-16.png', }, + 'allmusic': {'name': lazy_gettext('Allmusic'), 'icon': 'allmusic-16.png', }, + 'bandcamp': {'name': lazy_gettext('Bandcamp'), 'icon': 'bandcamp-16.png', }, + 'official homepage': {'name': lazy_gettext('Official homepage'), 'icon': 'home-16.png', }, + 'BBC Music page': {'name': lazy_gettext('BBC Music'), }, + } + external_urls = [] + for relation in url_list: + if relation['type'] in basic_types: + external_urls.append(dict(list(relation.items()) + list(basic_types[relation['type']].items()))) + else: + try: + target = urllib.parse.urlparse(relation['target']) + if relation['type'] == 'lyrics': + external_urls.append(dict( + relation.items() + { + 'name': lazy_gettext('Lyrics'), + 'disambiguation': target.netloc, + }.items())) + elif relation['type'] == 'wikipedia': + external_urls.append(dict( + relation.items() + { + 'name': lazy_gettext('Wikipedia'), + 'disambiguation': ( + target.netloc.split('.')[0] + + ':' + + urllib.parse.unquote(target.path.split('/')[2]).decode('utf8').replace("_", " ") + ), + 'icon': 'wikipedia-16.png', + }.items())) + elif relation['type'] == 'youtube': + path = target.path.split('/') + if path[1] == 'user' or path[1] == 'channel': + disambiguation = path[2] + else: + disambiguation = path[1] + external_urls.append(dict( + relation.items() + { + 'name': lazy_gettext('YouTube'), + 'disambiguation': disambiguation, + 'icon': 'youtube-16.png', + }.items())) + elif relation['type'] == 'social network': + if target.netloc == 'twitter.com': + external_urls.append(dict( + relation.items() + { + 'name': lazy_gettext('Twitter'), + 'disambiguation': target.path.split('/')[1], + 'icon': 'twitter-16.png', + }.items())) + else: + # TODO(roman): Process other types here + pass + except Exception: # FIXME(roman): Too broad exception clause. + # TODO(roman): Log error. + pass + + return sorted(external_urls, key=lambda k: k['name']) diff --git a/critiquebrainz/frontend/static/styles/main.less b/critiquebrainz/frontend/static/styles/main.less index ce3267a3f..eca975941 100644 --- a/critiquebrainz/frontend/static/styles/main.less +++ b/critiquebrainz/frontend/static/styles/main.less @@ -14,6 +14,7 @@ @recording-color: @blue; @event-color: @green; @place-color: @yellow; +@label-color: @blue; body { padding-bottom: 25px; @@ -134,6 +135,9 @@ ul.sharing { &.place { background-color: fade(@place-color, 70%); } + &.label { + background-color: fade(@label-color, 70%); + } &.event { background-color: fade(@event-color, 70%); } @@ -498,6 +502,9 @@ a#edit-review { margin-top: 20px; } &.place { background-color: fade(@place-color, 70%); } + &.label { + background-color: fade(@label-color, 70%); + } &.event { background-color: fade(@event-color, 70%); } diff --git a/critiquebrainz/frontend/templates/entity_review.html b/critiquebrainz/frontend/templates/entity_review.html index bbe996c2a..a0ff41366 100644 --- a/critiquebrainz/frontend/templates/entity_review.html +++ b/critiquebrainz/frontend/templates/entity_review.html @@ -7,6 +7,8 @@ {{ _('%(artist)s', artist = ''|safe + entity.name | default(_('[Unknown artist]')) + ''|safe) }} {% elif review.entity_type == 'recording' %} {{ _('%(recording)s', recording = ''|safe + entity.name | default(_('[Unknown recording]')) + ''|safe) }} + {% elif review.entity_type == 'label' %} + {{ _('%(label)s', label = ''|safe + entity.name | default(_('[Unknown label]')) + ''|safe) }} {% elif review.entity_type == 'event' %} {{ _('%(event)s', event = ''|safe + entity.name | default(_('[Unknown event]')) + ''|safe) }} {% elif review.entity_type == 'place' %} diff --git a/critiquebrainz/frontend/templates/label/entity.html b/critiquebrainz/frontend/templates/label/entity.html new file mode 100644 index 000000000..17ff6fbfc --- /dev/null +++ b/critiquebrainz/frontend/templates/label/entity.html @@ -0,0 +1,121 @@ +{% extends 'base.html' %} +{% from 'macros.html' import entity_rate_form, show_avg_rating with context %} + +{% block title %}{{ label.name }} - CritiqueBrainz{% endblock %} + +{% block content %} +
    +

    + {{ label.name }} + {% if label.disambiguation %} + ({{ label.disambiguation }}) + {% endif %} +

    + + {% if not my_review %} + + {{ _('Write a review') }} + + {% else %} + + {{ _('Edit my review') }} + + {% endif %} +
    + +
    +
    +

    {{ _('Reviews') }}

    + {% if not reviews %} +

    {{ _('No reviews found') }}

    + {% else %} + + + + + + + + + + {% for review in reviews %} + + + + + + {% endfor %} + +
    {{ _('Published on') }}{{ _('Votes (+/-)') }}
    + + {{ _('by %(reviewer)s', reviewer=' '|safe % review.user.avatar + review.user.display_name) }} + + {{ review.published_on | date }}{{ review.votes_positive_count }}/{{ review.votes_negative_count }}
    +
    + +
    + {% endif %} +
      +
      + +
      +

      {{ _('Label information') }}

      + {% if label.type %}

      {{ label.type }}

      {% endif %} + + {% if label['external-urls'] %} + {{ _('External links') }} + + {% endif %} + + + +

      + {{ entity_rate_form('label', 'label') }} + {% if avg_rating %} +
      + {{ show_avg_rating(avg_rating.rating, avg_rating.count, show_glyphicon = false) }} +
      + {% endif %} +
      +
      +{% endblock %} + +{% block scripts %} + + + +{% endblock %} diff --git a/critiquebrainz/frontend/templates/macros.html b/critiquebrainz/frontend/templates/macros.html index b6a46ea07..7915c98bb 100644 --- a/critiquebrainz/frontend/templates/macros.html +++ b/critiquebrainz/frontend/templates/macros.html @@ -60,6 +60,13 @@ {{ _('Recording') }} {% endif %} + {% elif entity_type == 'label' %} + + {% if overlay_type %} + + {{ _('Label') }} + + {% endif %} {% else %} {# release-group #} {% if overlay_type %} @@ -160,8 +167,10 @@ {% endif %} {% endmacro %} -{% macro show_avg_rating(rating, count) %} - +{% macro show_avg_rating(rating, count, show_glyphicon=True) %} + {% if show_glyphicon %} + + {% endif %} {{ rating }}/5 {{ _('based on %(number)s ratings', number=count) }} {% endmacro %} diff --git a/critiquebrainz/frontend/templates/navbar.html b/critiquebrainz/frontend/templates/navbar.html index 4ec147380..e3a78bc17 100644 --- a/critiquebrainz/frontend/templates/navbar.html +++ b/critiquebrainz/frontend/templates/navbar.html @@ -95,9 +95,10 @@
      diff --git a/critiquebrainz/frontend/templates/review/browse.html b/critiquebrainz/frontend/templates/review/browse.html index f007ae4b0..81092b066 100644 --- a/critiquebrainz/frontend/templates/review/browse.html +++ b/critiquebrainz/frontend/templates/review/browse.html @@ -15,6 +15,8 @@

      {{ _('Reviews') }}

      {{ _('Artist') }}
    • {{ _('Recording') }}
    • +
    • + {{ _('Label') }}
    • {{ _('Event') }}
    • diff --git a/critiquebrainz/frontend/templates/review/entity/label.html b/critiquebrainz/frontend/templates/review/entity/label.html new file mode 100644 index 000000000..204a0574f --- /dev/null +++ b/critiquebrainz/frontend/templates/review/entity/label.html @@ -0,0 +1,24 @@ +{% extends 'review/entity/base.html' %} + +{% set label = review.entity_id | entity_details(type='label') %} + +{% block title %} + {% set label_title = label.name | default(_('[Unknown label]')) %} + {{ _('Review of "%(label)s" by %(user)s', label=label_title, user=review.user.display_name) }} - CritiqueBrainz +{% endblock %} + +{% block entity_title %} +

      + {% if label %} + {% set label_name = '' | safe % url_for('label.entity', id=review.entity_id) ~ label.name ~ ''|safe %} + {% else %} + {% set label_name = _('[Unknown label]') %} + {% endif %} + + {{ _('%(label)s', label=label_name) }} + + {% if label['life-span'] %} + {{ label['life-span']['begin'][:4] }} + {% endif %} +

      +{% endblock %} diff --git a/critiquebrainz/frontend/templates/review/modify/label.html b/critiquebrainz/frontend/templates/review/modify/label.html new file mode 100644 index 000000000..373000939 --- /dev/null +++ b/critiquebrainz/frontend/templates/review/modify/label.html @@ -0,0 +1,21 @@ +{% if entity is not defined %} + {% set entity = review.entity_id | entity_details(type=entity_type) %} +{% endif %} +
      +
      +
      {{ _('Label') }}
      +
      + {{ entity['name'] | default(_('[Unknown label]')) }} + {% if entity['life-span'] %} + ({{ entity['life-span']['begin'] }} - {{ entity['life-span']['end'] }}) + {% endif %} +
      +
      {{ _('Type') }}
      +
      {{ entity['type'] or '-' }}
      +
      {{ _('Country') }}
      +
      {{ entity['area'] or '-' }}
      + {% block more_info %} + {# Information like creation date, votes etc. #} + {% endblock %} +
      +
      diff --git a/critiquebrainz/frontend/templates/review/modify/write.html b/critiquebrainz/frontend/templates/review/modify/write.html index 3b07bf22b..771f3c0d5 100644 --- a/critiquebrainz/frontend/templates/review/modify/write.html +++ b/critiquebrainz/frontend/templates/review/modify/write.html @@ -1,11 +1,5 @@ {% extends 'review/modify/base.html' %} -{% if entity_type == 'release_group' %} - {% set entity_title = entity.title %} -{% elif entity_type in ['event', 'place'] %} - {% set entity_title = entity.name %} -{% endif %} - {% block title %} {{ _('Write review of "%(entity)s"', entity=entity_title) }} - CritiqueBrainz {% endblock %} diff --git a/critiquebrainz/frontend/templates/search/index.html b/critiquebrainz/frontend/templates/search/index.html index fd367d26f..8bb5b2cf8 100644 --- a/critiquebrainz/frontend/templates/search/index.html +++ b/critiquebrainz/frontend/templates/search/index.html @@ -27,6 +27,7 @@

      {{ _('Search') }}

      + @@ -78,6 +79,12 @@

      {{ _('Search') }}

      {{ _('Artist') }} {{ _('Release group') }} + {% elif type=="label" %} + + {{ _('Name') }} + {{ _('Type') }} + {{ _('Country') }} + {% endif %} {% include 'search/results.html' %} diff --git a/critiquebrainz/frontend/templates/search/results.html b/critiquebrainz/frontend/templates/search/results.html index 2a537dbe4..eceb66f0e 100644 --- a/critiquebrainz/frontend/templates/search/results.html +++ b/critiquebrainz/frontend/templates/search/results.html @@ -88,5 +88,18 @@ + {% elif type=="label" %} + + + {{ result['name'] }} + + + {{ result['type'] or '-' }} + + + {{ result['country'] or '-' }} + + + {% endif %} {% endfor %} diff --git a/critiquebrainz/frontend/templates/search/selector.html b/critiquebrainz/frontend/templates/search/selector.html index 3e882dd85..2261a064f 100644 --- a/critiquebrainz/frontend/templates/search/selector.html +++ b/critiquebrainz/frontend/templates/search/selector.html @@ -21,6 +21,9 @@
    • {{ _('Recording') }}
    • +
    • + {{ _('Label') }} +
    • @@ -104,6 +107,26 @@

      {{ _('Place selection') }}

      +
      +

      {{ _('Label selection') }}

      +
      +
      + +
      + +
      +
      +
      +
      + +
      +
      + + +
      +
      +

      {{ _('Recording selection') }}

      @@ -123,7 +146,7 @@

      {{ _('Recording selection') }}

      - + @@ -133,6 +156,7 @@

      {{ _('Recording selection') }}

      or request.args.get('event', default=False) or request.args.get('place', default=False) or request.args.get('recording', default=False) + or request.args.get('label', default=False) %}
      {% if not results %} @@ -178,11 +202,17 @@

      {{ _('Recording selection') }}

      {{ _('Release group') }} + {% elif type=="label" %} + + {{ _('Name') }} + {{ _('Type') }} + {{ _('Country') }} + + {% endif %} {% include 'search/selector_results.html' %} -
      {% if count > limit %}
      diff --git a/critiquebrainz/frontend/templates/search/selector_results.html b/critiquebrainz/frontend/templates/search/selector_results.html index daa4b853a..f32742ab4 100644 --- a/critiquebrainz/frontend/templates/search/selector_results.html +++ b/critiquebrainz/frontend/templates/search/selector_results.html @@ -118,5 +118,21 @@ +{% elif type=="label" %} + + + {{ result['name'] }} + + + {{ result['type'] or '-' }} + + + {{ result['country'] or '-' }} + + + + + + {% endif %} {% endfor %} diff --git a/critiquebrainz/frontend/views/__init__.py b/critiquebrainz/frontend/views/__init__.py index 1f05d8b3c..51f6c13c4 100644 --- a/critiquebrainz/frontend/views/__init__.py +++ b/critiquebrainz/frontend/views/__init__.py @@ -2,6 +2,7 @@ import critiquebrainz.db.exceptions as db_exceptions ARTIST_REVIEWS_LIMIT = 5 +LABEL_REVIEWS_LIMIT = 5 BROWSE_RELEASE_GROUPS_LIMIT = 20 diff --git a/critiquebrainz/frontend/views/label.py b/critiquebrainz/frontend/views/label.py new file mode 100644 index 000000000..86a46e43e --- /dev/null +++ b/critiquebrainz/frontend/views/label.py @@ -0,0 +1,54 @@ +from flask import Blueprint, render_template, request +from werkzeug.exceptions import NotFound +from flask_login import current_user +from flask_babel import gettext +import critiquebrainz.db.review as db_review +import critiquebrainz.frontend.external.musicbrainz_db.label as mb_label +import critiquebrainz.frontend.external.musicbrainz_db.exceptions as mb_exceptions +from critiquebrainz.frontend.views import get_avg_rating, LABEL_REVIEWS_LIMIT +from critiquebrainz.frontend.forms.rate import RatingEditForm + + +label_bp = Blueprint('label', __name__) + + +@label_bp.route('/') +def entity(id): + id = str(id) + try: + label = mb_label.get_label_by_id(id) + except mb_exceptions.NoDataFoundException: + raise NotFound(gettext("Sorry, we couldn't find a label with that MusicBrainz ID.")) + + label_reviews_limit = LABEL_REVIEWS_LIMIT + if request.args.get('reviews') == "all": + label_reviews_limit = None + + if current_user.is_authenticated: + my_reviews, my_count = db_review.list_reviews( + entity_id=label['id'], + entity_type='label', + user_id=current_user.id, + ) + my_review = my_reviews[0] if my_count else None + else: + my_review = None + + reviews_offset = 0 + reviews, reviews_count = db_review.list_reviews( + entity_id=label['id'], + entity_type='label', + sort='popularity', + limit=label_reviews_limit, + offset=reviews_offset, + ) + + avg_rating = get_avg_rating(label['id'], "label") + + rating_form = RatingEditForm(entity_id=id, entity_type='label') + rating_form.rating.data = my_review['rating'] if my_review else None + + return render_template('label/entity.html', id=label['id'], label=label, + reviews=reviews, my_review=my_review, reviews_limit=label_reviews_limit, + reviews_count=reviews_count, avg_rating=avg_rating, rating_form=rating_form, + current_user=current_user) diff --git a/critiquebrainz/frontend/views/review.py b/critiquebrainz/frontend/views/review.py index cc52f1cc9..e0fafe460 100644 --- a/critiquebrainz/frontend/views/review.py +++ b/critiquebrainz/frontend/views/review.py @@ -269,9 +269,17 @@ def create(): flash.info(gettext("Please provide some text or a rating for this review.")) return render_template('review/modify/write.html', form=form, entity_type=entity_type, entity=entity, spotify_mappings=spotify_mappings, soundcloud_url=soundcloud_url) + + entity_title = None + if 'title' in entity: + entity_title = entity['title'] + elif 'name' in entity: + entity_title = entity['name'] + if not form.errors: flash.info(gettext("Please provide some text or a rating for this review.")) - return render_template('review/modify/write.html', form=form, entity_type=entity_type, entity=entity) + return render_template('review/modify/write.html', form=form, entity_type=entity_type, + entity_title=entity_title, entity=entity) @review_bp.route('//edit', methods=('GET', 'POST')) diff --git a/critiquebrainz/frontend/views/search.py b/critiquebrainz/frontend/views/search.py index fa2c3b22f..48602140f 100644 --- a/critiquebrainz/frontend/views/search.py +++ b/critiquebrainz/frontend/views/search.py @@ -18,6 +18,8 @@ def search_wrapper(query, type, offset=None): count, results = musicbrainz.search_release_groups(query, limit=RESULTS_LIMIT, offset=offset) elif type == "recording": count, results = musicbrainz.search_recordings(query, limit=RESULTS_LIMIT, offset=offset) + elif type == "label": + count, results = musicbrainz.search_labels(query, limit=RESULTS_LIMIT, offset=offset) else: count, results = 0, [] else: @@ -46,10 +48,10 @@ def more(): @search_bp.route('/selector') def selector(): - artist = request.args.get('artist') release_group = request.args.get('release_group') - artist = request.args.get('artist') recording = request.args.get('recording') + artist = request.args.get('artist') + label = request.args.get('label') event = request.args.get('event') place = request.args.get('place') type = request.args.get('type') @@ -62,6 +64,8 @@ def selector(): count, results = musicbrainz.search_artists(artist, limit=RESULTS_LIMIT) elif recording: count, results = musicbrainz.search_recordings(recording, limit=RESULTS_LIMIT) + elif label: + count, results = musicbrainz.search_labels(label, limit=RESULTS_LIMIT) elif event: count, results = musicbrainz.search_events(event, limit=RESULTS_LIMIT) elif place: @@ -71,7 +75,7 @@ def selector(): return render_template('search/selector.html', next=next, type=type, results=results, count=count, limit=RESULTS_LIMIT, artist=artist, release_group=release_group, event=event, - recording=recording, place=place) + recording=recording, place=place, label=label) @search_bp.route('/selector/more') @@ -79,6 +83,7 @@ def selector_more(): artist = request.args.get('artist') recording = request.args.get('recording') release_group = request.args.get('release_group') + label = request.args.get('label') event = request.args.get('event') place = request.args.get('place') type = request.args.get('type') @@ -91,6 +96,8 @@ def selector_more(): count, results = musicbrainz.search_artists(artist, limit=RESULTS_LIMIT, offset=offset) elif type == 'recording': count, results = musicbrainz.search_recordings(recording, limit=RESULTS_LIMIT, offset=offset) + elif type == 'label': + count, results = musicbrainz.search_labels(label, limit=RESULTS_LIMIT, offset=offset) elif type == 'event': count, results = musicbrainz.search_events(event, limit=RESULTS_LIMIT, offset=offset) elif type == 'place': diff --git a/docker/Dockerfile.test b/docker/Dockerfile.test index a4a6a733a..ef1928203 100644 --- a/docker/Dockerfile.test +++ b/docker/Dockerfile.test @@ -39,7 +39,7 @@ COPY . /code/ RUN pybabel compile -d critiquebrainz/frontend/translations CMD dockerize -wait tcp://db_test:5432 -timeout 60s \ - dockerize -wait tcp://musicbrainz_db:5432 -timeout 240s \ + dockerize -wait tcp://musicbrainz_db:5432 -timeout 360s \ python manage.py init_db --skip-create-db --test-db \ && py.test --junitxml=/data/test_report.xml \ --cov-report xml:/data/coverage.xml From 81b753594af2bd1eefc95901c4acb46ca5153246 Mon Sep 17 00:00:00 2001 From: spellew Date: Sun, 18 Aug 2019 15:24:00 -0400 Subject: [PATCH 12/20] Removed AcousticBrainz link from release_group entity page --- critiquebrainz/frontend/templates/release_group/entity.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/critiquebrainz/frontend/templates/release_group/entity.html b/critiquebrainz/frontend/templates/release_group/entity.html index 30998d283..17447a892 100644 --- a/critiquebrainz/frontend/templates/release_group/entity.html +++ b/critiquebrainz/frontend/templates/release_group/entity.html @@ -113,9 +113,6 @@

      {{ _('Tracklist') }}

      {{ track.number }} - {{ track.recording_title }} From 7b686ceecc7ac8bbd4796acf7c925a55128ab9ba Mon Sep 17 00:00:00 2001 From: spellew Date: Tue, 20 Aug 2019 09:13:43 -0400 Subject: [PATCH 13/20] Added titles for recording, artist, and label to user template --- .../frontend/templates/user/reviews.html | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/critiquebrainz/frontend/templates/user/reviews.html b/critiquebrainz/frontend/templates/user/reviews.html index 0ec89470c..2ccf53d24 100644 --- a/critiquebrainz/frontend/templates/user/reviews.html +++ b/critiquebrainz/frontend/templates/user/reviews.html @@ -48,6 +48,22 @@ {% endif %} {%- elif review.entity_type == 'place' -%} {{ entity.name | default(_('[Unknown place]')) }} + + {%- elif review.entity_type == 'recording' -%} + {{ entity.name | default(_('[Unknown recording]')) }} + - {{ entity['artist-credit-phrase'] | default(_('[Unknown artist]')) }} + + {%- elif review.entity_type == 'artist' -%} + {{ entity.name | default(_('[Unknown artist]')) }} + {% if entity['type'] %} + ({{ entity.type }}) + {% endif %} + + {%- elif review.entity_type == 'label' -%} + {{ entity.name | default(_('[Unknown label]')) }} + {% if entity['type'] %} + ({{ entity.type }}) + {% endif %} {%- endif -%} From 5fa205671fcca1125cd6d53f8d1c5fa05541305b Mon Sep 17 00:00:00 2001 From: spellew Date: Wed, 21 Aug 2019 20:34:04 -0400 Subject: [PATCH 14/20] Moved views/recording limit to __init__.py --- critiquebrainz/frontend/views/__init__.py | 1 + critiquebrainz/frontend/views/recording.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/critiquebrainz/frontend/views/__init__.py b/critiquebrainz/frontend/views/__init__.py index 51f6c13c4..13dc41eb8 100644 --- a/critiquebrainz/frontend/views/__init__.py +++ b/critiquebrainz/frontend/views/__init__.py @@ -3,6 +3,7 @@ ARTIST_REVIEWS_LIMIT = 5 LABEL_REVIEWS_LIMIT = 5 +RECORDING_REVIEWS_LIMIT = 10 BROWSE_RELEASE_GROUPS_LIMIT = 20 diff --git a/critiquebrainz/frontend/views/recording.py b/critiquebrainz/frontend/views/recording.py index f7db58d74..b09b3ac6e 100644 --- a/critiquebrainz/frontend/views/recording.py +++ b/critiquebrainz/frontend/views/recording.py @@ -6,7 +6,7 @@ import critiquebrainz.frontend.external.musicbrainz_db.recording as mb_recording import critiquebrainz.frontend.external.musicbrainz_db.exceptions as mb_exceptions from critiquebrainz.frontend.forms.rate import RatingEditForm -from critiquebrainz.frontend.views import get_avg_rating +from critiquebrainz.frontend.views import get_avg_rating, RECORDING_REVIEWS_LIMIT recording_bp = Blueprint('recording', __name__) @@ -25,7 +25,7 @@ def entity(id): else: external_reviews = [] - limit = int(request.args.get('limit', default=10)) + limit = int(request.args.get('limit', default=RECORDING_REVIEWS_LIMIT)) offset = int(request.args.get('offset', default=0)) if current_user.is_authenticated: my_reviews, my_count = db_review.list_reviews( From 1b57962392fd0c47099954b6ca04f9133480de7e Mon Sep 17 00:00:00 2001 From: spellew Date: Wed, 21 Aug 2019 21:04:48 -0400 Subject: [PATCH 15/20] Created separate track_length functions for seconds and milliseconds --- critiquebrainz/frontend/__init__.py | 3 ++- .../frontend/external/musicbrainz_db/recording.py | 1 - .../frontend/templates/release_group/entity.html | 2 +- .../frontend/templates/review/modify/recording.html | 2 +- critiquebrainz/frontend/templates/search/results.html | 2 +- .../frontend/templates/search/selector_results.html | 2 +- critiquebrainz/utils.py | 7 +++++++ 7 files changed, 13 insertions(+), 6 deletions(-) diff --git a/critiquebrainz/frontend/__init__.py b/critiquebrainz/frontend/__init__.py index 4b6bdb716..c4b9b221e 100644 --- a/critiquebrainz/frontend/__init__.py +++ b/critiquebrainz/frontend/__init__.py @@ -115,11 +115,12 @@ def create_app(debug=None, config_path=None): # TODO (code-master5): disabled no-member warnings just as a workaround to deal with failing tests till the # issue [https://github.com/PyCQA/pylint/issues/2563] with pylint is resolved app.jinja_env.add_extension('jinja2.ext.do') - from critiquebrainz.utils import reformat_date, reformat_datetime, track_length, parameterize + from critiquebrainz.utils import reformat_date, reformat_datetime, track_length, track_length_ms, parameterize from critiquebrainz.frontend.external.musicbrainz_db.entities import get_entity_by_id app.jinja_env.filters['date'] = reformat_date app.jinja_env.filters['datetime'] = reformat_datetime app.jinja_env.filters['track_length'] = track_length + app.jinja_env.filters['track_length_ms'] = track_length_ms app.jinja_env.filters['parameterize'] = parameterize app.jinja_env.filters['entity_details'] = get_entity_by_id from flask_babel import Locale, get_locale diff --git a/critiquebrainz/frontend/external/musicbrainz_db/recording.py b/critiquebrainz/frontend/external/musicbrainz_db/recording.py index 4431948cf..ff1e3fb3b 100644 --- a/critiquebrainz/frontend/external/musicbrainz_db/recording.py +++ b/critiquebrainz/frontend/external/musicbrainz_db/recording.py @@ -18,6 +18,5 @@ def get_recording_by_id(mbid): [mbid], includes=['artists', 'work-rels', 'url-rels'], ).get(mbid) - recording.update({'length': recording['length'] * 1000.0}) cache.set(key=key, val=recording, time=DEFAULT_CACHE_EXPIRATION) return recording diff --git a/critiquebrainz/frontend/templates/release_group/entity.html b/critiquebrainz/frontend/templates/release_group/entity.html index 17447a892..84d8324cf 100644 --- a/critiquebrainz/frontend/templates/release_group/entity.html +++ b/critiquebrainz/frontend/templates/release_group/entity.html @@ -119,7 +119,7 @@

      {{ _('Tracklist') }}

      {% if track.length %} - {{ track.length | track_length }} + {{ track.length | track_length_ms }} {% else %} - {% endif %} diff --git a/critiquebrainz/frontend/templates/review/modify/recording.html b/critiquebrainz/frontend/templates/review/modify/recording.html index c888fc210..40343417b 100644 --- a/critiquebrainz/frontend/templates/review/modify/recording.html +++ b/critiquebrainz/frontend/templates/review/modify/recording.html @@ -10,7 +10,7 @@
      {{ _('Length') }}
      {% if entity['length'] %} - {{ entity['length'] | track_length }} + {{ entity['length'] | track_length_ms }} {% else %} - {% endif %} diff --git a/critiquebrainz/frontend/templates/search/results.html b/critiquebrainz/frontend/templates/search/results.html index eceb66f0e..617c8e49a 100644 --- a/critiquebrainz/frontend/templates/search/results.html +++ b/critiquebrainz/frontend/templates/search/results.html @@ -71,7 +71,7 @@ {% if result['length'] %} - {{ result['length'] | track_length }} + {{ result['length'] | track_length_ms }} {% else %} - {% endif %} diff --git a/critiquebrainz/frontend/templates/search/selector_results.html b/critiquebrainz/frontend/templates/search/selector_results.html index b9616a40a..c0bd75d19 100644 --- a/critiquebrainz/frontend/templates/search/selector_results.html +++ b/critiquebrainz/frontend/templates/search/selector_results.html @@ -98,7 +98,7 @@ {% if result['length'] %} - {{ result['length'] | track_length }} + {{ result['length'] | track_length_ms }} {% else %} - {% endif %} diff --git a/critiquebrainz/utils.py b/critiquebrainz/utils.py index 8de829d56..9d3e892c6 100644 --- a/critiquebrainz/utils.py +++ b/critiquebrainz/utils.py @@ -46,6 +46,13 @@ def reformat_datetime(value, format=None): def track_length(value): + """Converts track length specified in seconds into a pretty string.""" + seconds = int(value) + minutes, seconds = divmod(seconds, 60) + return '%i:%02i' % (minutes, seconds) + + +def track_length_ms(value): """Converts track length specified in milliseconds into a pretty string.""" seconds = int(value) / 1000 minutes, seconds = divmod(seconds, 60) From 7e6159f96aac7016399a52e9994a99e07dc720db Mon Sep 17 00:00:00 2001 From: spellew Date: Sat, 24 Aug 2019 11:41:50 -0400 Subject: [PATCH 16/20] Fixed track list in review/modify --- critiquebrainz/frontend/templates/review/modify/recording.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/critiquebrainz/frontend/templates/review/modify/recording.html b/critiquebrainz/frontend/templates/review/modify/recording.html index 40343417b..c888fc210 100644 --- a/critiquebrainz/frontend/templates/review/modify/recording.html +++ b/critiquebrainz/frontend/templates/review/modify/recording.html @@ -10,7 +10,7 @@
      {{ _('Length') }}
      {% if entity['length'] %} - {{ entity['length'] | track_length_ms }} + {{ entity['length'] | track_length }} {% else %} - {% endif %} From 8fa4fc932d567b0e198fc03a0ab502798c5a9d85 Mon Sep 17 00:00:00 2001 From: spellew Date: Sat, 24 Aug 2019 11:59:41 -0400 Subject: [PATCH 17/20] Fixed artist in review/modify --- critiquebrainz/frontend/templates/review/modify/recording.html | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/critiquebrainz/frontend/templates/review/modify/recording.html b/critiquebrainz/frontend/templates/review/modify/recording.html index c888fc210..da6a30925 100644 --- a/critiquebrainz/frontend/templates/review/modify/recording.html +++ b/critiquebrainz/frontend/templates/review/modify/recording.html @@ -17,7 +17,7 @@
      {{ _('Artist') }}
      - {{ entity['artist'] or '-' }} + {{ entity['artist-credit-phrase'] or '-' }}
      {% block more_info %} {# Information like creation date, votes etc. #} diff --git a/requirements.txt b/requirements.txt index f279bed0a..d98d2e81e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -git+https://github.com/metabrainz/brainzutils-python.git@v1.13.0 +git+https://github.com/spellew/brainzutils-python.git@recording-multiple-credit-names#brainzutils beautifulsoup4==4.6.0 coverage==4.4.1 click==6.7 From b4ae26bc3eab156cb87c30bd5b2ef9f9b6f1c403 Mon Sep 17 00:00:00 2001 From: spellew Date: Tue, 27 Aug 2019 11:06:14 -0400 Subject: [PATCH 18/20] Removed unnecessary code --- .../frontend/templates/review/entity/recording.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/critiquebrainz/frontend/templates/review/entity/recording.html b/critiquebrainz/frontend/templates/review/entity/recording.html index 31e2d87e2..f495299ef 100644 --- a/critiquebrainz/frontend/templates/review/entity/recording.html +++ b/critiquebrainz/frontend/templates/review/entity/recording.html @@ -16,9 +16,5 @@

      {% endif %} {{ _('%(recording)s', recording=recording_name) }} - - {% if recording['life-span'] %} - {{ recording['life-span']['begin'][:4] }} - {% endif %}

      {% endblock %} From 2b41a34de75295474657144f851b6c06f48b9191 Mon Sep 17 00:00:00 2001 From: spellew Date: Fri, 30 Aug 2019 10:03:56 -0400 Subject: [PATCH 19/20] Updated brainzutils --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d98d2e81e..5d0abc8f8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -git+https://github.com/spellew/brainzutils-python.git@recording-multiple-credit-names#brainzutils +git+https://github.com/metabrainz/brainzutils-python.git@v1.14.0 beautifulsoup4==4.6.0 coverage==4.4.1 click==6.7 From 8fd7cf399bec98c24f0295a1a450aa388c15eefa Mon Sep 17 00:00:00 2001 From: spellew Date: Mon, 16 Dec 2019 01:10:30 -0500 Subject: [PATCH 20/20] Removed leftover tags --- critiquebrainz/frontend/templates/search/selector_results.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/critiquebrainz/frontend/templates/search/selector_results.html b/critiquebrainz/frontend/templates/search/selector_results.html index 32a26c4bf..f77e64a3a 100644 --- a/critiquebrainz/frontend/templates/search/selector_results.html +++ b/critiquebrainz/frontend/templates/search/selector_results.html @@ -118,7 +118,7 @@ -{% elif type=="recording" %} +{% elif type=="recording" %} {{ result['title'] }}