Commit b1ea8b25 authored by Isabella Sko艡epov谩's avatar Isabella Sko艡epov谩
Browse files

Initial commit 馃

parents
creds.json
node_modules
# goto
goes to given page: await goto('dorf1.php') opens resource view
usually not required for anything
# networkIdle
waits until network is idle
usually not required for anything
# login
logs you in with username and password login({ name: 'me', password: '1234' })
# getResourceBuildings
returns list of resource buildings, their levels and their ids
# getQueue
returns contents building queue
# upgradeBuilding
issues command to upgrade building.
WARNING! does not check if you have enough resources
upgradeBuilding(7)
# getTimeWhenUpgradePossible
returns time when upgrade will be possible or 0 if it is possible now
# close
closes browser
{
"name": "me",
"password": "123456789"
}
{
"name": "travian",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"agent-base": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.1.1.tgz",
"integrity": "sha512-yWGUUmCZD/33IRjG2It94PzixT8lX+47Uq8fjmd0cgQWITCMrJuXFaVIMnGDmDnZGGKAGdwTx8UGeU8lMR2urA==",
"requires": {
"es6-promisify": "5.0.0"
}
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
"requires": {
"balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
"integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
"requires": {
"inherits": "2.0.3",
"readable-stream": "2.3.3",
"typedarray": "0.0.6"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"debug": {
"version": "2.6.8",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
"integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
"requires": {
"ms": "2.0.0"
}
},
"es6-promise": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz",
"integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng=="
},
"es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
"requires": {
"es6-promise": "4.1.1"
}
},
"extract-zip": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.5.tgz",
"integrity": "sha1-maBnNbbqIOqbcF13ms/8yHz/BEA=",
"requires": {
"concat-stream": "1.6.0",
"debug": "2.2.0",
"mkdirp": "0.5.0",
"yauzl": "2.4.1"
},
"dependencies": {
"debug": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
"requires": {
"ms": "0.7.1"
}
},
"ms": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
"integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
}
}
},
"fd-slicer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
"requires": {
"pend": "1.2.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
},
"https-proxy-agent": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.1.0.tgz",
"integrity": "sha512-/DTVSUCbRc6AiyOV4DBRvPDpKKCJh4qQJNaCgypX0T41quD9hp/PB5iUyx/60XobuMPQa9ce1jNV9UOUq6PnTg==",
"requires": {
"agent-base": "4.1.1",
"debug": "2.6.8"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"mime": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz",
"integrity": "sha512-n9ChLv77+QQEapYz8lV+rIZAW3HhAPW2CXnzb1GN5uMkuczshwvkW7XPsbzU0ZQN3sP47Er2KVkp2p3KyqZKSQ=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "1.1.8"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
"integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=",
"requires": {
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1.0.2"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"progress": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
"integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8="
},
"proxy-from-env": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
"integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4="
},
"puppeteer": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-0.10.2.tgz",
"integrity": "sha512-dj1MdwiYfEwTemfFeBu0inGyhcaEe3cKREvTFSA/pkGHaCwyj/FFfJHJpr9vykXvSs/PbmcApOztsUyqzd1msA==",
"requires": {
"debug": "2.6.8",
"extract-zip": "1.6.5",
"https-proxy-agent": "2.1.0",
"mime": "1.4.0",
"progress": "2.0.0",
"proxy-from-env": "1.0.0",
"rimraf": "2.6.2",
"ws": "3.2.0"
}
},
"readable-stream": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "1.0.7",
"safe-buffer": "5.1.1",
"string_decoder": "1.0.3",
"util-deprecate": "1.0.2"
}
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"requires": {
"glob": "7.1.2"
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"requires": {
"safe-buffer": "5.1.1"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"ultron": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz",
"integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"ws": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-3.2.0.tgz",
"integrity": "sha512-hTS3mkXm/j85jTQOIcwVz3yK3up9xHgPtgEhDBOH3G18LDOZmSAG1omJeXejLKJakx+okv8vS1sopgs7rw0kVw==",
"requires": {
"async-limiter": "1.0.0",
"safe-buffer": "5.1.1",
"ultron": "1.1.0"
}
},
"yauzl": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
"integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
"requires": {
"fd-slicer": "1.0.1"
}
}
}
}
{
"name": "travian",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"puppeteer": "^0.10.2"
},
"devDependencies": {},
"scripts": {
"start": "node src/index.js"
},
"author": "",
"license": "ISC"
}
function timeout(ms) {
return new Promise(res => setTimeout(res, ms))
}
async function bot(travian) {
const queue = await travian.getQueue()
const buildings = await travian.getResourceBuildings()
if(queue.length < 1) {
console.log('Building queue is empty; Checking if building upgrade is possible')
const building = buildings.sort((a, b) => a.level < b.level ? -1 : 1)[0]
const time = await travian.getTimeWhenUpgradePossible(building.id)
if(!time) {
console.log('adding lowest level resource building')
await travian.upgradeBuilding(building.id)
} else {
const ms = time.getTime() - Date.now()
console.log('Building ('+building.id+') upgrade is not possible; waiting '+(ms/1000)+'s')
await timeout(ms)
}
} else {
console.log('Queue: '+queue.map(e => e.name+' '+e.level+' '+e.time).join('\n '))
}
await timeout(1000)
}
module.exports.bot = bot
const puppeteer = require('puppeteer')
const fs = require('fs')
const { promisify } = require('util')
const Travian = require('./travian')
async function readCredentials() {
return JSON.parse(await promisify(fs.readFile)('creds.json', 'utf-8'))
}
console.log('starting')
;(async () => {
const args = await Travian.generateArgs({
headless: true,
server: 'https://ts5.travian.cz/',
})
const impl = Travian.travianImpl
const travian = impl(...args)
try {
await travian.login(await readCredentials())
while(true) {
delete require.cache[require.resolve('./travian')]
delete require.cache[require.resolve('./bot')]
await require('./bot').bot(require('./travian').travianImpl(...args))
}
} catch(e) {
travian.close()
console.error(e)
process.exit(1)
}
})().catch(e => {
console.error(e)
process.exit(1)
});
const puppeteer = require('puppeteer')
const fs = require('fs')
const { promisify } = require('util')
const travianImpl = (page, browser, { state, setState }, { server, cookieStore, language }) => ({
async goto(path, opts = {}) {
if(state.path !== path) {
await page.goto(server+path, {
waitUntil: 'networkidle',
...opts
})
setState({ path })
}
},
async networkIdle() {
await page.waitForNavigation({
waitUntil: 'networkidle',
})
},
async login({ name, password }) {
await this.goto('dorf1.php')
if(await page.$('.outerLoginBox') !== null) {
await page.click('.account input')
await page.type(name)
await page.click('.pass input')
await page.type(password)
await page.click('.loginButtonRow button')
} else {
console.log('user was already logged in')
}
await this.networkIdle()
},
async getResourceBuildings() {
await this.goto('dorf1.php')
const areaNames = await page.evaluate(() => {
const areas = Array.from(document.querySelectorAll('#rx area'))
return areas.map(a => ({ alt: a.alt, href: a.href }))
})
return areaNames
.filter(a => a.alt)
.map(({ alt, href }) => {
const parts = alt.split(' ')
return {
level: Number.parseInt(parts[parts.length - 1]),
type: parts.slice(0, parts.length - 2).join(' '),
id: href.replace(server+'build.php?id=', ''),
}
})
.filter(a => a.type)
.map(a => ({
...a,
type: Object.entries(language.mines).find(([k,v]) => v === a.type)[0],
}))
.sort((a,b) => a.type === b.type
? 0
: a.type > b.type
? 1
: -1
)
},
async getQueue() {
await this.goto('dorf1.php')
return await page.evaluate(() =>{
const buildings = Array.from(document.querySelectorAll('.buildingList li'))
return buildings.map(b => ({
time: b.children[2].children[0].innerHTML,
name: b.children[1].innerHTML.split('<')[0].trim(),
level: b.children[1].children[0].innerHTML.split(' ').pop(),
}))
})
},
async upgradeBuilding(id) {
await this.goto('build.php?id='+id)
await page.click('.upgradeButtonsContainer .section1 button')
await this.networkIdle()
},
async getTimeWhenUpgradePossible(id) {
await this.goto('build.php?id='+id)
const startDate = new Date()
const className = await page.$eval('.upgradeButtonsContainer .section1 button', el => el.className)
if(!/gold/.exec(className)) return 0
const timeString = await page.$eval('.contractCosts .statusMessage', el => el.innerHTML.split('<')[0])
const [month, day, hour, minute] = timeString
.replace(/^.* ([0-9]+)\.([0-9]+)\..* ([0-9]+):([0-9]+)/, '$2,$1,$3,$4')
.split(',')
.map(a => Number.parseInt(a, 10))
const date = new Date(new Date().getFullYear(), month-1, day, hour, minute)
if(startDate.getTime() - 1000*3600*24 > date.getTime()) {
const ndate = new Date(new Date().getFullYear()+1, month-1, day, hour, minute)
return ndate
}
return date
},
close() {
return browser.close()
}
})
const generateArgs = async (_opts) => {
const opts = {
cookieStore: 'cookies.json',
headless: true,
language: {
mines: {
wood: 'D艡evorubec',
clay: 'Hlin臎n媒 d暖l',
iron: '沤elezn媒 d暖l',
wheat: 'Obiln茅 pole',
},
resources: {
wood: 'D艡evo',
clay: 'Hl铆na',
iron: '沤elezo',
wheat: 'Obil铆',
}
},
..._opts,
}
if(!opts.server) throw new Error('You have to specify server')
const browser = await puppeteer.launch({ headless: opts.headless })
try {
const page = await browser.newPage()
const state = {}
return [
page,
browser,
{
state,
setState: (patch) => { Object.assign(state, patch) },
},
opts,
]
} catch(e) {
browser.close()
throw e
}
}
const TravianFactory = async (_opts) => {
const args = generateArgs(_opts)
try {
travianImpl(...args)
} catch(e) {
args[1].close()
throw e
}
}
module.exports.default = TravianFactory
module.exports.generateArgs = generateArgs
module.exports.travianImpl = travianImpl
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment