Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blocking YouTube Video ads with Electron Ad-Blocker #2458

Closed
sgebr01 opened this issue Feb 19, 2022 · 45 comments
Closed

Blocking YouTube Video ads with Electron Ad-Blocker #2458

sgebr01 opened this issue Feb 19, 2022 · 45 comments

Comments

@sgebr01
Copy link

sgebr01 commented Feb 19, 2022

I have been able to block most site ads with the original filter list, but for some reason this filter list does not work on YouTube Video Ads. What can I do to make it work on YouTube Video Ads? Is there a recommended filter list for this use case?

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

Hi @sgebr01,

Could you please share how you are using/initializing the adblocker? This library does not contain filter lists per se, but does allow you to download community-driven lists with default presets for convenience. Not blocking ads on YouTube could either be an issue with the lists or with the adblocker library itself. If you can share the exact way you are creating the adblocker in your project I can try to reproduce.

@sgebr01
Copy link
Author

sgebr01 commented Feb 19, 2022

Thanks for responding, here is the code that I'm using that involves the ad-blocker.
ElectronBlocker.fromPrebuiltAdsAndTracking(fetch).then((blocker) => { blocker.enableBlockingInSession(session.defaultSession); });

I got this from the documentation, but really struggled to understand how this adblocker works since the documentation didn't really seem to cover most of it for me. This does block banner ads on every website I visit through my electron app, but it doesn't block Video ads on YouTube. My entire code in my main JS file is this.

const { app, BrowserWindow, session } = require('electron')
const path = require('path')
const { ElectronBlocker, fullLists, FiltersEngine } = require('@cliqz/adblocker-electron')
const fetch = require('cross-fetch') // required 'fetch'
const fs = require('fs');
const { BlockList } = require('net');

let mainWindow

async function createWindow() {
      // Create the browser window.
      mainWindow = new BrowserWindow({
            darkTheme: true,
            icon: 'Logo.png',
            center: 'true',
            resizable: 'true',
            movable: 'true',
            minimizable: 'true',
            maximizable: 'true',
            closable: 'true',
            focusable: 'true',
            fullscreen: 'false',
            frame: 'true',
            width: '800px',
            height: '800px',
            titleBarOverlay: 'color',
            webPreferences: {
                  preload: path.join(__dirname, 'preload.js'),
            }
      })
      if (mainWindow.webContents.session === undefined) {
            throw new Error('defaultSession is undefined');
      }
      mainWindow.loadURL('https://youtube.com')
      mainWindow.setTitle("YouTube")
      mainWindow.setBackgroundColor('#181818')

      ElectronBlocker.fromPrebuiltAdsAndTracking(fetch).then((blocker) => {
            blocker.enableBlockingInSession(session.defaultSession);
      });

      mainWindow.webContents.on("did-finish-load", () => {
            mainWindow.show();
      })

      mainWindow.on("page-title-updated", event => {
            event.preventDefault()
      })

      mainWindow.on('closed', function () {
            mainWindow = null
      })
}

app.on('ready', createWindow)

app.on('window-all-closed', function () {
      app.quit()
})

@sgebr01
Copy link
Author

sgebr01 commented Feb 19, 2022

Additionally, there are times when even the banners on YouTube don't get blocked - but I think this can easily be solved by adding another filter list.

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

I could reproduce. I seems like part of the adblocker features are not working on Electron anymore, it might have been caused by a regression with recent updates. To be honest I am not actively using Electron in any project at the moment and it has always been challenging to keep the adblocker working on this platform in the past. I will try to find some time to investigate.

@sgebr01
Copy link
Author

sgebr01 commented Feb 19, 2022

OK, so as of now - what should I do? Can I install a previous past version and that will work?

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

Let me check if I can find an older version that works.

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

For example v13 works, maybe a more recent version would also work.

@sgebr01
Copy link
Author

sgebr01 commented Feb 19, 2022

OK, I will try that out and let you know - additionally, I had one more question as to using multiple filter lists. I saw another closed post that used this, but when I tried that method, it did not work, none of the filter lists did their job. Here is the link - #1901 What I've tried to do my multiple filter lists is this - is this the right way?


      ElectronBlocker.fromPrebuiltAdsAndTracking(fetch).then((blocker) => {
            blocker.enableBlockingInSession(session.defaultSession);
      });

      const easylist= await ElectronBlocker.fromLists(fetch, [
            'https://easylist.to/easylist/easylist.txt'
      ]);

      easylist.enableBlockingInSession(session.defaultSession)

      const easyprivacy = await ElectronBlocker.fromLists(fetch, [
            'https://easylist.to/easylist/easyprivacy.txt'
      ]);
      easyprivacy.enableBlockingInSession(session.defaultSession)

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

No this will not work, at the moment you can only use one blocker per session. The only way would be to use fromLists(...) and give all the lists you need in one go. Are you trying to selectively enable part of the lists in a session based on some conditions?

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

There is something fishy with the adblocker in electron, I have been able to make it work with v17 (latest release) but it never works on the first start. If I cache the engine on disk then restart then it works, it is unclear to me why that is happening.

@sgebr01
Copy link
Author

sgebr01 commented Feb 19, 2022

I'm just trying to load all of these filter lists at once, to have a bigger database of filters. I have also noticed that the video ads are blocked at times, I'm not sure if that has anything to do with this, but it does work from time to time when I run it - even though I didn't cache the engine.

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

It seems that for some reason the preload script is either not registered as it should be, or does not manage to send messages to the main process. I am not sure why that is. Since that does not happen consistently I have tried to let some time with a setTimeout without success.

On your example above, you need to enable the blocker before you navigate to YouTube:

      await ElectronBlocker.fromPrebuiltAdsAndTracking(fetch).then((blocker) => {
            blocker.enableBlockingInSession(session.defaultSession);
      });

      mainWindow.loadURL('https://youtube.com')
      mainWindow.setTitle("YouTube")
      mainWindow.setBackgroundColor('#181818')

@sgebr01
Copy link
Author

sgebr01 commented Feb 19, 2022

OK, and this should work?

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

I'm just trying to load all of these filter lists at once, to have a bigger database of filters. I have also noticed that the video ads are blocked at times, I'm not sure if that has anything to do with this, but it does work from time to time when I run it - even though I didn't cache the engine.

Try to call fromLists only once with multiple list in the array then, it should work.

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

OK, and this should work?

There is still this issue where the preload script does not consistently work. But with your current code the adblocker will never block on initial page load.

@sgebr01
Copy link
Author

sgebr01 commented Feb 19, 2022

Using the array seems to work - here is what I have done -


const blocker = await ElectronBlocker.fromLists(fetch, [
            'https://easylist.to/easylist/easylist.txt',
            'https://easylist.to/easylist/easyprivacy.txt',
      ]);

      blocker.enableBlockingInSession(session.defaultSession)

      mainWindow.loadURL('https://youtube.com')

@sgebr01
Copy link
Author

sgebr01 commented Feb 19, 2022

Also, which is v13, my current version is only 1.23.6 using npm.

@remusao
Copy link
Collaborator

remusao commented Feb 19, 2022

Also, which is v13, my current version is only 1.23.6 using npm.

v13 should be the version of Electron you are using.

@sgebr01
Copy link
Author

sgebr01 commented Feb 20, 2022

My bad, I thought you were talking about the version of the ad blocker. I've tried using v13.0.0 of electron to no success. Could the version of electron-packager and builder make a difference? This is with the latest version of the ad-blocker.

@remusao
Copy link
Collaborator

remusao commented Feb 21, 2022

@sgebr01 Can you share the latest version of the code you are using please?

@sgebr01
Copy link
Author

sgebr01 commented Feb 21, 2022

Sure - my main.js is this

const { app, BrowserWindow, session } = require('electron')
const path = require('path')
const { ElectronBlocker, fullLists, FiltersEngine } = require('@cliqz/adblocker-electron')
const fetch = require('cross-fetch') // required 'fetch'
const fs = require('fs');
const { BlockList } = require('net');

