Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
funkwhale
funkwhale
Commits
8ae00b06
Verified
Commit
8ae00b06
authored
Mar 08, 2019
by
Eliot Berriot
Browse files
Fix #747: Support embedding full artist discographies
parent
1d787904
Pipeline
#3481
passed with stages
in 2 minutes and 48 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
api/funkwhale_api/music/serializers.py
View file @
8ae00b06
...
...
@@ -470,6 +470,36 @@ class OembedSerializer(serializers.Serializer):
"library_artist"
,
kwargs
=
{
"pk"
:
album
.
artist
.
pk
}
)
)
elif
match
.
url_name
==
"library_artist"
:
qs
=
models
.
Artist
.
objects
.
filter
(
pk
=
int
(
match
.
kwargs
[
"pk"
]))
try
:
artist
=
qs
.
get
()
except
models
.
Artist
.
DoesNotExist
:
raise
serializers
.
ValidationError
(
"No artist matching id {}"
.
format
(
match
.
kwargs
[
"pk"
])
)
embed_type
=
"artist"
embed_id
=
artist
.
pk
album
=
(
artist
.
albums
.
filter
(
cover__isnull
=
False
)
.
exclude
(
cover
=
""
)
.
order_by
(
"-id"
)
.
first
()
)
if
album
and
album
.
cover
:
data
[
"thumbnail_url"
]
=
federation_utils
.
full_url
(
album
.
cover
.
crop
[
"400x400"
].
url
)
data
[
"thumbnail_width"
]
=
400
data
[
"thumbnail_height"
]
=
400
data
[
"title"
]
=
artist
.
name
data
[
"description"
]
=
artist
.
name
data
[
"author_name"
]
=
artist
.
name
data
[
"height"
]
=
400
data
[
"author_url"
]
=
federation_utils
.
full_url
(
common_utils
.
spa_reverse
(
"library_artist"
,
kwargs
=
{
"pk"
:
artist
.
pk
})
)
else
:
raise
serializers
.
ValidationError
(
"Unsupported url: {}"
.
format
(
validated_data
[
"url"
])
...
...
api/funkwhale_api/music/spa_views.py
View file @
8ae00b06
...
...
@@ -2,6 +2,7 @@ import urllib.parse
from
django.conf
import
settings
from
django.urls
import
reverse
from
django.db.models
import
Q
from
funkwhale_api.common
import
utils
...
...
@@ -183,4 +184,22 @@ def library_artist(request, pk):
}
)
if
(
models
.
Upload
.
objects
.
filter
(
Q
(
track__artist
=
obj
)
|
Q
(
track__album__artist
=
obj
))
.
playable_by
(
None
)
.
exists
()
):
metas
.
append
(
{
"tag"
:
"link"
,
"rel"
:
"alternate"
,
"type"
:
"application/json+oembed"
,
"href"
:
(
utils
.
join_url
(
settings
.
FUNKWHALE_URL
,
reverse
(
"api:v1:oembed"
))
+
"?format=json&url={}"
.
format
(
urllib
.
parse
.
quote_plus
(
artist_url
))
),
}
)
# twitter player is also supported in various software
metas
+=
get_twitter_card_metas
(
type
=
"artist"
,
id
=
obj
.
pk
)
return
metas
api/funkwhale_api/music/views.py
View file @
8ae00b06
...
...
@@ -184,6 +184,8 @@ class TrackViewSet(
"title"
,
"album__release_date"
,
"size"
,
"position"
,
"disc_number"
,
"artist__name"
,
)
...
...
api/tests/music/test_spa_views.py
View file @
8ae00b06
...
...
@@ -149,6 +149,7 @@ def test_library_album(spa_html, no_api_auth, client, factories, settings):
def
test_library_artist
(
spa_html
,
no_api_auth
,
client
,
factories
,
settings
):
album
=
factories
[
"music.Album"
]()
factories
[
"music.Upload"
](
playable
=
True
,
track__album
=
album
)
artist
=
album
.
artist
url
=
"/library/artists/{}"
.
format
(
artist
.
pk
)
...
...
@@ -169,6 +170,25 @@ def test_library_artist(spa_html, no_api_auth, client, factories, settings):
settings
.
FUNKWHALE_URL
,
album
.
cover
.
crop
[
"400x400"
].
url
),
},
{
"tag"
:
"link"
,
"rel"
:
"alternate"
,
"type"
:
"application/json+oembed"
,
"href"
:
(
utils
.
join_url
(
settings
.
FUNKWHALE_URL
,
reverse
(
"api:v1:oembed"
))
+
"?format=json&url={}"
.
format
(
urllib
.
parse
.
quote_plus
(
utils
.
join_url
(
settings
.
FUNKWHALE_URL
,
url
))
)
),
},
{
"tag"
:
"meta"
,
"property"
:
"twitter:card"
,
"content"
:
"player"
},
{
"tag"
:
"meta"
,
"property"
:
"twitter:player"
,
"content"
:
serializers
.
get_embed_url
(
"artist"
,
id
=
artist
.
id
),
},
{
"tag"
:
"meta"
,
"property"
:
"twitter:player:width"
,
"content"
:
"600"
},
{
"tag"
:
"meta"
,
"property"
:
"twitter:player:height"
,
"content"
:
"400"
},
]
metas
=
utils
.
parse_meta
(
response
.
content
.
decode
())
...
...
api/tests/music/test_views.py
View file @
8ae00b06
...
...
@@ -701,3 +701,38 @@ def test_oembed_album(factories, no_api_auth, api_client, settings):
response
=
api_client
.
get
(
url
,
{
"url"
:
album_url
,
"format"
:
"json"
})
assert
response
.
data
==
expected
def
test_oembed_artist
(
factories
,
no_api_auth
,
api_client
,
settings
):
settings
.
FUNKWHALE_URL
=
"http://test"
settings
.
FUNKWHALE_EMBED_URL
=
"http://embed"
track
=
factories
[
"music.Track"
]()
album
=
track
.
album
artist
=
track
.
artist
url
=
reverse
(
"api:v1:oembed"
)
artist_url
=
"https://test.com/library/artists/{}"
.
format
(
artist
.
pk
)
iframe_src
=
"http://embed?type=artist&id={}"
.
format
(
artist
.
pk
)
expected
=
{
"version"
:
"1.0"
,
"type"
:
"rich"
,
"provider_name"
:
settings
.
APP_NAME
,
"provider_url"
:
settings
.
FUNKWHALE_URL
,
"height"
:
400
,
"width"
:
600
,
"title"
:
artist
.
name
,
"description"
:
artist
.
name
,
"thumbnail_url"
:
federation_utils
.
full_url
(
album
.
cover
.
crop
[
"400x400"
].
url
),
"thumbnail_height"
:
400
,
"thumbnail_width"
:
400
,
"html"
:
'<iframe width="600" height="400" scrolling="no" frameborder="no" src="{}"></iframe>'
.
format
(
iframe_src
),
"author_name"
:
artist
.
name
,
"author_url"
:
federation_utils
.
full_url
(
utils
.
spa_reverse
(
"library_artist"
,
kwargs
=
{
"pk"
:
artist
.
pk
})
),
}
response
=
api_client
.
get
(
url
,
{
"url"
:
artist_url
,
"format"
:
"json"
})
assert
response
.
data
==
expected
changes/changelog.d/747.feature
0 → 100644
View file @
8ae00b06
Support
embedding
full
artist
discographies
(
#747)
front/src/EmbedFrame.vue
View file @
8ae00b06
...
...
@@ -139,7 +139,7 @@ export default {
data
()
{
return
{
time
,
supportedTypes
:
[
'
track
'
,
'
album
'
],
supportedTypes
:
[
'
track
'
,
'
album
'
,
'
artist
'
],
baseUrl
:
''
,
error
:
null
,
type
:
null
,
...
...
@@ -158,6 +158,7 @@ export default {
},
created
()
{
let
params
=
getURLParams
()
this
.
baseUrl
=
params
.
b
||
''
this
.
type
=
params
.
type
if
(
this
.
supportedTypes
.
indexOf
(
this
.
type
)
===
-
1
)
{
this
.
error
=
'
invalid_type
'
...
...
@@ -229,7 +230,10 @@ export default {
this
.
fetchTrack
(
id
)
}
if
(
type
===
'
album
'
)
{
this
.
fetchTracks
({
album
:
id
,
playable
:
true
})
this
.
fetchTracks
({
album
:
id
,
playable
:
true
,
ordering
:
"
,disc_number,position
"
})
}
if
(
type
===
'
artist
'
)
{
this
.
fetchTracks
({
artist
:
id
,
playable
:
true
,
ordering
:
"
-release_date,disc_number,position
"
})
}
},
play
(
index
)
{
...
...
front/src/components/audio/EmbedWizard.vue
View file @
8ae00b06
...
...
@@ -29,7 +29,11 @@
</div>
</div>
<div
class=
"preview"
>
<h3><translate
:translate-context=
"'Popup/Embed/Title/Noun'"
>
Preview
</translate></h3>
<h3>
<a
:href=
"iframeSrc"
target=
"_blank"
>
<translate
:translate-context=
"'Popup/Embed/Title/Noun'"
>
Preview
</translate>
</a>
</h3>
<iframe
:width=
"frameWidth"
:height=
"height"
scrolling=
"no"
frameborder=
"no"
:src=
"iframeSrc"
></iframe>
</div>
</div>
...
...
front/src/components/library/Artist.vue
View file @
8ae00b06
...
...
@@ -35,6 +35,30 @@
<i
class=
"external icon"
></i>
<translate
:translate-context=
"'Content/*/Button.Label/Verb'"
>
View on MusicBrainz
</translate>
</a>
<template
v-if=
"publicLibraries.length > 0"
>
<button
@
click=
"showEmbedModal = !showEmbedModal"
class=
"ui button icon labeled"
>
<i
class=
"code icon"
></i>
<translate
:translate-context=
"'Content/*/Button.Label/Verb'"
>
Embed
</translate>
</button>
<modal
:show.sync=
"showEmbedModal"
>
<div
class=
"header"
>
<translate
:translate-context=
"'Popup/Artist/Title/Verb'"
>
Embed this artist work on your website
</translate>
</div>
<div
class=
"content"
>
<div
class=
"description"
>
<embed-wizard
type=
"artist"
:id=
"artist.id"
/>
</div>
</div>
<div
class=
"actions"
>
<div
class=
"ui deny button"
>
<translate
:translate-context=
"'Popup/*/Button.Label/Verb'"
>
Cancel
</translate>
</div>
</div>
</modal>
</
template
>
</div>
</section>
<div
class=
"ui small text container"
v-if=
"contentFilter"
>
...
...
@@ -72,7 +96,7 @@
<h2>
<translate
:translate-context=
"'Content/Artist/Title'"
>
User libraries
</translate>
</h2>
<library-widget
:url=
"'artists/' + id + '/libraries/'"
>
<library-widget
@
loaded=
"libraries = $event"
:url=
"'artists/' + id + '/libraries/'"
>
<translate
:translate-context=
"'Content/Artist/Paragraph'"
slot=
"subtitle"
>
This artist is present in the following libraries:
</translate>
</library-widget>
</section>
...
...
@@ -90,6 +114,8 @@ import RadioButton from "@/components/radios/Button"
import
PlayButton
from
"
@/components/audio/PlayButton
"
import
TrackTable
from
"
@/components/audio/track/Table
"
import
LibraryWidget
from
"
@/components/federation/LibraryWidget
"
import
EmbedWizard
from
"
@/components/audio/EmbedWizard
"
import
Modal
from
'
@/components/semantic/Modal
'
export
default
{
props
:
[
"
id
"
],
...
...
@@ -98,7 +124,9 @@ export default {
RadioButton
,
PlayButton
,
TrackTable
,
LibraryWidget
LibraryWidget
,
EmbedWizard
,
Modal
},
data
()
{
return
{
...
...
@@ -108,7 +136,9 @@ export default {
albums
:
null
,
totalTracks
:
0
,
totalAlbums
:
0
,
tracks
:
[]
tracks
:
[],
libraries
:
[],
showEmbedModal
:
false
}
},
created
()
{
...
...
@@ -185,6 +215,12 @@ export default {
return
album
.
cover
})[
0
]
},
publicLibraries
()
{
return
this
.
libraries
.
filter
(
l
=>
{
return
l
.
privacy_level
===
'
everyone
'
})
},
headerStyle
()
{
if
(
!
this
.
cover
||
!
this
.
cover
.
original
)
{
return
""
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment