Skip to content

Commit

Permalink
Add ability to log original and modified M3U content in m3u-prune scr…
Browse files Browse the repository at this point in the history
…iptlet
  • Loading branch information
AdamWr committed Jun 14, 2024
1 parent 59d1348 commit a80d212
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 4 deletions.
30 changes: 26 additions & 4 deletions src/scriptlets/m3u-prune.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
* - `propsToRemove` — optional, string or regular expression
* to match the URL line (segment) which will be removed alongside with its tags
* - `urlToMatch` — optional, string or regular expression for matching the request's URL
* - `logContent` — optional, string, if set to 'logContent' will log original and modified M3U content
*
* > Usage with no arguments will log response payload and URL to browser console;
* > it may be useful for debugging but it is not allowed for prod versions of filter lists.
Expand All @@ -53,6 +54,12 @@ import {
* example.org#%#//scriptlet('m3u-prune', 'example.com/video/', '.m3u8')
* ```
*
* 1. Removes a line which contains `example.com/video/`, only if request's URL contains `.m3u8` and log content
*
* ```adblock
* example.org#%#//scriptlet('m3u-prune', 'example.com/video/', '.m3u8', 'logContent')
* ```
*
* 1. Call with no arguments will log response payload and URL at the console
*
* ```adblock
Expand All @@ -69,7 +76,7 @@ import {
*/
/* eslint-enable max-len */

export function m3uPrune(source, propsToRemove, urlToMatch = '') {
export function m3uPrune(source, propsToRemove, urlToMatch = '', logContent) {
// do nothing if browser does not support fetch or Proxy (e.g. Internet Explorer)
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Expand All @@ -83,6 +90,8 @@ export function m3uPrune(source, propsToRemove, urlToMatch = '') {

let shouldPruneResponse = false;

const shouldLogContent = logContent === 'logContent';

const urlMatchRegexp = toRegExp(urlToMatch);

const SEGMENT_MARKER = '#';
Expand Down Expand Up @@ -307,16 +316,23 @@ export function m3uPrune(source, propsToRemove, urlToMatch = '') {
*/
// TODO: make it compatible with $hls modifier
const pruneM3U = (text) => {
if (shouldLogContent) {
logMessage(source, `Original M3U content:\n${text}`);
}

let lines = text.split(/\r?\n/);

if (text.includes(COMCAST_AD_MARKER.VMAP_AD_BREAK)) {
lines = pruneVmapBlock(lines);
return lines.filter((l) => !!l).join('\n');
lines = lines.filter((l) => !!l).join('\n');
if (shouldLogContent) {
logMessage(source, `Modified M3U content:\n${lines}`);
}
return lines;
}

lines = pruneSegments(lines);

return lines
lines = lines
.map((line, index, array) => {
if (typeof line === 'undefined') {
return line;
Expand All @@ -329,6 +345,12 @@ export function m3uPrune(source, propsToRemove, urlToMatch = '') {
})
.filter((l) => !!l)
.join('\n');

if (shouldLogContent) {
logMessage(source, `Modified M3U content:\n${lines}`);
}

return lines;
};

const nativeOpen = window.XMLHttpRequest.prototype.open;
Expand Down
49 changes: 49 additions & 0 deletions tests/scriptlets/m3u-prune.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,55 @@ if (!isSupported) {
done();
});

test('fetch match URL - remove ads 1 and log', async (assert) => {
assert.expect(8);

console.log = (...args) => {
if (args.length === 1 && args[0].includes('Original M3U content:')) {
assert.ok(args[0].includes('tvessaiprod.nbcuni.com/video/'), 'should log original text in console');
}
if (args.length === 1 && args[0].includes('Modified M3U content:')) {
assert.notOk(args[0].includes('tvessaiprod.nbcuni.com/video/'), 'should log modified text in console');
}
nativeConsole(...args);
};

const M3U8_PATH = M3U8_OBJECTS_PATH_01;
const MATCH_DATA = 'tvessaiprod.nbcuni.com/video/';
const MATCH_URL = '.m3u8';
const LOG_CONTENT = 'logContent';
const scriptletArgs = [MATCH_DATA, MATCH_URL, LOG_CONTENT];

runScriptlet(name, scriptletArgs);

const done = assert.async();

const response = await fetch(M3U8_PATH);
const responseM3U8 = await response.text();
assert.notOk(
responseM3U8.includes('tvessaiprod.nbcuni.com/video/'),
'check if "tvessaiprod.nbcuni.com/video/" has been removed',
);
assert.notOk(
responseM3U8.includes('#EXT-X-CUE:TYPE="SpliceOut"'),
'check if "#EXT-X-CUE:TYPE="SpliceOut"" has been removed',
);
assert.notOk(
responseM3U8.includes('#EXT-X-CUE-IN'),
'check if "#EXT-X-CUE-IN" has been removed',
);
assert.notOk(
responseM3U8.includes('#EXT-X-ASSET:CAID'),
'check if "#EXT-X-ASSET:CAID" has been removed',
);
assert.notOk(
responseM3U8.includes('#EXT-X-SCTE35:'),
'check if "#EXT-X-SCTE35:" has been removed',
);
assert.strictEqual(window.hit, 'FIRED', 'hit function fired');
done();
});

test('fetch match URL - remove ads 2', async (assert) => {
const M3U8_PATH = M3U8_OBJECTS_PATH_02;
const MATCH_DATA = 'VMAP-AD-BREAK';
Expand Down

0 comments on commit a80d212

Please sign in to comment.