Guides
June 12, 2021

Idling часов Steam через Termux

Для работы нам понадобятся:

  • NodeJS
  • Notepad++ или другой текстовый редактор
  • Termux
  • Смартфон на базе Android, желательно 6.0+

Подготовка

Создаём в любом удобном месте 3 файла с расширением .js и 2 файла сценария командной строки .cmd

index.js

const steamClientFactory = require('./steamClient.js');
var configsArray = [];
var config;
var botArray = [];

config = {};
config.username = 'nick1';
config.password = 'pass1';
config.sharedSecret = ''; //Shared Secret(for 2FA only) https://github.com/Jessecar96/SteamDesktopAuthenticator/releases
config.games = [730,440,570]
configsArray.push(config);
	
config = {};
config.username = 'nick2';
config.password = 'pass2';
config.sharedSecret = ''; //Shared Secret(for 2FA only) https://github.com/Jessecar96/SteamDesktopAuthenticator/releases
config.games = [730,440,570]
configsArray.push(config);
	
	
	
console.log('Number of configurations set up: ' + configsArray.length);
     
for	(index = 0; index < configsArray.length; index++) {
    var config = configsArray[index];
		
	var bot = steamClientFactory.buildBot(config);
	bot.doLogin();
	botArray.push(bot);
}
     
console.log('Running ' + botArray.length + ' bots.');

steamClient.js

var SteamUser = require('steam-user');
var SteamTotp = require('steam-totp');
var botFactory = {};
 
botFactory.buildBot = function (config)
{	
	var bot = new SteamUser({
        promptSteamGuardCode: false,
		dataDirectory: "./sentry",
		singleSentryfile: false
    });
	
	bot.username = config.username;
	bot.password = config.password;
	bot.sharedSecret = config.sharedSecret;
	bot.games = config.games;
	bot.messageReceived = {};
	
	bot.on('loggedOn', function(details) {
		console.log("[" + this.username + "] Logged into Steam as " + bot.steamID.getSteam3RenderedID());
		bot.setPersona(SteamUser.EPersonaState.Online);
		bot.gamesPlayed(this.games);
	});
 
	bot.on('error', function(e) {
		console.log("[" + this.username + "] " + e);
		setTimeout(function() {bot.doLogin();}, 30*60*1000);
	});
 
	bot.doLogin = function ()
	{
		this.logOn({ 
			"accountName": this.username,
			"password": this.password
		});
	}
	
	bot.on('steamGuard', function(domain, callback) {
		if ( !this.sharedSecret ) {
			var readlineSync = require('readline-sync');
			var authCode = readlineSync.question("[" + this.username + "] " + 'Steam Guard' + (!domain ? ' App' : '') + ' Code: ');
			callback(authCode);	
		} 
		else {
			var authCode = SteamTotp.generateAuthCode( this.sharedSecret );
			console.log("[" + this.username + "] Generated Auth Code: " + authCode);
			callback(authCode);	
		}
		
	});
	
	bot.on("friendMessage", function(steamID, message) {
		console.log("[" + this.username + "] Message from " + steamID+ ": " + message);
		if ( !this.messageReceived[steamID] ) {
			bot.chatMessage(steamID, "[Automated Message] I am currently idle. I will respond when I am next available.");
			this.messageReceived[steamID] = true;
		}
	});
	
	
	bot.on('vacBans', function(numBans, appids) {
		if(numBans > 0) {
			console.log( "[" + this.username + "] " + numBans + " VAC ban" + (numBans == 1 ? '' : 's') + "." + 
						(appids.length == 0 ? '' : " In apps: " + appids.join(', ')) );
		}
	});
	
	bot.on('accountLimitations', function(limited, communityBanned, locked, canInviteFriends) {
		var limitations = [];
 
		if(limited) {
			limitations.push('LIMITED');
		}
 
		if(communityBanned) {
			limitations.push('COMMUNITY BANNED');
		}
 
		if(locked) {
			limitations.push('LOCKED');
		}
 
		if(limitations.length !== 0) {
			console.log("[" + this.username + "] Limitations: " + limitations.join(', ') + ".");
		}
	});
	
	return bot;
}
 
module.exports = botFactory;

package.json

{
  "name": "ez-steam-idler",
  "version": "1.0.0",
  "dependencies": {
    "steam": "^1.4.1",
    "steam-user": "^4.12.5",
    "steam-totp": "^2.1.1",
    "readline-sync": "^1.4.10"
  }
}

Install.cmd

npm install
pause

startIdle.cmd

CD /D "%~dp0"
node .
pause

Настройка

Первый запуск на PC:

  • Устанавливаем Node.js
  • Запускаем Install.cmd
  • В index.js[7] указываем свои логин/пароль (shared secret для опытных)
  • В index.js[10] указываем appID приложений Steam
  • Настраиваем steamClient.js[21, 55] — Online/Offline и автоответчик

При желании можете сделать пробный запуск. Если нужен всего один аккаунт, комментируем нужные строки в index.js.

Пакуем index.js, steamClient.js и package.json в архив. Перемещаем на наше устройство.


Секс с эмулятором

Как же я ненавижу Termux.

Запаковали 3 файла, перекинули на смартфон. Далее важно, чтобы архив оказался в папке storage/Download, туда у Termux не требуется root.

За время экспериментов я столкнулся сразу с несколькими кейсами, рассмотрим каждый:

Первый кейс, решение

Как это должно работать.

  • Переходим в Termux, даём ему доступ к Storage

Начинаем секс с терминалом

apt update && apt upgrade // Обновляем пакеты и репозитории
termux-setup-storage // Ставим эмулятор хранилища
cd storage/download // Переходим в папку с архивом
mv Boost.zip $HOME // Перемещаем архив в домашнюю директорию терминала
clear
cd
ls // Чистим мусор, переходим в $home и выводим на экран список файлов и папок
unzip Boost.zip // Распаковываем наш архив

Так оно должно работать в идеале, однако я @%!$ в рот ваш Termux и работает оно немного иначе

Второй кейс, ошибка распаковки

Ошибка сразу возникает на этапе распаковки. В моём случае пришлось сверху ставить пакет 7z

pkg install p7zip
7za x Boost.zip

В случае ошибки распаковки лишь этот способ поможет. Причина, вероятно, в архивации через 7z, хотя мой наивный разум полагал, что проблем не возникнет.

Третий кейс, ошибка хранилища

Если каким-то чудом архив оказался во внешнем хранилище, то

cd /sdcard/Boost.zip // Если на устройстве нет SDcard слота
cd /sdcard0/Boost.zip // SDcard слот ест
cd /sdcard1/Boost.zip // Ты поместил архив на SDcard

А лучше не использовать external storage.


Запуск

Перемещаемся в домашнюю директорию к файлам, запускаем бота

clear
cd
npm install // Парсим наш .json и ставим оставшиеся пакеты
node . // Запускаем бота

Материал: