├── srs ├── static │ ├── logo │ │ ├── logo.png │ │ ├── favicon.ico │ │ └── logo.svg │ ├── js │ │ └── theme.js │ └── css │ │ └── tailwind.css ├── trigger.py ├── entry.sh ├── database.py ├── settings.py ├── templates │ ├── setup.html │ ├── layout.html │ ├── login.html │ ├── index.html │ ├── md5_results.html │ ├── results.html │ └── admin.html ├── peer_discovery.py ├── scheduler.py ├── search.py ├── indexer.py ├── previews.py └── 0din.py ├── requirements.txt ├── .gitignore ├── README.md └── LICENSE /srs/static/logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4rtemis-4rrow/0din/HEAD/srs/static/logo/logo.png -------------------------------------------------------------------------------- /srs/static/logo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4rtemis-4rrow/0din/HEAD/srs/static/logo/favicon.ico -------------------------------------------------------------------------------- /srs/trigger.py: -------------------------------------------------------------------------------- 1 | import indexer 2 | import database 3 | import sys 4 | 5 | path = sys.argv[1] 6 | 7 | conn = database.get_db_connection() 8 | 9 | indexer.indexer(path, conn) 10 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Pillow 2 | colorlog 3 | cryptography 4 | ebooklib 5 | flask 6 | gunicorn 7 | matplotlib 8 | psycopg2-binary 9 | pydub 10 | pymupdf 11 | python-docx 12 | python-dotenv 13 | python-pptx 14 | requests 15 | schedule 16 | -------------------------------------------------------------------------------- /srs/entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "${ENABLE_SSL}" = "true" ]; then 4 | gunicorn -w 4 -b 0.0.0.0:${NODE_PORT:-5000} 0din:app \ 5 | --certfile=cert.pem --keyfile=key.pem \ 6 | --log-level debug --access-logfile - --error-logfile - 7 | else 8 | gunicorn -w 4 -b 0.0.0.0:${NODE_PORT:-5000} 0din:app \ 9 | --log-level debug --access-logfile - --error-logfile - 10 | fi 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Virtual environment 2 | .venv/ 3 | venv/ 4 | 5 | # Python cache 6 | __pycache__/ 7 | *.pyc 8 | *.pyo 9 | 10 | # Logs and database 11 | *.log 12 | *.sqlite3 13 | 14 | # OS specific files 15 | .DS_Store 16 | Thumbs.db 17 | 18 | # IDE specific files 19 | .vscode/ 20 | .idea/ 21 | 22 | # Environment variables 23 | .env 24 | 25 | # Odin related files 26 | credentials.json 27 | settings.json 28 | database.db -------------------------------------------------------------------------------- /srs/static/js/theme.js: -------------------------------------------------------------------------------- 1 | // Theme toggle functionality 2 | document.addEventListener("DOMContentLoaded", () => { 3 | const themeToggle = document.getElementById("theme-toggle") 4 | 5 | // Check for saved theme preference or use the system preference 6 | const savedTheme = localStorage.getItem("theme") 7 | const systemPrefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches 8 | 9 | // Apply the theme 10 | if (savedTheme === "dark" || (!savedTheme && systemPrefersDark)) { 11 | document.body.classList.add("dark") 12 | } 13 | 14 | // Toggle theme when button is clicked 15 | themeToggle.addEventListener("click", () => { 16 | document.body.classList.toggle("dark") 17 | 18 | // Save the preference 19 | if (document.body.classList.contains("dark")) { 20 | localStorage.setItem("theme", "dark") 21 | } else { 22 | localStorage.setItem("theme", "light") 23 | } 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /srs/database.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sqlite3 3 | import logging 4 | from colorlog import ColoredFormatter 5 | 6 | # Logging setup 7 | log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 8 | formatter = ColoredFormatter( 9 | "%(asctime)s - %(name)s - %(log_color)s%(levelname)s%(reset)s - %(message)s", 10 | datefmt="%Y-%m-%d %H:%M:%S", 11 | log_colors={ 12 | 'DEBUG': 'cyan', 13 | 'INFO': 'green', 14 | 'WARNING': 'yellow', 15 | 'ERROR': 'red', 16 | 'CRITICAL': 'bold_red', 17 | } 18 | ) 19 | console_handler = logging.StreamHandler() 20 | console_handler.setFormatter(formatter) 21 | logger = logging.getLogger() 22 | logger.setLevel(logging.DEBUG) 23 | logger.addHandler(console_handler) 24 | 25 | # Path to SQLite database file 26 | DB_PATH = os.getenv('SQLITE_DB_PATH', 'database.db') 27 | 28 | def get_db_connection(): 29 | try: 30 | conn = sqlite3.connect(DB_PATH) 31 | conn.row_factory = sqlite3.Row 32 | logger.info("SQLite database connection established.") 33 | return conn 34 | except sqlite3.Error as e: 35 | logger.error(f"SQLite connection failed: {e}") 36 | raise 37 | 38 | def put_connection(conn): 39 | conn.close() 40 | -------------------------------------------------------------------------------- /srs/settings.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | # Define the path to the settings JSON file 5 | SETTINGS_FILE = 'settings.json' 6 | 7 | # This dictionary will hold the settings in memory 8 | settings = {} 9 | 10 | def load_settings(): 11 | """Load settings from the JSON file.""" 12 | global settings 13 | if os.path.exists(SETTINGS_FILE): 14 | with open(SETTINGS_FILE, 'r') as f: 15 | settings = json.load(f) 16 | # Convert 'known_nodes' back to a set if it exists 17 | if 'known_nodes' in settings: 18 | settings['known_nodes'] = set(settings['known_nodes']) 19 | else: 20 | # If the file doesn't exist, initialize with default settings 21 | settings = get_default_settings() 22 | _save_settings() 23 | 24 | def get_default_settings(): 25 | """Return default settings.""" 26 | return { 27 | 'NODE_ID': os.getenv('NODE_ID', '127.0.0.1:5000'), 28 | 'LAST_EXECUTION_FILE': 'last_execution.txt', 29 | 'INDEX_FILES_TIME': 1, 30 | 'PEER_DISCOVER_INTERVAL': 1, 31 | 'DIRECTORY': os.getenv("SHARED_DIRECTORY"), 32 | 'URL': 'https://raw.githubusercontent.com/username/repository/branch/path/to/file.json', 33 | 'HEARTBEAT_INTERVAL': 10, 34 | 'known_nodes': set(os.getenv('KNOWN_NODES', '').split(', ')), 35 | } 36 | 37 | def _save_settings(): 38 | """Save the current settings to the JSON file.""" 39 | # Convert 'known_nodes' from set to list before saving 40 | settings_to_save = settings.copy() 41 | if 'known_nodes' in settings_to_save: 42 | settings_to_save['known_nodes'] = list(settings_to_save['known_nodes']) 43 | 44 | with open(SETTINGS_FILE, 'w') as f: 45 | json.dump(settings_to_save, f, indent=4) 46 | 47 | def get_setting(key, default=None): 48 | """Retrieve a setting value by key.""" 49 | return settings.get(key, default) 50 | 51 | def set_setting(key, value): 52 | """Set a setting value and save the updated settings to the file.""" 53 | settings[key] = value 54 | _save_settings() 55 | 56 | def return_all(): 57 | return settings 58 | 59 | # Automatically load settings when the module is imported 60 | load_settings() 61 | 62 | -------------------------------------------------------------------------------- /srs/templates/setup.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block title %}Setup - 0din{% endblock %} 4 | 5 | {% block content %} 6 |
11 | Create your admin account to get started
15 | 16 | {% with messages = get_flashed_messages(with_categories=true) %} 17 | {% if messages %} 18 | {% for category, message in messages %} 19 |
18 |
21 | Enter your credentials to access the admin dashboard
25 | 26 | {% with messages = get_flashed_messages(with_categories=true) %} 27 | {% if messages %} 28 | {% for category, message in messages %} 29 |Search for files across all connected nodes
10 |10 | Results for MD5 hash: {{ md5_hash }} 11 |
12 |23 | No files with the MD5 hash "{{ md5_hash }}" were found. 24 |
25 |
37 | {% else %}
38 | 10 | Results for "{{ query }}" 11 | {% if category and category != 'all' %} 12 | in {{ category }} 13 | {% endif %} 14 |
15 |52 | Try adjusting your search or category to find what you're looking for. 53 |
54 |
66 | {% else %}
67 | Manage your file indexing system settings and operations
10 |Index files in a specific directory to make them searchable
32 |