├── requirements.txt ├── FYouToo_logo.png ├── adblock-blocker.png ├── Ad-blocker-logo-v1.1.jpg ├── Ad-blocker-logo-v1.1.png ├── .vscode └── settings.json ├── browser-extension ├── manifest.json ├── README.md └── content.js ├── extension_example_youfucktube.py ├── youfucktube.py ├── LICENSE ├── youfucktubeforever.py ├── src └── youfucktube │ └── __init__.py ├── youfucktubegui.py ├── README.md └── .gitignore /requirements.txt: -------------------------------------------------------------------------------- 1 | pyperclip -------------------------------------------------------------------------------- /FYouToo_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SchulerSimon/fyoutoo/HEAD/FYouToo_logo.png -------------------------------------------------------------------------------- /adblock-blocker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SchulerSimon/fyoutoo/HEAD/adblock-blocker.png -------------------------------------------------------------------------------- /Ad-blocker-logo-v1.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SchulerSimon/fyoutoo/HEAD/Ad-blocker-logo-v1.1.jpg -------------------------------------------------------------------------------- /Ad-blocker-logo-v1.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SchulerSimon/fyoutoo/HEAD/Ad-blocker-logo-v1.1.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.typeCheckingMode": "basic", 3 | "[python]": { 4 | "editor.defaultFormatter": "ms-python.black-formatter" 5 | }, 6 | "python.formatting.provider": "none" 7 | } -------------------------------------------------------------------------------- /browser-extension/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_scripts": [{ 3 | "all_frames": true, 4 | "js": [ "content.js" ], 5 | "matches": [ "https://www.youtube.com/*" ] 6 | }], 7 | "manifest_version": 3, 8 | "name": "Youfucktube", 9 | "version": "0.0.4", 10 | "browser_specific_settings": { 11 | "gecko": { 12 | "id": "{70c1ae1e-c90c-4a9a-825c-2ad1d204d951}" 13 | } 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /extension_example_youfucktube.py: -------------------------------------------------------------------------------- 1 | # This file gives an example on how to extend youfucktube 2 | # it just uses a given video_url as example 3 | 4 | import src.youfucktube as youfucktube 5 | 6 | 7 | def main(): 8 | video_url: str = "https://www.youtube.com/watch?v=dQw4w9WgXcQ" 9 | 10 | try: 11 | video_id = youfucktube.extract_video_id(video_url) 12 | except ValueError: 13 | print("Please copy the Video URL into the Clipboard.") 14 | exit(1) 15 | 16 | link = youfucktube.create_link(video_id) 17 | youfucktube.open_browser(link) 18 | exit(0) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /youfucktube.py: -------------------------------------------------------------------------------- 1 | import src.youfucktube as youfucktube 2 | 3 | try: 4 | import pyperclip 5 | except (ImportError, ImportWarning) as e: 6 | print( 7 | "Install pip packange pyperclip for this programm to work: 'pip install pyperclip'" 8 | ) 9 | exit(1) 10 | 11 | 12 | def main(): 13 | video_url: str = pyperclip.paste() 14 | 15 | try: 16 | video_id = youfucktube.extract_video_id(video_url) 17 | except ValueError: 18 | print("Please copy the Video URL into the Clipboard.") 19 | exit(1) 20 | 21 | link = youfucktube.create_link(video_id) 22 | youfucktube.open_browser(link) 23 | exit(0) 24 | 25 | 26 | if __name__ == "__main__": 27 | main() 28 | -------------------------------------------------------------------------------- /browser-extension/README.md: -------------------------------------------------------------------------------- 1 | # FYouToo - UNBLOCK YOUTUBE ADBLOCK-BLOCK Browser Extension 2 | Simply replaces the youtube video by embedded one. 3 | 4 | ## Quick start using uploaded version 5 | Install browser extension from GitHub [releases](https://github.com/granlem/youfucktube/releases/latest) 6 | 7 | ## Quick start using repository 8 | 1. Clone repository 9 | 2. Open Firefox 10 | 3. Navigate to `about:debugging#/runtime/this-firefox` 11 | 4. "Load Temporary Add-on..." 12 | 5. Select the manifest in browser-extension folder 13 | 6. Note, the extension is only loaded until you close your firefox 14 | 15 | ## Compatibility 16 | - Firefox Version >= 48.0 17 | - Android für Firefox Version >= 120.0a1 18 | - Google Chome (untested) 19 | - Microsoft Edge (untested) 20 | - Opera (tested) 21 | 22 | ## Known bugs 23 | - Ad-Free Player appears only after ~500ms 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Simon Schuler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /youfucktubeforever.py: -------------------------------------------------------------------------------- 1 | import time 2 | import src.youfucktube as youfucktube 3 | 4 | try: 5 | import pyperclip 6 | except (ImportError, ImportWarning) as e: 7 | print( 8 | "Install pip packange pyperclip for this programm to work: 'pip install pyperclip'" 9 | ) 10 | exit(1) 11 | 12 | def main(): 13 | 14 | prev_clipboard_content = "" 15 | try: 16 | while True: 17 | # get clipboard contents 18 | video_url: str = pyperclip.paste() 19 | 20 | # compare to last clipboard contents 21 | if video_url != prev_clipboard_content: 22 | 23 | # do the thing 24 | try: 25 | video_id = youfucktube.extract_video_id(video_url) 26 | link = youfucktube.create_link(video_id) 27 | youfucktube.open_browser(link) 28 | except ValueError: 29 | pass 30 | 31 | # save current clipboard contents 32 | prev_clipboard_content = video_url 33 | 34 | time.sleep(0.2) 35 | 36 | except (KeyboardInterrupt, InterruptedError, SystemExit): 37 | exit(0) 38 | 39 | if __name__ == "__main__": 40 | main() -------------------------------------------------------------------------------- /browser-extension/content.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | let v = undefined; 3 | setInterval(function() { 4 | 5 | // Only if ready, movie_player div loaded and when watching a video 6 | if (document.readyState !== 'complete' || ! document.getElementById("movie_player") || window.location.pathname != "/watch") { 7 | return; 8 | } 9 | 10 | // Stop all videos on page 11 | Array.from(document.getElementsByTagName("video")).forEach(e => e.pause); 12 | 13 | // Place player (or update if video has changed) 14 | let v2 = new URLSearchParams(window.location.search).get('v'); 15 | if (!document.getElementById("youfucktube-player") || v != v2) { 16 | v = v2; 17 | let iframe = document.createElement('iframe'); 18 | iframe.id = "youfucktube-player"; 19 | iframe.style = "border-left: 2px solid darkred; width: 100%; height: 100%;"; 20 | iframe.title="YouFuckTubePlayer"; 21 | iframe.frameborder="0"; 22 | iframe.allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"; 23 | iframe.allowfullscreen = "1"; 24 | iframe.src = "https://www.youtube.com/embed/" + v; 25 | document.getElementById("movie_player").innerHTML = iframe.outerHTML; 26 | console.log("youfucktube-player placed"); 27 | } 28 | 29 | }, 500); 30 | })() -------------------------------------------------------------------------------- /src/youfucktube/__init__.py: -------------------------------------------------------------------------------- 1 | # /bin/python3 2 | 3 | import webbrowser 4 | 5 | 6 | def extract_video_id(video_url: str) -> str: 7 | """takes a youtube url and extracts the video_id 8 | 9 | Args: 10 | video_url (str): url to a youtube video 11 | 12 | Raises: 13 | ValueError: when the given video_url is not a valid youtube.com/watch link 14 | 15 | Returns: 16 | str: the unique video_id 17 | """ 18 | if "www.youtube.com/watch" not in video_url: 19 | raise ValueError("Must provide a youtube.com/watch?v= link") 20 | 21 | video_id: str = video_url.split("?v=")[1] 22 | video_id: str = video_id.split("&")[0] 23 | return video_id 24 | 25 | 26 | def create_link(video_id: str) -> str: 27 | """creates the embedded link 28 | 29 | Args: 30 | video_id (str): the url of the video 31 | 32 | Returns: 33 | str: a link to an embedded version of the video 34 | """ 35 | embed_link = "https://www.youtube-nocookie.com/embed/{video_id}" 36 | link = embed_link.format(video_id=video_id) 37 | return link 38 | 39 | 40 | def open_browser(url: str): 41 | """opens the system default browser with the given url 42 | 43 | Args: 44 | url (str): the url to be displayed in a new tab 45 | """ 46 | try: 47 | # tries to open a new tab instead of a new window 48 | webbrowser.get().open(url=url, new=2) 49 | except Exception: 50 | print(f"Could not open default browser. Here is your link: {url}") 51 | exit(1) 52 | -------------------------------------------------------------------------------- /youfucktubegui.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import src.youfucktube as youfucktube 3 | 4 | 5 | def main(): 6 | app = tk.Tk() 7 | app.title("YouFuckTubeGUI") 8 | app.geometry("400x150") 9 | app.configure(bg="#252526") 10 | 11 | normal_font = ("Helvetica", 10) 12 | bold_font = ("Helvetica", 12, "bold") 13 | 14 | spacer_label = tk.Label(app, text="", bg="#252526").pack() 15 | 16 | input_label = tk.Label( 17 | app, text="Youtube URL:", font=bold_font, fg="white", bg="#252526" 18 | ) 19 | input_label.pack() 20 | 21 | url = tk.Entry(app, width=50, font=normal_font) 22 | url.pack() 23 | 24 | err_msg = tk.StringVar() 25 | 26 | spacer_label2 = tk.Label(app, text="", bg="#252526").pack() 27 | 28 | def button_press(): 29 | video_url: str = url.get() 30 | 31 | err_msg.set("") 32 | 33 | try: 34 | video_id: str = youfucktube.extract_video_id(video_url) 35 | except ValueError: 36 | err_msg.set("Please input a valid youtube URL.") 37 | return 38 | 39 | link = youfucktube.create_link(video_id) 40 | youfucktube.open_browser(link) 41 | 42 | return 43 | 44 | submit_button = tk.Button( 45 | app, 46 | text="Submit", 47 | command=button_press, 48 | font=bold_font, 49 | bg="#007acc", 50 | fg="white", 51 | borderwidth=1, 52 | ) 53 | submit_button.pack() 54 | 55 | warning_label = tk.Label( 56 | app, textvariable=err_msg, fg="#dadf49", bg="#252526", font=normal_font 57 | ) 58 | warning_label.pack() 59 | 60 | app.mainloop() 61 | 62 | 63 | if __name__ == "__main__": 64 | main() 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FYouToo - UNBLOCK YOUTUBE ADBLOCK-BLOCK 2 | 3 | ## Tired of this? 4 | ![FYouToo-Adblock-blcoker](adblock-blocker.png) 5 | 6 | # Here is your solution! 7 | 8 | ***

For the Browser extension have a look at [browser-extension](./browser-extension/README.md)

*** 9 | 10 | 11 | ## What do you need to do? 12 | 13 | - install [Pyhton3](https://www.python.org/downloads/): 14 | - Linux: `sudo apt install python3.12` 15 | - Windows: click [here](https://www.python.org/downloads/) 16 | - MacOS: click [here](https://www.python.org/downloads/) 17 | - install [pyperclip](https://pypi.org/project/pyperclip/): 18 | - `pip install pyperclip` 19 | - clone this repo: 20 | - `git clone https://github.com/SchulerSimon/youfucktube.git` 21 | - copy the URL of a youtube-video 22 | - `https://www.youtube.com/watch?v=dQw4w9WgXcQ` 23 | - execute the script: 24 | - `cd youfucktube` 25 | - CLI: 26 | - Dose it once, needs to be executed each time you copy a youtube-url. 27 | - `python youfucktube.py` 28 | - GUI: 29 | - Provides a Graphical User Interface you can interact with. 30 | - `python youfucktubegui.py` 31 | - SERVICE: 32 | - Runs in the background. Just start the script once. And every time you copy a youtube-url, it should open a new window in the browser. 33 | - `python youfucktubeforever.py` 34 | 35 | ## How dose it work? 36 | Its super simple: *YouTube's AdBlock-Block only works on their website. When you embed a Video into another website, you can watch it just fine. This script basically automates that process.* 37 | 38 | - **copies** a youtube-link from your **clipboard** 39 | - extracts the `video_id` from the link 40 | - creates a new link (like so `https://www.youtube-nocookie.com/embed/`) 41 | - calls the system-default browser to open this link and brings the browser to the front 42 | 43 | ## Things that could be improved: 44 | - make this whole thing more accessible 45 | - make the script explain itself better via textoutput 46 | - build into standalone executable for major platforms 47 | - polish the GUI-Version a bit 48 | - test MacOS, I cannot, have no mac. 49 | - make gui-version that runs as a service 50 | - try multiple browsers, when `webbrowser.get().open(link)` fails 51 | - en-/disable service script with hotkey(s) 52 | - do some SEO, so that this repo is more easily found via google/bing/duckduckgo etc. 53 | - think of/design a logo 54 | 55 | Any ideas, designs and PRs are welcome! 56 | 57 | ## Have your own idea? How to write extension for youfucktube? 58 | - Have a look at this [example](extension_example_youfucktube.py). 59 | 60 | 61 | 62 | ### Contributions: 63 | - Thanks to [MadaHaz](https://github.com/MadaHaz) there is also a Version with a GUI. 64 | - Thanks to the Idea of [granlem](https://github.com/granlem), there is also a Version that runs in the background like a service. 65 | - Thanks to [granlem](https://github.com/granlem), we now have a browser extension for major browsers that uses this concept and is easier to use. Look [here](./browser-extension/README.md) 66 | - Thanks to [4robrob](https://github.com/4robrob), we now have a logo. 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ --------------------------------------------------------------------------------