Remove betting/prediction system - focus on drops only
This commit is contained in:
192
README.md
192
README.md
@@ -32,10 +32,6 @@ Read more about Twitch Drops [here](https://help.twitch.tv/s/article/mission-bas
|
||||
5. 🔧 [Settings](#settings)
|
||||
- [LoggerSettings](#loggersettings)
|
||||
- [StreamerSettings](#streamersettings)
|
||||
- [BetSettings](#betsettings)
|
||||
- [Bet strategy](#bet-strategy)
|
||||
- [FilterCondition](#filtercondition)
|
||||
- [Example](#example)
|
||||
6. 🍪 [Migrating from an old repository (the original one)](#migrating-from-an-old-repository-the-original-one)
|
||||
7. 🪟 [Windows](#windows)
|
||||
8. 📱 [Termux](#termux)
|
||||
@@ -58,7 +54,6 @@ If you appreciate the original work this project is based on, consider supportin
|
||||
- Automatic downloading of the list of followers and using it as an input ✔️
|
||||
- Better 'Watch Streak' strategy in the priority system [#11](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/11) ✔️
|
||||
- Auto claiming [game drops](https://help.twitch.tv/s/article/mission-based-drops) from the Twitch inventory [#21](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/21) ✔️
|
||||
- Placing a bet / making a prediction with your channel points [#41](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/41) ([@lay295](https://github.com/lay295)) ✔️
|
||||
- Switchable analytics chart that shows the progress of your points with various annotations [#96](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/96) ✔️
|
||||
- Joining the IRC Chat to increase the watch time and get StreamElements points [#47](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/47) ✔️
|
||||
- [Moments](https://help.twitch.tv/s/article/moments) claiming [#182](https://github.com/rdavydov/Twitch-Channel-Points-Miner-v2/issues/182) ✔️
|
||||
@@ -74,18 +69,9 @@ If you appreciate the original work this project is based on, consider supportin
|
||||
%d/%m/%y %H:%M:%S - INFO - [set_offline]: 😴 Streamer(username=streamer-username3, channel_id=0000000, channel_points=61365) is Offline!
|
||||
%d/%m/%y %H:%M:%S - INFO - [set_offline]: 😴 Streamer(username=streamer-username4, channel_id=0000000, channel_points=3760) is Offline!
|
||||
%d/%m/%y %H:%M:%S - INFO - [set_online]: 🥳 Streamer(username=streamer-username, channel_id=0000000, channel_points=61365) is Online!
|
||||
%d/%m/%y %H:%M:%S - INFO - [start_bet]: 🔧 Start betting for EventPrediction(event_id=xxxx-xxxx-xxxx-xxxx, title=Please star this repo) owned by Streamer(username=streamer-username, channel_id=0000000, channel_points=61365)
|
||||
%d/%m/%y %H:%M:%S - INFO - [__open_coins_menu]: 🔧 Open coins menu for EventPrediction(event_id=xxxx-xxxx-xxxx-xxxx, title=Please star this repo)
|
||||
%d/%m/%y %H:%M:%S - INFO - [__click_on_bet]: 🔧 Click on the bet for EventPrediction(event_id=xxxx-xxxx-xxxx-xxxx, title=Please star this repo)
|
||||
%d/%m/%y %H:%M:%S - INFO - [__enable_custom_bet_value]: 🔧 Enable input of custom value for EventPrediction(event_id=xxxx-xxxx-xxxx-xxxx, title=Please star this repo)
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: ⏰ Place the bet after: 89.99s for: EventPrediction(event_id=xxxx-xxxx-xxxx-xxxx-15c61914ef69, title=Please star this repo)
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: 🚀 +12 → Streamer(username=streamer-username, channel_id=0000000, channel_points=61377) - Reason: WATCH.
|
||||
%d/%m/%y %H:%M:%S - INFO - [make_predictions]: 🍀 Going to complete bet for EventPrediction(event_id=xxxx-xxxx-xxxx-xxxx-15c61914ef69, title=Please star this repo) owned by Streamer(username=streamer-username, channel_id=0000000, channel_points=61377)
|
||||
%d/%m/%y %H:%M:%S - INFO - [make_predictions]: 🍀 Place 5k channel points on: SI (BLUE), Points: 848k, Users: 190 (70.63%), Odds: 1.24 (80.65%)
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: 🚀 +6675 → Streamer(username=streamer-username, channel_id=0000000, channel_points=64206) - Reason: PREDICTION.
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: 📊 EventPrediction(event_id=xxxx-xxxx-xxxx-xxxx, title=Please star this repo) - Result: WIN, Points won: 6675
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: 🚀 +12 → Streamer(username=streamer-username, channel_id=0000000, channel_points=64218) - Reason: WATCH.
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: 🚀 +12 → Streamer(username=streamer-username, channel_id=0000000, channel_points=64230) - Reason: WATCH.
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: 🚀 +12 → Streamer(username=streamer-username, channel_id=0000000, channel_points=61389) - Reason: WATCH.
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: 🚀 +12 → Streamer(username=streamer-username, channel_id=0000000, channel_points=61401) - Reason: WATCH.
|
||||
%d/%m/%y %H:%M:%S - INFO - [claim_bonus]: 🎁 Claiming the bonus for Streamer(username=streamer-username, channel_id=0000000, channel_points=64230)!
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: 🚀 +60 → Streamer(username=streamer-username, channel_id=0000000, channel_points=64290) - Reason: CLAIM.
|
||||
%d/%m/%y %H:%M:%S - INFO - [on_message]: 🚀 +12 → Streamer(username=streamer-username, channel_id=0000000, channel_points=64326) - Reason: WATCH.
|
||||
@@ -105,17 +91,7 @@ If you appreciate the original work this project is based on, consider supportin
|
||||
%d/%m %H:%M:%S - 😴 streamer-username3 (xxx points) is Offline!
|
||||
%d/%m %H:%M:%S - 😴 streamer-username4 (xxx points) is Offline!
|
||||
%d/%m %H:%M:%S - 🥳 streamer-username (xxx points) is Online!
|
||||
%d/%m %H:%M:%S - 🔧 Start betting for EventPrediction: Please star this repo owned by streamer-username (xxx points)
|
||||
%d/%m %H:%M:%S - 🔧 Open coins menu for EventPrediction: Please star this repo
|
||||
%d/%m %H:%M:%S - 🔧 Click on the bet for EventPrediction: Please star this repo
|
||||
%d/%m %H:%M:%S - 🔧 Enable input of custom value for EventPrediction: Please star this repo
|
||||
%d/%m %H:%M:%S - ⏰ Place the bet after: 89.99s EventPrediction: Please star this repo
|
||||
%d/%m %H:%M:%S - 🚀 +12 → streamer-username (xxx points) - Reason: WATCH.
|
||||
%d/%m %H:%M:%S - 🍀 Going to complete bet for EventPrediction: Please star this repo owned by streamer-username (xxx points)
|
||||
%d/%m %H:%M:%S - 🍀 Place 5k channel points on: SI (BLUE), Points: 848k, Users: 190 (70.63%), Odds: 1.24 (80.65%)
|
||||
%d/%m %H:%M:%S - 🚀 +6675 → streamer-username (xxx points) - Reason: PREDICTION.
|
||||
%d/%m %H:%M:%S - 📊 EventPrediction: Please star this repo - Result: WIN, Points won: 6675
|
||||
%d/%m %H:%M:%S - 🚀 +12 → streamer-username (xxx points) - Reason: WATCH.
|
||||
%d/%m %H:%M:%S - +12 → streamer-username (xxx points) - Reason: WATCH.
|
||||
%d/%m %H:%M:%S - 🚀 +12 → streamer-username (xxx points) - Reason: WATCH.
|
||||
%d/%m %H:%M:%S - 🚀 +60 → streamer-username (xxx points) - Reason: CLAIM.
|
||||
%d/%m %H:%M:%S - 🚀 +12 → streamer-username (xxx points) - Reason: WATCH.
|
||||
@@ -131,28 +107,8 @@ If you appreciate the original work this project is based on, consider supportin
|
||||
%d/%m/%y %H:%M:%S - 📄 Logs file: /.../path/Twitch-Channel-Points-Miner-v2/logs/username.timestamp.log
|
||||
%d/%m/%y %H:%M:%S - ⌛ Duration 10:29:19.547371
|
||||
|
||||
%d/%m/%y %H:%M:%S - 📊 BetSettings(Strategy=Strategy.SMART, Percentage=7, PercentageGap=20, MaxPoints=7500
|
||||
%d/%m/%y %H:%M:%S - 📊 EventPrediction(event_id=xxxx-xxxx-xxxx-xxxx, title="Event Title1")
|
||||
Streamer(username=streamer-username, channel_id=0000000, channel_points=67247)
|
||||
Bet(TotalUsers=1k, TotalPoints=11M), Decision={'choice': 'B', 'amount': 5289, 'id': 'xxxx-yyyy-zzzz'})
|
||||
Outcome0(YES (BLUE) Points: 7M, Users: 641 (58.49%), Odds: 1.6, (5}%)
|
||||
Outcome1(NO (PINK),Points: 4M, Users: 455 (41.51%), Odds: 2.65 (37.74%))
|
||||
Result: {'type': 'LOSE', 'won': 0}
|
||||
%d/%m/%y %H:%M:%S - 📊 EventPrediction(event_id=yyyy-yyyy-yyyy-yyyy, title="Event Title2")
|
||||
Streamer(username=streamer-username, channel_id=0000000, channel_points=3453464)
|
||||
Bet(TotalUsers=921, TotalPoints=11M), Decision={'choice': 'A', 'amount': 4926, 'id': 'xxxx-yyyy-zzzz'})
|
||||
Outcome0(YES (BLUE) Points: 9M, Users: 562 (61.02%), Odds: 1.31 (76.34%))
|
||||
Outcome1(YES (PINK) Points: 3M, Users: 359 (38.98%), Odds: 4.21 (23.75%))
|
||||
Result: {'type': 'WIN', 'won': 6531}
|
||||
%d/%m/%y %H:%M:%S - 📊 EventPrediction(event_id=ad152117-251b-4666-b683-18e5390e56c3, title="Event Title3")
|
||||
Streamer(username=streamer-username, channel_id=0000000, channel_points=45645645)
|
||||
Bet(TotalUsers=260, TotalPoints=3M), Decision={'choice': 'A', 'amount': 5054, 'id': 'xxxx-yyyy-zzzz'})
|
||||
Outcome0(YES (BLUE) Points: 689k, Users: 114 (43.85%), Odds: 4.24 (23.58%))
|
||||
Outcome1(NO (PINK) Points: 2M, Users: 146 (56.15%), Odds: 1.31 (76.34%))
|
||||
Result: {'type': 'LOSE', 'won': 0}
|
||||
|
||||
%d/%m/%y %H:%M:%S - 🤖 Streamer(username=streamer-username, channel_id=0000000, channel_points=67247), Total points gained (after farming - before farming): -7838
|
||||
%d/%m/%y %H:%M:%S - 💰 CLAIM(11 times, 550 gained), PREDICTION(1 times, 6531 gained), WATCH(35 times, 350 gained)
|
||||
%d/%m/%y %H:%M:%S - 🤖 Streamer(username=streamer-username, channel_id=0000000, channel_points=67247), Total points gained (after farming - before farming): 1243
|
||||
%d/%m/%y %H:%M:%S - 💰 CLAIM(11 times, 550 gained), WATCH(35 times, 350 gained)
|
||||
%d/%m/%y %H:%M:%S - 🤖 Streamer(username=streamer-username2, channel_id=0000000, channel_points=61365), Total points gained (after farming - before farming): 977
|
||||
%d/%m/%y %H:%M:%S - 💰 CLAIM(4 times, 240 gained), REFUND(1 times, 605 gained), WATCH(11 times, 132 gained)
|
||||
%d/%m/%y %H:%M:%S - 🤖 Streamer(username=streamer-username5, channel_id=0000000, channel_points=25960), Total points gained (after farming - before farming): 1680
|
||||
@@ -176,7 +132,6 @@ from TwitchChannelPointsMiner.classes.Webhook import Webhook
|
||||
from TwitchChannelPointsMiner.classes.Telegram import Telegram
|
||||
from TwitchChannelPointsMiner.classes.Gotify import Gotify
|
||||
from TwitchChannelPointsMiner.classes.Settings import Priority, Events, FollowersOrder
|
||||
from TwitchChannelPointsMiner.classes.entities.Bet import Strategy, BetSettings, Condition, OutcomeKeys, FilterCondition, DelayMode
|
||||
from TwitchChannelPointsMiner.classes.entities.Streamer import Streamer, StreamerSettings
|
||||
|
||||
twitch_miner = TwitchChannelPointsMiner(
|
||||
@@ -208,28 +163,28 @@ twitch_miner = TwitchChannelPointsMiner(
|
||||
),
|
||||
telegram=Telegram( # You can omit or set to None if you don't want to receive updates on Telegram
|
||||
chat_id=123456789, # Chat ID to send messages @getmyid_bot
|
||||
token="123456789:shfuihreuifheuifhiu34578347", # Telegram API token @BotFather
|
||||
token="123456789:shfuihreuifheuifheuifhiu34578347", # Telegram API token @BotFather
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION], # Only these events will be sent to the chat
|
||||
Events.CHAT_MENTION], # Only these events will be sent to the chat
|
||||
disable_notification=True, # Revoke the notification (sound/vibration)
|
||||
),
|
||||
discord=Discord(
|
||||
webhook_api="https://discord.com/api/webhooks/0123456789/0a1B2c3D4e5F6g7H8i9J", # Discord Webhook URL
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION], # Only these events will be sent to the chat
|
||||
Events.CHAT_MENTION], # Only these events will be sent to the chat
|
||||
),
|
||||
webhook=Webhook(
|
||||
endpoint="https://example.com/webhook", # Webhook URL
|
||||
method="GET", # GET or POST
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION], # Only these events will be sent to the endpoint
|
||||
Events.CHAT_MENTION], # Only these events will be sent to the endpoint
|
||||
),
|
||||
matrix=Matrix(
|
||||
username="twitch_miner", # Matrix username (without homeserver)
|
||||
password="...", # Matrix password
|
||||
homeserver="matrix.org", # Matrix homeserver
|
||||
room_id="...", # Room ID
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE, Events.BET_LOSE], # Only these events will be sent
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE], # Only these events will be sent
|
||||
),
|
||||
pushover=Pushover(
|
||||
userkey="YOUR-ACCOUNT-TOKEN", # Login to https://pushover.net/, the user token is on the main page
|
||||
@@ -242,32 +197,16 @@ twitch_miner = TwitchChannelPointsMiner(
|
||||
endpoint="https://example.com/message?token=TOKEN",
|
||||
priority=8,
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION],
|
||||
Events.CHAT_MENTION],
|
||||
)
|
||||
),
|
||||
streamer_settings=StreamerSettings(
|
||||
make_predictions=True, # If you want to Bet / Make prediction
|
||||
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
|
||||
claim_moments=True, # If set to True, https://help.twitch.tv/s/article/moments will be claimed when available
|
||||
watch_streak=True, # If a streamer go online change the priority of streamers array and catch the watch screak. Issue #11
|
||||
community_goals=False, # If True, contributes the max channel points per stream to the streamers' community challenge goals
|
||||
chat=ChatPresence.ONLINE, # Join irc chat to increase watch-time [ALWAYS, NEVER, ONLINE, OFFLINE]
|
||||
bet=BetSettings(
|
||||
strategy=Strategy.SMART, # Choose you strategy!
|
||||
percentage=5, # Place the x% of your channel points
|
||||
percentage_gap=20, # Gap difference between outcomesA and outcomesB (for SMART strategy)
|
||||
max_points=50000, # If the x percentage of your channel points is gt bet_max_points set this value
|
||||
stealth_mode=True, # If the calculated amount of channel points is GT the highest bet, place the highest value minus 1-2 points Issue #33
|
||||
delay_mode=DelayMode.FROM_END, # When placing a bet, we will wait until `delay` seconds before the end of the timer
|
||||
delay=6,
|
||||
minimum_points=20000, # Place the bet only if we have at least 20k points. Issue #113
|
||||
filter_condition=FilterCondition(
|
||||
by=OutcomeKeys.TOTAL_USERS, # Where apply the filter. Allowed [PERCENTAGE_USERS, ODDS_PERCENTAGE, ODDS, TOP_POINTS, TOTAL_USERS, TOTAL_POINTS]
|
||||
where=Condition.LTE, # 'by' must be [GT, LT, GTE, LTE] than value
|
||||
value=800
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -276,18 +215,18 @@ twitch_miner = TwitchChannelPointsMiner(
|
||||
# The streamers array can be a String -> username or Streamer instance.
|
||||
|
||||
# The settings priority are: settings in mine function, settings in TwitchChannelPointsMiner instance, default settings.
|
||||
# For example, if in the mine function you don't provide any value for 'make_prediction' but you have set it on TwitchChannelPointsMiner instance, the script will take the value from here.
|
||||
# For example, if in the mine function you don't provide any value but you have set it on TwitchChannelPointsMiner instance, the script will take the value from here.
|
||||
# If you haven't set any value even in the instance the default one will be used
|
||||
|
||||
#twitch_miner.analytics(host="127.0.0.1", port=5000, refresh=5, days_ago=7) # Start the Analytics web-server (replit: host="0.0.0.0")
|
||||
|
||||
twitch_miner.mine(
|
||||
[
|
||||
Streamer("streamer-username01", settings=StreamerSettings(make_predictions=True , follow_raid=False , claim_drops=True , watch_streak=True , community_goals=False , bet=BetSettings(strategy=Strategy.SMART , percentage=5 , stealth_mode=True, percentage_gap=20 , max_points=234 , filter_condition=FilterCondition(by=OutcomeKeys.TOTAL_USERS, where=Condition.LTE, value=800 ) ) )),
|
||||
Streamer("streamer-username02", settings=StreamerSettings(make_predictions=False , follow_raid=True , claim_drops=False , bet=BetSettings(strategy=Strategy.PERCENTAGE , percentage=5 , stealth_mode=False, percentage_gap=20 , max_points=1234 , filter_condition=FilterCondition(by=OutcomeKeys.TOTAL_POINTS, where=Condition.GTE, value=250 ) ) )),
|
||||
Streamer("streamer-username03", settings=StreamerSettings(make_predictions=True , follow_raid=False , watch_streak=True , community_goals=True , bet=BetSettings(strategy=Strategy.SMART , percentage=5 , stealth_mode=False, percentage_gap=30 , max_points=50000 , filter_condition=FilterCondition(by=OutcomeKeys.ODDS, where=Condition.LT, value=300 ) ) )),
|
||||
Streamer("streamer-username04", settings=StreamerSettings(make_predictions=False , follow_raid=True , watch_streak=True , )),
|
||||
Streamer("streamer-username05", settings=StreamerSettings(make_predictions=True , follow_raid=True , claim_drops=True , watch_streak=True , community_goals=True , bet=BetSettings(strategy=Strategy.HIGH_ODDS , percentage=7 , stealth_mode=True, percentage_gap=20 , max_points=90 , filter_condition=FilterCondition(by=OutcomeKeys.PERCENTAGE_USERS, where=Condition.GTE, value=300 ) ) )),
|
||||
Streamer("streamer-username01", settings=StreamerSettings(follow_raid=False , claim_drops=True , watch_streak=True , community_goals=False )),
|
||||
Streamer("streamer-username02", settings=StreamerSettings(follow_raid=True , claim_drops=False )),
|
||||
Streamer("streamer-username03", settings=StreamerSettings(follow_raid=False , watch_streak=True , community_goals=True )),
|
||||
Streamer("streamer-username04", settings=StreamerSettings(follow_raid=True , watch_streak=True )),
|
||||
Streamer("streamer-username05", settings=StreamerSettings(follow_raid=True , claim_drops=True , watch_streak=True , community_goals=True )),
|
||||
Streamer("streamer-username06"),
|
||||
Streamer("streamer-username07"),
|
||||
Streamer("streamer-username08"),
|
||||
@@ -442,12 +381,6 @@ ColorPalette(
|
||||
GAIN_FOR_CLAIM = Fore.YELLOW,
|
||||
GAIN_FOR_WATCH = Fore.YELLOW,
|
||||
GAIN_FOR_WATCH_STREAK = Fore.YELLOW,
|
||||
BET_WIN = Fore.GREEN,
|
||||
BET_LOSE = Fore.RED,
|
||||
BET_REFUND = Fore.RESET,
|
||||
BET_FILTERS = Fore.MAGENTA,
|
||||
BET_GENERAL = Fore.BLUE,
|
||||
BET_FAILED = Fore.RED,
|
||||
)
|
||||
```
|
||||
|
||||
@@ -469,7 +402,7 @@ Telegram(
|
||||
chat_id=123456789,
|
||||
token="123456789:shfuihreuifheuifhiu34578347",
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION],
|
||||
Events.CHAT_MENTION],
|
||||
disable_notification=True,
|
||||
)
|
||||
```
|
||||
@@ -494,7 +427,7 @@ If you want to receive log updates on Discord initialize a new Discord class, el
|
||||
Discord(
|
||||
webhook_api="https://discord.com/api/webhooks/0123456789/0a1B2c3D4e5F6g7H8i9J",
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION],
|
||||
Events.CHAT_MENTION],
|
||||
)
|
||||
```
|
||||
|
||||
@@ -512,7 +445,7 @@ Webhook(
|
||||
endpoint="https://example.com/webhook",
|
||||
method="GET",
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION],
|
||||
Events.CHAT_MENTION],
|
||||
)
|
||||
```
|
||||
|
||||
@@ -523,13 +456,6 @@ Webhook(
|
||||
- `GAIN_FOR_RAID`
|
||||
- `GAIN_FOR_CLAIM`
|
||||
- `GAIN_FOR_WATCH`
|
||||
- `BET_WIN`
|
||||
- `BET_LOSE`
|
||||
- `BET_REFUND`
|
||||
- `BET_FILTERS`
|
||||
- `BET_GENERAL`
|
||||
- `BET_FAILED`
|
||||
- `BET_START`
|
||||
- `BONUS_CLAIM`
|
||||
- `MOMENT_CLAIM`
|
||||
- `JOIN_RAID`
|
||||
@@ -540,13 +466,11 @@ Webhook(
|
||||
### StreamerSettings
|
||||
| Key | Type | Default | Description |
|
||||
|-------------------- |------------- |-------------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `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_moments` | bool | True | If set to True, [moments](https://help.twitch.tv/s/article/moments) will be claimed when available |
|
||||
| `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) |
|
||||
| `community_goals` | bool | False | If True, contributes the max channel points per stream to the streamers' community challenge goals |
|
||||
| `bet` | BetSettings | | Rules to follow for the bet |
|
||||
| `chat` | ChatPresence | ONLINE | 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) |
|
||||
|
||||
Allowed values for `chat` are:
|
||||
@@ -555,82 +479,6 @@ Allowed values for `chat` are:
|
||||
- `ONLINE` Partecipate to IRC chat if the streamer is online (leave if offline)
|
||||
- `OFFLINE` Partecipate to IRC chat if the streamer is offline (leave if online)
|
||||
|
||||
### BetSettings
|
||||
| Key | Type | Default | Description |
|
||||
|-------------------- |----------------- |--------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `strategy` | Strategy | SMART | Choose your strategy! See below 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) |
|
||||
| `delay_mode` | DelayMode | FROM_END | Define how is calculating the waiting time before placing a bet |
|
||||
| `delay` | float | 6 | Value to be used to calculate bet delay depending on `delay_mode` value |
|
||||
|
||||
#### Bet strategy
|
||||
|
||||
- **MOST_VOTED**: Select the option most voted based on users count
|
||||
- **HIGH_ODDS**: Select the option with the highest odds
|
||||
- **PERCENTAGE**: Select the option with the highest percentage based on odds (It's the same that show Twitch) - Should be the same as select LOWEST_ODDS
|
||||
- **SMART_MONEY**: Select the option with the highest points placed. [#331](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/331)
|
||||
- **SMART**: If the majority in percent chose an option, then follow the other users, otherwise select the option with the highest odds
|
||||
- **NUMBER_1**: Always select the 1st option, BLUE side if there are only two options
|
||||
- **NUMBER_2**: Always select the 2nd option, PINK side if there are only two options
|
||||
- **NUMBER_3**: Always select the 3rd option
|
||||
- **NUMBER_4**: Always select the 4th option
|
||||
- **NUMBER_5**: Always select the 5th option
|
||||
- **NUMBER_6**: Always select the 6th option
|
||||
- **NUMBER_7**: Always select the 7th option
|
||||
- **NUMBER_8**: Always select the 8th option
|
||||
|
||||

|
||||
|
||||
Here a concrete example:
|
||||
|
||||
- **MOST_VOTED**: 21 Users have select **'over 7.5'**, instead of 9 'under 7.5'
|
||||
- **HIGH_ODDS**: The highest odd is 2.27 on **'over 7.5'** vs 1.79 on 'under 7.5'
|
||||
- **PERCENTAGE**: The highest percentage is 56% for **'under 7.5'**
|
||||
- **SMART**: Calculate the percentage based on the users. The percentages are: 'over 7.5': 70% and 'under 7.5': 30%. If the difference between the two percentages is higher than `percentage_gap` select the highest percentage, else the highest odds.
|
||||
|
||||
In this case if percentage_gap = 20 ; 70-30 = 40 > percentage_gap, so the bot will select 'over 7.5'
|
||||
### FilterCondition
|
||||
| Key | Type | Default | Description |
|
||||
|------------- |------------- |--------- |---------------------------------------------------------------------------------- |
|
||||
| `by` | OutcomeKeys | None | Key to apply the filter |
|
||||
| `where` | Condition | None | Condition that should match for place bet |
|
||||
| `value` | number | None | Value to compare |
|
||||
|
||||
Allowed values for `by` are:
|
||||
- `PERCENTAGE_USERS` (no sum) [Would never want a sum as it'd always be 100%]
|
||||
- `ODDS_PERCENTAGE` (no sum) [Doesn't make sense to sum odds]
|
||||
- `ODDS` (no sum) [Doesn't make sense to sum odds]
|
||||
- `DECISION_USERS` (no sum)
|
||||
- `DECISION_POINTS` (no sum)
|
||||
- `TOP_POINTS` (no sum) [Doesn't make sense to the top points of both sides]
|
||||
- `TOTAL_USERS` (sum)
|
||||
- `TOTAL_POINTS` (sum)
|
||||
|
||||
Allowed values for `where` are: `GT, LT, GTE, LTE`
|
||||
|
||||
#### Example
|
||||
- If you want to place the bet ONLY if the total of users participants in the bet is greater than 200
|
||||
`FilterCondition(by=OutcomeKeys.TOTAL_USERS, where=Condition.GT, value=200)`
|
||||
- If you want to place the bet ONLY if the winning odd of your decision is greater than or equal to 1.3
|
||||
`FilterCondition(by=OutcomeKeys.ODDS, where=Condition.GTE, value=1.3)`
|
||||
- If you want to place the bet ONLY if the highest bet is lower than 2000
|
||||
`FilterCondition(by=OutcomeKeys.TOP_POINTS, where=Condition.LT, value=2000)`
|
||||
|
||||
### DelayMode
|
||||
|
||||
- **FROM_START**: Will wait `delay` seconds from when the bet was opened
|
||||
- **FROM_END**: Will until there is `delay` seconds left to place the bet
|
||||
- **PERCENTAGE**: Will place the bet when `delay` percent of the set timer is elapsed
|
||||
|
||||
Here's a concrete example. Let's suppose we have a bet that is opened with a timer of 10 minutes:
|
||||
|
||||
- **FROM_START** with `delay=20`: The bet will be placed 20s after the bet is opened
|
||||
- **FROM_END** with `delay=20`: The bet will be placed 20s before the end of the bet (so 9mins 40s after the bet is opened)
|
||||
- **PERCENTAGE** with `delay=0.2`: The bet will be placed when the timer went down by 20% (so 2mins after the bet is opened)
|
||||
|
||||
## Migrating from an old repository (the original one):
|
||||
If you already have a `twitch-cookies.pkl` and you don't want to log in again, please create a `cookies/` folder in the current directory and then copy the .pkl file with a new name `your-twitch-username.pkl`
|
||||
```
|
||||
|
||||
@@ -59,7 +59,6 @@ class TwitchChannelPointsMiner:
|
||||
"disable_at_in_nickname",
|
||||
"priority",
|
||||
"streamers",
|
||||
"events_predictions",
|
||||
"minute_watcher_thread",
|
||||
"sync_campaigns_thread",
|
||||
"ws_pool",
|
||||
@@ -132,7 +131,6 @@ class TwitchChannelPointsMiner:
|
||||
|
||||
# Init as default all the missing values
|
||||
streamer_settings.default()
|
||||
streamer_settings.bet.default()
|
||||
Settings.streamer_settings = streamer_settings
|
||||
|
||||
# user_agent = get_user_agent("FIREFOX")
|
||||
@@ -143,7 +141,6 @@ class TwitchChannelPointsMiner:
|
||||
self.priority = priority if isinstance(priority, list) else [priority]
|
||||
|
||||
self.streamers: list[Streamer] = []
|
||||
self.events_predictions = {}
|
||||
self.minute_watcher_thread = None
|
||||
self.sync_campaigns_thread = None
|
||||
self.ws_pool = None
|
||||
@@ -272,9 +269,6 @@ class TwitchChannelPointsMiner:
|
||||
streamer.settings = set_default_settings(
|
||||
streamer.settings, Settings.streamer_settings
|
||||
)
|
||||
streamer.settings.bet = set_default_settings(
|
||||
streamer.settings.bet, Settings.streamer_settings.bet
|
||||
)
|
||||
if streamer.settings.chat != ChatPresence.NEVER:
|
||||
streamer.irc_chat = ThreadChat(
|
||||
self.username,
|
||||
@@ -291,13 +285,11 @@ class TwitchChannelPointsMiner:
|
||||
# Populate the streamers with default values.
|
||||
# 1. Load channel points and auto-claim bonus
|
||||
# 2. Check if streamers are online
|
||||
# 3. DEACTIVATED: Check if the user is a moderator. (was used before the 5th of April 2021 to deactivate predictions)
|
||||
for streamer in self.streamers:
|
||||
time.sleep(random.uniform(0.3, 0.7))
|
||||
try:
|
||||
self.twitch.load_channel_points_context(streamer)
|
||||
self.twitch.check_streamer_online(streamer)
|
||||
# self.twitch.viewer_is_mod(streamer)
|
||||
except StreamerDoesNotExistException:
|
||||
logger.info(
|
||||
f"Streamer {streamer.username} does not exist",
|
||||
@@ -308,11 +300,6 @@ class TwitchChannelPointsMiner:
|
||||
streamer.channel_points for streamer in self.streamers
|
||||
]
|
||||
|
||||
# If we have at least one streamer with settings = make_predictions True
|
||||
make_predictions = at_least_one_value_in_settings_is(
|
||||
self.streamers, "make_predictions", True
|
||||
)
|
||||
|
||||
# If we have at least one streamer with settings = claim_drops True
|
||||
# Spawn a thread for sync inventory and dashboard
|
||||
if (
|
||||
@@ -337,7 +324,6 @@ class TwitchChannelPointsMiner:
|
||||
self.ws_pool = WebSocketsPool(
|
||||
twitch=self.twitch,
|
||||
streamers=self.streamers,
|
||||
events_predictions=self.events_predictions,
|
||||
)
|
||||
|
||||
# Subscribe to community-points-user. Get update for points spent or gains
|
||||
@@ -356,15 +342,6 @@ class TwitchChannelPointsMiner:
|
||||
)
|
||||
)
|
||||
|
||||
# Going to subscribe to predictions-user-v1. Get update when we place a new prediction (confirm)
|
||||
if make_predictions is True:
|
||||
self.ws_pool.submit(
|
||||
PubsubTopic(
|
||||
"predictions-user-v1",
|
||||
user_id=user_id,
|
||||
)
|
||||
)
|
||||
|
||||
for streamer in self.streamers:
|
||||
self.ws_pool.submit(
|
||||
PubsubTopic("video-playback-by-id", streamer=streamer)
|
||||
@@ -373,11 +350,6 @@ class TwitchChannelPointsMiner:
|
||||
if streamer.settings.follow_raid is True:
|
||||
self.ws_pool.submit(PubsubTopic("raid", streamer=streamer))
|
||||
|
||||
if streamer.settings.make_predictions is True:
|
||||
self.ws_pool.submit(
|
||||
PubsubTopic("predictions-channel-v1", streamer=streamer)
|
||||
)
|
||||
|
||||
if streamer.settings.claim_moments is True:
|
||||
self.ws_pool.submit(
|
||||
PubsubTopic("community-moments-channel-v1", streamer=streamer)
|
||||
@@ -465,28 +437,6 @@ class TwitchChannelPointsMiner:
|
||||
extra={"emoji": ":hourglass:"},
|
||||
)
|
||||
|
||||
if not Settings.logger.less and self.events_predictions != {}:
|
||||
print("")
|
||||
for event_id in self.events_predictions:
|
||||
event = self.events_predictions[event_id]
|
||||
if (
|
||||
event.bet_confirmed is True
|
||||
and event.streamer.settings.make_predictions is True
|
||||
):
|
||||
logger.info(
|
||||
f"{event.streamer.settings.bet}",
|
||||
extra={"emoji": ":wrench:"},
|
||||
)
|
||||
if event.streamer.settings.bet.filter_condition is not None:
|
||||
logger.info(
|
||||
f"{event.streamer.settings.bet.filter_condition}",
|
||||
extra={"emoji": ":pushpin:"},
|
||||
)
|
||||
logger.info(
|
||||
f"{event.print_recap()}",
|
||||
extra={"emoji": ":bar_chart:"},
|
||||
)
|
||||
|
||||
print("")
|
||||
for streamer_index in range(0, len(self.streamers)):
|
||||
if self.streamers[streamer_index].history != {}:
|
||||
|
||||
@@ -31,13 +31,6 @@ class Events(Enum):
|
||||
GAIN_FOR_CLAIM = auto()
|
||||
GAIN_FOR_WATCH = auto()
|
||||
GAIN_FOR_WATCH_STREAK = auto()
|
||||
BET_WIN = auto()
|
||||
BET_LOSE = auto()
|
||||
BET_REFUND = auto()
|
||||
BET_FILTERS = auto()
|
||||
BET_GENERAL = auto()
|
||||
BET_FAILED = auto()
|
||||
BET_START = auto()
|
||||
BONUS_CLAIM = auto()
|
||||
MOMENT_CLAIM = auto()
|
||||
JOIN_RAID = auto()
|
||||
|
||||
@@ -693,89 +693,6 @@ class Twitch(object):
|
||||
if streamer.settings.community_goals is True:
|
||||
self.contribute_to_community_goals(streamer)
|
||||
|
||||
if streamer.settings.community_goals is True:
|
||||
self.contribute_to_community_goals(streamer)
|
||||
|
||||
def make_predictions(self, event):
|
||||
decision = event.bet.calculate(event.streamer.channel_points)
|
||||
# selector_index = 0 if decision["choice"] == "A" else 1
|
||||
|
||||
logger.info(
|
||||
f"Going to complete bet for {event}",
|
||||
extra={
|
||||
"emoji": ":four_leaf_clover:",
|
||||
"event": Events.BET_GENERAL,
|
||||
},
|
||||
)
|
||||
if event.status == "ACTIVE":
|
||||
skip, compared_value = event.bet.skip()
|
||||
if skip is True:
|
||||
logger.info(
|
||||
f"Skip betting for the event {event}",
|
||||
extra={
|
||||
"emoji": ":pushpin:",
|
||||
"event": Events.BET_FILTERS,
|
||||
},
|
||||
)
|
||||
logger.info(
|
||||
f"Skip settings {event.bet.settings.filter_condition}, current value is: {compared_value}",
|
||||
extra={
|
||||
"emoji": ":pushpin:",
|
||||
"event": Events.BET_FILTERS,
|
||||
},
|
||||
)
|
||||
else:
|
||||
if decision["amount"] >= 10:
|
||||
logger.info(
|
||||
# f"Place {_millify(decision['amount'])} channel points on: {event.bet.get_outcome(selector_index)}",
|
||||
f"Place {_millify(decision['amount'])} channel points on: {event.bet.get_outcome(decision['choice'])}",
|
||||
extra={
|
||||
"emoji": ":four_leaf_clover:",
|
||||
"event": Events.BET_GENERAL,
|
||||
},
|
||||
)
|
||||
|
||||
json_data = copy.deepcopy(GQLOperations.MakePrediction)
|
||||
json_data["variables"] = {
|
||||
"input": {
|
||||
"eventID": event.event_id,
|
||||
"outcomeID": decision["id"],
|
||||
"points": decision["amount"],
|
||||
"transactionID": token_hex(16),
|
||||
}
|
||||
}
|
||||
response = self.post_gql_request(json_data)
|
||||
if (
|
||||
"data" in response
|
||||
and "makePrediction" in response["data"]
|
||||
and "error" in response["data"]["makePrediction"]
|
||||
and response["data"]["makePrediction"]["error"] is not None
|
||||
):
|
||||
error_code = response["data"]["makePrediction"]["error"]["code"]
|
||||
logger.error(
|
||||
f"Failed to place bet, error: {error_code}",
|
||||
extra={
|
||||
"emoji": ":four_leaf_clover:",
|
||||
"event": Events.BET_FAILED,
|
||||
},
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
f"Bet won't be placed as the amount {_millify(decision['amount'])} is less than the minimum required 10",
|
||||
extra={
|
||||
"emoji": ":four_leaf_clover:",
|
||||
"event": Events.BET_GENERAL,
|
||||
},
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
f"Oh no! The event is not active anymore! Current status: {event.status}",
|
||||
extra={
|
||||
"emoji": ":disappointed_relieved:",
|
||||
"event": Events.BET_FAILED,
|
||||
},
|
||||
)
|
||||
|
||||
def claim_bonus(self, streamer, claim_id):
|
||||
if Settings.logger.less is False:
|
||||
logger.info(
|
||||
|
||||
@@ -9,7 +9,6 @@ from threading import Thread, Timer
|
||||
from dateutil import parser
|
||||
|
||||
from TwitchChannelPointsMiner.classes.entities.CommunityGoal import CommunityGoal
|
||||
from TwitchChannelPointsMiner.classes.entities.EventPrediction import EventPrediction
|
||||
from TwitchChannelPointsMiner.classes.entities.Message import Message
|
||||
from TwitchChannelPointsMiner.classes.entities.Raid import Raid
|
||||
from TwitchChannelPointsMiner.classes.Settings import Events, Settings
|
||||
@@ -24,13 +23,12 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WebSocketsPool:
|
||||
__slots__ = ["ws", "twitch", "streamers", "events_predictions"]
|
||||
__slots__ = ["ws", "twitch", "streamers"]
|
||||
|
||||
def __init__(self, twitch, streamers, events_predictions):
|
||||
def __init__(self, twitch, streamers):
|
||||
self.ws = []
|
||||
self.twitch = twitch
|
||||
self.streamers = streamers
|
||||
self.events_predictions = events_predictions
|
||||
|
||||
"""
|
||||
API Limits
|
||||
@@ -254,152 +252,6 @@ class WebSocketsPool:
|
||||
ws.streamers[streamer_index], message.data["moment_id"]
|
||||
)
|
||||
|
||||
elif message.topic == "predictions-channel-v1":
|
||||
|
||||
event_dict = message.data["event"]
|
||||
event_id = event_dict["id"]
|
||||
event_status = event_dict["status"]
|
||||
|
||||
current_tmsp = parser.parse(message.timestamp)
|
||||
|
||||
if (
|
||||
message.type == "event-created"
|
||||
and event_id not in ws.events_predictions
|
||||
):
|
||||
if event_status == "ACTIVE":
|
||||
prediction_window_seconds = float(
|
||||
event_dict["prediction_window_seconds"]
|
||||
)
|
||||
# Reduce prediction window by 3/6s - Collect more accurate data for decision
|
||||
prediction_window_seconds = ws.streamers[
|
||||
streamer_index
|
||||
].get_prediction_window(prediction_window_seconds)
|
||||
event = EventPrediction(
|
||||
ws.streamers[streamer_index],
|
||||
event_id,
|
||||
event_dict["title"],
|
||||
parser.parse(event_dict["created_at"]),
|
||||
prediction_window_seconds,
|
||||
event_status,
|
||||
event_dict["outcomes"],
|
||||
)
|
||||
if (
|
||||
ws.streamers[streamer_index].is_online
|
||||
and event.closing_bet_after(current_tmsp) > 0
|
||||
):
|
||||
streamer = ws.streamers[streamer_index]
|
||||
bet_settings = streamer.settings.bet
|
||||
if (
|
||||
bet_settings.minimum_points is None
|
||||
or streamer.channel_points
|
||||
> bet_settings.minimum_points
|
||||
):
|
||||
ws.events_predictions[event_id] = event
|
||||
start_after = event.closing_bet_after(
|
||||
current_tmsp
|
||||
)
|
||||
|
||||
place_bet_thread = Timer(
|
||||
start_after,
|
||||
ws.twitch.make_predictions,
|
||||
(ws.events_predictions[event_id],),
|
||||
)
|
||||
place_bet_thread.daemon = True
|
||||
place_bet_thread.start()
|
||||
|
||||
logger.info(
|
||||
f"Place the bet after: {start_after}s for: {ws.events_predictions[event_id]}",
|
||||
extra={
|
||||
"emoji": ":alarm_clock:",
|
||||
"event": Events.BET_START,
|
||||
},
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
f"{streamer} have only {streamer.channel_points} channel points and the minimum for bet is: {bet_settings.minimum_points}",
|
||||
extra={
|
||||
"emoji": ":pushpin:",
|
||||
"event": Events.BET_FILTERS,
|
||||
},
|
||||
)
|
||||
|
||||
elif (
|
||||
message.type == "event-updated"
|
||||
and event_id in ws.events_predictions
|
||||
):
|
||||
ws.events_predictions[event_id].status = event_status
|
||||
# Game over we can't update anymore the values... The bet was placed!
|
||||
if (
|
||||
ws.events_predictions[event_id].bet_placed is False
|
||||
and ws.events_predictions[event_id].bet.decision == {}
|
||||
):
|
||||
ws.events_predictions[event_id].bet.update_outcomes(
|
||||
event_dict["outcomes"]
|
||||
)
|
||||
|
||||
elif message.topic == "predictions-user-v1":
|
||||
event_id = message.data["prediction"]["event_id"]
|
||||
if event_id in ws.events_predictions:
|
||||
event_prediction = ws.events_predictions[event_id]
|
||||
if (
|
||||
message.type == "prediction-result"
|
||||
and event_prediction.bet_confirmed
|
||||
):
|
||||
points = event_prediction.parse_result(
|
||||
message.data["prediction"]["result"]
|
||||
)
|
||||
|
||||
decision = event_prediction.bet.get_decision()
|
||||
choice = event_prediction.bet.decision["choice"]
|
||||
|
||||
logger.info(
|
||||
(
|
||||
f"{event_prediction} - Decision: {choice}: {decision['title']} "
|
||||
f"({decision['color']}) - Result: {event_prediction.result['string']}"
|
||||
),
|
||||
extra={
|
||||
"emoji": ":bar_chart:",
|
||||
"event": Events.get(
|
||||
f"BET_{event_prediction.result['type']}"
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
ws.streamers[streamer_index].update_history(
|
||||
"PREDICTION", points["gained"]
|
||||
)
|
||||
|
||||
# Remove duplicate history records from previous message sent in community-points-user-v1
|
||||
if event_prediction.result["type"] == "REFUND":
|
||||
ws.streamers[streamer_index].update_history(
|
||||
"REFUND",
|
||||
-points["placed"],
|
||||
counter=-1,
|
||||
)
|
||||
elif event_prediction.result["type"] == "WIN":
|
||||
ws.streamers[streamer_index].update_history(
|
||||
"PREDICTION",
|
||||
-points["won"],
|
||||
counter=-1,
|
||||
)
|
||||
|
||||
if event_prediction.result["type"]:
|
||||
# Analytics switch
|
||||
if Settings.enable_analytics is True:
|
||||
ws.streamers[
|
||||
streamer_index
|
||||
].persistent_annotations(
|
||||
event_prediction.result["type"],
|
||||
f"{ws.events_predictions[event_id].title}",
|
||||
)
|
||||
elif message.type == "prediction-made":
|
||||
event_prediction.bet_confirmed = True
|
||||
# Analytics switch
|
||||
if Settings.enable_analytics is True:
|
||||
ws.streamers[streamer_index].persistent_annotations(
|
||||
"PREDICTION_MADE",
|
||||
f"Decision: {event_prediction.bet.decision['choice']} - {event_prediction.title}",
|
||||
)
|
||||
elif message.topic == "community-points-channel-v1":
|
||||
if message.type == "community-goal-created":
|
||||
# TODO Untested, hard to find this happening live
|
||||
|
||||
@@ -1,345 +0,0 @@
|
||||
import copy
|
||||
from enum import Enum, auto
|
||||
from random import uniform
|
||||
|
||||
from millify import millify
|
||||
|
||||
#from TwitchChannelPointsMiner.utils import char_decision_as_index, float_round
|
||||
from TwitchChannelPointsMiner.utils import float_round
|
||||
|
||||
|
||||
class Strategy(Enum):
|
||||
MOST_VOTED = auto()
|
||||
HIGH_ODDS = auto()
|
||||
PERCENTAGE = auto()
|
||||
SMART_MONEY = auto()
|
||||
SMART = auto()
|
||||
NUMBER_1 = auto()
|
||||
NUMBER_2 = auto()
|
||||
NUMBER_3 = auto()
|
||||
NUMBER_4 = auto()
|
||||
NUMBER_5 = auto()
|
||||
NUMBER_6 = auto()
|
||||
NUMBER_7 = auto()
|
||||
NUMBER_8 = auto()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Condition(Enum):
|
||||
GT = auto()
|
||||
LT = auto()
|
||||
GTE = auto()
|
||||
LTE = auto()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class OutcomeKeys(object):
|
||||
# Real key on Bet dict ['']
|
||||
PERCENTAGE_USERS = "percentage_users"
|
||||
ODDS_PERCENTAGE = "odds_percentage"
|
||||
ODDS = "odds"
|
||||
TOP_POINTS = "top_points"
|
||||
# Real key on Bet dict [''] - Sum()
|
||||
TOTAL_USERS = "total_users"
|
||||
TOTAL_POINTS = "total_points"
|
||||
# This key does not exist
|
||||
DECISION_USERS = "decision_users"
|
||||
DECISION_POINTS = "decision_points"
|
||||
|
||||
|
||||
class DelayMode(Enum):
|
||||
FROM_START = auto()
|
||||
FROM_END = auto()
|
||||
PERCENTAGE = auto()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class FilterCondition(object):
|
||||
__slots__ = [
|
||||
"by",
|
||||
"where",
|
||||
"value",
|
||||
]
|
||||
|
||||
def __init__(self, by=None, where=None, value=None, decision=None):
|
||||
self.by = by
|
||||
self.where = where
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return f"FilterCondition(by={self.by.upper()}, where={self.where}, value={self.value})"
|
||||
|
||||
|
||||
class BetSettings(object):
|
||||
__slots__ = [
|
||||
"strategy",
|
||||
"percentage",
|
||||
"percentage_gap",
|
||||
"max_points",
|
||||
"minimum_points",
|
||||
"stealth_mode",
|
||||
"filter_condition",
|
||||
"delay",
|
||||
"delay_mode",
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategy: Strategy = None,
|
||||
percentage: int = None,
|
||||
percentage_gap: int = None,
|
||||
max_points: int = None,
|
||||
minimum_points: int = None,
|
||||
stealth_mode: bool = None,
|
||||
filter_condition: FilterCondition = None,
|
||||
delay: float = None,
|
||||
delay_mode: DelayMode = None,
|
||||
):
|
||||
self.strategy = strategy
|
||||
self.percentage = percentage
|
||||
self.percentage_gap = percentage_gap
|
||||
self.max_points = max_points
|
||||
self.minimum_points = minimum_points
|
||||
self.stealth_mode = stealth_mode
|
||||
self.filter_condition = filter_condition
|
||||
self.delay = delay
|
||||
self.delay_mode = delay_mode
|
||||
|
||||
def default(self):
|
||||
self.strategy = self.strategy if self.strategy is not None else Strategy.SMART
|
||||
self.percentage = self.percentage if self.percentage is not None else 5
|
||||
self.percentage_gap = (
|
||||
self.percentage_gap if self.percentage_gap is not None else 20
|
||||
)
|
||||
self.max_points = self.max_points if self.max_points is not None else 50000
|
||||
self.minimum_points = (
|
||||
self.minimum_points if self.minimum_points is not None else 0
|
||||
)
|
||||
self.stealth_mode = (
|
||||
self.stealth_mode if self.stealth_mode is not None else False
|
||||
)
|
||||
self.delay = self.delay if self.delay is not None else 6
|
||||
self.delay_mode = (
|
||||
self.delay_mode if self.delay_mode is not None else DelayMode.FROM_END
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"BetSettings(strategy={self.strategy}, percentage={self.percentage}, percentage_gap={self.percentage_gap}, max_points={self.max_points}, minimum_points={self.minimum_points}, stealth_mode={self.stealth_mode})"
|
||||
|
||||
|
||||
class Bet(object):
|
||||
__slots__ = ["outcomes", "decision", "total_users", "total_points", "settings"]
|
||||
|
||||
def __init__(self, outcomes: list, settings: BetSettings):
|
||||
self.outcomes = outcomes
|
||||
self.__clear_outcomes()
|
||||
self.decision: dict = {}
|
||||
self.total_users = 0
|
||||
self.total_points = 0
|
||||
self.settings = settings
|
||||
|
||||
def update_outcomes(self, outcomes):
|
||||
for index in range(0, len(self.outcomes)):
|
||||
self.outcomes[index][OutcomeKeys.TOTAL_USERS] = int(
|
||||
outcomes[index][OutcomeKeys.TOTAL_USERS]
|
||||
)
|
||||
self.outcomes[index][OutcomeKeys.TOTAL_POINTS] = int(
|
||||
outcomes[index][OutcomeKeys.TOTAL_POINTS]
|
||||
)
|
||||
if outcomes[index]["top_predictors"] != []:
|
||||
# Sort by points placed by other users
|
||||
outcomes[index]["top_predictors"] = sorted(
|
||||
outcomes[index]["top_predictors"],
|
||||
key=lambda x: x["points"],
|
||||
reverse=True,
|
||||
)
|
||||
# Get the first elements (most placed)
|
||||
top_points = outcomes[index]["top_predictors"][0]["points"]
|
||||
self.outcomes[index][OutcomeKeys.TOP_POINTS] = top_points
|
||||
|
||||
# Inefficient, but otherwise outcomekeys are represented wrong
|
||||
self.total_points = 0
|
||||
self.total_users = 0
|
||||
for index in range(0, len(self.outcomes)):
|
||||
self.total_users += self.outcomes[index][OutcomeKeys.TOTAL_USERS]
|
||||
self.total_points += self.outcomes[index][OutcomeKeys.TOTAL_POINTS]
|
||||
|
||||
if (
|
||||
self.total_users > 0
|
||||
and self.total_points > 0
|
||||
):
|
||||
for index in range(0, len(self.outcomes)):
|
||||
self.outcomes[index][OutcomeKeys.PERCENTAGE_USERS] = float_round(
|
||||
(100 * self.outcomes[index][OutcomeKeys.TOTAL_USERS]) / self.total_users
|
||||
)
|
||||
self.outcomes[index][OutcomeKeys.ODDS] = float_round(
|
||||
#self.total_points / max(self.outcomes[index][OutcomeKeys.TOTAL_POINTS], 1)
|
||||
0
|
||||
if self.outcomes[index][OutcomeKeys.TOTAL_POINTS] == 0
|
||||
else self.total_points / self.outcomes[index][OutcomeKeys.TOTAL_POINTS]
|
||||
)
|
||||
self.outcomes[index][OutcomeKeys.ODDS_PERCENTAGE] = float_round(
|
||||
#100 / max(self.outcomes[index][OutcomeKeys.ODDS], 1)
|
||||
0
|
||||
if self.outcomes[index][OutcomeKeys.ODDS] == 0
|
||||
else 100 / self.outcomes[index][OutcomeKeys.ODDS]
|
||||
)
|
||||
|
||||
self.__clear_outcomes()
|
||||
|
||||
def __repr__(self):
|
||||
return f"Bet(total_users={millify(self.total_users)}, total_points={millify(self.total_points)}), decision={self.decision})\n\t\tOutcome A({self.get_outcome(0)})\n\t\tOutcome B({self.get_outcome(1)})"
|
||||
|
||||
def get_decision(self, parsed=False):
|
||||
#decision = self.outcomes[0 if self.decision["choice"] == "A" else 1]
|
||||
decision = self.outcomes[self.decision["choice"]]
|
||||
return decision if parsed is False else Bet.__parse_outcome(decision)
|
||||
|
||||
@staticmethod
|
||||
def __parse_outcome(outcome):
|
||||
return f"{outcome['title']} ({outcome['color']}), Points: {millify(outcome[OutcomeKeys.TOTAL_POINTS])}, Users: {millify(outcome[OutcomeKeys.TOTAL_USERS])} ({outcome[OutcomeKeys.PERCENTAGE_USERS]}%), Odds: {outcome[OutcomeKeys.ODDS]} ({outcome[OutcomeKeys.ODDS_PERCENTAGE]}%)"
|
||||
|
||||
def get_outcome(self, index):
|
||||
return Bet.__parse_outcome(self.outcomes[index])
|
||||
|
||||
def __clear_outcomes(self):
|
||||
for index in range(0, len(self.outcomes)):
|
||||
keys = copy.deepcopy(list(self.outcomes[index].keys()))
|
||||
for key in keys:
|
||||
if key not in [
|
||||
OutcomeKeys.TOTAL_USERS,
|
||||
OutcomeKeys.TOTAL_POINTS,
|
||||
OutcomeKeys.TOP_POINTS,
|
||||
OutcomeKeys.PERCENTAGE_USERS,
|
||||
OutcomeKeys.ODDS,
|
||||
OutcomeKeys.ODDS_PERCENTAGE,
|
||||
"title",
|
||||
"color",
|
||||
"id",
|
||||
]:
|
||||
del self.outcomes[index][key]
|
||||
for key in [
|
||||
OutcomeKeys.PERCENTAGE_USERS,
|
||||
OutcomeKeys.ODDS,
|
||||
OutcomeKeys.ODDS_PERCENTAGE,
|
||||
OutcomeKeys.TOP_POINTS,
|
||||
]:
|
||||
if key not in self.outcomes[index]:
|
||||
self.outcomes[index][key] = 0
|
||||
|
||||
'''def __return_choice(self, key) -> str:
|
||||
return "A" if self.outcomes[0][key] > self.outcomes[1][key] else "B"'''
|
||||
|
||||
def __return_choice(self, key) -> int:
|
||||
largest=0
|
||||
for index in range(0, len(self.outcomes)):
|
||||
if self.outcomes[index][key] > self.outcomes[largest][key]:
|
||||
largest = index
|
||||
return largest
|
||||
|
||||
def __return_number_choice(self, number) -> int:
|
||||
if (len(self.outcomes) > number):
|
||||
return number
|
||||
else:
|
||||
return 0
|
||||
|
||||
def skip(self) -> bool:
|
||||
if self.settings.filter_condition is not None:
|
||||
# key == by , condition == where
|
||||
key = self.settings.filter_condition.by
|
||||
condition = self.settings.filter_condition.where
|
||||
value = self.settings.filter_condition.value
|
||||
|
||||
fixed_key = (
|
||||
key
|
||||
if key not in [OutcomeKeys.DECISION_USERS, OutcomeKeys.DECISION_POINTS]
|
||||
else key.replace("decision", "total")
|
||||
)
|
||||
if key in [OutcomeKeys.TOTAL_USERS, OutcomeKeys.TOTAL_POINTS]:
|
||||
compared_value = (
|
||||
self.outcomes[0][fixed_key] + self.outcomes[1][fixed_key]
|
||||
)
|
||||
else:
|
||||
#outcome_index = char_decision_as_index(self.decision["choice"])
|
||||
outcome_index = self.decision["choice"]
|
||||
compared_value = self.outcomes[outcome_index][fixed_key]
|
||||
|
||||
# Check if condition is satisfied
|
||||
if condition == Condition.GT:
|
||||
if compared_value > value:
|
||||
return False, compared_value
|
||||
elif condition == Condition.LT:
|
||||
if compared_value < value:
|
||||
return False, compared_value
|
||||
elif condition == Condition.GTE:
|
||||
if compared_value >= value:
|
||||
return False, compared_value
|
||||
elif condition == Condition.LTE:
|
||||
if compared_value <= value:
|
||||
return False, compared_value
|
||||
return True, compared_value # Else skip the bet
|
||||
else:
|
||||
return False, 0 # Default don't skip the bet
|
||||
|
||||
def calculate(self, balance: int) -> dict:
|
||||
self.decision = {"choice": None, "amount": 0, "id": None}
|
||||
if self.settings.strategy == Strategy.MOST_VOTED:
|
||||
self.decision["choice"] = self.__return_choice(OutcomeKeys.TOTAL_USERS)
|
||||
elif self.settings.strategy == Strategy.HIGH_ODDS:
|
||||
self.decision["choice"] = self.__return_choice(OutcomeKeys.ODDS)
|
||||
elif self.settings.strategy == Strategy.PERCENTAGE:
|
||||
self.decision["choice"] = self.__return_choice(OutcomeKeys.ODDS_PERCENTAGE)
|
||||
elif self.settings.strategy == Strategy.SMART_MONEY:
|
||||
self.decision["choice"] = self.__return_choice(OutcomeKeys.TOP_POINTS)
|
||||
elif self.settings.strategy == Strategy.NUMBER_1:
|
||||
self.decision["choice"] = self.__return_number_choice(0)
|
||||
elif self.settings.strategy == Strategy.NUMBER_2:
|
||||
self.decision["choice"] = self.__return_number_choice(1)
|
||||
elif self.settings.strategy == Strategy.NUMBER_3:
|
||||
self.decision["choice"] = self.__return_number_choice(2)
|
||||
elif self.settings.strategy == Strategy.NUMBER_4:
|
||||
self.decision["choice"] = self.__return_number_choice(3)
|
||||
elif self.settings.strategy == Strategy.NUMBER_5:
|
||||
self.decision["choice"] = self.__return_number_choice(4)
|
||||
elif self.settings.strategy == Strategy.NUMBER_6:
|
||||
self.decision["choice"] = self.__return_number_choice(5)
|
||||
elif self.settings.strategy == Strategy.NUMBER_7:
|
||||
self.decision["choice"] = self.__return_number_choice(6)
|
||||
elif self.settings.strategy == Strategy.NUMBER_8:
|
||||
self.decision["choice"] = self.__return_number_choice(7)
|
||||
elif self.settings.strategy == Strategy.SMART:
|
||||
difference = abs(
|
||||
self.outcomes[0][OutcomeKeys.PERCENTAGE_USERS]
|
||||
- self.outcomes[1][OutcomeKeys.PERCENTAGE_USERS]
|
||||
)
|
||||
self.decision["choice"] = (
|
||||
self.__return_choice(OutcomeKeys.ODDS)
|
||||
if difference < self.settings.percentage_gap
|
||||
else self.__return_choice(OutcomeKeys.TOTAL_USERS)
|
||||
)
|
||||
|
||||
if self.decision["choice"] is not None:
|
||||
#index = char_decision_as_index(self.decision["choice"])
|
||||
index = self.decision["choice"]
|
||||
self.decision["id"] = self.outcomes[index]["id"]
|
||||
self.decision["amount"] = min(
|
||||
int(balance * (self.settings.percentage / 100)),
|
||||
self.settings.max_points,
|
||||
)
|
||||
if (
|
||||
self.settings.stealth_mode is True
|
||||
and self.decision["amount"]
|
||||
>= self.outcomes[index][OutcomeKeys.TOP_POINTS]
|
||||
):
|
||||
reduce_amount = uniform(1, 5)
|
||||
self.decision["amount"] = (
|
||||
self.outcomes[index][OutcomeKeys.TOP_POINTS] - reduce_amount
|
||||
)
|
||||
self.decision["amount"] = int(self.decision["amount"])
|
||||
return self.decision
|
||||
@@ -1,94 +0,0 @@
|
||||
from TwitchChannelPointsMiner.classes.entities.Bet import Bet
|
||||
from TwitchChannelPointsMiner.classes.entities.Streamer import Streamer
|
||||
from TwitchChannelPointsMiner.classes.Settings import Settings
|
||||
from TwitchChannelPointsMiner.utils import _millify, float_round
|
||||
|
||||
|
||||
class EventPrediction(object):
|
||||
__slots__ = [
|
||||
"streamer",
|
||||
"event_id",
|
||||
"title",
|
||||
"created_at",
|
||||
"prediction_window_seconds",
|
||||
"status",
|
||||
"result",
|
||||
"box_fillable",
|
||||
"bet_confirmed",
|
||||
"bet_placed",
|
||||
"bet",
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
streamer: Streamer,
|
||||
event_id,
|
||||
title,
|
||||
created_at,
|
||||
prediction_window_seconds,
|
||||
status,
|
||||
outcomes,
|
||||
):
|
||||
self.streamer = streamer
|
||||
|
||||
self.event_id = event_id
|
||||
self.title = title.strip()
|
||||
self.created_at = created_at
|
||||
self.prediction_window_seconds = prediction_window_seconds
|
||||
self.status = status
|
||||
self.result: dict = {"string": "", "type": None, "gained": 0}
|
||||
|
||||
self.box_fillable = False
|
||||
self.bet_confirmed = False
|
||||
self.bet_placed = False
|
||||
self.bet = Bet(outcomes, streamer.settings.bet)
|
||||
|
||||
def __repr__(self):
|
||||
return f"EventPrediction(event_id={self.event_id}, streamer={self.streamer}, title={self.title})"
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"EventPrediction: {self.streamer} - {self.title}"
|
||||
if Settings.logger.less
|
||||
else self.__repr__()
|
||||
)
|
||||
|
||||
def elapsed(self, timestamp):
|
||||
return float_round((timestamp - self.created_at).total_seconds())
|
||||
|
||||
def closing_bet_after(self, timestamp):
|
||||
return float_round(self.prediction_window_seconds - self.elapsed(timestamp))
|
||||
|
||||
def print_recap(self) -> str:
|
||||
return f"{self}\n\t\t{self.bet}\n\t\tResult: {self.result['string']}"
|
||||
|
||||
def parse_result(self, result) -> dict:
|
||||
result_type = result["type"]
|
||||
|
||||
points = {}
|
||||
points["placed"] = (
|
||||
self.bet.decision["amount"] if result_type != "REFUND" else 0
|
||||
)
|
||||
points["won"] = (
|
||||
result["points_won"]
|
||||
if result["points_won"] or result_type == "REFUND"
|
||||
else 0
|
||||
)
|
||||
points["gained"] = (
|
||||
points["won"] - points["placed"] if result_type != "REFUND" else 0
|
||||
)
|
||||
points["prefix"] = "+" if points["gained"] >= 0 else ""
|
||||
|
||||
action = (
|
||||
"Lost"
|
||||
if result_type == "LOSE"
|
||||
else ("Refunded" if result_type == "REFUND" else "Gained")
|
||||
)
|
||||
|
||||
self.result = {
|
||||
"string": f"{result_type}, {action}: {points['prefix']}{_millify(points['gained'])}",
|
||||
"type": result_type,
|
||||
"gained": points["gained"],
|
||||
}
|
||||
|
||||
return points
|
||||
@@ -6,7 +6,6 @@ from datetime import datetime
|
||||
from threading import Lock
|
||||
|
||||
from TwitchChannelPointsMiner.classes.Chat import ChatPresence, ThreadChat
|
||||
from TwitchChannelPointsMiner.classes.entities.Bet import BetSettings, DelayMode
|
||||
from TwitchChannelPointsMiner.classes.entities.Stream import Stream
|
||||
from TwitchChannelPointsMiner.classes.Settings import Events, Settings
|
||||
from TwitchChannelPointsMiner.constants import URL
|
||||
@@ -17,39 +16,32 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class StreamerSettings(object):
|
||||
__slots__ = [
|
||||
"make_predictions",
|
||||
"follow_raid",
|
||||
"claim_drops",
|
||||
"claim_moments",
|
||||
"watch_streak",
|
||||
"community_goals",
|
||||
"bet",
|
||||
"chat",
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
make_predictions: bool = None,
|
||||
follow_raid: bool = None,
|
||||
claim_drops: bool = None,
|
||||
claim_moments: bool = None,
|
||||
watch_streak: bool = None,
|
||||
community_goals: bool = None,
|
||||
bet: BetSettings = None,
|
||||
chat: ChatPresence = None,
|
||||
):
|
||||
self.make_predictions = make_predictions
|
||||
self.follow_raid = follow_raid
|
||||
self.claim_drops = claim_drops
|
||||
self.claim_moments = claim_moments
|
||||
self.watch_streak = watch_streak
|
||||
self.community_goals = community_goals
|
||||
self.bet = bet
|
||||
self.chat = chat
|
||||
|
||||
def default(self):
|
||||
for name in [
|
||||
"make_predictions",
|
||||
"follow_raid",
|
||||
"claim_drops",
|
||||
"claim_moments",
|
||||
@@ -59,13 +51,11 @@ class StreamerSettings(object):
|
||||
setattr(self, name, True)
|
||||
if self.community_goals is None:
|
||||
self.community_goals = False
|
||||
if self.bet is None:
|
||||
self.bet = BetSettings()
|
||||
if self.chat is None:
|
||||
self.chat = ChatPresence.ONLINE
|
||||
|
||||
def __repr__(self):
|
||||
return f"BetSettings(make_predictions={self.make_predictions}, follow_raid={self.follow_raid}, claim_drops={self.claim_drops}, claim_moments={self.claim_moments}, watch_streak={self.watch_streak}, community_goals={self.community_goals}, bet={self.bet}, chat={self.chat})"
|
||||
return f"StreamerSettings(follow_raid={self.follow_raid}, claim_drops={self.claim_drops}, claim_moments={self.claim_moments}, watch_streak={self.watch_streak}, community_goals={self.community_goals}, chat={self.chat})"
|
||||
|
||||
|
||||
class Streamer(object):
|
||||
@@ -199,18 +189,6 @@ class Streamer(object):
|
||||
else 0
|
||||
)
|
||||
|
||||
def get_prediction_window(self, prediction_window_seconds):
|
||||
delay_mode = self.settings.bet.delay_mode
|
||||
delay = self.settings.bet.delay
|
||||
if delay_mode == DelayMode.FROM_START:
|
||||
return min(delay, prediction_window_seconds)
|
||||
elif delay_mode == DelayMode.FROM_END:
|
||||
return max(prediction_window_seconds - delay, 0)
|
||||
elif delay_mode == DelayMode.PERCENTAGE:
|
||||
return prediction_window_seconds * delay
|
||||
else:
|
||||
return prediction_window_seconds
|
||||
|
||||
# === ANALYTICS === #
|
||||
def persistent_annotations(self, event_type, event_text):
|
||||
event_type = event_type.upper()
|
||||
|
||||
38
example.py
38
example.py
@@ -12,7 +12,6 @@ from TwitchChannelPointsMiner.classes.Matrix import Matrix
|
||||
from TwitchChannelPointsMiner.classes.Pushover import Pushover
|
||||
from TwitchChannelPointsMiner.classes.Gotify import Gotify
|
||||
from TwitchChannelPointsMiner.classes.Settings import Priority, Events, FollowersOrder
|
||||
from TwitchChannelPointsMiner.classes.entities.Bet import Strategy, BetSettings, Condition, OutcomeKeys, FilterCondition, DelayMode
|
||||
from TwitchChannelPointsMiner.classes.entities.Streamer import Streamer, StreamerSettings
|
||||
|
||||
twitch_miner = TwitchChannelPointsMiner(
|
||||
@@ -40,32 +39,31 @@ twitch_miner = TwitchChannelPointsMiner(
|
||||
color_palette=ColorPalette( # You can also create a custom palette color (for the common message).
|
||||
STREAMER_online="GREEN", # Don't worry about lower/upper case. The script will parse all the values.
|
||||
streamer_offline="red", # Read more in README.md
|
||||
BET_wiN=Fore.MAGENTA # Color allowed are: [BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET].
|
||||
),
|
||||
telegram=Telegram( # You can omit or set to None if you don't want to receive updates on Telegram
|
||||
chat_id=123456789, # Chat ID to send messages @getmyid_bot
|
||||
token="123456789:shfuihreuifheuifhiu34578347", # Telegram API token @BotFather
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION], # Only these events will be sent to the chat
|
||||
Events.CHAT_MENTION], # Only these events will be sent to the chat
|
||||
disable_notification=True, # Revoke the notification (sound/vibration)
|
||||
),
|
||||
discord=Discord(
|
||||
webhook_api="https://discord.com/api/webhooks/0123456789/0a1B2c3D4e5F6g7H8i9J", # Discord Webhook URL
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION], # Only these events will be sent to the chat
|
||||
Events.CHAT_MENTION], # Only these events will be sent to the chat
|
||||
),
|
||||
webhook=Webhook(
|
||||
endpoint="https://example.com/webhook", # Webhook URL
|
||||
method="GET", # GET or POST
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION], # Only these events will be sent to the endpoint
|
||||
Events.CHAT_MENTION], # Only these events will be sent to the endpoint
|
||||
),
|
||||
matrix=Matrix(
|
||||
username="twitch_miner", # Matrix username (without homeserver)
|
||||
password="...", # Matrix password
|
||||
homeserver="matrix.org", # Matrix homeserver
|
||||
room_id="...", # Room ID
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE, Events.BET_LOSE], # Only these events will be sent
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE], # Only these events will be sent
|
||||
),
|
||||
pushover=Pushover(
|
||||
userkey="YOUR-ACCOUNT-TOKEN", # Login to https://pushover.net/, the user token is on the main page
|
||||
@@ -78,32 +76,16 @@ twitch_miner = TwitchChannelPointsMiner(
|
||||
endpoint="https://example.com/message?token=TOKEN",
|
||||
priority=8,
|
||||
events=[Events.STREAMER_ONLINE, Events.STREAMER_OFFLINE,
|
||||
Events.BET_LOSE, Events.CHAT_MENTION],
|
||||
Events.CHAT_MENTION],
|
||||
)
|
||||
),
|
||||
streamer_settings=StreamerSettings(
|
||||
make_predictions=True, # If you want to Bet / Make prediction
|
||||
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
|
||||
claim_moments=True, # If set to True, https://help.twitch.tv/s/article/moments will be claimed when available
|
||||
watch_streak=True, # If a streamer go online change the priority of streamers array and catch the watch screak. Issue #11
|
||||
community_goals=False, # If True, contributes the max channel points per stream to the streamers' community challenge goals
|
||||
chat=ChatPresence.ONLINE, # Join irc chat to increase watch-time [ALWAYS, NEVER, ONLINE, OFFLINE]
|
||||
bet=BetSettings(
|
||||
strategy=Strategy.SMART, # Choose you strategy!
|
||||
percentage=5, # Place the x% of your channel points
|
||||
percentage_gap=20, # Gap difference between outcomesA and outcomesB (for SMART strategy)
|
||||
max_points=50000, # If the x percentage of your channel points is gt bet_max_points set this value
|
||||
stealth_mode=True, # If the calculated amount of channel points is GT the highest bet, place the highest value minus 1-2 points Issue #33
|
||||
delay_mode=DelayMode.FROM_END, # When placing a bet, we will wait until `delay` seconds before the end of the timer
|
||||
delay=6,
|
||||
minimum_points=20000, # Place the bet only if we have at least 20k points. Issue #113
|
||||
filter_condition=FilterCondition(
|
||||
by=OutcomeKeys.TOTAL_USERS, # Where apply the filter. Allowed [PERCENTAGE_USERS, ODDS_PERCENTAGE, ODDS, TOP_POINTS, TOTAL_USERS, TOTAL_POINTS]
|
||||
where=Condition.LTE, # 'by' must be [GT, LT, GTE, LTE] than value
|
||||
value=800
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -119,11 +101,11 @@ twitch_miner = TwitchChannelPointsMiner(
|
||||
|
||||
twitch_miner.mine(
|
||||
[
|
||||
Streamer("streamer-username01", settings=StreamerSettings(make_predictions=True , follow_raid=False , claim_drops=True , watch_streak=True , community_goals=False , bet=BetSettings(strategy=Strategy.SMART , percentage=5 , stealth_mode=True, percentage_gap=20 , max_points=234 , filter_condition=FilterCondition(by=OutcomeKeys.TOTAL_USERS, where=Condition.LTE, value=800 ) ) )),
|
||||
Streamer("streamer-username02", settings=StreamerSettings(make_predictions=False , follow_raid=True , claim_drops=False , bet=BetSettings(strategy=Strategy.PERCENTAGE , percentage=5 , stealth_mode=False, percentage_gap=20 , max_points=1234 , filter_condition=FilterCondition(by=OutcomeKeys.TOTAL_POINTS, where=Condition.GTE, value=250 ) ) )),
|
||||
Streamer("streamer-username03", settings=StreamerSettings(make_predictions=True , follow_raid=False , watch_streak=True , community_goals=True , bet=BetSettings(strategy=Strategy.SMART , percentage=5 , stealth_mode=False, percentage_gap=30 , max_points=50000 , filter_condition=FilterCondition(by=OutcomeKeys.ODDS, where=Condition.LT, value=300 ) ) )),
|
||||
Streamer("streamer-username04", settings=StreamerSettings(make_predictions=False , follow_raid=True , watch_streak=True , )),
|
||||
Streamer("streamer-username05", settings=StreamerSettings(make_predictions=True , follow_raid=True , claim_drops=True , watch_streak=True , community_goals=True , bet=BetSettings(strategy=Strategy.HIGH_ODDS , percentage=7 , stealth_mode=True, percentage_gap=20 , max_points=90 , filter_condition=FilterCondition(by=OutcomeKeys.PERCENTAGE_USERS, where=Condition.GTE, value=300 ) ) )),
|
||||
Streamer("streamer-username01", settings=StreamerSettings(follow_raid=False , claim_drops=True , watch_streak=True , community_goals=False)),
|
||||
Streamer("streamer-username02", settings=StreamerSettings(follow_raid=True , claim_drops=False)),
|
||||
Streamer("streamer-username03", settings=StreamerSettings(follow_raid=False , watch_streak=True , community_goals=True)),
|
||||
Streamer("streamer-username04", settings=StreamerSettings(follow_raid=True , watch_streak=True)),
|
||||
Streamer("streamer-username05", settings=StreamerSettings(follow_raid=True , claim_drops=True , watch_streak=True , community_goals=True)),
|
||||
Streamer("streamer-username06"),
|
||||
Streamer("streamer-username07"),
|
||||
Streamer("streamer-username08"),
|
||||
|
||||
Reference in New Issue
Block a user