Skip to content

Commit f457cf2

Browse files
committed
fixes #85
1 parent 7440eca commit f457cf2

File tree

4 files changed

+220
-52
lines changed

4 files changed

+220
-52
lines changed

v3/data/inject/index.js

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
const args = new URLSearchParams(location.search);
3+
const args = {};
44
const list = document.getElementById('list');
55

66
const formatBytes = (bytes, decimals = 0) => {
@@ -15,17 +15,17 @@ const formatBytes = (bytes, decimals = 0) => {
1515
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
1616
};
1717

18-
chrome.runtime.sendMessage({
19-
cmd: 'get-links'
20-
}, response => {
21-
document.getElementById('number').textContent = response.length;
18+
onmessage = e => {
19+
args.referrer = e.data.referrer;
20+
21+
document.getElementById('number').textContent = e.data.map.length;
2222

2323
const active = {
2424
m3u8: -1,
2525
media: -1
2626
};
2727

28-
response.forEach(([url, o], index) => {
28+
e.data.map.forEach(([url, o], index) => {
2929
let ext = o && o.type ? o.type : url.split(/[#?]/)[0].split('.').pop().trim();
3030
if (ext.includes('/')) {
3131
ext = '';
@@ -88,7 +88,8 @@ URL: ${url}`;
8888
else {
8989
list.selectedIndex = 1;
9090
}
91-
});
91+
};
92+
9293
addEventListener('load', () => setTimeout(() => {
9394
list.focus();
9495
window.focus();
@@ -134,7 +135,7 @@ document.addEventListener('click', e => {
134135
chrome.runtime.sendMessage({
135136
cmd: 'open-in',
136137
url: urls[0],
137-
referrer: args.get('referrer')
138+
referrer: args.referrer
138139
}, () => {
139140
chrome.runtime.lastError;
140141
chrome.runtime.sendMessage({
@@ -146,7 +147,7 @@ document.addEventListener('click', e => {
146147
chrome.runtime.sendMessage({
147148
cmd: 'combine',
148149
urls,
149-
referrer: args.get('referrer')
150+
referrer: args.referrer
150151
}, () => {
151152
chrome.runtime.lastError;
152153
chrome.runtime.sendMessage({

v3/data/inject/inject.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77
dialog.classList.add('open-in-vlc');
88

99
const iframe = document.createElement('iframe');
10-
const args = new URLSearchParams(location.search);
11-
args.set('referrer', location.href);
12-
iframe.src = chrome.runtime.getURL('/data/inject/index.html?' + args.toString());
10+
iframe.onload = () => {
11+
iframe.contentWindow.postMessage({
12+
map: self.map,
13+
referrer: location.href
14+
}, '*');
15+
delete self.map;
16+
};
17+
iframe.src = chrome.runtime.getURL('/data/inject/index.html');
1318
dialog.append(iframe);
1419
document.body.append(dialog);
1520
dialog.showModal();
1621
}
17-

v3/extract.js

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Based on https://github.com/chandler-stimson/live-stream-downloader/blob/master/v3/data/job/extract.js
2+
3+
const extract = {};
4+
5+
/* extract storage */
6+
extract.storage = async tabId => {
7+
try {
8+
const a = await chrome.scripting.executeScript({
9+
target: {
10+
tabId
11+
},
12+
injectImmediately: true,
13+
func: () => {
14+
self.storage = self.storage || new Map();
15+
16+
return [...self.storage.values()];
17+
}
18+
});
19+
return a[0].result;
20+
}
21+
catch (e) {
22+
return [];
23+
}
24+
};
25+
26+
/* extract from performance */
27+
extract.performance = async tabId => {
28+
try {
29+
const types = [
30+
'flv', 'avi', 'wmv', 'mov', 'mp4', 'webm', 'mkv', // video
31+
'pcm', 'wav', 'mp3', 'aac', 'ogg', 'wma', // audio
32+
'm3u8', 'mpd' // stream
33+
];
34+
35+
const a = await chrome.scripting.executeScript({
36+
target: {
37+
tabId
38+
},
39+
injectImmediately: true,
40+
func: types => performance.getEntriesByType('resource').filter(o => {
41+
if (o.contentType?.startsWith('video/') || o.contentType?.startsWith('audio/')) {
42+
return true;
43+
}
44+
if (['video', 'audio', 'other', 'xmlhttprequest'].includes(o.initiatorType)) {
45+
for (const type of types) {
46+
if (o.name.includes('.' + type)) {
47+
return true;
48+
}
49+
}
50+
}
51+
}).map(o => ({
52+
initiator: location.href,
53+
url: o.name,
54+
timeStamp: performance.timeOrigin + o.startTime,
55+
source: 'performance'
56+
})),
57+
world: 'MAIN',
58+
args: [types]
59+
});
60+
return a[0].result;
61+
}
62+
catch (e) {
63+
return [];
64+
}
65+
};
66+
67+
/* extract media from jwplayer and videojs objects */
68+
extract.player = async tabId => {
69+
try {
70+
const a = await chrome.scripting.executeScript({
71+
target: {
72+
tabId,
73+
allFrames: true
74+
},
75+
injectImmediately: true,
76+
func: () => {
77+
const list = [];
78+
try {
79+
for (const o of self.jwplayer().getPlaylist()) {
80+
if (o.file) {
81+
list.push({
82+
initiator: location.href,
83+
url: new URL(o.file, location.href).href,
84+
timeStamp: performance.timing.domComplete,
85+
source: 'jwplayer'
86+
});
87+
}
88+
if (o.sources) {
89+
for (const p of o.sources) {
90+
if (p.file) {
91+
list.push({
92+
initiator: location.href,
93+
url: new URL(p.file, location.href).href,
94+
timeStamp: performance.timing.domComplete,
95+
source: 'jwplayer'
96+
});
97+
}
98+
}
99+
}
100+
}
101+
}
102+
catch (e) {}
103+
104+
// videojs
105+
const apd = v => {
106+
try {
107+
const o = v.tech().currentSource_;
108+
if (o) {
109+
const m = {
110+
initiator: location.href,
111+
url: o.src,
112+
timeStamp: performance.timing.domComplete,
113+
source: 'videojs'
114+
};
115+
if (o.type) {
116+
m.responseHeaders = [{
117+
name: 'Content-Type',
118+
value: o.type
119+
}];
120+
}
121+
list.push(m);
122+
}
123+
}
124+
catch (e) {}
125+
};
126+
127+
try {
128+
for (const v of self.videojs.getAllPlayers()) {
129+
apd(v);
130+
}
131+
}
132+
catch (e) {}
133+
for (const e of document.querySelectorAll('video-js, .video-js')) {
134+
const o = e.player;
135+
if (o) {
136+
apd(o);
137+
}
138+
}
139+
140+
return list;
141+
},
142+
world: 'MAIN'
143+
});
144+
return a.map(o => o.result).flat().filter(a => a);
145+
}
146+
catch (e) {
147+
return [];
148+
}
149+
};

v3/worker.js

+53-39
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
/* global TYPES */
1+
/* global TYPES, extract */
22

33
if (typeof importScripts !== 'undefined') {
4-
self.importScripts('const.js', 'native.js', 'context.js', 'open.js');
4+
self.importScripts('const.js', 'native.js', 'context.js', 'open.js', 'extract.js');
55
}
66

77
const notify = self.notify = (e, tabId) => {
@@ -194,65 +194,79 @@ const copy = async (tabId, content) => {
194194
};
195195

196196
// actions
197-
chrome.action.onClicked.addListener(tab => {
197+
chrome.action.onClicked.addListener(async tab => {
198198
// VLC can play YouTube. Allow user to send the YouTube link to VLC
199199
if (tab.url && tab.url.startsWith('https://www.youtube.com/watch?v=')) {
200200
open(tab, tab.id, tab.url);
201201
}
202202
else {
203-
chrome.scripting.executeScript({
204-
target: {
205-
tabId: tab.id
206-
},
207-
func: () => self.links ? [...self.links.keys()] : []
208-
}).then(async r => {
209-
if (r) {
210-
const links = r[0]?.result || [];
203+
const target = {
204+
tabId: tab.id
205+
};
206+
207+
try {
208+
const map = new Map();
211209

212-
if (links.length === 1) {
210+
// check page's media players (from Live Stream Downloader extension)
211+
for (const o of await extract.performance(tab.id)) {
212+
map.set(o.url, {});
213+
}
214+
for (const o of await extract.player(tab.id)) {
215+
map.set(o.url, {});
216+
}
217+
// storage
218+
const r = await chrome.scripting.executeScript({
219+
target,
220+
func: () => self.links ? [...self.links.entries()] : []
221+
});
222+
if (r && r[0]?.result) {
223+
for (const [url, o] of r[0].result) {
224+
map.set(url, o);
225+
}
226+
}
227+
228+
if (map.size) {
229+
if (map.size === 1) {
213230
open({
214231
title: tab.title,
215-
url: links[0]
232+
url: map.entries().next().value[0]
216233
}, tab.id, tab.url);
217234
}
218-
else if (links.length > 1) {
235+
else {
236+
const args = [[
237+
[tab.url], // first entry must be the page address
238+
...map.entries()
239+
]];
240+
await chrome.scripting.executeScript({
241+
target,
242+
func: map => self.map = map,
243+
args
244+
});
219245
await chrome.scripting.insertCSS({
220-
target: {
221-
tabId: tab.id
222-
},
246+
target,
223247
files: ['/data/inject/inject.css']
224248
});
225249
chrome.scripting.executeScript({
226-
target: {
227-
tabId: tab.id
228-
},
250+
target,
229251
files: ['/data/inject/inject.js']
230252
});
231253
}
232-
else if (tab.url) {
233-
open(tab, tab.id, tab.url);
234-
}
235-
else {
236-
notify('Cannot send an internal page to VLC', tab.id);
237-
}
238254
}
239-
}).catch(e => notify(e, tab.id));
255+
else if (tab.url) {
256+
open(tab, tab.id, tab.url);
257+
}
258+
else {
259+
notify('Cannot send an internal page to VLC', tab.id);
260+
}
261+
}
262+
catch (e) {
263+
notify(e, tab.id);
264+
}
240265
}
241266
});
242267

243268
chrome.runtime.onMessage.addListener((request, sender, response) => {
244-
if (request.cmd === 'get-links') {
245-
chrome.scripting.executeScript({
246-
target: {
247-
tabId: sender.tab.id
248-
},
249-
func: () => self.links ? [...self.links.entries()] : []
250-
}).then(r => {
251-
response([[sender.tab.url], ...(r[0].result || [])]);
252-
});
253-
return true;
254-
}
255-
else if (request.cmd === 'copy') {
269+
if (request.cmd === 'copy') {
256270
copy(sender.tab.id, request.content);
257271
}
258272
else if (request.cmd === 'close-me') {

0 commit comments

Comments
 (0)