let mainWindow

async function createWindow() {
      // Create the browser window.
      mainWindow = new BrowserWindow({
            darkTheme: true,
            icon: 'AdExtractLogo.png',
            center: 'true',
            resizable: 'true',
            movable: 'true',
            minimizable: 'true',
            maximizable: 'true',
            closable: 'true',
            focusable: 'true',
            fullscreen: 'false',
            frame: 'true',
            width: '800px',
            height: '800px',
            titleBarOverlay: 'color',
            webPreferences: {
                  preload: path.join(__dirname, 'preload.js'),
            }
      })
      if (mainWindow.webContents.session === undefined) {
            throw new Error('defaultSession is undefined');
      }

      ElectronBlocker.fromPrebuiltAdsAndTracking(fetch).then((blocker) => {
            blocker.enableBlockingInSession(session.defaultSession);
      });

      mainWindow.loadURL('https://youtube.com')
      mainWindow.setTitle("YouTube")
      mainWindow.setBackgroundColor('#181818')

      mainWindow.webContents.on("did-finish-load", () => {
            mainWindow.show();
      })

      mainWindow.on("page-title-updated", event => {
            event.preventDefault()
      })

      mainWindow.on('closed', function () {
            mainWindow = null
      })
}

app.on('ready', createWindow)

app.on('window-all-closed', function () {
      app.quit()
})

This is my preload.js

window.addEventListener('DOMContentLoaded', () => {
      const replaceText = (selector, text) => {
            const element = document.getElementById(selector)
            if (element) element.innerText = text
      }

      for (const type of ['chrome', 'node', 'electron']) {
            replaceText(`${type}-version`, process.versions[type])
      }
})

And my package.json

{
  "name": "youtube-desktop",
  "ProductName": "YouTube",
  "version": "1.0",
  "description": "YouTube App for Desktops",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "osx": "electron-packager . --overwrite --platform=darwin --arch=x64 --icon=./icon/youtube.icns --prune=true --out=./dist ",
    "windows": "electron-packager . --overwrite --platform=win32 --arch=ia32 --icon=./icon/youtube.icns --prune=true --out=./dist ",
    "linux": "electron-packager . --overwrite --platform=linux  --icon=./icon/youtube.icns --prune=true --out=./dist "
  },
  "dependencies": {
    "@cliqz/adblocker-electron": "^1.23.6",
    "electron": "^13.0.0",
    "electron-builder": "^22.14.13",
    "electron-packager": "^15.4.0",
    "tslint-config-standard": "^9.0.0"
  }
}

Additionally these are the packages that are installed


