Skip to content

Commit

Permalink
tweak(ext/cfx-ui): youtube embeds for community tweets
Browse files Browse the repository at this point in the history
Some RTs (like https://twitter.com/xinerki/status/1666055508548018178)
have a YouTube link rather than a native Twitter embed.
  • Loading branch information
blattersturm committed Jun 11, 2023
1 parent 9a8c902 commit 358da49
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 8 deletions.
Expand Up @@ -46,8 +46,13 @@
}

// Video element does not naturally grow - stretch it
video.media {
video.media, iframe.media {
height: 90%;
aspect-ratio: ui.use('ar');
}

// iframes have a border
iframe.media {
border: none;
}
}
Expand Up @@ -11,7 +11,7 @@ const Outlet = createOutlet();
export const AcitivityItemMediaViewer = observer(function AcitivityItemMediaViewer() {
const state = AcitivityItemMediaViewerState;

const ref = React.useRef<HTMLImageElement | HTMLVideoElement | null>(null);
const ref = React.useRef<HTMLImageElement | HTMLVideoElement | HTMLIFrameElement | null>(null);
const [toRect, setToRect] = React.useState<IRect | null>(null);

React.useEffect(() => {
Expand Down Expand Up @@ -68,7 +68,7 @@ export const AcitivityItemMediaViewer = observer(function AcitivityItemMediaView

const TargetElement = state.media.type === 'video'
? 'video'
: 'img';
: (state.media.type === 'youtube' ? 'iframe' : 'img');

return (
<Outlet>
Expand Down
55 changes: 52 additions & 3 deletions ext/cfx-ui/src/cfx/common/services/activity/twitter.ts
@@ -1,5 +1,26 @@
import { splitByIndices } from "cfx/utils/string";
import { IActivityItemData, IActivityItemMedia, IRawTweet } from "./types";
import { IActivityItemData, IActivityItemMedia, IRawTweet, IRawTweetTypes } from "./types";

function parseYoutube(url: string): [ boolean, string ] {
const parsedUrl = new URL(url);
if (parsedUrl.hostname === 'youtu.be' && parsedUrl.pathname.length >= 5) {
return [ true, parsedUrl.pathname.substring(1) ];
} else if (parsedUrl.hostname == 'youtube.com' && parsedUrl.pathname.startsWith('/watch')) {
const v = parsedUrl.searchParams.get('v');

if (v) {
return [ true, v ];
}
}

return [ false, '' ];
}

function isYoutube(url: string) {
const [ valid ] = parseYoutube(url);

return valid;
}

export function rawTweetToActivityDataItem(rawTweet: IRawTweet): IActivityItemData | null {
let actualTweet = rawTweet;
Expand Down Expand Up @@ -35,14 +56,42 @@ export function rawTweetToActivityDataItem(rawTweet: IRawTweet): IActivityItemDa

if (mediaEntity.type === 'animated_gif' || mediaEntity.type === 'video') {
mediaItem.fullAspectRatio = mediaEntity.video_info.aspect_ratio[0] / mediaEntity.video_info.aspect_ratio[1];
mediaItem.fullUrl = mediaEntity.video_info.variants.filter(a => a.content_type?.startsWith('video/')).sort((a, b) => b.bitrate - a.bitrate)[0].url;
mediaItem.fullUrl = mediaEntity.video_info.variants
.filter(a => a.content_type?.startsWith('video/'))
.sort((a, b) => b.bitrate - a.bitrate)[0]
.url;
}

media.push(mediaItem);
}
}

const mediaIndicesFull = (actualTweet.entities.media || []).map((media) => media.indices);
const youtubeIndices: IRawTweetTypes.Indices[] = [];

// some tweets (e.g. https://twitter.com/Lucas7yoshi_RS/status/1665445339946418178) may have both an embed and a
// YT link
if (media.length === 0) {
const youtubeUrls = actualTweet.entities?.urls?.filter(x => isYoutube(x.expanded_url)) || [];

for (const youtube of youtubeUrls) {
const [ _, videoId ] = parseYoutube(youtube.expanded_url);

media.push({
id: videoId,
type: 'youtube',

previewAspectRatio: 16 / 9,
previewUrl: `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`,

fullAspectRatio: 16 / 9,
fullUrl: `https://www.youtube.com/embed/${videoId}?enablejsapi=1&autoplay=1`,
});

youtubeIndices.push(youtube.indices);
}
}

const mediaIndicesFull = (actualTweet.entities.media || []).map((media) => media.indices).concat(youtubeIndices);
const mediaIndices = mediaIndicesFull.map(([x]) => x);

const urlIndicesFull = (actualTweet.entities.urls || []).map((url) => url.indices);
Expand Down
2 changes: 1 addition & 1 deletion ext/cfx-ui/src/cfx/common/services/activity/types.ts
Expand Up @@ -200,7 +200,7 @@ export interface IActivityItemData {

export interface IActivityItemMedia {
id: string,
type: 'photo' | 'animated_gif' | 'video',
type: 'photo' | 'animated_gif' | 'video' | 'youtube',

blurhash?: string,
previewUrl?: string,
Expand Down
3 changes: 2 additions & 1 deletion ext/cfx-ui/src/cfx/ui/ActivityItem/ActivityItem.tsx
Expand Up @@ -68,7 +68,8 @@ function Media({ media }: { media: IActivityItemMedia }) {

switch (media.type) {
case 'animated_gif':
case 'photo': {
case 'photo':
case 'youtube': {
view = (
<ImagePreview media={media} />
);
Expand Down

1 comment on commit 358da49

@tris-ten
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

Please sign in to comment.