Open Wiedmolol opened 1 year ago
Hi, Just noted that also: [] {'page': 1, 'per_page': 15, 'distance': {'lat': 50.038838, 'lng': 19.9600552, 'range': 15000}, 'hide_unavailable': True, 'food_type': ['meals', 'bakery', 'shop'], 'collection_time': {'from': '00:00:00', 'to': '23:59:59'}} {'errors': ['Aby kontynuować zaloguj lub zarejestruj się.']}
@kacpi2442
I think I found the endpoint to login but I don't know what to from here. Tried to get cookie but its empty. POST https://api.foodsi.pl/api/v2/auth/sign_in with body { "email":"...", "password":"..." }
Then I have 200 and returns the user details
{'data': {'id': xxxxx, 'provider': 'email', 'uid': 'xxxxx, 'email': 'xxxxx', 'name': 'xxxx', 'phone': None, 'picture': {'url': None}, 'phone_validation': None, 'phone_validated_at': None, 'allow_password_change': False, 'favourite_restaurants': []}}
dobra robota @antonioli86 - pokombinowałem i te headery, które dostajesz w zwrotce od autoryzacji przekaż do requestu, a konkretniej to wystraczy: Access-Token, Uid, Client --- You need to pass Access-Token, Uid, Client headers from auth response
dobra robota @antonioli86 - pokombinowałem i te headery, które dostajesz w zwrotce od autoryzacji przekaż do requestu, a konkretniej to wystraczy: Access-Token, Uid, Client --- You need to pass Access-Token, Uid, Client headers from auth response
Dzięki @grutkowski-doz ! It works... it did a "drewniany" script and hardcoded the header parameters from the answer of auth in the header of the POST to restaurants and it works like a charm!
foodsi_api = requests.post('https://api.foodsi.pl/api/v2/restaurants', headers = {'Content-type':'application/json', 'system-version':'android_3.0.0', 'user-agent':'okhttp/3.12.0', 'Access-Token': 'xxxxxxxxxx', 'Client': 'xxxxxxxxxxx', 'Uid': 'xxxxxxxx'}, data = json.dumps(req_json))
And answer with the items:
{'page': 1, 'per_page': 15, 'distance': {'lat': '50.038838', 'lng': '19.9600552', 'range': '15000'}, 'hide_unavailable': True, 'food_type': ['meals', 'bakery', 'shop'], 'collection_time': {'from': '00:00:00', 'to': '23:59:59'}}
{'total_pages': 1, 'current_page': 1, 'data': [{'id': 1268582, 'address': 'Henryka Kamieńskiego 11, Kraków', 'address_notes': '', 'distance': '1.2', 'image': {'url': 'https://foodsi-backend-production.s3.amazonaws.com/uploads/package/image/2805/d53173efeb.jpg'}, 'important_notes': '', 'latitude': '50.02861492917916', 'logo': {'url': 'https://foodsi-backend-production.s3.amazonaws.com/uploads/venue/logo/1906/6c94f65f63.jpg'}, 'longitude': '19.95326270135493', 'meal': {'description': '🥗🥘🍝 Restauracja Olimp to miejsce, w którym uratujesz pyszne dania obiadowe, surówki i zupy. ', 'original_price': '54.0', 'price': '17.99'}, 'name': 'OLIMP BONARKA', 'package_day': {'availability_label': 'OSTATNIA PACZKA', 'availability_label_number': 1, 'isNew': False, 'collection_day': {'id': 1268582, 'week_day': 7, 'schedule_id': 1, 'active': True, 'closed_at': '2000-01-01T17:30:00.000Z', 'opened_at': '2000-01-01T16:00:00.000Z'}, 'meals_left': 1, 'soldOut': None}, 'package_id': 2805, 'package_type': 'paczka niespodzianka'
....
Now is just necessary to automate it and do in proper way! :P Thanks again grutkowski-doz
@boofuls w zwrotce samej nie, ale w zwróconych headerach, jeśli używasz postmana to wchodzisz w zakładkę Headers zamiast Body
Skąd wziąć Access-Token? W zwrotce od autoryzacji nie jest podany...
In the headers.
Dzięki @grutkowski-doz :)
Zrobiłem u siebie poprawkę, możecie to wprowadzić w swoich aplikacjach po odpowiednim dostosowaniu ;)
def _setHeaders(self) -> None:
try:
self._headers = {
'Content-type':'application/json',
'system-version':'android_3.0.0',
'user-agent':'okhttp/3.12.0',
'Access-Token': self._config.get('foodsi_access_token'),
'Client': self._config.get('foodsi_client'),
'Uid': self._config.get('foodsi_uid')
}
except Exception as e:
self._log.add('Foodsi [_setHeaders]', str(e), str(traceback.format_exc()))
exit(1)
def newCredentials(self) -> None:
try:
req_json = {
'email' : self._config.get('foodsi_email'),
'password' : self._getPassword(),
}
response = requests.post('https://api.foodsi.pl/api/v2/auth/sign_in', headers = {'Content-type':'application/json', 'system-version':'android_3.0.0', 'user-agent':'okhttp/3.12.0'}, data = json.dumps(req_json), timeout = 10)
if response.status_code == 200:
self._config.update('foodsi_access_token', str(response.headers['Access-Token']))
self._config.update('foodsi_client', str(response.headers['Client']))
self._config.update('foodsi_uid', str(response.headers['Uid']))
return self._setHeaders()
self._log.add('Foodsi [newCredentials]', str(response.json()))
time.sleep(150)
return self.newCredentials()
except Exception as e:
self._log.add('Foodsi [newCredentials]', str(e), str(traceback.format_exc()))
self._telegram.sendText(str(traceback.format_exc()))
exit(1)
pomoże ktoś jak zrobić zeby ten program działał?
nie mogę nic znaleźć :(
@Kirri777 @antonioli86
@Kirri777 @antonioli86
* please help * proszę o pomoc
I attached my version of watch_script.py You need also to extend the config.json
{
"telegram": {
"bot_token": "xyz",
"bot_chatID": -00000
},
"location": {
"lat": 0.0,
"long": 0.0,
"range": 15
},
"auth": {
"email": "xxxx",
"password": "xxxxx"
}
}
Basic code. ;) Working so far... time to time foodsi API is down during night and my container goes do - I need to start manually.
okay, will try now and let you know. thanks for the response and for the help
okay, will try now and let you know. thanks for the response and for the help
No problem. Is not a "sexy" code but works for me. :)
File "C:\Users\rober\OneDrive\Pulpit\am_bot-main\watch_script.py", line 366, in refresh foodsi() File "C:\Users\rober\OneDrive\Pulpit\am_bot-main\watch_script.py", line 282, in foodsi items += parse_foodsi_api(foodsi_api.json()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\rober\OneDrive\Pulpit\am_bot-main\watch_script.py", line 249, in parse_foodsi_api for restaurant in api_result['data']:
KeyError: 'data'
sends me this, i think its about the api right?
{ "telegram": { "bot_token": "xxx", "bot_chatID": xxx }, "location": { "lat": xxx, "long": xx, "range": 10 }, "auth": { "email": "xxx", "password": "xxx" }, "tgtg": { "access_token": "xxx", "refresh_token": "xxx", "user_id": "xxx", "cookie": "xx" } }
thats how i setup the config by the way , the TGTG part got added after
@antonioli86 sorry for mentioning (if its annoying let me know)
i think its due to the api being down?
nvm, saw the file lol.
I only use the code for the Foodsi btw. I removed the TGTG part. ;) For TGTG I use https://github.com/ahivert/tgtg-python
edit: correction: I use https://github.com/Der-Henning/tgtg
thanks mate, u really helped me with that
hey man, how can i start the TGTG u mentioned lol? i cant find the .py file or .exe to use it i installed with pip but cant find it @antonioli86
or i have to make it?
I have a container (I built with Docker). But you can run manually: python3 watch_script.py
.py file is zipped in the message above:
foodsi works perfectly fine, but i dont know about too good to go
i think i have to make too good to go .py file manually? from the info on there: https://github.com/ahivert/tgtg-python
foodsi works perfectly fine, but i dont know about too good to go
Sorry for that. :( But in general I just removed the TGTG part from original file - https://github.com/kacpi2442/am_bot/blob/main/watch_script.py - and extended the Foodsi with authentication.
@antonioli86 do you speak polish?
if not:
@antonioli86 could you help
@antonioli86 could you help
My mistake - to TGTG I use https://github.com/Der-Henning/tgtg. If you don't want to run as container you have option "Run from source".
I did not merged - I use am_bot to Foodsi, /Der-Henning/tgtg to TGTG.
it works 100%? because i never had a notification when shop got from sold to items available @antonioli86
it works 100%? because i never had a notification when shop got from sold to items available @antonioli86
https://github.com/Der-Henning/tgtg works perfectly to me. Need keep in mind it uses crontab... maximum can do is to check every minute.
My Docker compose:
version: "3.3"
services:
app:
image: derhenning/tgtg:latest ## pre build image from docker hub
environment:
- TZ=Europe/Warsaw ## Set timezone for pickupdate, otherwise will be utc
- DEBUG=false ## true for debug log messages
- TGTG_USERNAME= xxxx@xxx ## TGTG Username / Login EMail
- SLEEP_TIME=60 ## Time to wait till next scan in seconds - default 60 seconds
- SCHEDULE_CRON=* 7-23 * * * ## (optional) Scheduler in cron schedule expression
## Example of cron schedule expression:
## - SCHEDULE_CRON=* 12-14 * * 1-5
## => allowed to run at hours between 12:00 and 14:59 on monday to friday
## more help with formatting at https://crontab.guru/#*_12-14_*_*_1-5
## The Scanner will not make any requests to the TGTG API in the excluded periods
- METRICS=false ## Enable to export metrics for Prometheus
- METRICS_PORT=8000 ## Port for metrics http server
- DISABLE_TESTS=false ## true to disable test notifications on startup
- QUIET=false ## true to disable all console messages. Only errors and console notifier messages
- LOCALE=en_US ## set locale to localize ${{pickupdate}}
- CONSOLE=false ## true = enable simple console notifications
#- CONSOLE_BODY= ## console message with variables as described below
#- CONSOLE_CRON= ## Disable notifications based on cron
- TELEGRAM=true ## true = enable notifications via Telegram
- TELEGRAM_TOKEN=62..................## Telegram Bot token - see @botfather
- TELEGRAM_CHAT_IDS=-67.......... ## Telegram Chat id, multiple ids separated by comma
- TELEGRAM_TIMEOUT=60 ## Timeout for Telegram API requests
#- TELEGRAM_CRON=
#- TELEGRAM_BODY= ## Optional message body as markdown, variables as described below
## Example:
## 'TELEGRAM_BODY=*$${{display_name}}*\n*Available*: $${{items_available}}\n*Rating*: $${{rating}}\n*Price*: $${{price}} $${{currency}}\n*Pickup*: $${{pickupdate}}'
## In some cases you may have to add
## 'TELEGRAM_BODY={{` ... `}}'
volumes:
- tokens:/tokens ## volume to save TGTG credentials to reuse on next start up and avoid login mail
volumes:
tokens:
@antonioli86 what is the sleep time and schedule cron for
@antonioli86 what is the sleep time and schedule cron for
Cron is basically will define the intervals when will run the scanner. It is the the documentation:
https://github.com/Der-Henning/tgtg/wiki/Configuration
My crontab is defined to run from 7:00 till 23:59 to scan every minute.
foodsi works perfectly fine, but i dont know about too good to go
Which errors you have with TGTG using am_bot?
TGTG on am works good but i dont know how to make it work with foodsi
TGTG on am works good but i dont know how to make it work with foodsi
You mean the original file - https://github.com/kacpi2442/am_bot/blob/main/watch_script.py - works fine with TGTG, right? You just need to edit the foodsi function - def foodsi():
def foodsi():
"""
Retrieves the data from foodsi API and selects the message to send.
"""
try:
req_json = {
'email' : config['auth']['email'],
'password' : config['auth']['password']
}
response = requests.post('https://api.foodsi.pl/api/v2/auth/sign_in', headers = {'Content-type':'application/json', 'system-version':'android_3.0.0', 'user-agent':'okhttp/3.12.0'}, data = json.dumps(req_json), timeout = 10)
if response.status_code == 200:
access_token = str(response.headers['Access-Token'])
client = str(response.headers['Client'])
uid = str(response.headers['Uid'])
except Exception as e:
telegram_bot_sendtext(str(e))
exit(1)
items = list()
page = 1
totalpages = 1
while page <= totalpages:
req_json = {
"page": page,
"distance": {
"per_page": 15,
"lat": config['location']['lat'],
"lng": config['location']['long'],
"range": config['location']['range']*1000
},
"hide_unavailable": True,
"food_type": ['meals','bakery','shop'],
"collection_time": {
"from": "00:00:00",
"to": "23:59:59"
}
}
foodsi_api = requests.post('https://api.foodsi.pl/api/v2/restaurants', headers = {'Content-type':'application/json', 'system-version':'android_3.0.0', 'user-agent':'okhttp/3.12.0', 'Access-Token': access_token, 'Client': client, 'Uid': uid}, data = json.dumps(req_json))
items += parse_foodsi_api(foodsi_api.json())
totalpages = foodsi_api.json()['total_pages']
page += 1
print("Foodsi total items: " + str(len(items)))
# Get the global variable of items in stock
global foodsi_in_stock
# Go through all favourite items and compare the stock
for item in items:
try:
old_stock = [stock['package_day']['meals_left'] for stock in foodsi_in_stock if stock['id'] == item['id']][0]
except IndexError:
old_stock = 0
try:
item['msg_id'] = [stock['msg_id'] for stock in foodsi_in_stock if stock['id'] == item['id']][0]
except:
pass
new_stock = item['package_day']['meals_left']
# Check, if the stock has changed. Send a message if so.
if new_stock != old_stock:
# Check if the stock was replenished, send an encouraging image message
if old_stock == 0 and new_stock > 0:
#TODO: tommorrow date
message = f"🍽 There are {new_stock} new goodie bags at [{item['name']}]({item['url']})\n"\
f"_{item['meal']['description']}_\n"\
f"_{item['package_type']}_\n"\
f"💰 *{item['meal']['price']}PLN*/{item['meal']['original_price']}PLN\n"\
f"⏰ {item['opened_at']}-{item['closed_at']}\n"\
"ℹ️ foodsi.pl"
# message += f"\ndebug id: {item['id']}"
tg = telegram_bot_sendimage(item['image']['url'], message)
try:
item['msg_id'] = tg['result']['message_id']
except:
print(json.dumps(tg))
#### print(item['image']['url'])
print(message)
print(traceback.format_exc())
elif old_stock > new_stock and new_stock != 0:
# customer feedback: This message is not needed
pass
## Prepare a generic string, but with the important info
# message = f" 📉 Decrease from {old_stock} to {new_stock} available goodie bags at {[item['name'] for item in new_api_result if item['id'] == item_id][0]}."
# telegram_bot_sendtext(message)
elif old_stock > new_stock and new_stock == 0:
# message = f" ⭕ Sold out! There are no more goodie bags available at {item['name']}."
# telegram_bot_sendtext(message)
try:
tg = telegram_bot_delete_message([stock['msg_id'] for stock in foodsi_in_stock if stock['id'] == item['id']][0])
except:
print(f"Failed to remove message for item id: {item['id']}")
print(traceback.format_exc())
else:
# Prepare a generic string, but with the important info
message = f"There was a change of number of goodie bags in stock from {old_stock} to {new_stock} at {item['name']}."
telegram_bot_sendtext(message)
# Reset the global information with the newest fetch
foodsi_in_stock = items
# Print out some maintenance info in the terminal
print(f"Foodsi: API run at {time.ctime(time.time())} successful.")
# for item in foodsi_in_stock:
# print(f"{item['name']}({item['id']}): {item['package_day']['meals_left']}")
yeah
yeah
Just edit the foodsi function with my code. It should work.
From original code just added the authentication part in the beginning of foodsi function:
try:
req_json = {
'email' : config['auth']['email'],
'password' : config['auth']['password']
}
response = requests.post('https://api.foodsi.pl/api/v2/auth/sign_in', headers = {'Content-type':'application/json', 'system-version':'android_3.0.0', 'user-agent':'okhttp/3.12.0'}, data = json.dumps(req_json), timeout = 10)
if response.status_code == 200:
access_token = str(response.headers['Access-Token'])
client = str(response.headers['Client'])
uid = str(response.headers['Uid'])
except Exception as e:
telegram_bot_sendtext(str(e))
exit(1)
Then I updated the request to include the Access Token, client and uid (from the response of the authentication before):
foodsi_api = requests.post('https://api.foodsi.pl/api/v2/restaurants', headers = {'Content-type':'application/json', 'system-version':'android_3.0.0', 'user-agent':'okhttp/3.12.0', 'Access-Token': access_token, 'Client': client, 'Uid': uid}, data = json.dumps(req_json))
it crashes instantly
it crashes instantly
Errors? And config.json includes
"auth": {
"email": "xxxx@wp.pl",
"password": "xxxxx"
}
?
"auth": {
"email": "xxxxxx@gmail.com",
"password": "xxxx"
yeah
idk which error, it just flashes and closes the python file
idk which error, it just flashes and closes the python file
And no telegram message?
yeah
Wygląda na to, że Foodsi wprowadziło dzisiaj autentykację do requestów po API. W tym momencie API zwraca: