Last active
July 7, 2023 18:29
-
-
Save hinell/747e1a937dd07ad027d359993e5327c1 to your computer and use it in GitHub Desktop.
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
/******************** | |
Name : SC.Tracks snippet | |
Version : 0.4.5 | |
Created.......: Jan 9, 2019 | |
Last-Modified : July 07, 2023 | |
Description : | |
note: Created date actually is much ealier | |
The programm walks over tracks: | |
Tracks.nodes = [ | |
1track | |
2track <---- tracks.current | |
3track | |
4track | |
5track | |
] | |
History: | |
0.1.3 | |
* Updated Accidental Click Page Transition Guard | |
0.1.2 | |
* Added confirmation dialog when accidentally clicking relocation | |
**********************/ | |
var text = [ | |
"Little Earth (Preview)", | |
'DarkBright' | |
]; | |
console.clear(); | |
// Utils | |
HTMLElement.prototype.$ = function(){return this.querySelector.apply(this,arguments) }; | |
HTMLElement.prototype.$$= function(){return this.querySelectorAll.apply(this,arguments)}; | |
String.prototype.contains = function(str){ return new RegExp(str).test(this) } | |
Array.prototype.forEach = | |
Array.prototype.each = function (fn ,this_){ | |
if(this.length <=0 || fn == undefined) return; | |
let i = 0 | |
if (this_) fn = fn.bind(this_); | |
while (i < this.length) { | |
fn(this[i],i++); | |
} | |
}; | |
Set.prototype.toArray = function(){ | |
let arr = [], iterator = this.values(), current; | |
while(!(current = iterator.next() ).done) arr.push(current.value) ; | |
return arr | |
}; | |
Error.prototype.throw = function(){ | |
throw this | |
} | |
NodeList.prototype.addEventListener = function (name, handler){ | |
[].slice.call(this).forEach(el => el.addEventListener(name, handler)); | |
} | |
NodeList.prototype.removeEventListener = function (name, handler){ | |
[].slice.call(this).forEach(el => el.removeEventListener(name, handler)); | |
} | |
/** | |
* Class that helps to handle NodeList items | |
**/ | |
var NodeListX = class extends Object { | |
constructor(nodes){ | |
this.nodes = Array.from(nodes); | |
} | |
filter(fn, that){ return new NodeListX(this.nodes.filter(fn, that)) } | |
addEventListener(name, handler){ | |
if (!this.nodes.length) { return } | |
this.nodes.forEach(el => el.addEventListener(name, handler)); | |
} | |
removeEventListener(name, handler){ | |
if (!this.nodes.length) { return } | |
this.nodes.forEach(el => el.removeEventListener(name, handler)); | |
} | |
concat(nodelistx) { | |
return new NodeListX(this.nodes.concat(nodelistx.nodes)) | |
} | |
push(nodeOrNodes){ | |
if(nodeOrNodes instanceof Element) this.pushOne(nodeOrNodes); | |
if(nodeOrNodes instanceof NodeList) this.pushOne(nodeOrNodes); | |
} | |
pushOne(node){ | |
var isNode = node instanceof Element; | |
if (!isNode) { throw new TypeError(`Invalid argument: Element is expected`) } | |
return this.nodes.push(node); | |
} | |
pushAll(nodes){ | |
var isNodes = nodes instanceof NodeList; | |
if (!isNode) { throw new TypeError(`Invalid argument: Element is expected`) } | |
isNodes.forEach((node) => this.nodes.push(node)); | |
return this.nodes.length | |
} | |
remove(){ | |
this.nodes.forEach(node => node.remove()); | |
this.nodes = []; // resetting array | |
} | |
} | |
/** | |
* Class that helps to handle EventTarget-s items specifically | |
**/ | |
var EventTargetsList = class { | |
push(eventTarget){ | |
if (!(eventTarget instanceof EventTarget)) { | |
throw new TypeError(`Invalid argument type: EventTarget instance is expected!`); | |
} | |
super.push(eventTarget); | |
} | |
} | |
// Major classes | |
// Class which runs certain function "fn" at fixed interval of time | |
var Observer = function(fn,frequency){ | |
this.fn = fn | |
this.fr = frequency | |
} | |
Observer.prototype.observe = | |
Observer.prototype.start = function (){ | |
if(this.interval || this.running) {return}; | |
this.running = true; | |
this.interval = setInterval(function(){ | |
this.fn(); | |
}.bind(this),this.fr); | |
return this | |
} | |
Observer.prototype.disconnect = | |
Observer.prototype.stop = | |
Observer.prototype.cancel = function(){ | |
if(this.running && this.interval) { | |
clearInterval(this.interval); | |
return this.running = this.interval = false; | |
} | |
return this.running | |
} | |
var Observer = class { | |
constructor({ fn, frequency }){ | |
if (!fn) throw new Error(`Invalid arg: fn is required`); | |
this.fn = fn | |
this.fr = frequency | |
} | |
cancel() { throw new Error(`This API is deprecated!`); } | |
observe() { throw new Error(`This API is deprecated!`); } | |
start(){ | |
if(this.interval || this.running) {return}; | |
this.running = true; | |
this.interval = setInterval(function(){ | |
this.fn(); | |
}.bind(this),this.fr); | |
return this | |
} | |
stop(){ | |
if(this.running && this.interval) { | |
clearInterval(this.interval); | |
return this.running = this.interval = false; | |
} | |
return this.running | |
} | |
} | |
var Button = class { | |
constructor (tag, id, style) { | |
this.el = document.getElementById(id) || document.createElement(tag || 'span'); | |
this.el.id = id; | |
this.el.style = style || ''; | |
this.defaultStyle = style; | |
} | |
insertInto (el){ el.appendChild(el) } | |
listen(event,fn){ this.el.addEventListener(event, fn) } | |
label(str) { this.el.innerText = str || ''} | |
style(st){ | |
this.el.style = this.defaultStyle+st; | |
} | |
} | |
var SCButton = Button; | |
var Waveforms = class { | |
constructor(selector){ | |
this.selector = selector; | |
} | |
} | |
var Track = class { | |
// Element's selectors | |
static playCSSSelector = `.sc-button-play`; | |
static stateCSSSelector = ``; | |
constructor(e){ | |
this.e = e; | |
this.mouseClickEvent = new MouseEvent('click', {bubble: true, cancelable: true, composed: false}); | |
} | |
play(){ this.toggle(); return this } | |
toggle(){ | |
let selector = this.constructor.playCSSSelector; | |
this.e.querySelector(selector) | |
.dispatchEvent(this.mouseClickEvent) | |
return this | |
} | |
} | |
// I'm tasked with fetching (downloading) tracks | |
// and removing excessive ones which may pollute memory. | |
// Events listeners: | |
// tracks.onRunning - Called when searching is running | |
// tracks.onStop - Called when searching is paused/stopped | |
// tracks.onBad | |
// tracks.onFound | |
// tracks.onFetch(Array<node>) - Called when tracks are fetched. Provided with an argument of fetched trackss | |
// tracks.onTrackRemoval(node) - Called when track is removed from the list. Provided with a node to be removed | |
var Tracks = function(el,opt){ | |
this.update(el); | |
this.current = this.nodes[0]; | |
this.currentIndex = 0; // current checked node index of the tracks | |
this.totalTracksFetched = this.nodes.length; | |
// maximum nodes to load & to enumerate over | |
this.searchTreshhold = opt.searchTreshhold || 1024 * 2; | |
this.direction = 'wn' // searching direction: up or wn (down); | |
// Tracks removal config | |
this.remove = opt.nodeRemove == void 0 ? false : opt.nodeRemove | |
this.hide = opt.nodeHide == void 0 ? true : opt.nodeHide | |
this.tracksLimit = opt.tracksLimit || 200; | |
this.subSelectorsToRemove = | |
Array.isArray(opt.subSelectorsToRemove) ? opt.subSelectorsToRemove : [] | |
// Removing extr tracks | |
this.removedTracks= 0; | |
// this.extraTrackRemoveObject = new Observer(this.truncateToLimit.bind(this), 2000); | |
this.check = function(){ | |
this._match(); | |
if(this.found) { | |
this.onFound && this.onFound(); | |
console.clear(); | |
console.log('IT IS FOUND :) ',this.nodes.length); | |
console.log(this.current); | |
this.observers.forEach(o => o.cancel()); | |
return | |
} | |
// if(this._hasNext()) return this._walk(); | |
if(this._hasNext()) { | |
this.onRunning && this.onRunning(this); | |
this._walk(); | |
} else | |
// FINALLY: NOTHING FOUND | |
if(this._isExceedingTreshhold()){ | |
console.clear(); | |
console.log('NOTHING FOUND :( )',this.nodes.length); | |
this.onBad && this.onBad(this); | |
// window.scroll(0,0); | |
this.observers.forEach(o => o.cancel()); | |
return | |
} else { | |
this._fetch(); | |
} | |
if(this._isExceedingLimit()) { | |
this.truncateToLimit(); | |
} | |
}.bind(this); | |
this.fetchCb = function(){ | |
if (!this.current) { | |
throw new Error(`Fetching failed: something went wrong, no current element is found, checkout the code, Alex!`); | |
} else | |
if (!this.current.nextElementSibling) { | |
this._fetch(); | |
} | |
// this._fetch(); | |
}.bind(this); | |
// fetching triggers soundcloud tracks dowload | |
this.fetching = new Observer({ | |
frequency: 100*4, | |
fn: this.fetchCb | |
}); | |
// Most important part. | |
// Checking method iterates over fetched tracks | |
// and checks match for the track we have provided by Tracks.find() method | |
this.checking = new Observer({ | |
frequency: 100*1.5, | |
fn: this.check | |
}); | |
// MAIN LOOOP with observers | |
this.observers = [ | |
this.checking | |
// , this.fetching | |
// , this.extraTrackRemoveObject | |
] | |
} | |
Tracks.prototype.truncateToLimit = function(){ | |
let tracksToRemove = []; | |
tracksToRemove = [].slice.call(tracks.nodes, 0, this.tracksLimit); | |
tracksToRemove.forEach(e => { | |
if(this.onTrackRemoval) { | |
this.onTrackRemoval(e); | |
} | |
e.remove(); | |
e = null; | |
}); | |
this.removedTracks += tracksToRemove.length; | |
console.log(`Total tracks removed: %d`, this.removedTracks); | |
return tracksToRemove | |
} | |
// Resets nodes to the specified element's children | |
Tracks.prototype.update = function(el){ | |
this.el = el; | |
if(!el) { | |
this.nodes = []; | |
return | |
} | |
this.className = '.'+el.className.split(/\s/g).join('.'); | |
this.nodes = el.children; | |
} | |
Tracks.prototype._fetch = function(limit){ | |
let lastPosition = window.scrollY; | |
window.scroll(0,9999999); | |
// window.scroll(0,lastPosition); | |
this.onFetch && setTimeout(() => { | |
let newlyAddedNodes = [].slice.call(this.nodes, this.currentIndex); | |
this.onFetch(newlyAddedNodes); | |
}, 1000); | |
} | |
Tracks.prototype._match = function(selector){ | |
this.remove && (this.checked = this.checked == void 0 ? 0 : ++this.checked); | |
let textelem = this.current.querySelector(this.selector || selector); | |
textelem || new Error('Invalid selector: the target for string search hasn\'t been found! ').throw(); | |
if(this.str instanceof Array) { | |
return this.found = this.str.some(searchString => new RegExp(searchString).test(textelem.innerText) ); | |
} | |
this.found = textelem.innerText.contains(this.str); | |
} | |
Tracks.prototype._isExceedingTreshhold= function(){ | |
return this.totalTracksFetched > this.searchTreshhold; | |
} | |
Tracks.prototype._isExceedingLimit = function() { | |
let v = this.tracksLimit | |
&& this.nodes.length > this.tracksLimit | |
&& this.currentIndex > this.tracksLimit | |
return v | |
} | |
// True if a sibling of the current node exists | |
Tracks.prototype._hasNext= function(){ | |
switch (this.direction){ | |
case 'up': return this.current.previousElementSibling; | |
case 'wn': return this.current.nextElementSibling; | |
} | |
} | |
// Walking next | |
Tracks.prototype._walk = function(){ | |
this.previous = this.current; | |
this.previous.style.display == 'none' && (this.current.style.display = ''); | |
switch (this.direction){ | |
case 'up': this.current = this.current.previousElementSibling; break; | |
case 'wn': this.current = this.current.nextElementSibling; | |
} | |
// Mark currently traversed element by red border | |
if(this.hide) { | |
this.previous.style.display = 'none'; | |
} else { | |
this.previous.style.border = 'none' | |
this.previous.removeAttribute('style'); | |
} | |
this.current.style.border = 'inset .6em #ff5500'; | |
// Remove specified sub elements (saving memory); | |
if (this.subSelectorsToRemove.length !== 0) { | |
this.subSelectorsToRemove.forEach((sel) => { | |
nodeToRemove = this.current.querySelector(sel); | |
if (!(nodeToRemove === null || nodeToRemove === void 0)) { | |
nodeToRemove.remove(); | |
} | |
}); | |
} | |
this.totalTracksFetched++; | |
this.currentIndex = [].slice.call(this.nodes).indexOf(this.current); | |
} | |
// Entry method. That's where algorithm gets started | |
Tracks.prototype.find = function(searchstring,selector,direction = 'wn'){ | |
this.str = searchstring || this.str || new Error('Invalid argument: string required!').throw(); | |
this.selector = selector || this.selector || new Error('Invalid argument: selector for string search required!').throw(); | |
this.direction= direction || this.direction|| 'wn'; | |
console.log('SEARCHING ',this.direction == 'wn' ? 'DOWN' : 'UP'); | |
} | |
Tracks.prototype.pause = | |
Tracks.prototype.stop = function(){ | |
if(!this.el) { return } | |
this.running = false | |
this.observers.forEach(e => e.stop() ); | |
this.onStop && this.onStop(this); | |
} | |
Tracks.prototype.start = function(){ | |
if(!this.el){ | |
this.running = false; | |
return | |
} | |
if(this.nodes.length !== this.el.children.length){ | |
this.pause(); | |
this.reset(); | |
} | |
this.running = true | |
this.observers.forEach(e => e.start() ); | |
} | |
Tracks.prototype.toggle = function(){ | |
if(!this.el) { return } | |
this.observers.every(o => o.running) | |
? this.pause() | |
: this.start(); | |
} | |
// RESET SEARCH. Tip: uset it only after pausing | |
Tracks.prototype.reset = function(){ | |
this.current = this.nodes[this.currentIndex = 0]; | |
} | |
Tracks.prototype.show = function(){ | |
[].slice.call(this.nodes).each(e => e.style.display = '') | |
} | |
/** | |
* Confirmation Popup. | |
* Every accidental click must be confirmed before page transition starts. | |
**/ | |
var ConfirmationPopup = class { | |
constructor() { | |
this.isOpen = false; | |
this.defaultMessage = `No message is left here!`; | |
} | |
open(message){ | |
let result; | |
if (this.isOpen) { | |
return | |
} | |
this.isOpen = true; | |
result = confirm(message || this.defaultMessage); | |
setTimeout(function(){ | |
this.isOpen = false; | |
}.bind(this)); | |
return result | |
} | |
} | |
/** | |
* Mouse Link Click event interceptor. | |
* This class provides specific event listener to every nodes | |
* and keeps all nodes accountable **/ | |
var PageTransitionGuard = class { | |
static LINK_STOP_WORDS = /Play|Pause|Stop|Continue|Repeat/g | |
static LINK_STOP_CLASSES = [ | |
`compactTrackList__moreLink` | |
, `soundTitle__title` | |
, `header__userNavActivitiesButton` | |
]; | |
static MessageTemplate = class { | |
generate (link = `<UnspecifiedLink>`){ | |
return `You are currently in search mode. Are you sure you want to go to ${link}? | |
(press cancel to stay here)` | |
} | |
} | |
constructor({ popup, abortTransitionWhen }){ | |
if (!(popup instanceof ConfirmationPopup)) { | |
throw new TypeError(`Invalid argument: ConfirmationPopup instance is expected!`); | |
} | |
this.popup = popup; | |
this.nodes = new Set(); | |
this.message = new this.constructor.MessageTemplate(); | |
this.enabled = true; | |
this.abortTransitionWhen = abortTransitionWhen; | |
this.listener = function (e) { | |
const alreadyAssigned = this.nodes.has(e.target); | |
const containsStopWord = this.constructor.LINK_STOP_WORDS.test(e.target.title); | |
const haveExcludedClasses = this.constructor.LINK_STOP_CLASSES.some((className) => { | |
return e.target.classList.contains(className); | |
}); | |
const isNotEligible = | |
alreadyAssigned | |
// || containsStopWord | |
|| haveExcludedClasses; | |
if (isNotEligible) { return } | |
if (this.isTransitionAllowed !== undefined | |
&& this.abortTransitionWhen()) { | |
return | |
} | |
e.stopPropagation(); | |
let allowTransition = false; | |
if (this.popup.isOpen) { return } | |
allowTransition = this.popup.open(this.message.generate(e.currentTarget.href)); | |
if (!allowTransition) { | |
e.preventDefault(); | |
}; | |
}.bind(this); | |
} | |
toggle() { this.enabled = !this.enabled } | |
/** | |
* Add listener to provided node | |
**/ | |
add(node) { | |
node.addEventListener(`click`, this.listener); | |
return this.nodes.add(node); | |
} | |
/** | |
* Remove node from links set | |
**/ | |
rem(node){ | |
node.removeEventListener(`click`, this.listener); | |
return this.nodes.delete(node); | |
} | |
addMany(collection){ | |
Array.prototype.forEach.call(collection, this.add.bind(this)); | |
} | |
remMany(collection){ | |
Array.prototype.forEach.call(collection, this.rem.bind(this)); | |
} | |
} | |
// Initializing Buttons | |
if(tracks instanceof Tracks) { tracks.pause(); tracks = undefined } | |
// RESET & STOP BUTTON | |
var tracks; | |
// Previously path the /stream changed to /stream | |
var streamingPath = "/feed" // /stream - previously | |
var tracksClassName = '.lazyLoadingList__list.sc-list-nostyle.sc-clearfix'; | |
var initTrackSearch = function(){ | |
// Guard from accident relocation | |
document.querySelector('div.header__middle').style='display: none'; | |
var panel = document.querySelector('.'+'header__right sc-clearfix'.split(' ').join('.')); | |
// elementType, id, style | |
var resetButton, stopButton; | |
resetButton = new SCButton('span', 'snippetResetButtonTrack', 'cursor: pointer'); | |
resetButton.el.innerText = "R"; | |
resetButton.el.title = "Reset button. Press to reset search to 0"; | |
resetButton.listen('click', () => { | |
tracks.pause(); | |
tracks.reset(); | |
stopButton.label('PROCEED: ' + tracks.currentIndex); | |
stopButton.el.style = ''; | |
}); | |
stopButton = new SCButton('span', 'trackFinderStopButton', 'width: 9em; cursor: pointer'); | |
stopButton.el.innerText = 'START SEARCH'; | |
stopButton.el.onclick = () => tracks.toggle(); | |
stopButton.el.title = 'Start/Pause button' | |
nextButton = new SCButton('span', 'trackPassOverButton', 'cursor: pointer'); | |
nextButton.el.innerText = 'N'; | |
nextButton.el.title = 'Proceed to the next track'; | |
nextButton.el.onclick = function(){ | |
let next = tracks.current.nextElementSibling; | |
if(!next) { return } | |
tracks.current = next; | |
tracks.start(); | |
} | |
currentTrackButton = new SCButton('span', 'snippetShowCurrentTruck', 'cursor: pointer;' ); | |
currentTrackButton.el.innerText = 'CR'; | |
currentTrackButton.el.title = 'Scroll current track into view' | |
currentTrackButton.el.onclick = function(){ | |
tracks.current.scrollIntoView(); | |
tracks.current.style.border = 'inset .6em #ff5500'; | |
setTimeout(() => tracks.current.style.border = '', 5000 ); | |
}; | |
[resetButton, stopButton, nextButton, currentTrackButton] | |
.forEach(b => b.el.className = 'header__link header__proUpsell'); | |
// INITIALIZING BUTTONS | |
var buttons = [nextButton, resetButton, stopButton, currentTrackButton]; | |
buttons.reverse().forEach(function(button){ | |
let buttonEl = document.getElementById(button.el.id); | |
if(!buttonEl) { | |
panel.insertAdjacentElement('afterbegin', button.el); | |
} | |
}); | |
// resetButton.el.style = stopButton.el.style = ''; // display | |
if(document.location.pathname === streamingPath){ | |
var tracklist = document.querySelector(tracksClassName); | |
if(tracks) { | |
tracks.update(tracklist); | |
console.log('Elements update interval cleared!'); | |
} else { | |
contentElement = document.getElementById(`content`); | |
subSelectorsToRemove = [ | |
`.commentForm` | |
, `.sound__waveform` | |
, `.sc-button-share` | |
, `.sound__artwork` | |
]; | |
// Tracks iterator | |
tracks = new Tracks(tracklist, { | |
tracksLimit : 512 | |
,nodeHide : false // Hide nodes | |
,subSelectorsToRemove | |
}); | |
// waveforms = new Waveforms(); | |
// waveforms.hide(); | |
} | |
// INITIALIZING CLICK PAGE TRANSITION GUARD | |
var confirmationDialog = new ConfirmationPopup(); | |
var transitionGuard = new PageTransitionGuard({ | |
popup : confirmationDialog, | |
abortTransitionWhen: () => tracks.running | |
}); | |
// Add links to the interceptor so every link clicked gets confirmation window shown | |
transitionGuard.addMany(document.querySelectorAll(`a`)); | |
transitionGuard.addMany(document.querySelectorAll(`.soundTitle__tagContainer`)); | |
let nodeToRemove; | |
// tracks.onFetch = interceptor.addMany.bind(interceptor); | |
// tracks.onTrackRemoval = interceptor.rem.bind(interceptor); | |
tracks.onFetch = function(nodes){ | |
nodes.forEach((node) => { | |
transitionGuard.addMany(node.querySelectorAll(`a`)); | |
transitionGuard.addMany(node.querySelectorAll(`.soundTitle__tagContainer`)); | |
}); | |
} | |
tracks.onTrackRemoval = function(node){ | |
transitionGuard.rem(node); | |
} | |
// Specify whether to alert when traverser reaches boundary | |
// at which clicking on play songs would reload page | |
var alertOnReachingBoundary = true; | |
tracks.onRunning = function(){ | |
stopButton.label('...' + tracks.totalTracksFetched); | |
stopButton.style('cursor: wait'); | |
// play every 10th track | |
// if(!(tracks.totalTracksFetched % 10)) { | |
// try { | |
// var t = new Track(this.current); | |
// t.toggle(); | |
// } | |
// catch (e) { | |
// console.log('Whooops. Play is failed!', e); | |
// } | |
// } | |
if (this.totalTracksFetched >= 1200 && alertOnReachingBoundary) { | |
alertOnReachingBoundary = false; | |
this.toggle(); | |
alert(`Play song now and later use [ctrl + shift + <right array>] in order to go through songs!`); | |
} | |
} | |
tracks.onBad = function(tracks){ | |
stopButton.label('BAD :('+tracks.totalTracksFetched); | |
} | |
tracks.onFound = function(){ | |
stopButton.label(`SUCCESS ${this.totalTracksFetched}:`); | |
var removeHighlight = function(){ | |
this.current.style.border = '' | |
} | |
// Highlight found node | |
currentTrackButton.el.onclick(); | |
this.current.addEventListener('mouseover', removeHighlight); | |
setTimeout(function(){ | |
this.current.removeEventListener('mouseover', removeHighlight); | |
}.bind(this)); | |
// window.scroll(0,this.foundnode.offsetTop); | |
// window.scroll(0,this.current.getClientRects()[0].top+window.pageYOffset); | |
} | |
tracks.onStop = function(){ | |
stopButton.label('CONTINUE: ' + tracks.totalTracksFetched); | |
stopButton.style(''); | |
} | |
textsearchselector = '.soundTitle__usernameTitleContainer' | |
;tracks.find(text,textsearchselector,'wn'); | |
// ;tracks.toggle(); | |
// If location not streamingPath then remove control UI elements | |
} else { | |
let button = buttons[0]; | |
let out = [] | |
for (let buttonIndx = 0; buttonIndx < buttons; buttonIndx++) { | |
button = buttons[buttonIndx] | |
if(document.getElementById(button.el.id)) { | |
// button.el.style = 'display: none'); // hide | |
button.el.remove() // remove element entirely | |
} | |
} | |
tracks && tracks.update(undefined); | |
tracks = null; | |
document.querySelector('div.header__middle').style='display:'; | |
} | |
} | |
// ENTRY POINT | |
if (window.location.pathname !== streamingPath) { | |
const stream = `https://soundcloud.com/feed`; | |
window.location.assign(stream); | |
alert(`You are about to go to the right page.\n Don't forget to run scripts!`); | |
} else { | |
var tracksFindingInterval; | |
if(tracksFindingInterval){ | |
clearInterval(tracksFindingInterval); | |
}; | |
// tracksFindingInterval = setInterval(initTrackSearch, 5000); | |
initTrackSearch(); | |
;test = function(str, str2){ return new RegExp(str).test(str2 || str) }; | |
} | |
// ex:expandtab |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment