Instantly share code, notes, and snippets.
Last active
June 14, 2022 07:16
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save sidneys/23018bf607466ebeb5b11c7889774665 to your computer and use it in GitHub Desktop.
BitChute | 'Add to Playlist' Button Everywhere
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name BitChute: Add-to-Playlist-Button for all Videos | |
// @namespace org.sidneys.userscripts | |
// @homepage https://gist.githubusercontent.com/sidneys/23018bf607466ebeb5b11c7889774665/raw/ | |
// @version 0.9.7 | |
// @description Adds the BitChute playlist button to every video thumbnail, right next to the 'Watch Later' button. | |
// @author sidneys | |
// @icon https://i.imgur.com/4GUWzW5.png | |
// @noframes | |
// @match *://*.bitchute.com/* | |
// @require https://greasyfork.org/scripts/38888-greasemonkey-color-log/code/Greasemonkey%20%7C%20Color%20Log.js | |
// @require https://greasyfork.org/scripts/374849-library-onelementready-es7/code/Library%20%7C%20onElementReady%20ES7.js | |
// @connect bitchute.com | |
// @grant GM.addStyle | |
// @grant GM.download | |
// @grant unsafeWindow | |
// @run-at document-start | |
// ==/UserScript== | |
/** | |
* ESLint | |
* @global | |
*/ | |
/* global Debug, onElementReady */ | |
Debug = false | |
/** | |
* Inject Stylesheet | |
*/ | |
let injectStylesheet = () => { | |
console.debug('injectStylesheet') | |
GM.addStyle(` | |
/* ========================================================================== | |
ELEMENTS | |
========================================================================== */ | |
/* .show-playlist-modal | |
========================================================================== */ | |
.action-button.show-playlist-modal | |
{ | |
top: 30px; | |
font-size: 24px; | |
width: 30px; | |
height: 30px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
.action-button.show-playlist-modal > svg.action-icon:hover | |
{ | |
transform: unset; | |
} | |
.action-button | |
{ | |
cursor: pointer; | |
} | |
`) | |
} | |
/** | |
* Monkey Patch History.pushState() to emit a 'pushstate' event on <window>. | |
* @see {@link https://stackoverflow.com/a/4585031/1327892} | |
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/History/pushState} | |
*/ | |
const originalPushState = unsafeWindow.history.pushState | |
unsafeWindow.history.pushState = (state, title = '', url) => { | |
console.debug('history.pushState()', 'state:', JSON.stringify(state), 'title:', title, 'url:', url) | |
// Create event | |
const event = new CustomEvent('pushstate', { 'detail': state, 'bubbles': true, 'cancelable': false }) | |
// Emit event | |
unsafeWindow.dispatchEvent(event) | |
// Call original | |
originalPushState.call(unsafeWindow.history, state, title, url) | |
} | |
/** | |
* Register Event Handlers | |
*/ | |
let registerEventHandlers = () => { | |
console.debug('registerEventHandlers') | |
// Add BitChute's internal event handlers | |
unsafeWindow.playlistAttachEvents() | |
unsafeWindow.playlistAttachModalEvents() | |
unsafeWindow.spaAttachEvents() | |
unsafeWindow.scrollerAttachEvents() | |
// Log message after Playlist shown | |
unsafeWindow.jQuery('.playlist-modal') | |
.off('shown.bs.modal') | |
.on('shown.bs.modal', (event) => { | |
console.debug('.playlist-modal#shown.bs.modal') | |
console.info('Shown', 'Playlist') | |
}) | |
// Log message after Playlist hidden | |
unsafeWindow.jQuery('.playlist-modal') | |
.off('hidden.bs.modal') | |
.on('hidden.bs.modal', (event) => { | |
console.debug('.playlist-modal#hidden.bs.modal') | |
console.info('Hidden', 'Playlist') | |
}) | |
} | |
/** | |
* Render Button 'Add to Playlist' | |
* @param {Element} element - Target Element | |
*/ | |
let renderButtonElement = (element) => { | |
console.debug('renderButtonElement') | |
// Create Element | |
const buttonElement = document.createElement('span') | |
buttonElement.className = 'show-playlist-modal' | |
buttonElement.innerHTML = ` | |
<i class="action-icon fas fa-list fa-fw"></i> | |
` | |
buttonElement.title = 'Add to Playlist' | |
buttonElement.dataset.toggle = 'tooltip' | |
buttonElement.dataset.placement = 'bottom' | |
unsafeWindow.jQuery(buttonElement).data('video', unsafeWindow.jQuery(element).data('video')) | |
if (element.classList.contains('action-button')) { | |
buttonElement.classList.add('action-button') | |
} | |
if (element.classList.contains('toolbox-button')) { | |
buttonElement.classList.add('toolbox-button') | |
} | |
// Render Element | |
element.after(buttonElement) | |
// Status | |
console.debug('Rendered', 'Button Element') | |
} | |
/** | |
* Render Modal 'Playlist' | |
* @param {Element} element - Target Element | |
*/ | |
let renderPlaylistElement = (element) => { | |
console.debug('renderPlaylistElement') | |
// Abort if exists | |
if (document.querySelector('.playlist-modal')) { return } | |
// Create Element | |
const playlistElement = document.createElement('div') | |
playlistElement.setAttribute('role', 'dialog') | |
playlistElement.className = 'modal fade playlist-modal' | |
playlistElement.innerHTML = ` | |
<div class="modal-dialog"> | |
<div class="modal-content"> | |
<div class="modal-header"> | |
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"> | |
<i class="fas fa-times fa-fw"></i> | |
</button> | |
<a href="/" class="spa"> | |
<img class="modal-logo logo-full" src="/static/v130/images/logo-full-day.png" alt="BitChute"> | |
</a> | |
</div> | |
<div class="modal-body"> | |
<div class="form-group"> | |
<div class="create-playlist-entry-error alert alert-danger hidden"></div> | |
<label>Add to Playlist</label> | |
<span class="options"></span> | |
</div> | |
<div class="create-playlist-error alert alert-danger hidden"></div> | |
<div class="form-group"> | |
<form method="post" id="create-playlist-form"> | |
<input type="hidden" name="csrfmiddlewaretoken" value="XA3zoHAEsntOaFTteSV3rhIVboyJf5P5HeYjAioyqn2hKQ8IXcBOcKZCTduYIVc4"> | |
<label>Create a New Playlist</label> | |
<div class="create-playlist-error-playlist alert alert-danger hidden"></div> | |
<div class="name"> | |
<input type="text" name="playlist" class="form-control" autocomplete="off" placeholder="My Playlist" maxlength="100" id="id_playlist"> | |
<span class="toolbox-button create" data-video="UkfyMnll0o9O" data-toggle="tooltip" data-placement="bottom" title="Create Playlist"> | |
<span class="fa-layers"> | |
<i class="fal fa-square"></i> | |
<i class="far fa-plus" data-fa-transform="shrink-7"></i> | |
</span> | |
</span> | |
</div> | |
<p class="help">This must be unique. Maximum 100 characters.</p> | |
</form> | |
</div> | |
</div> | |
</div> | |
</div> | |
` | |
// Render Element | |
element.before(playlistElement) | |
// Status | |
console.debug('Rendered', 'Playlist Element') | |
} | |
/** | |
* Init | |
*/ | |
let init = () => { | |
console.info('init') | |
// Add Stylesheet | |
injectStylesheet() | |
// Add Playlist | |
onElementReady('.container', true, (element) => { | |
renderPlaylistElement(element) | |
}) | |
// Add Buttons | |
onElementReady('.playlist-watch-later', false, (element) => { | |
// Render Element | |
renderButtonElement(element) | |
// Attach Events | |
registerEventHandlers() | |
}) | |
} | |
/** | |
* @listens document:Event#readystatechange | |
*/ | |
document.addEventListener('readystatechange', () => { | |
console.debug('document#readystatechange', document.readyState) | |
if (document.readyState !== 'interactive') { return } | |
/** | |
* @listens window:Event#jQuery(document).ready | |
*/ | |
unsafeWindow.jQuery(document).ready(() => { | |
console.debug('window#jQuery(document).ready') | |
init() | |
}) | |
}) | |
/** | |
* Handle in-page navigation on BitChute | |
* @listens window:Event#pushstate | |
*/ | |
unsafeWindow.addEventListener('pushstate', (event) => { | |
console.debug('window#pushstate', 'event.detail:', JSON.stringify(event.detail)) | |
init() | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment