Skip to content

Commit

Permalink
Merge pull request #47 from anoviel/chat-client
Browse files Browse the repository at this point in the history
Connect user to chat to increase watchtime
  • Loading branch information
Tkd-Alex authored Mar 12, 2021
2 parents 2fd04ac + 7465308 commit f09e8aa
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 17 deletions.
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

0 comments on commit f09e8aa

Please sign in to comment.