BrickTracker/app.py

561 lines
21 KiB
Python
Raw Normal View History

from flask import Flask, request, redirect, jsonify, render_template, Response,url_for
2024-02-28 20:08:16 +01:00
import json
2024-02-29 14:47:12 +01:00
from pprint import pprint as pp
2024-03-03 11:15:38 +01:00
from pathlib import Path
2024-04-16 21:36:34 +02:00
import time,random,string,sqlite3
import numpy as np
2024-04-16 21:36:34 +02:00
import re #regex
import rebrick #rebrickable api
import requests # request img from web
import shutil # save img locally
2024-02-28 20:08:16 +01:00
app = Flask(__name__)
@app.route('/favicon.ico')
2024-03-03 11:15:38 +01:00
2024-04-18 11:43:23 +02:00
@app.route('/delete/<tmp>',methods=['POST', 'GET'])
def delete(tmp):
conn = sqlite3.connect('app.db')
cursor = conn.cursor()
if request.method == 'POST':
print("POST")
if request.method == "GET":
print("GET")
print(tmp)
2024-04-18 12:51:09 +02:00
tables = ['inventory', 'sets', 'minifigures', 'missing']
for t in tables:
cursor.execute('DELETE FROM ' + t + ' where u_id="' +tmp+ '";')
conn.commit()
cursor.close()
conn.close()
2024-04-18 11:43:23 +02:00
return redirect('/')
2024-04-16 21:36:34 +02:00
@app.route('/create',methods=['GET', 'POST'])
def create():
conn = sqlite3.connect('app.db')
cursor = conn.cursor()
count = 0
if request.method == 'GET':
print('get')
if request.method == 'POST':
set_num = request.form['inputField']
# add_duplicate = request.form.get('addDuplicate', False) == 'true'
2024-04-16 21:36:34 +02:00
# Do something with the input value and the checkbox value
# print("Input value:", set_num)
# print("Add duplicate:", add_duplicate)
2024-04-16 21:36:34 +02:00
# You can perform any further processing or redirect to another page
if '-' not in set_num:
set_num = set_num + '-1'
print ("Adding set: " + set_num)
with open('api','r') as f:
api_key = f.read().replace('\n','')
rb = rebrick.init(api_key)
unique_set_id = generate_unique_set_unique()
2024-04-18 11:43:23 +02:00
2024-04-16 21:36:34 +02:00
# Get Set info and add to SQL
response = ''
try:
response = json.loads(rebrick.lego.get_set(set_num).read())
except Exception as e:
print(e.code)
if e.code == 404:
return render_template('create.html',error=set_num)
2024-04-16 21:36:34 +02:00
count+=1
2024-04-16 21:36:34 +02:00
cursor.execute('''INSERT INTO sets (
set_num,
name,
year,
theme_id,
num_parts,
set_img_url,
set_url,
last_modified_dt,
mini_col,
set_check,
set_col,
2024-04-16 21:36:34 +02:00
u_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', (response['set_num'], response['name'], response['year'], response['theme_id'], response['num_parts'],response['set_img_url'],response['set_url'],response['last_modified_dt'],False,False,False,unique_set_id))
2024-04-16 21:36:34 +02:00
conn.commit()
2024-04-18 11:43:23 +02:00
2024-04-16 21:36:34 +02:00
# Get set image. Saved under ./static/sets/xxx-x.jpg
set_img_url = response["set_img_url"]
print('Saving set image:',end='')
res = requests.get(set_img_url, stream = True)
count+=1
if res.status_code == 200:
with open("./static/sets/"+set_num+".jpg",'wb') as f:
shutil.copyfileobj(res.raw, f)
print(' OK')
else:
print('Image Couldn\'t be retrieved for set ' + set_num)
logging.error('set_img_url: ' + set_num)
print(' ERROR')
# Get inventory and add to SQL
response = json.loads(rebrick.lego.get_set_elements(set_num,page_size=20000).read())
count+=1
for i in response['results']:
# Get part image. Saved under ./static/parts/xxxx.jpg
part_img_url = i['part']['part_img_url']
part_img_url_id = 'nil'
2024-04-16 21:36:34 +02:00
try:
pattern = r'/([^/]+)\.(?:png|jpg)$'
match = re.search(pattern, part_img_url)
2024-04-16 21:36:34 +02:00
if match:
part_img_url_id = match.group(1)
print("Part number:", part_img_url_id)
else:
print("Part number not found in the URL.")
print(">>> " + part_img_url)
except Exception as e:
print("Part number not found in the URL.")
print(">>> " + str(part_img_url))
print(str(e))
2024-04-16 21:36:34 +02:00
cursor.execute('''INSERT INTO inventory (
set_num,
id,
part_num,
name,
part_img_url,
part_img_url_id,
color_id,
color_name,
quantity,
is_spare,
element_id,
u_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', (set_num, i['id'], i['part']['part_num'],i['part']['name'],i['part']['part_img_url'],part_img_url_id,i['color']['id'],i['color']['name'],i['quantity'],i['is_spare'],i['element_id'],unique_set_id))
if not Path("./static/parts/"+part_img_url_id+".jpg").is_file():
print('Saving part image:',end='')
if part_img_url is not None:
res = requests.get(part_img_url, stream = True)
count+=1
if res.status_code == 200:
with open("./static/parts/"+part_img_url_id+".jpg",'wb') as f:
shutil.copyfileobj(res.raw, f)
print(' OK')
else:
print('Image Couldn\'t be retrieved for set ' + part_img_url_id)
logging.error('part_img_url: ' + part_img_url_id)
print(' ERROR')
2024-04-16 21:36:34 +02:00
else:
print('Part url is None')
print(i)
2024-04-16 21:36:34 +02:00
else:
print(part_img_url_id + '.jpg exists!')
conn.commit()
# Get minifigs
print('Savings minifigs')
tmp_set_num = set_num
2024-04-16 21:36:34 +02:00
response = json.loads(rebrick.lego.get_set_minifigs(set_num).read())
count+=1
print(response)
for i in response['results']:
# Get set image. Saved under ./static/minifigs/xxx-x.jpg
set_img_url = i["set_img_url"]
set_num = i['set_num']
print('Saving set image:',end='')
if not Path("./static/minifigs/"+set_num+".jpg").is_file():
res = requests.get(set_img_url, stream = True)
count+=1
if res.status_code == 200:
with open("./static/minifigs/"+set_num+".jpg",'wb') as f:
shutil.copyfileobj(res.raw, f)
print(' OK')
else:
print('Image Couldn\'t be retrieved for set ' + set_num)
logging.error('set_img_url: ' + set_num)
print(' ERROR')
else:
print(set_img_url + '.jpg exists!')
2024-04-16 21:36:34 +02:00
cursor.execute('''INSERT INTO minifigures (
fig_num,
2024-04-16 21:36:34 +02:00
set_num,
name,
quantity,
set_img_url,
u_id
) VALUES (?, ?, ?, ?, ?, ?) ''', (i['set_num'],tmp_set_num, i['set_name'], i['quantity'],i['set_img_url'],unique_set_id))
2024-04-16 21:36:34 +02:00
conn.commit()
# Get minifigs inventory
response_minifigs = json.loads(rebrick.lego.get_minifig_elements(i['set_num']).read())
count+=1
for i in response_minifigs['results']:
# Get part image. Saved under ./static/parts/xxxx.jpg
part_img_url = i['part']['part_img_url']
part_img_url_id = 'nil'
try:
pattern = r'/([^/]+)\.(?:png|jpg)$'
match = re.search(pattern, part_img_url)
if match:
part_img_url_id = match.group(1)
print("Part number:", part_img_url_id)
if not Path("./static/parts/"+part_img_url_id+".jpg").is_file():
print('Saving part image:',end='')
res = requests.get(part_img_url, stream = True)
count+=1
if res.status_code == 200:
with open("./static/parts/"+part_img_url_id+".jpg",'wb') as f:
shutil.copyfileobj(res.raw, f)
print(' OK')
else:
print('Image Couldn\'t be retrieved for set ' + part_img_url_id)
logging.error('part_img_url: ' + part_img_url_id)
print(' ERROR')
else:
print(part_img_url_id + '.jpg exists!')
except Exception as e:
print("Part number not found in the URL.")
print(">>> " + str(part_img_url))
print(str(e))
2024-04-16 21:36:34 +02:00
cursor.execute('''INSERT INTO inventory (
set_num,
id,
part_num,
name,
part_img_url,
part_img_url_id,
2024-04-16 21:36:34 +02:00
color_id,
color_name,
quantity,
is_spare,
element_id,
u_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', (i['set_num'], i['id'], i['part']['part_num'],i['part']['name'],i['part']['part_img_url'],part_img_url_id,i['color']['id'],i['color']['name'],i['quantity'],i['is_spare'],i['element_id'],unique_set_id))
2024-04-16 21:36:34 +02:00
conn.commit()
conn.close()
print(count)
return redirect('/')
2024-04-16 21:36:34 +02:00
conn.close()
print('Count: ' + str(count))
return render_template('create.html')
def generate_unique_set_unique():
timestamp = int(time.time() * 1000) # Current timestamp in milliseconds
random_chars = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8)) # 8-digit alphanumeric
return f'{timestamp}{random_chars}'
@app.route('/',methods=['GET','POST'])
2024-03-03 11:15:38 +01:00
def index():
2024-04-16 21:36:34 +02:00
set_list = []
theme_file = np.loadtxt("themes.csv",delimiter=",",dtype="str")
if request.method == 'GET':
conn = sqlite3.connect('app.db')
cursor = conn.cursor()
cursor.execute('SELECT * from sets;')
2024-04-16 21:43:30 +02:00
results = cursor.fetchall()
set_list = [list(i) for i in results]
2024-04-16 21:36:34 +02:00
print(set_list)
2024-04-16 21:43:30 +02:00
for i in set_list:
try:
i[3] = theme_file[theme_file[:, 0] == str(i[3])][0][1]
except Exception as e:
print(e)
2024-04-16 21:36:34 +02:00
cursor.close()
conn.close()
return render_template('index.html',set_list=set_list,themes_list=theme_file)
@app.route('/<tmp>/<u_id>', methods=['GET', 'POST'])
def inventory(tmp,u_id):
if request.method == 'GET':
conn = sqlite3.connect('app.db')
cursor = conn.cursor()
# Get set info
cursor.execute("SELECT * from sets where set_num = '" + tmp + "' and u_id = '" + u_id + "';")
2024-04-16 21:36:34 +02:00
results = cursor.fetchall()
set_list = [list(i) for i in results]
# Get inventory
cursor.execute("SELECT * from inventory where set_num = '" + tmp + "' and u_id = '" + u_id + "';")
2024-04-16 21:36:34 +02:00
results = cursor.fetchall()
inventory_list = [list(i) for i in results]
# Get missing parts
cursor.execute("SELECT * from missing where u_id = '" + u_id + "';")
2024-04-16 21:36:34 +02:00
results = cursor.fetchall()
missing_list = [list(i) for i in results]
# Get minifigures
cursor.execute("SELECT * from minifigures where set_num = '" + tmp + "' and u_id = '" + u_id + "';")
results = cursor.fetchall()
minifig_list = [list(i) for i in results]
minifig_inventory_list = []
for i in minifig_list:
cursor.execute("SELECT * from inventory where set_num = '" + i[0] + "' and u_id = '" + u_id + "';")
results = cursor.fetchall()
tmp_inv = [list(i) for i in results]
minifig_inventory_list.append(tmp_inv)
2024-04-16 21:36:34 +02:00
cursor.close()
conn.close()
2024-04-18 11:43:23 +02:00
return render_template('table.html', u_id=u_id,tmp=tmp,title=set_list[0][1],set_list=set_list,inventory_list=inventory_list,missing_list=missing_list,minifig_list=minifig_list,minifig_inventory_list=minifig_inventory_list)
2024-04-16 21:36:34 +02:00
if request.method == 'POST':
set_num = request.form.get('set_num')
id = request.form.get('id')
part_num = request.form.get('part_num')
color_id = request.form.get('color_id')
element_id = request.form.get('element_id')
u_id = request.form.get('u_id')
missing = request.form.get('missing')
conn = sqlite3.connect('app.db')
cursor = conn.cursor()
# If quantity is not empty
2024-04-16 21:43:30 +02:00
if missing != '' and missing != '0':
2024-04-16 21:36:34 +02:00
#Check if there's an existing entry
cursor.execute('''SELECT quantity FROM missing
WHERE set_num = ? AND
id = ? AND
part_num = ? AND
color_id = ? AND
element_id = ? AND
u_id = ?''',
(set_num, id, part_num, color_id, element_id, u_id))
existing_quantity = cursor.fetchone()
#If there's an existing entry or if entry isn't the same as the new value
if existing_quantity is None or existing_quantity[0] != missing:
cursor.execute('''INSERT OR REPLACE INTO missing (
set_num,
id,
part_num,
color_id,
quantity,
element_id,
u_id
) VALUES (?, ?, ?, ?, ?, ?, ?) ''',
(set_num, id, part_num, color_id, missing, element_id, u_id))
conn.commit()
# If quantity is empty, delete the entry.
else:
cursor.execute('''DELETE FROM missing
WHERE set_num = ? AND
id = ? AND
part_num = ? AND
color_id = ? AND
element_id = ? AND
u_id = ?''',
(set_num, id, part_num, color_id, element_id, u_id))
conn.commit()
cursor.close()
conn.close()
return ('', 204)
@app.route('/old', methods=['GET', 'POST'])
def frontpage():
2024-03-03 11:15:38 +01:00
pathlist = Path('./info/').rglob('*.json')
set_list = []
json_file = {}
theme_file = np.loadtxt("themes.csv", delimiter=",",dtype="str")
if request.method == 'GET':
for path in pathlist:
set_num = re.findall(r"\b\d+(?:-\d+)?\b",str(path))[0]
with open('./static/sets/'+set_num+'/info.json') as info:
info_file = json.loads(info.read())
try:
info_file['theme_id'] = theme_file[theme_file[:, 0] == str(info_file['theme_id'])][0][1]
except Exception as e:
print(e)
with open('./info/'+set_num+'.json') as info:
json_file[set_num] = json.loads(info.read())
set_list.append(info_file)
return render_template('frontpage.html',set_list=set_list,themes_list=theme_file,json_file=json_file)
if request.method == 'POST':
set_num = request.form.get('set_num')
2024-04-14 22:10:07 +02:00
index = request.form.get('index')
minif = request.form.get('minif')
scheck = request.form.get('scheck')
scol = request.form.get('scol')
with open('./info/'+set_num+'.json') as info:
json_file = json.loads(info.read())
if minif != None:
2024-04-14 22:10:07 +02:00
json_file['unit'][int(index)]['Minifigs Collected'] = minif
if scheck != None:
2024-04-14 22:10:07 +02:00
json_file['unit'][int(index)]['Set Checked'] = scheck
if scol != None:
2024-04-14 22:10:07 +02:00
json_file['unit'][int(index)]['Set Collected'] = scol
with open('./info/'+set_num+'.json', 'w') as dump_file:
json.dump(json_file,dump_file)
return ('', 204)
2024-03-03 11:15:38 +01:00
2024-04-16 21:36:34 +02:00
@app.route('/old/<tmp>', methods=['GET', 'POST'])
2024-03-03 11:15:38 +01:00
def sets(tmp):
with open('./static/sets/'+tmp+'/info.json') as info:
2024-02-28 21:31:43 +01:00
info_file = json.loads(info.read())
2024-04-12 14:46:02 +02:00
with open('./static/sets/'+tmp+'/minifigs.json') as info:
minifigs_file = json.loads(info.read())
with open('./static/sets/'+tmp+'/inventory.json') as inventory:
2024-02-28 21:31:43 +01:00
inventory_file = json.loads(inventory.read())
2024-02-29 13:24:47 +01:00
with open('./info/'+tmp+'.json') as info:
json_file = json.loads(info.read())
if request.method == 'POST':
part_num = request.form.get('brickpartpart_num')
color = request.form.get('brickcolorname')
index = request.form.get('index')
number = request.form.get('numberInput')
is_spare = request.form.get('is_spare')
# print(part_num)
# print(color)
# print(index)
# print(number)
# print(is_spare)
if number is not None:
print(part_num)
print(color)
print(number)
print(is_spare)
with open('./info/'+tmp+'.json') as info:
json_file = json.loads(info.read())
print(json_file['count'])
data = '{"brick" : {"ID":"' + part_num + '","is_spare": "' + is_spare + '","color_name": "' + color + '","amount":"' + number + '"}}'
if len(json_file['unit'][int(index)]['bricks']['missing']) == 0:
json_file['unit'][int(index)]['bricks']['missing'].append(json.loads(data))
print(json_file)
elif number == '':
for idx,i in enumerate(json_file['unit'][int(index)]['bricks']['missing']):
if i['brick']['ID'] == part_num and i['brick']['is_spare'] == is_spare and i['brick']['color_name'] == color:
json_file['unit'][int(index)]['bricks']['missing'].pop(idx)
else:
found = False
for idx,i in enumerate(json_file['unit'][int(index)]['bricks']['missing']):
if not found and i['brick']['ID'] == part_num and i['brick']['is_spare'] == is_spare and i['brick']['color_name'] == color:
json_file['unit'][int(index)]['bricks']['missing'][idx]['brick']['amount'] = number
found = True
if not found:
json_file['unit'][int(index)]['bricks']['missing'].append(json.loads(data))
with open('./info/'+tmp+'.json', 'w') as dump_file:
json.dump(json_file,dump_file)
#return Response(status=200)
return ('', 204)
else:
return render_template('bootstrap_table.html', tmp=tmp,title=info_file['name'],
2024-04-12 14:46:02 +02:00
info_file=info_file,inventory_file=inventory_file,json_file=json_file,minifigs_file=minifigs_file)
2024-02-28 20:08:16 +01:00
2024-02-29 19:44:28 +01:00
@app.route('/<tmp>/saveNumber', methods=['POST'])
def save_number(tmp):
part_num = request.form.get('brickpartpart_num')
color = request.form.get('brickcolorname')
2024-03-04 15:41:48 +01:00
index = request.form.get('index')
2024-02-28 20:08:16 +01:00
number = request.form.get('numberInput')
is_spare = request.form.get('is_spare')
2024-02-28 20:08:16 +01:00
if number is not None:
2024-02-28 21:31:43 +01:00
2024-03-04 15:41:48 +01:00
print(part_num)
print(color)
2024-02-28 21:31:43 +01:00
print(number)
print(is_spare)
2024-02-28 21:31:43 +01:00
with open('./info/'+tmp+'.json') as info:
json_file = json.loads(info.read())
2024-03-04 15:41:48 +01:00
data = '{"brick" : {"ID":"' + part_num + '","is_spare": "' + is_spare + '","color_name": "' + color + '","amount":"' + number + '"}}'
2024-02-29 15:22:55 +01:00
2024-03-04 18:17:19 +01:00
if len(json_file['unit'][int(index)]['bricks']['missing']) == 0:
json_file['unit'][int(index)]['bricks']['missing'].append(json.loads(data))
print(json_file)
elif number == '':
2024-03-04 18:17:19 +01:00
for idx,i in enumerate(json_file['unit'][int(index)]['bricks']['missing']):
if i['brick']['ID'] == part_num and i['brick']['is_spare'] == is_spare and i['brick']['color_name'] == color:
json_file['unit'][int(index)]['bricks']['missing'].pop(idx)
2024-03-04 18:17:19 +01:00
else:
found = False
for idx,i in enumerate(json_file['unit'][int(index)]['bricks']['missing']):
if not found and i['brick']['ID'] == part_num and i['brick']['is_spare'] == is_spare and i['brick']['color_name'] == color:
json_file['unit'][int(index)]['bricks']['missing'][idx]['brick']['amount'] = number
found = True
if not found:
json_file['unit'][int(index)]['bricks']['missing'].append(json.loads(data))
2024-03-04 15:41:48 +01:00
with open('./info/'+tmp+'.json', 'w') as dump_file:
json.dump(json_file,dump_file)
2024-03-04 15:41:48 +01:00
return Response(status=204)
2024-02-28 20:08:16 +01:00
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, port=3333)