[FIX] Spotify oEmbed (#19825)

pull/19689/head
Tasso Evangelista 5 years ago committed by GitHub
parent 7a21974bb3
commit 346077171d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      app/oembed/client/baseWidget.js
  2. 5
      app/oembed/server/providers.js
  3. 4
      app/spotify/client/index.js
  4. 16
      app/spotify/client/oembedSpotifyWidget.html
  5. 16
      app/spotify/client/oembedSpotifyWidget.js
  6. 69
      app/spotify/lib/spotify.js
  7. 4
      app/spotify/server/index.js
  8. 1
      client/importPackages.js
  9. 1
      client/startup/beforeSaveMessage/index.js
  10. 10
      client/startup/beforeSaveMessage/spotify.js
  11. 1
      client/startup/index.js
  12. 1
      client/startup/renderMessage/index.js
  13. 11
      client/startup/renderMessage/spotify.js

@ -7,27 +7,19 @@ createCollapseable(Template.oembedBaseWidget, (instance) => instance.data.settin
Template.oembedBaseWidget.helpers({
template() {
const { collapsedMedia } = Template.instance();
this.collapsedMediaVar = function() { return collapsedMedia; };
this.collapsedMediaVar = () => collapsedMedia;
this.collapsed = collapsedMedia.get();
let contentType;
if (this.headers) {
contentType = this.headers.contentType;
}
if (this._overrideTemplate) {
return this._overrideTemplate;
}
if (this.headers && contentType && contentType.match(/image\/.*/)) {
if (this.headers?.contentType?.match(/image\/.*/)) {
return 'oembedImageWidget';
}
if (this.headers && contentType && contentType.match(/audio\/.*/)) {
if (this.headers?.contentType?.match(/audio\/.*/)) {
return 'oembedAudioWidget';
}
if ((this.headers && contentType && contentType.match(/video\/.*/)) || (this.meta && this.meta.twitterPlayerStreamContentType && this.meta.twitterPlayerStreamContentType.match(/video\/.*/))) {
if (this.headers?.contentType?.match(/video\/.*/) || this.meta?.twitterPlayerStreamContentType?.match(/video\/.*/)) {
return 'oembedVideoWidget';
}
if (this.meta && this.meta.oembedHtml) {
if (this.meta?.oembedHtml) {
return 'oembedFrameWidget';
}
return 'oembedUrlWidget';

@ -73,6 +73,11 @@ providers.registerProvider({
endPoint: 'https://publish.twitter.com/oembed',
});
providers.registerProvider({
urls: [new RegExp('https?://(play|open)\\.spotify\\.com/(track|album|playlist|show)/\\S+')],
endPoint: 'https://open.spotify.com/oembed',
});
export const oembed = {};
oembed.providers = providers;

@ -1,4 +0,0 @@
import './oembedSpotifyWidget';
import './oembedSpotifyWidget.html';
export { createSpotifyMessageRenderer, createSpotifyBeforeSaveMessageHandler } from '../lib/spotify';

@ -1,16 +0,0 @@
<template name="oembedSpotifyWidget">
{{#if parsedUrl}}
<blockquote class="message-oembed background-transparent-darker-before">
<a href="https://www.spotify.com" rel="noopener noreferrer" style="color: #9e9ea6">Spotify</a><br/>
{{#if match meta.ogAudio "spotify:artist:\\S+"}}
<a rel="noopener noreferrer" href="{{url}}" target="_blank">{{{meta.ogTitle}}}</a>
{{else}}
<a rel="noopener noreferrer" href="{{url}}" target="_blank">{{{replace meta.ogDescription ", an? (?:song|album) by (.+?) on Spotify" " - $1" regex=true}}}</a>
{{/if}}
{{> collapseArrow collapsedMedia=collapsedMediaVar}} <br>
{{#unless collapsed}}
<iframe width="300" height="380" src="{{meta.twitterPlayer}}" rel="noopener noreferrer" frameborder="0"></iframe><br>
{{/unless}}
</blockquote>
{{/if}}
</template>

@ -1,16 +0,0 @@
import { Template } from 'meteor/templating';
Template.registerHelper('replace', function(source, find, replace, option) {
if (option.hash.regex === true) {
find = new RegExp(find);
}
return source.replace(find, replace);
});
Template.registerHelper('match', (source, regex) => new RegExp(regex).test(source));
Template.oembedBaseWidget.onCreated(function() {
if (this.data && (this.data.meta && /^(music\.song|music\.album)$/.test(this.data.meta.ogType)) && this.data.parsedUrl && this.data.parsedUrl.host === 'open.spotify.com') {
this.data._overrideTemplate = 'oembedSpotifyWidget';
}
});

@ -1,15 +1,8 @@
/*
* Spotify a named function that will process Spotify links or syntaxes (ex: spotify:track:1q6IK1l4qpYykOaWaLJkWG)
* @param {Object} message - The message object
*/
import _ from 'underscore';
const process = (message, source, callback) => {
if (!source?.trim()) {
return;
}
// Separate text in code blocks and non code blocks
const msgParts = source.split(/(```\w*[\n ]?[\s\S]*?```+?)|(`(?:[^`]+)`)/);
for (let index = 0; index < msgParts.length; index++) {
const part = msgParts[index];
@ -19,55 +12,27 @@ const process = (message, source, callback) => {
}
};
class Spotify {
static transform(message) {
let urls = [];
if (Array.isArray(message.urls)) {
urls = urls.concat(message.urls);
}
let changed = false;
export const createSpotifyBeforeSaveMessageHandler = () => (message) => {
const urls = Array.isArray(message.urls) ? message.urls : [];
process(message, message.msg, function(message, msgParts, index, part) {
const re = /(?:^|\s)spotify:([^:\s]+):([^:\s]+)(?::([^:\s]+))?(?::(\S+))?(?:\s|$)/g;
let changed = false;
let match;
while ((match = re.exec(part)) != null) {
const data = _.filter(match.slice(1), (value) => value != null);
const path = _.map(data, (value) => _.escape(value)).join('/');
const url = `https://open.spotify.com/${ path }`;
urls.push({ url, source: `spotify:${ data.join(':') }` });
changed = true;
}
});
process(message, message.msg, (message, msgParts, index, part) => {
const re = /(?:^|\s)spotify:([^:\s]+):([^:\s]+)(?::([^:\s]+))?(?::(\S+))?(?:\s|$)/g;
// Re-mount message
if (changed) {
message.urls = urls;
let match;
while ((match = re.exec(part)) != null) {
const data = match.slice(1).filter(Boolean);
const path = data.map((value) => encodeURI(value)).join('/');
const url = `https://open.spotify.com/${ path }`;
urls.push({ url, source: `spotify:${ data.join(':') }` });
changed = true;
}
});
return message;
}
static render(message) {
process(message, message.html, function(message, msgParts, index, part) {
if (Array.isArray(message.urls)) {
for (const item of Array.from(message.urls)) {
if (item.source) {
const quotedSource = item.source.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
const re = new RegExp(`(^|\\s)${ quotedSource }(\\s|$)`, 'g');
msgParts[index] = part.replace(re, `$1<a href="${ item.url }" target="_blank">${ item.source }</a>$2`);
}
}
message.html = msgParts.join('');
return message.html;
}
});
return message;
if (changed) {
message.urls = urls;
}
}
export const createSpotifyMessageRenderer = () => Spotify.render;
export const createSpotifyBeforeSaveMessageHandler = () => Spotify.transform;
return message;
};

@ -1,12 +1,10 @@
import { Meteor } from 'meteor/meteor';
import { callbacks } from '../../callbacks';
import { createSpotifyBeforeSaveMessageHandler, createSpotifyMessageRenderer } from '../lib/spotify';
import { createSpotifyBeforeSaveMessageHandler } from '../lib/spotify';
Meteor.startup(() => {
const beforeSaveMessage = createSpotifyBeforeSaveMessageHandler();
const renderMessage = createSpotifyMessageRenderer();
callbacks.add('beforeSaveMessage', beforeSaveMessage, callbacks.priority.LOW, 'spotify-save');
callbacks.add('renderMessage', renderMessage, callbacks.priority.MEDIUM, 'spotify-render');
});

@ -57,7 +57,6 @@ import '../app/slashcommands-kick/client';
import '../app/slashcommands-open';
import '../app/slashcommands-topic/client';
import '../app/slashcommands-unarchiveroom/client';
import '../app/spotify/client';
import '../app/tokenpass/client';
import '../app/ui';
import '../app/ui-account';

@ -1,10 +0,0 @@
import { Meteor } from 'meteor/meteor';
import { callbacks } from '../../../app/callbacks';
Meteor.startup(() => {
import('../../../app/spotify/client').then(({ createSpotifyBeforeSaveMessageHandler }) => {
const beforeSaveMessage = createSpotifyBeforeSaveMessageHandler();
callbacks.add('beforeSaveMessage', beforeSaveMessage, callbacks.priority.LOW, 'spotify-save');
});
});

@ -1,4 +1,3 @@
import './beforeSaveMessage';
import './contextualBar';
import './emailVerification';
import './i18n';

@ -8,4 +8,3 @@ import './issuelink';
import './katex';
import './markdown';
import './mentionsMessage';
import './spotify';

@ -1,11 +0,0 @@
import { Meteor } from 'meteor/meteor';
import { callbacks } from '../../../app/callbacks';
Meteor.startup(() => {
import('../../../app/spotify/client').then(({ createSpotifyMessageRenderer }) => {
const renderMessage = createSpotifyMessageRenderer();
callbacks.add('renderMessage', renderMessage, callbacks.priority.MEDIUM, 'spotify-render');
});
});
Loading…
Cancel
Save