+-- @cliqz/adblocker-electron@1.23.6
+-- electron-builder@22.14.13
+-- electron-packager@15.4.0
+-- electron@13.0.0
`-- tslint-config-standard@9.0.0

@sgebr01
Copy link
Author

sgebr01 commented Feb 21, 2022

I can see that a lot of requests are getting blocked, but the ad and its corresponding ad banner is not getting blocked.
image

@sgebr01
Copy link
Author

sgebr01 commented Feb 24, 2022

Have you been able to find out why? If you are busy since it's a weekday, no worries - I appreciate your help so far.

@remusao
Copy link
Collaborator

remusao commented Feb 24, 2022

Hey @sgebr01, sorry I did not get the time to investigate further but I will try to find the time. It's definitely something that needs fixing.

@sgebr01
Copy link
Author

sgebr01 commented Feb 24, 2022

No worries, go at your own pace.

@kylegundersen
Copy link
Contributor

kylegundersen commented Feb 25, 2022

Hello @sgebr01,
I would just like to chime in and say that it does work for me. I am using Electron 16.
with the following configuration. Hopefully this helps.

Also note the use of async and await to wait for the fetch to complete.

import { ElectronBlocker, fullLists } from '@cliqz/adblocker-electron';
import { fetch } from 'cross-fetch';
import { session } from 'electron';
import { readFileSync, writeFileSync } from "original-fs";

module.exports = async function enableAdBlocker(){
        var adBlocker = await ElectronBlocker.fromLists(
            fetch,
            fullLists,
            {
            enableCompression: true
            },
            {
            path: `engine.bin`, 
            read: async (...args) => readFileSync(...args),
            write: async (...args) => writeFileSync(...args),
            }
        );
       adBlocker.enableBlockingInSession(session.defaultSession);
}

Also make sure you are using the latest version: "@cliqz/adblocker-electron": "^1.23.6"

@remusao
Copy link
Collaborator

remusao commented Feb 25, 2022

Thanks for chiming in @kylegundersen. Out of curiosity, does it also work when you start your Electron app immediately after deleting the on-disk cache? (engine.bin)

(sorry for closing/opening, wrong button :))

@remusao remusao closed this as completed Feb 25, 2022
@remusao remusao reopened this Feb 25, 2022
@kylegundersen
Copy link
Contributor

kylegundersen commented Feb 25, 2022

@remusao yea it does. Actually I had the same issue a week or two ago. Upgrading to the latest version is what fixed the YouTube Ad issue for me, because of the filter updates in the lists.

@sgebr01
Copy link
Author

sgebr01 commented Feb 25, 2022

Sure, I will try this out later today, and get back to you if it works.

@sgebr01
Copy link
Author

sgebr01 commented Feb 25, 2022

@kylegundersen I am still seeing some video ads, here is my code - however, I am guessing that some are getting blocked since I can see in my terminal [4468:0225/185105.745:ERROR:ssl_client_socket_impl.cc(983)] handshake failed; returned -1, SSL error code 1, net_error -100

Main.js Code

const { ElectronBlocker, fullLists } = require('@cliqz/adblocker-electron');
const { fetch } = require('cross-fetch');
const { session, BrowserWindow, app } = require('electron');
const { readFileSync, writeFileSync } = require("original-fs");
const path = require('path');


let mainWindow


module.exports = async function enableAdBlocker(){
      var adBlocker = await ElectronBlocker.fromLists(
          fetch,
          fullLists,
          {
          enableCompression: true
          },
          {
          path: `engine.bin`, 
          read: async (...args) => readFileSync(...args),
          write: async (...args) => writeFileSync(...args),
          }
      );
     adBlocker.enableBlockingInSession(session.defaultSession);
}

async function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    titleBarStyle: 'hidden',
    darkTheme: true,
    icon: 'icon/youtube.ico',
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    }
  })
  if (mainWindow.webContents.session === undefined) {
    throw new Error('defaultSession is undefined');
  }
  mainWindow.loadURL('https://youtube.com')
  mainWindow.setTitle("Youtube")
  mainWindow.setBackgroundColor('#181818')

  mainWindow.webContents.on("did-finish-load", () => {
    mainWindow.show();
  })
  mainWindow.webContents.on("did-fail-load", () => {
    if(confirm("Youtube could not be loaded. Retry?")) {
      mainWindow.reload()
    }
    else {
      mainWindow.close()
    }})

  mainWindow.on("page-title-updated", event => {
    event.preventDefault()
  })

  mainWindow.on('closed', function () {
    mainWindow = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', function () {
  app.quit()
})

@kylegundersen
Copy link
Contributor

Hey @sgebr01, I was using commonJS to load it from a separate file, so you can remove the module.exports = . Also you need to trigger that function enableAdBlocker() because I am not seeing that in the code above. Let me know how it goes, good luck.

@sgebr01
Copy link
Author

sgebr01 commented Feb 26, 2022

My bad, I'm trying that out now - also thank you for your help. Are the error codes I showed you in my previous comment showing that the video is getting blocked?

I tried it, and I'm still getting video ads.

@sgebr01
Copy link
Author

sgebr01 commented Feb 26, 2022

Here is my updated code.

const { ElectronBlocker, fullLists } = require('@cliqz/adblocker-electron');
const { fetch } = require('cross-fetch');
const { session, BrowserWindow, app } = require('electron');
const { readFileSync, writeFileSync } = require("original-fs");
const path = require('path');


let mainWindow


async function enableAdBlocker(){
      var adBlocker = await ElectronBlocker.fromLists(
          fetch,
          fullLists,
          {
          enableCompression: true
          },
          {
          path: `engine.bin`, 
          read: async (...args) => readFileSync(...args),
          write: async (...args) => writeFileSync(...args),
          }
      );
     adBlocker.enableBlockingInSession(session.defaultSession);
}

enableAdBlocker();

async function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    titleBarStyle: 'hidden',
    darkTheme: true,
    icon: 'icon/youtube.ico',
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    }
  })
  if (mainWindow.webContents.session === undefined) {
    throw new Error('defaultSession is undefined');
  }
  mainWindow.loadURL('https://youtube.com')
  mainWindow.setTitle("Youtube")
  mainWindow.setBackgroundColor('#181818')

  mainWindow.webContents.on("did-finish-load", () => {
    mainWindow.show();
  })
  mainWindow.webContents.on("did-fail-load", () => {
    if(confirm("Youtube could not be loaded. Retry?")) {
      mainWindow.reload()
    }
    else {
      mainWindow.close()
    }})

  mainWindow.on("page-title-updated", event => {
    event.preventDefault()
  })

  mainWindow.on('closed', function () {
    mainWindow = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', function () {
  app.quit()
})

@kylegundersen
Copy link
Contributor

kylegundersen commented Feb 26, 2022

Sorry to hear that @sgebr01. What version of Electron and Cliqz are you running? Also I would try adding await and putting the enableAdBlocker function inside the createWindow function as it fires when everything in Electron is ready.

BTW I tested it locally with the code you provided above and it worked as expected for me once I moved the enableAdBlocker function.

Here was my package.json dependencies.

    "dependencies": {
      "@cliqz/adblocker-electron": "^1.23.6",
      "cross-fetch": "^3.1.5"
    },
    "devDependencies": {
      "electron": "^16.0.6"
    }

@sgebr01
Copy link
Author

sgebr01 commented Feb 26, 2022

I tried this out as well, it works on some videos, but on others it doesn't, Is it 100% effective for you? I replaced my dependencies and installed the exact versions with npm, afterwards, I moved the enableAdBlocker function inside my create window function as well. I'm guessing this is still an issue with the ad-blocker?

@kylegundersen
Copy link
Contributor

@sgebr01 Yea it has been 100% effective for me. When upgrading dependencies did you then delete the bin file?

@sgebr01
Copy link
Author

sgebr01 commented Feb 26, 2022

That might be the issue, I think I need to do that.

@kylegundersen
Copy link
Contributor

kylegundersen commented Feb 26, 2022

Yea its my bad, I probably should have removed it from the sample, its just a simple way to cache filters for consecutive startups.

@sgebr01
Copy link
Author

sgebr01 commented Feb 26, 2022

Still didn't work, after deleting that file.

@sgebr01
Copy link
Author

sgebr01 commented Feb 26, 2022

Maybe there is a preferred place to put the enableAdBlocker function? What is the updated code that you used? I put it into the createWindow function, I'm not sure if placing it towards the end or the beginning will have an effect?

@kylegundersen
Copy link
Contributor

AD-blocker YouTube.zip
Here is my simple sample I made from the code you provided.

@sgebr01
Copy link
Author

sgebr01 commented Feb 26, 2022

OK, I tried this, it looks like it is working, but I think I will need to test it more. I'll try it tomorrow, and get back to you. Thank You for the Help!

@sgebr01
Copy link
Author

sgebr01 commented Feb 26, 2022

Looks like it's working, I'm not sure why I didn't it work for me before. I am guessing that this should work on webview elements as well?
Edit - Testing it out - it does.

@kylegundersen
Copy link
Contributor

@sgebr01 Awesome, glad you got it all to work. Please feel free to close this issue.😄

@sgebr01
Copy link
Author

sgebr01 commented Mar 1, 2022

Sure, I'm just wondering why it didn't work with the previous versions - thanks though for the help, I really appreciate it!

@sgebr01 sgebr01 closed this as completed Mar 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants