-
Notifications
You must be signed in to change notification settings - Fork 1
/
steam_idle_cli.py
executable file
·153 lines (137 loc) · 6.31 KB
/
steam_idle_cli.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python
from __future__ import print_function
import os
import sys
import argparse
import atexit
from time import sleep
from datetime import timedelta, datetime
from math import ceil
import logging
from steamweb import SteamWebBrowserCfg as SteamWebBrowser
from steam_idle import steam_api
from steam_idle.page_parser import SteamBadges
from steam_idle.idle import strfsec, IdleChild, calc_delay
def main_idle(apps):
# Just to make sure it's ordered
apps = sorted(apps, key=lambda x: x.playTime, reverse=True)
if not args.skip_multi:
# Idle all apps with playTime < 2h in parallel
processes = []
for app in [app for app in apps if app.playTime < 2.0]:
delay = int((2.0 - app.playTime) * 60 * 60)
endtime = (datetime.now() + timedelta(seconds=delay))
p = IdleChild(app)
p.start()
processes.append((endtime, p))
if args.verbose:
print(p.name)
# Steam client will crash if childs spawn too fast; Fixes #1
sleep(0.25)
if args.verbose:
print('Multi-Idling %d apps' % len(processes))
# Should be ordered, shortest idle first
for endtime, p in processes:
now = datetime.now()
if endtime < now:
print(p, 'endtime (%s) is in the past, shutting down' % (endtime,))
p.terminate()
p.join()
continue
diff = int(ceil((endtime - now).total_seconds()))
if diff <= 0:
print(p, 'diff (%s) is below 0, shutting down' % (diff,))
p.terminate()
p.join()
continue
print('Sleeping for %s till %s' %(
strfsec(diff),
(datetime.now() + timedelta(seconds=diff)).strftime('%c')
))
sleep(diff)
if args.verbose:
print(p, 'Woke up, shutting down')
p.terminate()
p.join()
if processes:
# Multi-Idled some apps, update values as they will have changed
apps = [app for app in sbb.get_apps(fetch_images=False).values() if app.remainingDrops > 0]
# If there are still apps with < 2.0h play time, restart
if sum(app.playTime < 2.0 for app in apps) > 1:
print('There are still apps within refund time, restarting multi-idle')
return main_idle(apps)
# All apps should be out of refund time, (playTime >= 2h), idle one by one
if args.verbose:
print('Startin sequential idle of %d apps' % len(apps))
new_apps = [] # new apps added douring idle
for app in apps:
p = IdleChild(app)
p.start()
while app.remainingDrops > 0:
delay = calc_delay(app.remainingDrops)
print('"%s" has %d remaining drops: Idling for %s (\'till %s)' % (
app.name,
app.remainingDrops,
strfsec(delay),
(datetime.now() + timedelta(seconds=delay)).strftime('%c')
))
sleep(delay)
# Re check for remainingDrops and new apps
for a in sbb.get_apps(fetch_images=False).values():
if a.remainingDrops > 0 and not [x for x in apps + new_apps if x.appid == a.appid]:
print('Found a new app to idle: "%s" has %d remaining drops, play time till now: %0.1f hours' % (a.name, a.remainingDrops, a.playTime))
if a.playTime >= 2.0:
# Already out of refund time, add to the one by one idle list
apps.append(a)
else:
# Needs "refund-idle"
new_apps.append(a)
continue
if a.appid == app.appid:
# Still drops left for this app, continue idleing
app = a
print('%d drops remaining, playtime is %0.1f' %(app.remainingDrops, app.playTime))
# Stop idleing
p.terminate()
p.join()
if new_apps:
# We've found new apps that need "refund-idle"
print('Found %d new apps that need "refund-idle":' %(len(new_apps),))
if args.verbose:
for app in new_apps:
print('"%s" has %d remaining drops, play time till now: %0.1f hours' % (app.name, app.remainingDrops, app.playTime))
return main_idle(new_apps)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Idle all steam apps with card drops left.')
parser.add_argument('-v', '--verbose', help='increase output verbosity', action='store_true')
parser.add_argument('-d', '--debug', help='enable debug output', action='store_true')
parser.add_argument('-l', '--list', help='don\'t idle, just list apps with card drops', action='store_true')
parser.add_argument('--skip-multi', help='don\'t multi-idle all apps with playtime < 2h first', action='store_true')
parser.add_argument('-a', '--appid', help='idle only specific app ID\'s', type=int, nargs='*')
args = parser.parse_args()
if args.debug:
logging.basicConfig(format='%(asctime)s (%(name)s.%(funcName)s) [%(levelname)s] %(message)s', level=logging.DEBUG)
swb = SteamWebBrowser()
sbb = SteamBadges(swb)
if not args.list:
# make sure this is only run once
pidfile = os.path.join(os.path.dirname(__file__), 'steam-idle.pid')
if os.path.isfile(pidfile):
print('already running ("%s")' % pidfile)
sys.exit(1)
with open(pidfile, 'w') as pf:
pf.write(str(os.getpid()))
atexit.register(os.unlink, pidfile)
# Check if Steam is running
if not steam_api.IsSteamRunning():
print('Could not find a running Steam instance!')
print('Please start your Steam Client.')
sys.exit(1)
apps = [app for app in sbb.get_apps(fetch_images=False).values() if app.remainingDrops > 0]
print('%d games with a total of %d card drops left:' % (len(apps), sum([app.remainingDrops for app in apps])))
if args.verbose or args.list:
for app in apps:
print('"%s" has %d remaining drops, play time till now: %0.1f hours' % (app.name, app.remainingDrops, app.playTime))
if args.list:
sys.exit(0)
main_idle(apps)