12 |
13 | );
14 |
15 | export default NotFoundPage;
16 |
--------------------------------------------------------------------------------
/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 | user nginx;
2 | worker_processes auto;
3 |
4 | error_log /var/log/nginx/error.log notice;
5 | pid /var/run/nginx.pid;
6 |
7 |
8 | events {
9 | worker_connections 1024;
10 | }
11 |
12 |
13 | http {
14 | include /etc/nginx/mime.types;
15 | default_type application/octet-stream;
16 |
17 | # log_format main '[$time_local] "$request" '
18 | # '$status $body_bytes_sent "$http_referer" '
19 | # '"$http_user_agent" "$http_x_forwarded_for"';
20 |
21 | # access_log /var/log/nginx/access.log main;
22 | access_log off;
23 | #error_log /etc/nginx/logs/error.log warn;
24 | error_log /dev/null crit;
25 |
26 | sendfile on;
27 | #tcp_nopush on;
28 |
29 | keepalive_timeout 65;
30 |
31 | gzip on;
32 |
33 | include /etc/nginx/conf.d/*.conf;
34 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SponsorBlock Landing
2 |
3 | This uses the `gatsby` static site generator.
4 |
5 | Install `npm` to start.
6 |
7 | Then `cd SponsorBlockSite`.
8 |
9 | ### Install dependencies
10 |
11 | ```shell
12 | npm install
13 | ```
14 |
15 | ### Developing
16 |
17 | ```shell
18 | npm run develop
19 | ```
20 |
21 | This will start a development server on http://localhost:8000.
22 |
23 | Before making a pull request, run `npm run format` to format the code.
24 |
25 | ### Building
26 |
27 | ```shell
28 | npm run build
29 | ```
30 |
31 | This will create a folder called `public`, which will contain a statically generated version of the site that can be easily served with any website or deployment service.
32 |
33 | You can then use `npm run serve` to preview the website before deployment.
34 |
35 | ---
36 |
37 | Thanks for the rewrite [@jplsek](https://github.com/jplsek)!
38 |
--------------------------------------------------------------------------------
/gatsby-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | siteMetadata: {
3 | title: "SponsorBlock",
4 | description:
5 | "SponsorBlock is a crowdsourced browser extension to skip sponsor segments in YouTube videos.",
6 | author: "Ajay Ramachandran",
7 | icon: "https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png",
8 | },
9 | plugins: [
10 | "gatsby-plugin-react-helmet",
11 | {
12 | resolve: "gatsby-plugin-manifest",
13 | options: {
14 | name: "SponsorBlock",
15 | short_name: "SponsorBlock",
16 | start_url: "/",
17 | background_color: "#fff",
18 | theme_color: "#fff",
19 | icon: "static/LogoSponsorBlockSimple256px.png",
20 | },
21 | },
22 | "gatsby-plugin-sass",
23 | ],
24 | };
25 |
--------------------------------------------------------------------------------
/src/components/donate.scss:
--------------------------------------------------------------------------------
1 | .donate-modal {
2 | background-color: rgb(26, 26, 26, 0.95);
3 | border-radius: 15px;
4 |
5 | display: flex;
6 | justify-content: center;
7 | align-items: center;
8 | flex-wrap: wrap;
9 | }
10 |
11 | .donate-modal-container {
12 | position: fixed;
13 | display: flex;
14 | align-items: center;
15 | justify-content: center;
16 | top: 0;
17 | left: 0;
18 | width: 100%;
19 | height: 100%;
20 | }
21 |
22 | .donate-modal > div {
23 | width: 100%;
24 |
25 | display: flex;
26 | justify-content: center;
27 | padding: 10px;
28 | }
29 |
30 | .donate-modal a {
31 | text-decoration: none;
32 | color: #eee;
33 | border-radius: 15px;
34 | background-color: rgb(58, 58, 58, 0.9);
35 | padding: 15px;
36 |
37 | margin-right: 20px;
38 | transition: background-color 0.3s ease;
39 | }
40 |
41 | .donate-modal a:hover {
42 | background-color: rgba(70, 70, 70, 0.9);
43 | }
44 |
45 | .donate-modal a.active {
46 | background-color: rgba(139, 0, 0, 0.9);
47 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Ajay Ramachandran
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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sponsorblock",
3 | "private": true,
4 | "description": "SponsorBlock is a crowdsourced browser extension to block sponsor segments of YouTube videos.",
5 | "version": "1.0.0",
6 | "author": "Ajay Ramachandran",
7 | "dependencies": {
8 | "@fortawesome/fontawesome-free": "^6.7.2",
9 | "classnames": "^2.5.1",
10 | "gatsby": "^5.13.1",
11 | "gatsby-plugin-manifest": "^5.14.0",
12 | "gatsby-plugin-react-helmet": "^6.14.0",
13 | "gatsby-plugin-sass": "^6.14.0",
14 | "lmdb": "^3.4.0",
15 | "msgpackr": "^1.11.4",
16 | "normalize.css": "^8.0.1",
17 | "prop-types": "^15.8.1",
18 | "react": "^18.2.0",
19 | "react-dom": "^18.2.0",
20 | "react-helmet": "^6.1.0",
21 | "sass": "^1.89.2"
22 | },
23 | "devDependencies": {
24 | "prettier": "^3.2.4"
25 | },
26 | "license": "MIT",
27 | "engines": {
28 | "node": ">=18"
29 | },
30 | "scripts": {
31 | "build": "gatsby build",
32 | "develop": "gatsby develop",
33 | "format": "prettier --write \"**/*.{js,jsx,json,md,scss}\"",
34 | "start": "npm run develop",
35 | "serve": "gatsby serve",
36 | "clean": "gatsby clean"
37 | },
38 | "repository": {
39 | "type": "git",
40 | "url": "https://github.com/ajayyy/SponsorBlock"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # dotenv environment variable files
55 | .env*
56 |
57 | # gatsby files
58 | .cache/
59 | public
60 |
61 | # Mac files
62 | .DS_Store
63 |
64 | # Yarn
65 | yarn-error.log
66 | .pnp/
67 | .pnp.js
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # IDEs
72 | .vscode/
73 | .idea/
74 |
--------------------------------------------------------------------------------
/nginx/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | listen [::]:80;
4 | server_name localhost;
5 |
6 | #access_log /var/log/nginx/host.access.log main;
7 |
8 | location / {
9 | root /usr/share/nginx/html;
10 | index index.html index.htm;
11 | }
12 |
13 | location /news {
14 | return 301 https://blog.ajay.app/sponsorblock;
15 | }
16 |
17 | location /viewer {
18 | return 301 https://sb.ltn.fi;
19 | }
20 |
21 | error_page 404 /404.html;
22 |
23 | # redirect server error pages to the static page /50x.html
24 | #
25 | error_page 500 502 503 504 /50x.html;
26 | location = /50x.html {
27 | root /usr/share/nginx/html;
28 | }
29 |
30 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80
31 | #
32 | #location ~ \.php$ {
33 | # proxy_pass http://127.0.0.1;
34 | #}
35 |
36 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
37 | #
38 | #location ~ \.php$ {
39 | # root html;
40 | # fastcgi_pass 127.0.0.1:9000;
41 | # fastcgi_index index.php;
42 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
43 | # include fastcgi_params;
44 | #}
45 |
46 | # deny access to .htaccess files, if Apache's document root
47 | # concurs with nginx's one
48 | #
49 | #location ~ /\.ht {
50 | # deny all;
51 | #}
52 | }
--------------------------------------------------------------------------------
/.github/workflows/docker-build.yml:
--------------------------------------------------------------------------------
1 | # Based on https://github.com/ajayyy/sb-mirror/blob/main/.github/workflows/docker-build.yml
2 | name: multi-build-docker
3 | on:
4 | workflow_call:
5 | inputs:
6 | name:
7 | required: true
8 | type: string
9 | username:
10 | required: true
11 | type: string
12 | secrets:
13 | GH_TOKEN:
14 | required: true
15 |
16 | jobs:
17 | build_container:
18 | runs-on: ubuntu-latest
19 | steps:
20 | - name: Checkout
21 | uses: actions/checkout@v2
22 | - uses: actions/setup-node@v3
23 | with:
24 | node-version: '18'
25 | - name: Install build dependencies
26 | run: sudo apt-get install -y build-essential python3 && npm ci
27 | - name: Build site
28 | run: npm run build
29 | - name: Docker meta
30 | id: meta
31 | uses: docker/metadata-action@v3
32 | with:
33 | images: |
34 | ghcr.io/${{ inputs.username }}/${{ inputs.name }}
35 | tags: |
36 | type-raw,value=alpine
37 | flavor: |
38 | latest=true
39 | - name: Login to GHCR
40 | uses: docker/login-action@v1
41 | with:
42 | registry: ghcr.io
43 | username: ${{ github.repository_owner }}
44 | password: ${{ secrets.GH_TOKEN }}
45 | - name: Set up QEMU
46 | uses: docker/setup-qemu-action@v1
47 | with:
48 | platforms: arm,arm64
49 | - name: Set up buildx
50 | uses: docker/setup-buildx-action@v1
51 | - name: push
52 | uses: docker/build-push-action@v2
53 | with:
54 | context: .
55 | platforms: linux/amd64,linux/arm64
56 | push: true
57 | tags: ${{ steps.meta.outputs.tags }}
--------------------------------------------------------------------------------
/src/pages/donate.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Layout from "../components/layout";
4 | import Seo from "../components/seo";
5 | import { DonateComponent } from "../components/donate";
6 |
7 | const IndexPage = () => (
8 |
9 |
10 |
11 |
12 |
Donate
13 |
14 |
15 | Hi, I'm Ajay.
16 | For the past 5 years, I've been working open-source tools like SponsorBlock and DeArrow.
17 | Thanks to your support, I am now able to work on these open-source projects full time.
18 |
19 |
20 |
21 | If you'd like to help make that possible, consider supporting using an option below.
22 |
23 |
24 |
25 |
26 |
27 |
28 |
Creators
29 |
30 |
31 | Consider helping out the creators of videos you watch by
32 | donating to their crowdfunding campaigns, or subscribing to
33 | services such as YouTube Premium.
34 |
12 | List of emails I have received about inserting malware into my
13 | extension
14 |
15 |
16 | I've been seeing a lot of stories about extensions getting taken
17 | over by unknown developers and becoming malware. Sadly, with how
18 | many permissions many extensions have, it can do a lot of
19 | damage. I decided to compile a list of these sketchy emails I
20 | have received, to show the kinds of offers that exist.
21 |
22 |
23 | To be clear I will never do anything of this
24 | sort, but make sure any extensions you install are from trusted
25 | developers and have as few permissions as possible. Most of
26 | these scams wouldn't even work with SponsorBlock due to lack
27 | of permissions (it only has access to youtube.com), but they
28 | spam email all developers anyway.
29 |
30 |
From partners@infatica.io (A proxy service (botnet?)):
36 | Here's the code for
37 | their sdk. In the email they told me it was "open", so that
38 | should mean it is meant to be public.
39 |
40 |
44 |
48 |
52 |
56 |
From extensionmetric.com
57 |
58 | The site disapeared exactly one month after their email, almost
59 | like they weren't planning on paying anything after all...
60 | Here's the code for
61 | their sdk. This one is FAR worse than infatica. There are some
62 | calls to getAllResponseHeaders, which could mean stealing logged
63 | in accounts.
64 |
14 | When you visit a YouTube video, it will check the database to
15 | see if anyone has made any submissions for the video. If so, the
16 | segment will automatically get skipped when you reach it.
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 | Once the sponsorship is skipped, you can upvote or downvote this
29 | segment and it will be recorded in the database.
30 |
31 |
32 |
33 | Instead of just sending the top reported segment, it finds all
34 | of the overlapping segments. Only one segment from each group of
35 | overlapping segments will be sent to the user.
36 |
37 |
38 |
Pseudo-random distribution
39 |
40 |
41 | To prevent one submission with a lot of votes never being able
42 | to be replaced, I decided to use a weighted random distribution
43 | based on the equation on the right.
44 |
45 |
50 | This formula makes the first few votes matter a lot more than
51 | votes on a submission that already has a lot of votes. This
52 | gives newly submitted segments a better chance of being sent out
53 | to users to get votes. So, most users will get the best
54 | submission, but some users will get lesser votes submissions so
55 | that they can either be upvoted or downvoted. Submissions with
56 | less than -1 votes are ignored entirely.
57 |
58 |
59 |
60 | You can read more about my algorithm{" "}
61 |
62 | here
63 |
64 | .
65 |
66 |
67 |
Submissions
68 |
69 |
70 | Anyone can submit segments, either by clicking on the button
71 | that is added to the YouTube player or by opening the extensions
72 | popup. The button in the YouTube player can be hidden. You click
73 | once to indicate the start of a segment, then click again to
74 | indicate the end. You can submit as many segments as there are
75 | in the video. Make sure to choose the correct category for each
76 | segment.
77 |
78 |
79 |
What data is stored?
80 |
81 |
82 | The bare minimum. Check{" "}
83 |
84 | this list
85 | {" "}
86 | for more information
87 |
88 |
89 |
Previous projects like this
90 |
91 |
92 | In January 2019, a group of people tried to do a similar thing,
93 | but instead of using other people's submissions to skip sponsor
94 | segments for everyone, they{" "}
95 |
96 | ran the data through a neural network
97 |
98 | . Sadly, this project was abandoned.
99 |
100 |
101 |
102 | I don't want something similar to happen to this project, that's
103 | why all this code is open-sourced and, most importantly, the
104 | database can be downloaded by anyone. The database may even be
105 | automatically backed up by archive.org! The database will always
106 | be available{" "}
107 | here. It is
108 | a csv and can be opened in any csv or text reading program.
109 | Certain sensitive info is not in this database and is not public
110 | such as individual votes (not vote counts) and hashed IP
111 | addresses. That information isn't needed by anyone else, only
112 | the server.
113 |
114 |
115 |
When was this started
116 |
117 |
118 | The project was started July 5th 2019 and was first released to
119 | the public July 26th 2019.
120 |
121 |
122 |
Contact Info
123 |
124 |
If you have any suggestions, feel free to tell me.
40 | SponsorBlock is an open-source crowdsourced browser
41 | extension and open API for skipping sponsor segments in
42 | YouTube videos. Users submit when a sponsor happens from
43 | the extension, and the extension automatically skips
44 | sponsors it knows about using a{" "}
45 |
46 | privacy preserving query system
47 |
48 | . It also supports skipping other categories, such as
49 | intros, outros and reminders to subscribe, and skipping
50 | to the point with highlight.
51 |