Skip to content

Commit a3d7ccf

Browse files
zamgizamgi
authored andcommitted
firefox extension 2.2
1 parent b95db86 commit a3d7ccf

10 files changed

Lines changed: 177 additions & 184 deletions

File tree

Binary file not shown.

m3u8-browser-extensions/m3u8-firefox-extension/install.rdf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<Description about="urn:mozilla:install-manifest">
66
<em:id>denisov72@mail.ru</em:id>
7-
<em:version>2.1</em:version>
7+
<em:version>2.2</em:version>
88
<em:type>2</em:type>
99

1010
<em:targetApplication>
@@ -15,8 +15,8 @@
1515
</Description>
1616
</em:targetApplication>
1717

18-
<em:name>m3u8 file downloader 2.1</em:name>
19-
<em:description>m3u8 file downloader firefox extension 2.1</em:description>
18+
<em:name>m3u8 file downloader 2.2</em:name>
19+
<em:description>m3u8 file downloader firefox extension 2.2</em:description>
2020
<em:creator>zamgi</em:creator>
2121
<em:homepageURL>https://github.com/zamgi/m3u8</em:homepageURL>
2222
</Description>
Lines changed: 86 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,128 @@
11
const root = browser; //chrome;
2-
window.onload = function () {
2+
window.addEventListener('load', function () {
33
window.workInfo = new workInfoType();
44

55
let requestHeaders_by_url = {};
6-
root.webRequest.onCompleted.addListener(function (d/*details*/) {
6+
root.webRequest.onCompleted.addListener(async d => {
77
let ext = (d.url.split('?')[ 0 ].split('.').pop() || '').toLowerCase();
88
if (ext === 'm3u8') {
99
let requestHeaders = requestHeaders_by_url[d.url];
1010
if (requestHeaders) delete requestHeaders_by_url[d.url];
11-
window.workInfo.addM3u8Urls( d.tabId, d.url, requestHeaders );
12-
try {
13-
let t = window.workInfo.tabs[ d.tabId ];
14-
t.connectPort.postMessage({ method: 'setM3u8Urls', data: t.m3u8_urls });
15-
} catch (ex) {
16-
console.log(ex);
17-
}
18-
window.workInfo.setUrlsCountText({ tabId: d.tabId });
11+
12+
window.workInfo.addM3u8Urls(d.tabId, d.url, requestHeaders);
13+
await window.workInfo.setUrlsCountText(d.tabId);
1914
}
2015
},
21-
{urls: ["<all_urls>"]});
16+
{urls: ['<all_urls>']});
2217

23-
root.webRequest.onBeforeSendHeaders.addListener(async function (d/*details*/) {
18+
root.webRequest.onBeforeSendHeaders.addListener(d => {
2419
let ext = (d.url.split('?')[ 0 ].split('.').pop() || '').toLowerCase();
2520
if (ext === 'm3u8') {
26-
//console.log('onBeforeSendHeaders() => tabId: ' + d.tabId + ', url: ' + d.url );
2721
requestHeaders_by_url[d.url] = JSON.stringify(d.requestHeaders);
2822
}
29-
//else console.log('discarded => tabId: ' + d.tabId + ', url: ' + d.url );
3023
},
3124
{urls: ['<all_urls>']}, ['requestHeaders']);
3225

3326
// set handler to tabs
34-
root.tabs.onActivated.addListener(d => window.workInfo.onActivated(d.tabId));
35-
36-
// set handler to tabs: need for send objects
37-
if (root.extension.onConnect) {
38-
root.extension.onConnect.addListener(port => port.onMessage.addListener(workInfo_methodCaller));
39-
}
27+
root.tabs.onActivated.addListener(async d => await window.workInfo.activateTab(d.tabId));
4028

4129
// set handler to tabs
42-
root.tabs.onUpdated.addListener(function (tabId, info, tab) {
30+
root.tabs.onUpdated.addListener(async (tabId, info, tab) => {
4331
if (!info?.status || (info.status.toLowerCase() !== 'complete')) return;
4432

4533
// if user open empty tab or ftp protocol and etc.
46-
if ((tabId === undefined) || !tab?.url || ((tab.url.indexOf('http:') === -1) && (tab.url.indexOf('https:') === -1))) {
47-
if (tabId !== undefined) root.browserAction.disable(tabId);
48-
return (0);
34+
if ((tabId === undefined) || !tab?.url || (!tab.url.startsWith('http://') && !tab.url.startsWith('https://'))) {
35+
if (tabId !== undefined) await root.browserAction.disable(tabId);
4936
}
37+
else {
38+
let opt = await root.storage.local.get();
39+
if (!opt.saveUrlListBetweenTabReload) {
40+
window.workInfo.resetM3u8Urls(tabId);
41+
}
5042

51-
window.workInfo.onActivated(tabId);
52-
root.browserAction.enable(tabId);
53-
54-
// save tab info if need
55-
window.workInfo.addTab(tab);
56-
57-
// connect with new tab, and save object
58-
let port = root.tabs.connect(tabId);
59-
let t = window.workInfo.tabs[tabId];
60-
t.connectPort = port;
61-
62-
// run function in script_in_content.js
63-
root.tabs.executeScript(tabId, { code: "popupInfo_init()" });
64-
65-
// send tabId, hosts and others information into script_in_content.js
66-
port.postMessage({ method: 'setTabId' , data: tabId });
67-
port.postMessage({ method: 'setM3u8Urls', data: t.m3u8_urls });
68-
port.postMessage({ method: 'connect2Extension' });
43+
//if (opt.enableButtonEvenIfNoUrls) {
44+
// await root.browserAction.enable(tabId);
45+
//}
46+
await window.workInfo.activateTab(tabId);
47+
}
6948
});
7049

71-
root.tabs.onRemoved.addListener(tabId => window.workInfo.deleteTab(tabId));
72-
};
73-
74-
function workInfo_methodCaller(obj) {
75-
if (obj?.method) {
76-
window.workInfo[obj.method](obj?.data);
77-
}
78-
}
50+
root.tabs.onRemoved.addListener(async tabId => await window.workInfo.deleteTab(tabId));
51+
});
7952

8053
window.workInfoType = function () { };
8154
window.workInfoType.prototype = {
8255
tabs: {},
83-
active_tabId: null,
56+
activeTabId: null,
8457

85-
addTab: function (tab) {
86-
if (tab && (tab.id !== undefined)) {
87-
let o = this.tabs[tab.id];
58+
activateTab: async function (tabId) {
59+
// set active tab
60+
this.activeTabId = tabId;
61+
62+
let d = { m3u8_urls: [] };
63+
if (tabId !== undefined) {
64+
let o = this.tabs[tabId];
8865
if (!o) {
89-
this.tabs[tab.id] = { tab_obj: tab };
90-
} else {
66+
o = this.tabs[tabId] = { m3u8_urls: [] };
67+
}
68+
else if (!o.m3u8_urls) {
9169
o.m3u8_urls = [];
9270
}
93-
94-
this.setUrlsCountText({ tabId: tab.id });
71+
d.m3u8_urls = o.m3u8_urls;
9572
}
73+
await this.setUrlsCountText(tabId);
9674
},
97-
deleteTab: function (tabId) {
75+
deleteTab: async function (tabId) {
9876
let has = !!this.tabs[tabId];
99-
if (has) delete this.tabs[tabId];
77+
if (has) {
78+
delete this.tabs[tabId];
79+
await this.setUrlsCountText(tabId);
80+
}
10081
},
101-
deleteTabUrls: async function (tabId) {
102-
let has = !!this.tabs[tabId];
103-
if (has) delete this.tabs[tabId];
82+
deleteUrlsFromActivateTab: async function () { await this.deleteTab(this.activeTabId); },
83+
84+
setUrlsCountText: async function (tabId) {
85+
//if (tabId !== undefined) {
86+
// const cnt = this.tabs[tabId]?.m3u8_urls?.length;
87+
// if (tabId === this.activeTabId) {
88+
// await root.browserAction.setBadgeText({ text: (cnt || '') + '' });
89+
// }
90+
91+
// let opt = await root.storage.local.get();
92+
// if (!opt.enableButtonEvenIfNoUrls) {
93+
// if (cnt) await root.browserAction.enable(tabId);
94+
// else await root.browserAction.disable(tabId)
95+
// }
96+
//}
10497

105-
await this.setUrlsCountText({ tabId: tabId });
106-
//if (has) await this.save2Storage();
98+
if (tabId !== undefined) {
99+
let opt = await root.storage.local.get();
100+
if (opt.enableButtonEvenIfNoUrls) {
101+
await root.browserAction.enable(tabId);
102+
103+
if (tabId === this.activeTabId) {
104+
const cnt = this.tabs[tabId]?.m3u8_urls?.length;
105+
await root.browserAction.setBadgeText({ text: (cnt || '') + '' });
106+
}
107+
} else {
108+
const cnt = this.tabs[tabId]?.m3u8_urls?.length;
109+
if (tabId === this.activeTabId) {
110+
await root.browserAction.setBadgeText({ text: (cnt || '') + '' });
111+
}
112+
113+
if (cnt) await root.browserAction.enable(tabId);
114+
else await root.browserAction.disable(tabId)
115+
}
116+
}
117+
},
118+
119+
resetM3u8Urls: function (tabId) {
120+
const o = this.tabs[tabId];
121+
if (o) {
122+
o.m3u8_urls = [];
123+
o.requestHeaders = {};
124+
//await this.setUrlsCountText(tabId);
125+
}
107126
},
108127
addM3u8Urls: function (tabId, m3u8_url, requestHeaders) {
109128
if ((tabId !== undefined) && m3u8_url) {
@@ -123,35 +142,8 @@ window.workInfoType.prototype = {
123142
}
124143
}
125144
},
126-
setUrlsCountText: function (d) {
127-
let o = d ? this.tabs[d.tabId] : null, cnt = o?.m3u8_urls?.length;
128-
if (cnt) {
129-
root.browserAction.setBadgeText({ text: cnt + '' });
130-
return (0);
131-
} else {
132-
root.browserAction.setBadgeText({ text: '' });
133-
}
134-
},
135-
onActivated: function (tabId) {
136-
// set active tab
137-
this.active_tabId = tabId;
138-
139-
let d = { m3u8_urls: [] };
140-
141-
if (tabId !== undefined) {
142-
let o = this.tabs[tabId];
143-
if (!o) {
144-
o = this.tabs[tabId] = { m3u8_urls: [] };
145-
}
146-
else if (!o.m3u8_urls) {
147-
o.m3u8_urls = [];
148-
}
149-
d.m3u8_urls = o.m3u8_urls;
150-
}
151-
this.setUrlsCountText({ tabId: tabId });
152-
},
153-
getM3u8Urls: function () {
154-
let o = (this.active_tabId !== undefined) ? this.tabs[this.active_tabId] : null;
145+
getM3u8UrlsByActiveTabId: function (activeTabId) {
146+
let o = this.tabs[activeTabId] || this.tabs[this.activeTabId]
155147
return (o?.m3u8_urls ? { m3u8_urls: o.m3u8_urls, requestHeaders: o.requestHeaders || {} } : { m3u8_urls: [], requestHeaders: {} });
156148
}
157149
};

m3u8-browser-extensions/m3u8-firefox-extension/js/m3u8.js

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
const root = browser; //chrome;
2+
async function getActiveTabId() {
3+
// Query for the active tab in the current window
4+
const tabs = await root.tabs.query({ active: true, currentWindow: true });
5+
6+
if (tabs?.length) {
7+
return (tabs[ 0 ].id);
8+
}
9+
}
210
window.addEventListener('load', async function () {
311
try {
412
// get m3u8 urls for current active tab
5-
let backgroundPage = root.extension.getBackgroundPage();
6-
let t = backgroundPage.workInfo.getM3u8Urls();
7-
let m3u8_urls = t.m3u8_urls;
8-
9-
let opt = await root.storage.local.get(); if (!opt) opt = {}; if (opt.groupByAudioVideo === undefined) opt.groupByAudioVideo = true;
10-
if (opt.directionRtl === undefined) opt.directionRtl = true;
13+
const backgroundPage = root.extension.getBackgroundPage();
14+
const activeTabId = await getActiveTabId();
15+
const tabInfo = backgroundPage.workInfo.getM3u8UrlsByActiveTabId(activeTabId);
16+
17+
const set_def_val = (d, prop, defVal) => { if (d[prop] === undefined) d[prop] = defVal; };
18+
let opt = await root.storage.local.get(); if (!opt) opt = {}; set_def_val(opt, 'groupByAudioVideo', true);
19+
set_def_val(opt, 'directionRtl' , true);
20+
set_def_val(opt, 'saveUrlListBetweenTabReload', false);
1121
const renderFunc = async function (groupByAudioVideo) {
1222
if (groupByAudioVideo) {
13-
let urls = group_by_audio_video(m3u8_urls, t.requestHeaders);
23+
let urls = group_by_audio_video(tabInfo.m3u8_urls, tabInfo.requestHeaders);
1424
render_grouped_m3u8_urls(urls);
1525
} else {
16-
render_m3u8_urls(m3u8_urls, t.requestHeaders);
26+
render_m3u8_urls(tabInfo.m3u8_urls, tabInfo.requestHeaders);
1727
}
1828
}
1929
let ch = document.getElementById('groupByAudioVideo');
@@ -27,26 +37,30 @@ window.addEventListener('load', async function () {
2737

2838
let content = document.getElementById('content');
2939
ch = document.getElementById('directionRtl');
30-
ch.checked = !!opt.directionRtl; //(content.style.direction === 'rtl');
40+
ch.checked = !!opt.directionRtl;
3141
content.style.direction = ch.checked ? 'rtl' : '';
3242
ch.addEventListener('click', async function () {
3343
content.style.direction = this.checked ? 'rtl' : '';
3444
opt.directionRtl = this.checked;
3545
await root.storage.local.set(opt);
3646
});
3747

38-
//ch = document.getElementById('saveUrlListBetweenTabReload');
39-
//ch.checked = !!opt.saveUrlListBetweenTabReload;
40-
//ch.addEventListener('click', async function () { await root.storage.local.set({ saveUrlListBetweenTabReload: this.checked }); });
48+
ch = document.getElementById('saveUrlListBetweenTabReload');
49+
ch.checked = !!opt.saveUrlListBetweenTabReload;
50+
ch.addEventListener('click', async function () {
51+
opt.saveUrlListBetweenTabReload = this.checked;
52+
await root.storage.local.set(opt);
53+
});
4154

42-
if (m3u8_urls?.length) {
55+
if (tabInfo.m3u8_urls?.length) {
4356
let bt = document.getElementById('clearUrlList');
4457
bt.style.display = '';
45-
bt.addEventListener('click', async function (/*e*/) {
58+
bt.addEventListener('click', async function () {
4659
render_m3u8_urls();
4760
this.style.display = 'none';
61+
tabInfo.m3u8_urls = tabInfo.requestHeaders = null;
4862

49-
await backgroundPage.workInfo.deleteTabUrls(backgroundPage.workInfo.active_tabId/*tabId*/);
63+
await backgroundPage.workInfo.deleteUrlsFromActivateTab();
5064
});
5165
}
5266

@@ -98,24 +112,6 @@ function group_by_audio_video(m3u8_urls, requestHeaders) {
98112
}
99113
}
100114

101-
//if (m3u8_url.endsWith(SUFFIX_v)) {
102-
// let grouped_url = m3u8_url.substring(0, m3u8_url.length - SUFFIX_v.length),
103-
// url_a = grouped_url + SUFFIX_a,
104-
// idx = m3u8_urls.indexOf(url_a);
105-
// if (idx !== -1) {
106-
// skiped_urls[url_a] = 1;
107-
108-
// let o = {
109-
// is_group_by_audio_video: true,
110-
// grouped_url_text: grouped_url + ' + (' + SUFFIX_a + ') + (' + SUFFIX_v + ')',
111-
// video: { url: m3u8_url, requestHeaders: requestHeaders_4_url },
112-
// audio: { url: url_a , requestHeaders: requestHeaders[url_a] || ''}
113-
// };
114-
// res.push(o);
115-
// continue;
116-
// }
117-
//}
118-
119115
res.push({ url: m3u8_url, requestHeaders: requestHeaders_4_url });
120116
}
121117
return (res);
@@ -287,9 +283,9 @@ function create_grouped_msgObj(a, auto_start_download) {
287283
is_group_by_audio_video: true,
288284
auto_start_download : !!auto_start_download,
289285
video_url : a.getAttribute('video-url'),
290-
video_requestHeaders : a.getAttribute('video-requestHeaders'),
286+
video_requestHeaders : a.getAttribute('video-requestHeaders') || '',
291287
audio_url : a.getAttribute('audio-url'),
292-
audio_requestHeaders : a.getAttribute('audio-requestHeaders')
288+
audio_requestHeaders : a.getAttribute('audio-requestHeaders') || ''
293289
};
294290
}
295291
function create_msgObj(a, auto_start_download) {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const root = browser; //chrome;
2+
window.addEventListener('load', async function () {
3+
const set_def_val = (d, prop, defVal) => { if (d[prop] === undefined) d[prop] = defVal; };
4+
let opt = await root.storage.local.get(); if (!opt) opt = {}; set_def_val(opt, 'groupByAudioVideo', true);
5+
set_def_val(opt, 'directionRtl' , true);
6+
set_def_val(opt, 'saveUrlListBetweenTabReload', false);
7+
set_def_val(opt, 'enableButtonEvenIfNoUrls' , false);
8+
9+
const set_proc_func = (checkboxId, opt_prop) => {
10+
if (!opt_prop) opt_prop = checkboxId;
11+
12+
const ch = document.getElementById(checkboxId);
13+
ch.checked = !!opt[opt_prop];
14+
ch.addEventListener('click', async function () {
15+
opt[opt_prop] = this.checked;
16+
await root.storage.local.set(opt);
17+
});
18+
};
19+
set_proc_func('groupByAudioVideo');
20+
set_proc_func('directionRtl');
21+
set_proc_func('saveUrlListBetweenTabReload');
22+
set_proc_func('enableButtonEvenIfNoUrls');
23+
});

0 commit comments

Comments
 (0)