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
Pleroma
pleroma
Commits
5a4e2905
Commit
5a4e2905
authored
Feb 22, 2019
by
kaniini
Browse files
Merge branch 'fix/twittercards' into 'develop'
Fix Twitter Cards See merge request
pleroma/pleroma!815
parents
eeeb8124
f4bfc628
Pipeline
#8051
passed with stages
in 3 minutes and 41 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
lib/pleroma/web/metadata/opengraph.ex
View file @
5a4e2905
...
...
@@ -3,12 +3,10 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule
Pleroma
.
Web
.
Metadata
.
Providers
.
OpenGraph
do
alias
Pleroma
.
HTML
alias
Pleroma
.
Formatter
alias
Pleroma
.
User
alias
Pleroma
.
Web
.
Metadata
alias
Pleroma
.
Web
.
MediaProxy
alias
Pleroma
.
Web
.
Metadata
.
Providers
.
Provider
alias
Pleroma
.
Web
.
Metadata
.
Utils
@behaviour
Provider
...
...
@@ -19,7 +17,7 @@ def build_tags(%{
user:
user
})
do
attachments
=
build_attachments
(
object
)
scrubbed_content
=
scrub_html_and_truncate
(
object
)
scrubbed_content
=
Utils
.
scrub_html_and_truncate
(
object
)
# Zero width space
content
=
if
scrubbed_content
!=
""
and
scrubbed_content
!=
"
\u200
B"
do
...
...
@@ -44,13 +42,14 @@ def build_tags(%{
{
:meta
,
[
property:
"og:description"
,
content:
"
#{
user_name_string
(
user
)
}
"
<>
content
content:
"
#{
Utils
.
user_name_string
(
user
)
}
"
<>
content
],
[]},
{
:meta
,
[
property:
"og:type"
,
content:
"website"
],
[]}
]
++
if
attachments
==
[]
or
Metadata
.
activity_nsfw?
(
object
)
do
[
{
:meta
,
[
property:
"og:image"
,
content:
attachment_url
(
User
.
avatar_url
(
user
))],
[]},
{
:meta
,
[
property:
"og:image"
,
content:
Utils
.
attachment_url
(
User
.
avatar_url
(
user
))],
[]},
{
:meta
,
[
property:
"og:image:width"
,
content:
150
],
[]},
{
:meta
,
[
property:
"og:image:height"
,
content:
150
],
[]}
]
...
...
@@ -61,17 +60,17 @@ def build_tags(%{
@impl
Provider
def
build_tags
(%{
user:
user
})
do
with
truncated_bio
=
scrub_html_and_truncate
(
user
.
bio
||
""
)
do
with
truncated_bio
=
Utils
.
scrub_html_and_truncate
(
user
.
bio
||
""
)
do
[
{
:meta
,
[
property:
"og:title"
,
content:
user_name_string
(
user
)
content:
Utils
.
user_name_string
(
user
)
],
[]},
{
:meta
,
[
property:
"og:url"
,
content:
User
.
profile_url
(
user
)],
[]},
{
:meta
,
[
property:
"og:description"
,
content:
truncated_bio
],
[]},
{
:meta
,
[
property:
"og:type"
,
content:
"website"
],
[]},
{
:meta
,
[
property:
"og:image"
,
content:
attachment_url
(
User
.
avatar_url
(
user
))],
[]},
{
:meta
,
[
property:
"og:image"
,
content:
Utils
.
attachment_url
(
User
.
avatar_url
(
user
))],
[]},
{
:meta
,
[
property:
"og:image:width"
,
content:
150
],
[]},
{
:meta
,
[
property:
"og:image:height"
,
content:
150
],
[]}
]
...
...
@@ -93,14 +92,15 @@ defp build_attachments(%{data: %{"attachment" => attachments}}) do
case
media_type
do
"audio"
->
[
{
:meta
,
[
property:
"og:"
<>
media_type
,
content:
attachment_url
(
url
[
"href"
])],
[]}
{
:meta
,
[
property:
"og:"
<>
media_type
,
content:
Utils
.
attachment_url
(
url
[
"href"
])],
[]}
|
acc
]
"image"
->
[
{
:meta
,
[
property:
"og:"
<>
media_type
,
content:
attachment_url
(
url
[
"href"
])],
[]},
{
:meta
,
[
property:
"og:"
<>
media_type
,
content:
Utils
.
attachment_url
(
url
[
"href"
])],
[]},
{
:meta
,
[
property:
"og:image:width"
,
content:
150
],
[]},
{
:meta
,
[
property:
"og:image:height"
,
content:
150
],
[]}
|
acc
...
...
@@ -108,7 +108,8 @@ defp build_attachments(%{data: %{"attachment" => attachments}}) do
"video"
->
[
{
:meta
,
[
property:
"og:"
<>
media_type
,
content:
attachment_url
(
url
[
"href"
])],
[]}
{
:meta
,
[
property:
"og:"
<>
media_type
,
content:
Utils
.
attachment_url
(
url
[
"href"
])],
[]}
|
acc
]
...
...
@@ -120,37 +121,4 @@ defp build_attachments(%{data: %{"attachment" => attachments}}) do
acc
++
rendered_tags
end
)
end
defp
scrub_html_and_truncate
(%{
data:
%{
"content"
=>
content
}}
=
object
)
do
content
# html content comes from DB already encoded, decode first and scrub after
|>
HtmlEntities
.
decode
()
|>
String
.
replace
(
~r/<br\s?\/
?>
/
,
" "
)
|>
HTML
.
get_cached_stripped_html_for_object
(
object
,
__MODULE__
)
|>
Formatter
.
demojify
()
|>
Formatter
.
truncate
()
end
defp
scrub_html_and_truncate
(
content
)
when
is_binary
(
content
)
do
content
# html content comes from DB already encoded, decode first and scrub after
|>
HtmlEntities
.
decode
()
|>
String
.
replace
(
~r/<br\s?\/
?>
/
,
" "
)
|>
HTML
.
strip_tags
()
|>
Formatter
.
demojify
()
|>
Formatter
.
truncate
()
end
defp
attachment_url
(
url
)
do
MediaProxy
.
url
(
url
)
end
defp
user_name_string
(
user
)
do
"
#{
user
.
name
}
"
<>
if
user
.
local
do
"(@
#{
user
.
nickname
}
@
#{
Pleroma
.
Web
.
Endpoint
.
host
()
}
)"
else
"(@
#{
user
.
nickname
}
)"
end
end
end
lib/pleroma/web/metadata/player_view.ex
0 → 100644
View file @
5a4e2905
defmodule
Pleroma
.
Web
.
Metadata
.
PlayerView
do
use
Pleroma
.
Web
,
:view
import
Phoenix
.
HTML
.
Tag
,
only:
[
content_tag:
3
,
tag:
2
]
def
render
(
"player.html"
,
%{
"mediaType"
=>
type
,
"href"
=>
href
})
do
{
tag_type
,
tag_attrs
}
=
case
type
do
"audio"
<>
_
->
{
:audio
,
[]}
"video"
<>
_
->
{
:video
,
[
loop
:
true
]}
end
content_tag
(
tag_type
,
[
tag
(
:source
,
src:
href
,
type:
type
),
"Your browser does not support
#{
type
}
playback."
],
[
controls:
true
]
++
tag_attrs
)
end
end
lib/pleroma/web/metadata/twitter_card.ex
View file @
5a4e2905
...
...
@@ -3,44 +3,122 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule
Pleroma
.
Web
.
Metadata
.
Providers
.
TwitterCard
do
alias
Pleroma
.
Web
.
Metadata
.
Providers
.
Provid
er
alias
Pleroma
.
Us
er
alias
Pleroma
.
Web
.
Metadata
alias
Pleroma
.
Web
.
Metadata
.
Providers
.
Provider
alias
Pleroma
.
Web
.
Metadata
.
Utils
@behaviour
Provider
@impl
Provider
def
build_tags
(%{
object:
object
})
do
if
Metadata
.
activity_nsfw?
(
object
)
or
object
.
data
[
"attachment"
]
==
[]
do
build_tags
(
nil
)
else
case
find_first_acceptable_media_type
(
object
)
do
"image"
->
[{
:meta
,
[
property:
"twitter:card"
,
content:
"summary_large_image"
],
[]}]
"audio"
->
[{
:meta
,
[
property:
"twitter:card"
,
content:
"player"
],
[]}]
"video"
->
[{
:meta
,
[
property:
"twitter:card"
,
content:
"player"
],
[]}]
_
->
build_tags
(
nil
)
def
build_tags
(%{
activity_id:
id
,
object:
object
,
user:
user
})
do
attachments
=
build_attachments
(
id
,
object
)
scrubbed_content
=
Utils
.
scrub_html_and_truncate
(
object
)
# Zero width space
content
=
if
scrubbed_content
!=
""
and
scrubbed_content
!=
"
\u200
B"
do
"“"
<>
scrubbed_content
<>
"”"
else
""
end
[
{
:meta
,
[
property:
"twitter:title"
,
content:
Utils
.
user_name_string
(
user
)
],
[]},
{
:meta
,
[
property:
"twitter:description"
,
content:
content
],
[]}
]
++
if
attachments
==
[]
or
Metadata
.
activity_nsfw?
(
object
)
do
[
{
:meta
,
[
property:
"twitter:image"
,
content:
Utils
.
attachment_url
(
User
.
avatar_url
(
user
))],
[]},
{
:meta
,
[
property:
"twitter:card"
,
content:
"summary_large_image"
],
[]}
]
else
attachments
end
end
end
@impl
Provider
def
build_tags
(
_
)
do
[{
:meta
,
[
property:
"twitter:card"
,
content:
"summary"
],
[]}]
def
build_tags
(%{
user:
user
})
do
with
truncated_bio
=
Utils
.
scrub_html_and_truncate
(
user
.
bio
||
""
)
do
[
{
:meta
,
[
property:
"twitter:title"
,
content:
Utils
.
user_name_string
(
user
)
],
[]},
{
:meta
,
[
property:
"twitter:description"
,
content:
truncated_bio
],
[]},
{
:meta
,
[
property:
"twitter:image"
,
content:
Utils
.
attachment_url
(
User
.
avatar_url
(
user
))],
[]},
{
:meta
,
[
property:
"twitter:card"
,
content:
"summary"
],
[]}
]
end
end
def
find_first_acceptable_media_type
(%{
data:
%{
"attachment"
=>
attachment
}})
do
Enum
.
find_value
(
attachment
,
fn
attachment
->
Enum
.
find_value
(
attachment
[
"url"
],
fn
url
->
Enum
.
find
([
"image"
,
"audio"
,
"video"
],
fn
media_type
->
String
.
starts_with?
(
url
[
"mediaType"
],
media_type
)
defp
build_attachments
(
id
,
z
=
%{
data:
%{
"attachment"
=>
attachments
}})
do
IO
.
puts
(
inspect
(
z
))
Enum
.
reduce
(
attachments
,
[],
fn
attachment
,
acc
->
rendered_tags
=
Enum
.
reduce
(
attachment
[
"url"
],
[],
fn
url
,
acc
->
media_type
=
Enum
.
find
([
"image"
,
"audio"
,
"video"
],
fn
media_type
->
String
.
starts_with?
(
url
[
"mediaType"
],
media_type
)
end
)
# TODO: Add additional properties to objects when we have the data available.
case
media_type
do
"audio"
->
[
{
:meta
,
[
property:
"twitter:card"
,
content:
"player"
],
[]},
{
:meta
,
[
property:
"twitter:player:width"
,
content:
"480"
],
[]},
{
:meta
,
[
property:
"twitter:player:height"
,
content:
"80"
],
[]},
{
:meta
,
[
property:
"twitter:player"
,
content:
player_url
(
id
)],
[]}
|
acc
]
"image"
->
[
{
:meta
,
[
property:
"twitter:card"
,
content:
"summary_large_image"
],
[]},
{
:meta
,
[
property:
"twitter:player"
,
content:
Utils
.
attachment_url
(
url
[
"href"
])
],
[]}
|
acc
]
# TODO: Need the true width and height values here or Twitter renders an iFrame with a bad aspect ratio
"video"
->
[
{
:meta
,
[
property:
"twitter:card"
,
content:
"player"
],
[]},
{
:meta
,
[
property:
"twitter:player"
,
content:
player_url
(
id
)],
[]},
{
:meta
,
[
property:
"twitter:player:width"
,
content:
"480"
],
[]},
{
:meta
,
[
property:
"twitter:player:height"
,
content:
"480"
],
[]}
|
acc
]
_
->
acc
end
end
)
end
)
acc
++
rendered_tags
end
)
end
defp
player_url
(
id
)
do
Pleroma
.
Web
.
Router
.
Helpers
.
o_status_url
(
Pleroma
.
Web
.
Endpoint
,
:notice_player
,
id
)
end
end
lib/pleroma/web/metadata/utils.ex
0 → 100644
View file @
5a4e2905
# Pleroma: A lightweight social networking server
# Copyright \xc2\xa9 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule
Pleroma
.
Web
.
Metadata
.
Utils
do
alias
Pleroma
.
HTML
alias
Pleroma
.
Formatter
alias
Pleroma
.
Web
.
MediaProxy
def
scrub_html_and_truncate
(%{
data:
%{
"content"
=>
content
}}
=
object
)
do
content
# html content comes from DB already encoded, decode first and scrub after
|>
HtmlEntities
.
decode
()
|>
String
.
replace
(
~r/<br\s?\/
?>
/
,
" "
)
|>
HTML
.
get_cached_stripped_html_for_object
(
object
,
__MODULE__
)
|>
Formatter
.
demojify
()
|>
Formatter
.
truncate
()
end
def
scrub_html_and_truncate
(
content
)
when
is_binary
(
content
)
do
content
# html content comes from DB already encoded, decode first and scrub after
|>
HtmlEntities
.
decode
()
|>
String
.
replace
(
~r/<br\s?\/
?>
/
,
" "
)
|>
HTML
.
strip_tags
()
|>
Formatter
.
demojify
()
|>
Formatter
.
truncate
()
end
def
attachment_url
(
url
)
do
MediaProxy
.
url
(
url
)
end
def
user_name_string
(
user
)
do
"
#{
user
.
name
}
"
<>
if
user
.
local
do
"(@
#{
user
.
nickname
}
@
#{
Pleroma
.
Web
.
Endpoint
.
host
()
}
)"
else
"(@
#{
user
.
nickname
}
)"
end
end
end
lib/pleroma/web/ostatus/ostatus_controller.ex
View file @
5a4e2905
...
...
@@ -156,6 +156,7 @@ def notice(conn, %{"id" => id}) do
%
Object
{}
=
object
=
Object
.
normalize
(
activity
.
data
[
"object"
])
Fallback
.
RedirectController
.
redirector_with_meta
(
conn
,
%{
activity_id:
activity
.
id
,
object:
object
,
url:
Pleroma
.
Web
.
Router
.
Helpers
.
o_status_url
(
...
...
@@ -187,6 +188,30 @@ def notice(conn, %{"id" => id}) do
end
end
# Returns an HTML embedded <audio> or <video> player suitable for embed iframes.
def
notice_player
(
conn
,
%{
"id"
=>
id
})
do
with
%
Activity
{
data:
%{
"type"
=>
"Create"
}}
=
activity
<-
Activity
.
get_by_id
(
id
),
true
<-
ActivityPub
.
is_public?
(
activity
),
%
Object
{}
=
object
<-
Object
.
normalize
(
activity
.
data
[
"object"
]),
%{
data:
%{
"attachment"
=>
[%{
"url"
=>
[
url
|
_
]}
|
_
]}}
<-
object
,
true
<-
String
.
starts_with?
(
url
[
"mediaType"
],
[
"audio"
,
"video"
])
do
conn
|>
put_layout
(
:metadata_player
)
|>
put_resp_header
(
"x-frame-options"
,
"ALLOW"
)
|>
put_resp_header
(
"content-security-policy"
,
"default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;"
)
|>
put_view
(
Pleroma
.
Web
.
Metadata
.
PlayerView
)
|>
render
(
"player.html"
,
url
)
else
_error
->
conn
|>
put_status
(
404
)
|>
Fallback
.
RedirectController
.
redirector
(
nil
,
404
)
end
end
defp
represent_activity
(
conn
,
"activity+json"
,
...
...
lib/pleroma/web/router.ex
View file @
5a4e2905
...
...
@@ -505,6 +505,7 @@ defmodule Pleroma.Web.Router do
get
(
"/objects/:uuid"
,
OStatus
.
OStatusController
,
:object
)
get
(
"/activities/:uuid"
,
OStatus
.
OStatusController
,
:activity
)
get
(
"/notice/:id"
,
OStatus
.
OStatusController
,
:notice
)
get
(
"/notice/:id/embed_player"
,
OStatus
.
OStatusController
,
:notice_player
)
get
(
"/users/:nickname/feed"
,
OStatus
.
OStatusController
,
:feed
)
get
(
"/users/:nickname"
,
OStatus
.
OStatusController
,
:feed_redirect
)
...
...
lib/pleroma/web/templates/layout/metadata_player.html.eex
0 → 100644
View file @
5a4e2905
<!DOCTYPE html>
<html>
<body>
<style
type=
"text/css"
>
video
,
audio
{
width
:
100%
;
max-width
:
600px
;
height
:
auto
;
}
</style>
<%=
render
@view_module
,
@view_template
,
assigns
%>
</body>
</html>
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