commit 2a97b20245b377cfe59b80b75fecd049701a4c97 Author: Rodolphe Houdas Date: Thu Jun 17 08:54:49 2021 +0100 :tada: First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afe6a35 --- /dev/null +++ b/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/python,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=python,visualstudiocode + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +pytestdebug.log + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ +doc/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +#poetry.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +# .env +.env/ +.venv/ +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +pythonenv* + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# operating system-related files +# file properties cache/storage on macOS +*.DS_Store +# thumbnail cache on Windows +Thumbs.db + +# profiling data +.prof + + +### VisualStudioCode ### +.vscode +# .vscode/* +# !.vscode/settings.json +# !.vscode/tasks.json +# !.vscode/launch.json +# !.vscode/extensions.json +*.code-workspace + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/python,visualstudiocode diff --git a/DEV-README.md b/DEV-README.md new file mode 100644 index 0000000..f53ceba --- /dev/null +++ b/DEV-README.md @@ -0,0 +1,3 @@ +Example URL for news : https://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid=892970&count=8&maxlength=300&format=json + +The result can be found in `dev-examples/news.json` \ No newline at end of file diff --git a/dev-examples/news.json b/dev-examples/news.json new file mode 100644 index 0000000..ef29a7d --- /dev/null +++ b/dev-examples/news.json @@ -0,0 +1,115 @@ +{ + "appnews":{ + "appid":892970, + "newsitems":[ + { + "gid":"4093189984239069725", + "title":"Valheim's Hearth & Home update is coming this autumn", + "url":"https://steamstore-a.akamaihd.net/news/externalpost/Rock, Paper, Shotgun/4093189984239069725", + "is_external_url":true, + "author":"", + "contents":"Valheim's developers have responded to the overwhelming success of the viking survival game by revamping their update roadmap. The Hearth & Home update will still be the first to arrive, but they're now aiming for launch this autumn. More broadly, Iron Gate will be \"putting aside the smaller updates...", + "feedlabel":"Rock, Paper, Shotgun", + "date":1623348040, + "feedname":"Rock, Paper, Shotgun", + "feed_type":0, + "appid":892970 + }, + { + "gid":"4093189984238644326", + "title":"Valheim roadmap update, Hearth & Home due 'Q3 2021' and we know some of what's coming", + "url":"https://steamstore-a.akamaihd.net/news/externalpost/GamingOnLinux/4093189984238644326", + "is_external_url":true, + "author":"", + "contents":"While it's disappointing that it's going to be a while before seeing the big Hearth & Home update for Valheim, the reasoning can't be argued with and we at least now know some of what will come. Read the full article here: https://www.gamingonlinux.com/2021/06/valheim-roadmap-update-hearth-a-home-du...", + "feedlabel":"GamingOnLinux", + "date":1623337575, + "feedname":"GamingOnLinux", + "feed_type":0, + "appid":892970 + }, + { + "gid":"4093189984238423388", + "title":"Roadmap changes, Hearth & Home content, & reddit AMA", + "url":"https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/4093189984238423388", + "is_external_url":true, + "author":"ht", + "contents":"Hi Everyone, We want to start by thanking you all for the patience and kindness you’ve shown us since we launched in February. We launched into Early Access because we want to build the game with you, but never in our wildest dreams could we have imagined how many of you want to join us on this jour...", + "feedlabel":"Community Announcements", + "date":1623332844, + "feedname":"steam_community_announcements", + "feed_type":1, + "appid":892970 + }, + { + "gid":"4093189984234580630", + "title":"Valheim update fixes two bugged raid events", + "url":"https://steamstore-a.akamaihd.net/news/externalpost/eurogamer/4093189984234580630", + "is_external_url":true, + "author":"", + "contents":"We're still waiting for that big Heath and Home update, but in the meantime developer Iron Gate has rolled out another small patch to fix some of Valheim's bugs. This patch makes two previously-bugged raid events actually trigger in-game, and provides a number of other handy fixes to make your time ...", + "feedlabel":"Eurogamer", + "date":1623241080, + "feedname":"eurogamer", + "feed_type":0, + "appid":892970 + }, + { + "gid":"4093189984234038994", + "title":"Turns out some Valheim events weren't happening as expected so prepare for more now", + "url":"https://steamstore-a.akamaihd.net/news/externalpost/GamingOnLinux/4093189984234038994", + "is_external_url":true, + "author":"", + "contents":"Valheim is an epic game, selling multiple millions and clearly loved by many. Another fresh fixer-upper update is out now, which has some curious fixes. Read the full article here: https://www.gamingonlinux.com/2021/06/turns-out-some-valheim-events-werent-happening-as-expected-so-prepare-for-more-no...", + "feedlabel":"GamingOnLinux", + "date":1623228423, + "feedname":"GamingOnLinux", + "feed_type":0, + "appid":892970 + }, + { + "gid":"4093189984233993883", + "title":"Patch note 0.154.1", + "url":"https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/4093189984233993883", + "is_external_url":true, + "author":"richard", + "contents":"Hello everybody! Another one of our beloved fixer upper patches. Besides fixing some bugs and minor issues we found that some of our main random events never triggered as expected. So please welcome two new events: “You are being hunted…” and “The horde is attacking”. I'm sure they will brighten up ...", + "feedlabel":"Community Announcements", + "date":1623227692, + "feedname":"steam_community_announcements", + "feed_type":1, + "appid":892970, + "tags":[ + "patchnotes" + ] + }, + { + "gid":"4069544815359906543", + "title":"Development news 28/05/21", + "url":"https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/4069544815359906543", + "is_external_url":true, + "author":"IronLisa", + "contents":"Time flies and summer is just around the corner. Here at Iron Gate, we’re still working from home, and we’re still looking for the perfect office. While those two things remain unchanged, exciting things are still happening within the company. The last couple of weeks we’ve been having interviews wi...", + "feedlabel":"Community Announcements", + "date":1622207279, + "feedname":"steam_community_announcements", + "feed_type":1, + "appid":892970 + }, + { + "gid":"4069544181429491862", + "title":"Valheim has sold 6.8 million copies now", + "url":"https://steamstore-a.akamaihd.net/news/externalpost/Rock, Paper, Shotgun/4069544181429491862", + "is_external_url":true, + "author":"", + "contents":"Back when Valheim had sold 3 million copies, we put together a totally legitimate and expert chart predicting how the survival game's sales would continue. We predicted that it would have sold 6.8 million copies by around the 4th of March, which means today's announcement that it has now sold that m...", + "feedlabel":"Rock, Paper, Shotgun", + "date":1621548677, + "feedname":"Rock, Paper, Shotgun", + "feed_type":0, + "appid":892970 + } + ], + "count":94 + } + } \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b444538 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,17 @@ +aiodns==3.0.0 +aiohttp==3.7.4.post0 +async-timeout==3.0.1 +attrs==21.2.0 +cchardet==2.1.7 +cffi==1.14.5 +chardet==4.0.0 +flake8==3.9.2 +idna==3.2 +mccabe==0.6.1 +multidict==5.1.0 +pycares==4.0.0 +pycodestyle==2.7.0 +pycparser==2.20 +pyflakes==2.3.1 +typing-extensions==3.10.0.0 +yarl==1.6.3 diff --git a/valheim.py b/valheim.py new file mode 100644 index 0000000..b0d07d3 --- /dev/null +++ b/valheim.py @@ -0,0 +1,149 @@ +import json +import aiohttp +import asyncio +import sys +import select + +# Read DEV-README.md to have example of requests and data returned + + +stop = False +tasks = [] + + +def indent(string, spaces=4): + return (' ' * spaces) + string + '\n' + + +class ValheimNewsJSONDecoder(json.JSONDecoder): + + def decode(dct): + value = dct + if "gid" in dct: + value = ValheimNewsItem(dct) + elif "newsitems" in dct: + value = ValheimNewsItems(dct) + elif "appnews" in dct: + value = ValheimNews(dct) + return value + + +class ValheimNewsBase: + KEYS = [] + + def __init__(self, dct): + for key, value in dct.items(): + if key in self.KEYS: + setattr(self, key, value) + + def to_string(self, spaces=0, in_list=False): + string = "" + content = list(vars(self).items()) + if in_list: + (key, value), content = content[0], content[1:] + string += indent("- {}: {}".format(key, value), spaces - 2) + for key, value in content: + string += indent("{}: {}".format(key, value), spaces) + return string + + def __repr__(self): + return self.to_string() + + +class ValheimNews(ValheimNewsBase): + KEYS = [ + "appnews" + ] + + def to_string(self, spaces=0): + return "appnews: \n{}".format(self.appnews.to_string(spaces + 4)) + + +class ValheimNewsItems(ValheimNewsBase): + + KEYS = [ + "appid", + "newsitems", + "count" + ] + + def to_string(self, spaces=0): + newsitems = "" + for newsitem in self.newsitems: + newsitems += newsitem.to_string(spaces + 4, True) + return \ + indent("appid: {}".format(self.appid)) + \ + indent("newsitems: \n{}".format(newsitems)) + \ + indent("count: {}".format(self.count)) + + +class ValheimNewsItem(ValheimNewsBase): + + KEYS = [ + "gid", + "title", + "url", + "is_external_url", + "author", + "contents", + "feedlabel", + "date", + "feedname", + "feed_type", + "appid" + ] + + +async def getnews(count=2, maxlength=15): + url = "https://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?" \ + "appid={}&count={}&maxlength={}&format={}" \ + .format(892970, count, maxlength, "json") + + print("Fetching {}".format(url)) + + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + print("Checking news... {}".format(response.status)) + if (response.status != 200): + return + if (response.headers['content-type'].split(";")[0] + != "application/json"): + return + result = json.loads( + await response.text(), + object_hook=ValheimNewsJSONDecoder.decode + ) + print(result) + + +async def check_for_news(delay=5): + global stop + while not stop: + await getnews() + await asyncio.sleep(5) + + +async def do_nothing(): + global stop + while not stop: + i, o, e = select.select([sys.stdin], [], [], 0) + if i: + for task in tasks: + task.cancel() + await asyncio.sleep(0.1) + + +async def main(): + global tasks + tasks = [ + asyncio.create_task(do_nothing()), + asyncio.create_task(check_for_news()), + ] + await asyncio.gather(*tasks) + + +if __name__ == "__main__": + try: + asyncio.get_event_loop().run_until_complete(main()) + except asyncio.CancelledError: + print("Goodbye!")