Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect user to chat to increase watchtime #47

Merged
merged 10 commits into from
Mar 12, 2021
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,4 @@ cookies/*
logs/*
screenshots/*
htmls/*
analytics/*
analytics/*
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ twitch_miner = TwitchChannelPointsMiner(
follow_raid=True, # Follow raid to obtain more points
claim_drops=True, # We can't filter rewards base on stream. Set to False for skip viewing counter increase and you will never obtain a drop reward from this script. Issue #21
watch_streak=True, # If a streamer go online change the priotiry of streamers array and catch the watch screak. Issue #11
join_chat=True, # Join irc chat to increase watch-time
bet=BetSettings(
strategy=Strategy.SMART, # Choose you strategy!
percentage=5, # Place the x% of your channel points
Expand Down Expand Up @@ -334,18 +335,19 @@ ColorPalette(
|-------------------- |------------- |-------------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `make_predictions` | bool | True | Choose if you want to make predictions / bet or not |
| `follow_raid` | bool | True | Choose if you want to follow raid +250 points |
| `claim_drops` | bool | True | If this value is True, the script will increase the watch-time for the current game. With this, you can claim the drops from Twitch Inventory [#21](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/21) |
| `claim_drops` | bool | True | If this value is True, the script will increase the watch-time for the current game. With this, you can claim the drops from Twitch Inventory [#21](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/21) |
| `watch_streak` | bool | True | Choose if you want to change a priority for these streamers and try to catch the Watch Streak event [#11](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/11) |
| `bet` | BetSettings | | Rules to follow for the bet |
| `follow_raid` | bool | True | Choose if you want to follow raid +250 points |
### BetSettings
| Key | Type | Default | Description |
|-------------------- |----------------- |--------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `strategy` | Strategy | SMART | Choose your strategy! See above for more info |
| `percentage` | int | 5 | Place the x% of your channel points |
| `percentage_gap` | int | 20 | Gap difference between outcomesA and outcomesB (for SMART stragegy) |
| `max_points` | int | 50000 | If the x percentage of your channel points is GT bet_max_points set this value |
| `stealth_mode` | bool | False | If the calculated amount of channel points is GT the highest bet, place the highest value minus 1-2 points [#33](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/33) |
| `filter_condition` | FilterCondition | None | Based on this filter the script will skip some bet [#29](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/29) |
| Key | Type | Default | Description |
|-------------------- |----------------- |--------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `strategy` | Strategy | SMART | Choose your strategy! See above for more info |
| `percentage` | int | 5 | Place the x% of your channel points |
| `percentage_gap` | int | 20 | Gap difference between outcomesA and outcomesB (for SMART stragegy) |
| `max_points` | int | 50000 | If the x percentage of your channel points is GT bet_max_points set this value |
| `stealth_mode` | bool | False | If the calculated amount of channel points is GT the highest bet, place the highest value minus 1-2 points [#33](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/33) |
| `join_chat` | bool | True | Join IRC-Chat to appear online in chat and attempt to get StreamElements channel points and increase view-time [#47](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/47) |

#### Bet strategy

Expand Down
17 changes: 17 additions & 0 deletions TwitchChannelPointsMiner/TwitchChannelPointsMiner.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pathlib import Path

from TwitchChannelPointsMiner.classes.AnalyticsServer import AnalyticsServer
from TwitchChannelPointsMiner.classes.Chat import ThreadChat
from TwitchChannelPointsMiner.classes.entities.PubsubTopic import PubsubTopic
from TwitchChannelPointsMiner.classes.entities.Streamer import (
Streamer,
Expand All @@ -36,9 +37,13 @@
# - chardet.charsetprober - [get_confidence]
# - requests - [Starting new HTTPS connection (1)]
# - Flask (werkzeug) logs
# - irc.client - [process_data]
# - irc.client - [_dispatcher]
# - irc.client - [_handle_message]
logging.getLogger("chardet.charsetprober").setLevel(logging.ERROR)
logging.getLogger("requests").setLevel(logging.ERROR)
logging.getLogger("werkzeug").setLevel(logging.ERROR)
logging.getLogger("irc.client").setLevel(logging.ERROR)

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -180,6 +185,12 @@ def run(self, streamers: list = [], blacklist: list = [], followers=False):
streamer.settings.bet = set_default_settings(
streamer.settings.bet, Settings.streamer_settings.bet
)
if streamer.settings.join_chat is True:
streamer.irc_chat = ThreadChat(
self.username,
self.twitch.twitch_login.get_auth_token(),
streamer.username,
)
self.streamers.append(streamer)
except StreamerDoesNotExistException:
logger.info(
Expand Down Expand Up @@ -283,6 +294,12 @@ def run(self, streamers: list = [], blacklist: list = [], followers=False):
def end(self, signum, frame):
logger.info("CTRL+C Detected! Please wait just a moment!")

for streamer in self.streamers:
if streamer.irc_chat is not None:
streamer.leave_chat()
if streamer.irc_chat.is_alive() is True:
streamer.irc_chat.join()

self.running = self.twitch.running = False
self.ws_pool.end()

Expand Down
75 changes: 75 additions & 0 deletions TwitchChannelPointsMiner/classes/Chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import logging
import time
from threading import Thread

from irc.bot import SingleServerIRCBot

from TwitchChannelPointsMiner.constants import IRC, IRC_PORT

logger = logging.getLogger(__name__)


class ClientIRC(SingleServerIRCBot):
def __init__(self, username, token, channel):
self.token = token
self.channel = "#" + channel
self.__active = False

super(ClientIRC, self).__init__(
[(IRC, IRC_PORT, f"oauth:{token}")], username, username
)

def on_welcome(self, client, event):
client.join(self.channel)

def start(self):
self.__active = True
self._connect()
while self.__active:
try:
self.reactor.process_once(timeout=0.2)
time.sleep(0.01)
except Exception as e:
logger.error(
f"Exception raised: {e}. Thread is active: {self.__active}"
)

def die(self, msg="Bye, cruel world!"):
self.connection.disconnect(msg)
self.__active = False

"""
def on_join(self, connection, event):
logger.info(f"Event: {event}", extra={"emoji": ":speech_balloon:"})

def on_pubmsg(self, client, message):
logger.info(f"Message: {message}", extra={"emoji": ":speech_balloon:"})
"""


class ThreadChat(Thread):
def __deepcopy__(self, memo):
return None

def __init__(self, username, token, channel):
super(ThreadChat, self).__init__()

self.username = username
self.token = token
self.channel = channel

self.chat_irc = None

def run(self):
self.chat_irc = ClientIRC(self.username, self.token, self.channel)
logger.info(
f"Join IRC Chat: {self.channel}", extra={"emoji": ":speech_balloon:"}
)
self.chat_irc.start()

def stop(self):
if self.chat_irc is not None:
logger.info(
f"Leave IRC Chat: {self.channel}", extra={"emoji": ":speech_balloon:"}
)
self.chat_irc.die()
8 changes: 4 additions & 4 deletions TwitchChannelPointsMiner/classes/WebSocketsPool.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import json
import logging
import random
import threading
import time
from threading import Thread, Timer

from dateutil import parser

Expand Down Expand Up @@ -67,7 +67,7 @@ def __new(self, index):
)

def __start(self, index):
thread_ws = threading.Thread(target=lambda: self.ws[index].run_forever())
thread_ws = Thread(target=lambda: self.ws[index].run_forever())
thread_ws.daemon = True
thread_ws.name = f"WebSocket #{self.ws[index].index}"
thread_ws.start()
Expand Down Expand Up @@ -99,7 +99,7 @@ def run():
)
WebSocketsPool.handle_reconnection(ws)

thread_ws = threading.Thread(target=run)
thread_ws = Thread(target=run)
thread_ws.daemon = True
thread_ws.start()

Expand Down Expand Up @@ -271,7 +271,7 @@ def on_message(ws, message):
current_tmsp
)

place_bet_thread = threading.Timer(
place_bet_thread = Timer(
start_after,
ws.twitch.make_predictions,
(ws.events_predictions[event_id],),
Expand Down
34 changes: 32 additions & 2 deletions TwitchChannelPointsMiner/classes/entities/Streamer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from datetime import datetime
from threading import Lock

from TwitchChannelPointsMiner.classes.Chat import ThreadChat
from TwitchChannelPointsMiner.classes.entities.Bet import BetSettings
from TwitchChannelPointsMiner.classes.entities.Stream import Stream
from TwitchChannelPointsMiner.classes.Settings import Settings
Expand All @@ -21,6 +22,7 @@ class StreamerSettings(object):
"claim_drops",
"watch_streak",
"bet",
"join_chat",
]

def __init__(
Expand All @@ -30,22 +32,30 @@ def __init__(
claim_drops: bool = None,
watch_streak: bool = None,
bet: BetSettings = None,
join_chat: bool = True,
):
self.make_predictions = make_predictions
self.follow_raid = follow_raid
self.claim_drops = claim_drops
self.watch_streak = watch_streak
self.bet = bet
self.join_chat = join_chat

def default(self):
for name in ["make_predictions", "follow_raid", "claim_drops", "watch_streak"]:
for name in [
"make_predictions",
"follow_raid",
"claim_drops",
"watch_streak",
"join_chat",
]:
if getattr(self, name) is None:
setattr(self, name, True)
if self.bet is None:
self.bet = BetSettings()

def __repr__(self):
return f"BetSettings(make_predictions={self.make_predictions}, follow_raid={self.follow_raid}, claim_drops={self.claim_drops}, watch_streak={self.watch_streak}, bet={self.bet})"
return f"BetSettings(make_predictions={self.make_predictions}, follow_raid={self.follow_raid}, claim_drops={self.claim_drops}, watch_streak={self.watch_streak}, bet={self.bet}, join_chat={self.join_chat})"


class Streamer(object):
Expand All @@ -60,6 +70,7 @@ class Streamer(object):
"channel_points",
"minute_watched_requests",
"viewer_is_mod",
"irc_chat",
"stream",
"raid",
"history",
Expand All @@ -78,6 +89,7 @@ def __init__(self, username, settings=None):
self.channel_points = 0
self.minute_watched_requests = None
self.viewer_is_mod = False
self.irc_chat = None

self.stream = Stream()

Expand All @@ -102,6 +114,7 @@ def set_offline(self):
if self.is_online is True:
self.offline_at = time.time()
self.is_online = False
self.leave_chat()

logger.info(
f"{self} is Offline!",
Expand All @@ -116,6 +129,7 @@ def set_online(self):
self.online_at = time.time()
self.is_online = True
self.stream.init_watch_streak()
self.join_chat()

logger.info(
f"{self} is Online!",
Expand Down Expand Up @@ -194,3 +208,19 @@ def __save_json(self, key, data={}, event_type="Watch"):

json_data[key].append(data)
json.dump(json_data, open(fname, "w"), indent=4)

def leave_chat(self):
if self.irc_chat is not None:
self.irc_chat.stop()

# Recreate a new thread to start again
# raise RuntimeError("threads can only be started once")
self.irc_chat = ThreadChat(
self.irc_chat.username,
self.irc_chat.token,
self.username,
)

def join_chat(self):
if self.irc_chat is not None:
self.irc_chat.start()
2 changes: 2 additions & 0 deletions TwitchChannelPointsMiner/constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Twitch endpoints
URL = "https://www.twitch.tv"
API = "https://api.twitch.tv"
IRC = "irc.chat.twitch.tv"
IRC_PORT = 6667
WEBSOCKET = "wss://pubsub-edge.twitch.tv/v1"
CLIENT_ID = "kimne78kx3ncx6brgo4mv6wki5h1ko"
DROP_ID = "c2542d6d-cd10-4532-919b-3d19f30a768b"
Expand Down
1 change: 1 addition & 0 deletions example.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
follow_raid=True, # Follow raid to obtain more points
claim_drops=True, # We can't filter rewards base on stream. Set to False for skip viewing counter increase and you will never obtain a drop reward from this script. Issue #21
watch_streak=True, # If a streamer go online change the priotiry of streamers array and catch the watch screak. Issue #11
join_chat=True, # Join irc chat to increase watch-time
bet=BetSettings(
strategy=Strategy.SMART, # Choose you strategy!
percentage=5, # Place the x% of your channel points
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ python-dateutil
emoji
millify
pre-commit
flask
colorama
flask
irc