Skip to content
Snippets Groups Projects
Commit 7e8619ce authored by Damian Janus's avatar Damian Janus
Browse files

feat: add 3speak embedder

parent 2557c06b
No related branches found
No related tags found
1 merge request!18feat: add 3speak embedder
Pipeline #100356 failed
......@@ -55,6 +55,26 @@ export class StaticConfig {
fn: (src: string) => {
return src;
}
},
{
// eslint-disable-next-line security/detect-unsafe-regex
re: /^(?:https?:)?\/\/(?:3speak\.(?:tv|online|co))\/embed\?v=([^&\s]+)/i,
fn: (src: string) => {
if (!src) return null;
const match = src.match(/3speak\.(?:tv|online|co)\/embed\?v=([^&\s]+)/i);
if (!match || match.length !== 2) return null;
return `https://3speak.tv/embed?v=${match[1]}`;
}
},
{
// eslint-disable-next-line security/detect-unsafe-regex
re: /^(?:https?:)?\/\/(?:3speak\.(?:tv|online|co))\/watch\?v=([^&\s]+)/i,
fn: (src: string) => {
if (!src) return null;
const match = src.match(/3speak\.(?:tv|online|co)\/watch\?v=([^&\s]+)/i);
if (!match || match.length !== 2) return null;
return `https://3speak.tv/embed?v=${match[1]}`;
}
}
],
noImageText: '(Image not shown due to low ratings)',
......
......@@ -2,6 +2,7 @@ import ow from 'ow';
import {LocalizationOptions} from '../Localization';
import {AbstractEmbedder} from './embedders/AbstractEmbedder';
import {SpotifyEmbedder} from './embedders/SpotifyEmbedder';
import {ThreeSpeakEmbedder} from './embedders/ThreeSpeakEmbedder';
import {TwitchEmbedder} from './embedders/TwitchEmbedder';
import {VimeoEmbedder} from './embedders/VimeoEmbedder';
import {YoutubeEmbedder} from './embedders/YoutubeEmbedder';
......@@ -20,7 +21,8 @@ export class AssetEmbedder {
new YoutubeEmbedder(),
new VimeoEmbedder(),
new TwitchEmbedder(options),
new SpotifyEmbedder()
new SpotifyEmbedder(),
new ThreeSpeakEmbedder()
];
}
......
import {expect} from 'chai';
import {ThreeSpeakEmbedder} from './ThreeSpeakEmbedder';
describe('ThreeSpeakEmbedder', () => {
let embedder: ThreeSpeakEmbedder;
beforeEach(() => {
embedder = new ThreeSpeakEmbedder();
});
describe('getEmbedMetadata', () => {
it('should return correct metadata for valid 3Speak URL', () => {
const url = 'https://3speak.tv/watch?v=username/video-id';
const metadata = embedder.getEmbedMetadata(url);
expect(metadata).to.deep.equal({
id: 'username/video-id',
url: 'https://3speak.tv/watch?v=username/video-id'
});
});
it('should return undefined for invalid URL', () => {
const url = 'https://example.com/invalid';
const metadata = embedder.getEmbedMetadata(url);
expect(metadata).to.be.undefined;
});
it('should handle embed URLs', () => {
const url = 'https://3speak.tv/embed?v=username/video-id';
const metadata = embedder.getEmbedMetadata(url);
expect(metadata).to.deep.equal({
id: 'username/video-id',
url: 'https://3speak.tv/watch?v=username/video-id'
});
});
});
describe('processEmbed', () => {
it('should generate correct iframe HTML', () => {
const id = 'username/video-id';
const size = {width: 500, height: 300};
const result = embedder.processEmbed(id, size);
expect(result).to.equal(
'<div class="threeSpeakWrapper"><iframe width="500" height="300" src="https://3speak.tv/embed?v=username/video-id" frameborder="0" allowfullscreen></iframe></div>'
);
});
});
});
import {Log} from '../../../../Log';
import {StaticConfig} from '../../StaticConfig';
import {AbstractEmbedder, EmbedMetadata} from './AbstractEmbedder';
export class ThreeSpeakEmbedder extends AbstractEmbedder {
public type = '3speak';
private static readonly linkRegex = /^(?:https?:\/\/)?(?:(?:3speak\.(?:tv|online|co)\/watch\?v=)|(?:3speak\.tv\/embed\?v=))([a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+)(?:&.*)?$/;
public getEmbedMetadata(input: string | HTMLObjectElement): EmbedMetadata | undefined {
const url = typeof input === 'string' ? input : input.data;
try {
const match = url.match(ThreeSpeakEmbedder.linkRegex);
if (match && match[1]) {
const id = match[1];
return {
id,
url: `https://3speak.tv/watch?v=${id}`
};
}
} catch (error) {
Log.log().error(error);
}
return undefined;
}
public processEmbed(id: string, size: {width: number; height: number}): string {
const threeSpeakConfig = StaticConfig.sanitization.iframeWhitelist.find((item) => item.re.toString().includes('3speak'));
if (!threeSpeakConfig) {
Log.log().error('3Speak configuration not found in StaticConfig');
return '';
}
const embedUrl = `https://3speak.tv/embed?v=${id}`;
if (!embedUrl) {
Log.log().error('Failed to generate valid 3Speak embed URL');
return '';
}
return `<div class="threeSpeakWrapper"><iframe width="${size.width}" height="${size.height}" src="${embedUrl}" frameborder="0" allowfullscreen></iframe></div>`;
}
private static get3SpeakMetadataFromLink(data: string): {id: string; url: string} | undefined {
if (!data) {
return undefined;
}
const match = data.match(ThreeSpeakEmbedder.linkRegex);
if (!match) {
return undefined;
}
const id = match[1];
const url = `https://3speak.tv/watch?v=${id}`;
return {id, url};
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment