Skip to content

Instantly share code, notes, and snippets.

@Ephellon
Last active June 7, 2020 16:12
Show Gist options
  • Save Ephellon/b89178a1a8ab5c5f2742a75a59457605 to your computer and use it in GitHub Desktop.
Save Ephellon/b89178a1a8ab5c5f2742a75a59457605 to your computer and use it in GitHub Desktop.
Twitch - Auto-claim Channel Points

Auto-claim Twitch Channel Points

To make this a bookmark, go to Twitch, press Ctrl + D, and for the URL use the code below →

javascript:(()=>{let t=(t,e=document)=>{let i=[...e.querySelectorAll(t)];return i.length>1?{...i,first:i[0],last:i[i.length-1]}:{...i[0],first:i[0],last:i[0]}},e=1e3,i=60*e,n=!0,r=0,s=0,a=0,l=!1,o={get update(){return p.update=setInterval(w,3e3)},get writer(){return p.writer=setInterval(()=>m.innerText,30*e)}},c=t("#auto-community-points").first,u=t('#auto-community-points svg[class*="channelpoints"i], img[class*="channelpoints"i]').first,m=t('#auto-community-points [class$="animated-number"i]').first,p={update:null,writer:null},d={Watching:0,Actively_Watching:0,Earned:{Watching:5,Actively_Watching:15},Oldest:()=>Math.min.apply(null,Object.values(d).filter(t=>+t))},f=t=>null!=t,y=(...t)=>{for(let e of t)clearInterval(p[e])},h=(...t)=>{for(let e of t)o[e]},w=()=>{if(n&&(a=t('#auto-community-points [data-test-selector="community-points-summary"i] button + [role="tooltip"]').first.innerText=t('[data-test-selector="community-points-summary"i] button + [role="tooltip"]').last.innerText,a=parseInt(a.replace(/^\s*([\d,]+).*/,"$1").replace(/\D+/g,""))||0,s!=a))if(l){for(let t in d)"number"==typeof d[t]&&d[t]<=+new Date+e&&(d[t]=+new Date+d.Earned[t]*i);y("update","writer"),h("update","writer")}else r=s=a,l=!0;f(w.COLLECTING_BONUS_POINTS)||(w.COLLECTING_BONUS_POINTS=(()=>{setInterval(()=>{let e=t('[data-test-selector="community-points-summary"i] button.tw-button.tw-button--success.tw-interactive').first;e&&n&&e.click()},3e3);return c.onclick=(t=>{(n=!n)?h("update","writer"):y("update","writer"),m.innerText=["OFF","ON"][+n],u.setAttribute("style",`fill: var(--color-${["red","accent"][+n]})!important;`)}),!0})())};if(!f(c)){let e=t('[data-test-selector="community-points-summary"i]').first,i=t(".top-nav__menu > div").last,n=(t('button + [role="tooltip"i]',e).first,document.createElement("div"));if(!f(e))throw"This streamer has not enabled community channel points.";n.id="auto-community-points",n.classList.add("community-points-summary","tw-align-items-center","tw-flex","tw-full-height"),n.innerHTML=e.outerHTML,i.insertBefore(n,i.children[1]),t('#auto-community-points [data-test-selector="community-points-summary"i] > div:last-child:not(:first-child)').first.remove(),c=n,u=t('svg[class*="channel"i][class*="points"i], img[class*="channel"i][class*="points"i]',n).first,(m=t('[class$="animated-number"i]',n).first).innerText="ON",h("update","writer")}})();
/** Twitch Channel Points System
*
* [Amount Name] ([Amount Earned])
* [Amount Requirements]
*
* Watching (+10)
* Viewer watches 5min of live content.
* Double for subscribers.
*
* Actively Watching (+50)
* Viewer watches 15min of live content (click to redeem).
* Double for subscribers.
*
* Raiding (+250)
* Viewer joins in a raid.
*
* Following (+300)
* Granted (once) upon a new follow.
*
* Watch Streaks (+300, +350, +400, and +450)
* Viewer returns for 2 or more consecutive streams.
* 2, 3, 4, 5 or more (respectively).
* Streams must be 10min long and at least 30min apart.
*
* Cheering (+350)
* Granted (once) per month upon the first cheer of that month.
*
* Gifted Subscription (+500)
* Viewer gifts another viewer a subscription.
*/
(() => {
let $ = (e, c = document) => { let n = [...c.querySelectorAll(e)]; return n.length > 1? { ...n, first: n[0], last: n[n.length - 1] }: { ...n[0], first: n[0], last: n[0] } },
S = 1000,
M = 60*S,
H = 60*M,
D = 24*H;
let ENABLED = true,
INTERVAL = 3000,
POINTS = 0,
COLLECTED = 0,
COLLECTING = 0,
INITIALIZED = false,
DEFAULT = {
get update() {
return Intervals.update = setInterval(Update, INTERVAL);
},
get writer() {
return Intervals.writer = setInterval(() => AnimatedTextElement.innerText/* = comify(++POINTS) */, 30 * S);
},
};
let AutoPointsElement = $('#auto-community-points').first,
AutoPointsIcon = $('#auto-community-points svg[class*="channelpoints"i], img[class*="channelpoints"i]').first,
AnimatedTextElement = $('#auto-community-points [class$="animated-number"i]').first,
Intervals = { update: null, writer: null },
Timers = {
Watching: 0,
Actively_Watching: 0,
Earned: { Watching: 5, Actively_Watching: 15 },
Oldest: () => Math.min.apply(null, Object.values(Timers).filter(n => +n)),
},
comify = number => (number += '').split('').reverse().join('').replace(/(\d{3})/g,'$1,').split('').reverse().join(''),
toTime = time => {
let output = [], X;
for(let x of [D, H, M, S])
if(time >= x || !!~[M, S].indexOf(x)) {
output.push(('00' + (X = Math.floor(time / x))).slice(-2));
time -= x * X;
}
return output.join(':').replace(/^[0:]+?(\d:\d{2})$/, '$1');
},
defined = value => (value !== undefined && value !== null),
clear = (...intervals) => {
for(let interval of intervals)
clearInterval(Intervals[interval]);
},
run = (...intervals) => {
for(let interval of intervals)
DEFAULT[interval];
};
let Update = () => {
if(ENABLED) {
COLLECTING
= $('#auto-community-points [data-test-selector="community-points-summary"i] button + [role="tooltip"]').first.innerText
= $('[data-test-selector="community-points-summary"i] button + [role="tooltip"]').last.innerText;
COLLECTING = parseInt(COLLECTING.replace(/^\s*([\d,]+).*/, '$1').replace(/\D+/g, '')) || 0;
if(COLLECTED != COLLECTING)
if(!INITIALIZED) {
POINTS = COLLECTED = COLLECTING;
INITIALIZED = true;
} else {
for(let timer in Timers)
if(typeof Timers[timer] == 'number')
if(Timers[timer] <= +(new Date) + S)
Timers[timer] = +(new Date) + (Timers.Earned[timer] * M);
clear('update', 'writer');
// AnimatedTextElement.innerText = ((A, B) => {
// POINTS = COLLECTED = COLLECTING;
//
// return (B >= A? '+': '') + (B - A);
// })(COLLECTED, COLLECTING);
run('update', 'writer');
}
}
if(!defined(Update.COLLECTING_BONUS_POINTS))
Update.COLLECTING_BONUS_POINTS = (() => {
let CollectBonusPoints = () => {
let BonusPoints = $('[data-test-selector="community-points-summary"i] button.tw-button.tw-button--success.tw-interactive').first;
if(BonusPoints && ENABLED)
BonusPoints.click();
};
let CollectingBonusPoints = setInterval(CollectBonusPoints, INTERVAL);
AutoPointsElement.onclick = event => {
ENABLED = !ENABLED;
if(!ENABLED)
clear('update', 'writer');
else
run('update', 'writer');
AnimatedTextElement.innerText = ['OFF', 'ON'][+ENABLED];
AutoPointsIcon.setAttribute('style', `fill: var(--color-${ ['red','accent'][+ENABLED] })!important;`);
};
return true;
})();
};
if(!defined(AutoPointsElement)) {
let original = $('[data-test-selector="community-points-summary"i]').first,
heading = $('.top-nav__menu > div').last,
tooltip = $('button + [role="tooltip"i]', original).first,
container = document.createElement('div');
if(!defined(original))
throw 'This streamer has not enabled community channel points.';
container.id = 'auto-community-points';
container.classList.add('community-points-summary', 'tw-align-items-center', 'tw-flex', 'tw-full-height');
container.innerHTML = original.outerHTML;
heading.insertBefore(container, heading.children[1]);
$('#auto-community-points [data-test-selector="community-points-summary"i] > div:last-child:not(:first-child)').first.remove();
AutoPointsElement = container;
AutoPointsIcon = $('svg[class*="channel"i][class*="points"i], img[class*="channel"i][class*="points"i]', container).first;
AnimatedTextElement = $('[class$="animated-number"i]', container).first;
AnimatedTextElement.innerText = 'ON';
run('update', 'writer');
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment