Skip to content

Commit

Permalink
Fix vimeo #278
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrews54757 committed Oct 31, 2024
1 parent e70133f commit 85730e3
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 2 deletions.
21 changes: 19 additions & 2 deletions chrome/background/background.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1270,10 +1270,11 @@ chrome.webRequest.onBeforeSendHeaders.addListener((details) => {
urls: ['<all_urls>'],
}, webRequestPerms);

// Exclude urls from facebook.
// Exclude urls from facebook and vimeo.
const initiatorBlacklist = [
'https://www.facebook.com',
'https://www.instagram.com',
'https://vimeo.com',
];

chrome.webRequest.onHeadersReceived.addListener(
Expand All @@ -1292,7 +1293,23 @@ chrome.webRequest.onHeadersReceived.addListener(
initiatorBlacklist.some((a) => {
return details.initiator.startsWith(a);
})) {
return;
if (url.startsWith('https://vod-adaptive') && url.includes('playlist.json')) {
ext = 'vmpatch';
// chrome.tabs.sendMessage(details.tabId, {
// type: 'vmurl',
// url: url,
// headers: frame.requestHeaders.get(details.requestId),
// }, {
// frameId: details.frameId,
// }, () => {
// BackgroundUtils.checkMessageError('vmurl');
// });
// return;
} else if (ext === 'json') {

} else {
return;
}
}

const output = CustomSourcePatternsMatcher.match(url);
Expand Down
11 changes: 11 additions & 0 deletions chrome/player/FastStreamClient.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {VirtualAudioNode} from './ui/audio/VirtualAudioNode.mjs';
import {SyncedAudioPlayer} from './players/SyncedAudioPlayer.mjs';
import {AlertPolyfill} from './utils/AlertPolyfill.mjs';
import {MessageTypes} from './enums/MessageTypes.mjs';
import {patchVimeoSource} from './players/patches/vimeo.mjs';

const SET_VOLUME_USING_NODE = !EnvUtils.isSafari() && EnvUtils.isWebAudioSupported();

Expand Down Expand Up @@ -562,6 +563,16 @@ export class FastStreamClient extends EventEmitter {
try {
source = source.copy();

try {
if (source.mode === PlayerModes.PATCHED_VIMEO) {
source = await patchVimeoSource(source);
}
} catch (e) {
console.error(e);
this.failedToLoad(Localize.getMessage('player_error_load'));
return;
}

let timeFromURL = null;
if (source.mode === PlayerModes.ACCELERATED_YT) {
timeFromURL = URLUtils.get_param(source.url, 't') || URLUtils.get_param(source.url, 'start') || '';
Expand Down
1 change: 1 addition & 0 deletions chrome/player/enums/PlayerModes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export const PlayerModes = {
ACCELERATED_DASH: 'accelerated_dash',
ACCELERATED_YT: 'accelerated_yt',
IFRAME: 'iframe',
PATCHED_VIMEO: 'patched_vimeo',
};
152 changes: 152 additions & 0 deletions chrome/player/players/patches/vimeo.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import {PlayerModes} from '../../enums/PlayerModes.mjs';
import {RequestUtils} from '../../utils/RequestUtils.mjs';


class Vimeo2Dash {
constructor() {
this.document = document.implementation.createDocument('', '', null);
}

playlistToDash(url, playlist) {
const base_url = playlist.base_url;
const new_base_url = new URL(base_url, url).href;

const MPD = this.makeMPD(new_base_url, playlist);
const xml = new XMLSerializer().serializeToString(MPD);
return '<?xml version="1.0" encoding="utf-8"?>' + xml;
}

loadDashTracks(tracks) {
const AdaptationSet = this.document.createElement('AdaptationSet');
tracks.forEach((track)=>{
AdaptationSet.appendChild(this.loadDashTrack(track));
});
return AdaptationSet;
}

loadDashTrack(track) {
const id = track.id;
const baseUrl = track.base_url;
const bandwidth = track.avg_bitrate;
const mimeType = track.mime_type;
const codecs = track.codecs;
const width = track.width;
const height = track.height;
const frameRate = track.framerate;
const startWithSap = 1;

// const codecid = track.codecid;
const Representation = this.document.createElement('Representation');
Representation.setAttribute('id', id);
Representation.setAttribute('codecs', codecs);
Representation.setAttribute('bandwidth', bandwidth);
Representation.setAttribute('width', width);
Representation.setAttribute('height', height);
if (frameRate) Representation.setAttribute('frameRate', frameRate);
Representation.setAttribute('startWithSAP', startWithSap);
Representation.setAttribute('mimeType', mimeType);

const BaseURL = this.document.createElement('BaseURL');
BaseURL.textContent = baseUrl;
Representation.appendChild(BaseURL);

const SegmentList = this.document.createElement('SegmentList');
SegmentList.setAttribute('duration', track.max_segment_duration);
SegmentList.setAttribute('timescale', 1);

Representation.appendChild(SegmentList);

const index_segment = track.index_segment;
const init_segment_data_b64 = track.init_segment;
const segments = track.segments;


const RepresentationIndex = this.document.createElement('RepresentationIndex');
RepresentationIndex.setAttribute('sourceURL', index_segment);
SegmentList.appendChild(RepresentationIndex);

const Initialization = this.document.createElement('Initialization');
Initialization.setAttribute('sourceURL', 'data:application/octet-stream;base64,' + init_segment_data_b64);
SegmentList.appendChild(Initialization);

segments.forEach((segment)=>{
const SegmentURL = this.document.createElement('SegmentURL');
SegmentURL.setAttribute('media', segment.url);
SegmentList.appendChild(SegmentURL);
});

return Representation;
}

makeMPD(baseURL, dashData) {
let duration = 0;
dashData.video.forEach((video)=>{
if (video.duration > duration) {
duration = video.duration;
}
});

dashData.audio.forEach((audio)=>{
if (audio.duration > duration) {
duration = audio.duration;
}
});

const minBufferTime = 1.5;
const videoAdaptationSet = this.loadDashTracks(dashData.video);
const audioAdaptationSet = this.loadDashTracks(dashData.audio);
// const dolby = dashData.dolby;
// const flac = dashData.flac;

const MPD = this.document.createElement('MPD');
MPD.setAttribute('xmlns', 'urn:mpeg:dash:schema:mpd:2011');
MPD.setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
MPD.setAttribute('xsi:schemaLocation', 'urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd');
MPD.setAttribute('profiles', 'urn:mpeg:dash:profile:isoff-main:2011');
MPD.setAttribute('minBufferTime', `PT${minBufferTime}S`);
MPD.setAttribute('type', 'static');
MPD.setAttribute('mediaPresentationDuration', `PT${duration}S`);

if (baseURL) {
const BaseURL = this.document.createElement('BaseURL');
BaseURL.textContent = baseURL;
MPD.appendChild(BaseURL);
}

const Period = this.document.createElement('Period');
MPD.appendChild(Period);

Period.appendChild(videoAdaptationSet);
Period.appendChild(audioAdaptationSet);
return MPD;
}
}

export async function patchVimeoSource(source) {
const hc = [];
for (const key in source.headers) {
if (Object.hasOwn(source.headers, key)) {
hc.push({
operation: 'set',
header: key,
value: source.headers[key],
});
}
}

const xhr = await RequestUtils.request({
url: source.url,
header_commands: hc,
responseType: 'json',
});

const convert = new Vimeo2Dash();
const dashManifest = convert.playlistToDash(source.url, xhr.response);
source.url = URL.createObjectURL(new Blob([dashManifest], {type: 'application/dash+xml'}));
source.mode = PlayerModes.ACCELERATED_DASH;

console.log('Vimeo source patched');
console.log(dashManifest);

return source;
}
2 changes: 2 additions & 0 deletions chrome/player/utils/URLUtils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ ModesMap.set('m3u', PlayerModes.ACCELERATED_HLS);
ModesMap.set('mpd', PlayerModes.ACCELERATED_DASH);
ModesMap.set('youtube', PlayerModes.ACCELERATED_YT);

ModesMap.set('vmpatch', PlayerModes.PATCHED_VIMEO);

export class URLUtils {
static get_yt_identifier(urlStr) {
try {
Expand Down

0 comments on commit 85730e3

Please sign in to comment.