Greasy Fork is available in English.

Pending barcodes (Networked)

Collects barcodes with the reliability of v2.2.0 and syncs them via a local server.

Autor
Hamad AlShegifi
Denně instalací
0
Celkem instalací
1
Hodnocení
0 0 0
Verze
3.5.1
Vytvořeno
02. 10. 2025
Aktualizováno
16. 10. 2025
Size
19,0 KB
Licence
neuvedeno
Spustit na

import json
import socket
import threading
import time
from flask import Flask, request, jsonify
from flask_cors import CORS
import os

# --- Configuration ---
BARCODES_FILE = 'barcodes.json'
SERVER_PORT = 5678 # Port for the web server (for Tampermonkey)
BROADCAST_PORT = 5679 # Port for network discovery and sync
BROADCAST_INTERVAL = 20 # Seconds between sync broadcasts

# --- Flask Web Server Setup ---
app = Flask(__name__)
CORS(app) # Allow requests from the Tampermonkey script

# --- Barcode Data Management ---
data_lock = threading.Lock()

def load_barcodes():
"""Safely loads barcodes from the JSON file."""
with data_lock:
if not os.path.exists(BARCODES_FILE):
return []
try:
with open(BARCODES_FILE, 'r') as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
return []

def save_barcodes(barcodes):
"""Safely saves barcodes to the JSON file."""
with data_lock:
# Sort by count to maintain some order
barcodes.sort(key=lambda x: x.get('count', 0))
with open(BARCODES_FILE, 'w') as f:
json.dump(barcodes, f, indent=4)

def merge_barcodes(local_list, received_list):
"""Merges two lists of barcodes, avoiding duplicates based on the 'barcode' value."""
merged_dict = {item['barcode']: item for item in local_list}
changed = False
for item in received_list:
if item['barcode'] not in merged_dict:
merged_dict[item['barcode']] = item
changed = True
else:
if item.get('found', False) and not merged_dict[item['barcode']].get('found', False):
merged_dict[item['barcode']]['found'] = True
changed = True

if not changed:
return local_list # Return original list if no changes

final_list = list(merged_dict.values())
for i, item in enumerate(final_list):
item['count'] = i + 1
return final_list


# --- API Endpoints for Tampermonkey ---

@app.route('/get_barcodes', methods=['GET'])
def get_barcodes():
"""Endpoint for the script to fetch the current list of barcodes."""
return jsonify(load_barcodes())

# *** NEW, SAFER ENDPOINT FOR ADDING BARCODES ***
@app.route('/add_barcode', methods=['POST'])
def add_barcode():
"""Endpoint for the script to send a single new barcode."""
new_entry = request.json
if not new_entry or 'barcode' not in new_entry:
return jsonify({"status": "error", "message": "Invalid data format."}), 400

barcodes = load_barcodes()

# Check for duplicates
if any(b['barcode'] == new_entry['barcode'] for b in barcodes):
return jsonify({"status": "success", "message": "Barcode already exists."}), 200

# Add the new entry and re-assign counts
barcodes.append(new_entry)
for i, item in enumerate(barcodes):
item['count'] = i + 1

save_barcodes(barcodes)
print(f"[{time.ctime()}] Added new barcode: {new_entry['barcode']}")
return jsonify({"status": "success", "message": "Barcode added."}), 201

@app.route('/update_barcodes', methods=['POST'])
def update_barcodes():
"""Endpoint for the script to send a full list of barcodes (e.g., after deleting)."""
new_barcodes = request.json
if isinstance(new_barcodes, list):
save_barcodes(new_barcodes)
return jsonify({"status": "success", "message": "Barcode list updated."}), 200
return jsonify({"status": "error", "message": "Invalid data format."}), 400


# --- Network Syncing Logic (UDP Broadcast) ---

def broadcast_sync():
"""Periodically sends the entire local barcode list to the network."""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
while True:
time.sleep(BROADCAST_INTERVAL)
barcodes = load_barcodes()
if barcodes:
message = json.dumps(barcodes).encode('utf-8')
try:
sock.sendto(message, ('', BROADCAST_PORT))
# print(f"[{time.ctime()}] Sent sync broadcast with {len(barcodes)} items.")
except Exception as e:
print(f"Error sending broadcast: {e}")

def listen_for_sync():
"""Listens for barcode lists from other computers and merges them."""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', BROADCAST_PORT))
print(f"Listening for sync data on UDP port {BROADCAST_PORT}")
my_ip = socket.gethostbyname(socket.gethostname())

while True:
try:
data, addr = sock.recvfrom(65507)
if addr[0] != my_ip:
received_barcodes = json.loads(data.decode('utf-8'))
local_barcodes = load_barcodes()
merged_list = merge_barcodes(local_barcodes, received_barcodes)

if merged_list is not local_barcodes:
save_barcodes(merged_list)
print(f"[{time.ctime()}] Received and merged {len(received_barcodes)} barcodes from {addr[0]}. New total: {len(merged_list)}.")
except Exception as e:
print(f"Error receiving sync data: {e}")


if __name__ == '__main__':
print("--- Barcode Sync Server ---")
if not os.path.exists(BARCODES_FILE):
save_barcodes([])
print(f"Created empty barcodes file at: {os.path.abspath(BARCODES_FILE)}")

listener_thread = threading.Thread(target=listen_for_sync, daemon=True)
listener_thread.start()
broadcaster_thread = threading.Thread(target=broadcast_sync, daemon=True)
broadcaster_thread.start()

print(f"Starting web server for Tampermonkey on http://localhost:{SERVER_PORT}")
app.run(host='0.0.0.0', port=SERVER_PORT)