PDF Page Comparison Tool

 import fitz  # PyMuPDF

from PIL import Image, ImageChops, ImageDraw

import difflib

import os


OUTPUT_DIR = "pdf_diff_output"

os.makedirs(OUTPUT_DIR, exist_ok=True)


# ----------------------------------------------------

# Extract text from a PDF page

# ----------------------------------------------------

def extract_text(pdf_path, page_num):

    doc = fitz.open(pdf_path)

    if page_num >= len(doc):

        return ""

    return doc[page_num].get_text()


# ----------------------------------------------------

# Render page as image

# ----------------------------------------------------

def render_page_image(pdf_path, page_num, zoom=2):

    doc = fitz.open(pdf_path)

    page = doc[page_num]

    mat = fitz.Matrix(zoom, zoom)

    pix = page.get_pixmap(matrix=mat)

    img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)

    return img


# ----------------------------------------------------

# Text Difference

# ----------------------------------------------------

def text_diff(text1, text2):

    diff = difflib.unified_diff(

        text1.splitlines(),

        text2.splitlines(),

        lineterm=""

    )

    return "\n".join(diff)


# ----------------------------------------------------

# Image Difference (highlight changes)

# ----------------------------------------------------

def image_diff(img1, img2):

    diff = ImageChops.difference(img1, img2)

    diff = diff.convert("RGB")


    # Highlight differences in red

    pixels = diff.load()

    for y in range(diff.height):

        for x in range(diff.width):

            r, g, b = pixels[x, y]

            if r + g + b > 50:

                pixels[x, y] = (255, 0, 0)


    return diff


# ----------------------------------------------------

# Compare PDFs

# ----------------------------------------------------

def compare_pdfs(pdf1, pdf2):

    doc1 = fitz.open(pdf1)

    doc2 = fitz.open(pdf2)


    total_pages = max(len(doc1), len(doc2))


    for page in range(total_pages):

        print(f"šŸ” Comparing page {page + 1}")


        # ----- TEXT COMPARISON -----

        text1 = extract_text(pdf1, page)

        text2 = extract_text(pdf2, page)

        diff_text = text_diff(text1, text2)


        text_output = os.path.join(

            OUTPUT_DIR, f"page_{page + 1}_text_diff.txt"

        )

        with open(text_output, "w", encoding="utf-8") as f:

            f.write(diff_text)


        # ----- IMAGE COMPARISON -----

        try:

            img1 = render_page_image(pdf1, page)

            img2 = render_page_image(pdf2, page)


            diff_img = image_diff(img1, img2)

            img_output = os.path.join(

                OUTPUT_DIR, f"page_{page + 1}_image_diff.png"

            )

            diff_img.save(img_output)


        except Exception as e:

            print(f"⚠️ Image diff skipped for page {page + 1}: {e}")


    print("\n✅ PDF comparison complete.")

    print(f"šŸ“ Results saved in: {OUTPUT_DIR}")


# ----------------------------------------------------

# RUN

# ----------------------------------------------------

if __name__ == "__main__":

    pdf_a = input("Enter first PDF path: ").strip()

    pdf_b = input("Enter second PDF path: ").strip()


    compare_pdfs(pdf_a, pdf_b)


Smart Screen Recorder with Auto-Pause

import cv2

import numpy as np

import mss

import time

from datetime import datetime


# -----------------------------

# CONFIGURATION

# -----------------------------

FPS = 10

MOTION_THRESHOLD = 50000   # Higher = less sensitive

NO_MOTION_TIME = 2         # seconds to auto pause


# -----------------------------

# Setup screen capture

# -----------------------------

sct = mss.mss()

monitor = sct.monitors[1]   # Primary screen


width = monitor["width"]

height = monitor["height"]


fourcc = cv2.VideoWriter_fourcc(*"XVID")

output_file = f"screen_record_{datetime.now().strftime('%Y%m%d_%H%M%S')}.avi"

out = cv2.VideoWriter(output_file, fourcc, FPS, (width, height))


print("šŸŽ„ Screen recording started...")

print("🟢 Recording will pause automatically when screen is idle.")

print("šŸ”“ Press 'Q' to stop recording.\n")


prev_frame = None

last_motion_time = time.time()

recording = True


# -----------------------------

# Recording Loop

# -----------------------------

while True:

    img = np.array(sct.grab(monitor))

    frame = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    gray = cv2.GaussianBlur(gray, (21, 21), 0)


    if prev_frame is None:

        prev_frame = gray

        continue


    # Frame difference

    frame_diff = cv2.absdiff(prev_frame, gray)

    thresh = cv2.threshold(frame_diff, 25, 255, cv2.THRESH_BINARY)[1]

    motion_score = np.sum(thresh)


    if motion_score > MOTION_THRESHOLD:

        last_motion_time = time.time()

        recording = True

    else:

        if time.time() - last_motion_time > NO_MOTION_TIME:

            recording = False


    # Write frame only if motion exists

    if recording:

        out.write(frame)

        status_text = "RECORDING"

        color = (0, 255, 0)

    else:

        status_text = "PAUSED (No Motion)"

        color = (0, 0, 255)


    # Overlay status

    cv2.putText(

        frame,

        status_text,

        (20, 40),

        cv2.FONT_HERSHEY_SIMPLEX,

        1,

        color,

        2

    )


    cv2.imshow("Smart Screen Recorder", frame)

    prev_frame = gray


    if cv2.waitKey(1) & 0xFF == ord("q"):

        break


# -----------------------------

# Cleanup

# -----------------------------

out.release()

cv2.destroyAllWindows()


print(f"\n✅ Recording saved as: {output_file}")


Daily Habit Forecasting Using Time-Series

import pandas as pd

import matplotlib.pyplot as plt

from statsmodels.tsa.holtwinters import ExponentialSmoothing


# --------------------------------------------------

# Load & Prepare Data

# --------------------------------------------------

def load_habit_data(csv_path, habit_name):

    df = pd.read_csv(csv_path)

    df["date"] = pd.to_datetime(df["date"])


    habit_df = df[df["habit"] == habit_name]

    habit_df = habit_df.sort_values("date")


    habit_df.set_index("date", inplace=True)

    ts = habit_df["completed"]


    return ts


# --------------------------------------------------

# Forecast Habit Completion

# --------------------------------------------------

def forecast_habit(ts, days=7):

    model = ExponentialSmoothing(

        ts,

        trend="add",

        seasonal=None,

        initialization_method="estimated"

    )


    fitted_model = model.fit()

    forecast = fitted_model.forecast(days)


    return fitted_model, forecast


# --------------------------------------------------

# Risk Analysis

# --------------------------------------------------

def habit_risk_score(forecast):

    avg_completion = forecast.mean()


    if avg_completion < 0.4:

        return "🚨 High Risk (likely to break)"

    elif avg_completion < 0.7:

        return "⚠️ Medium Risk"

    else:

        return "✅ Low Risk (stable habit)"


# --------------------------------------------------

# Visualization

# --------------------------------------------------

def plot_forecast(ts, forecast, habit_name):

    plt.figure(figsize=(10, 5))


    plt.plot(ts.index, ts.values, label="Past Completion", marker="o")

    plt.plot(forecast.index, forecast.values, label="Forecast", linestyle="--", marker="x")


    plt.ylim(-0.1, 1.1)

    plt.ylabel("Habit Completed (1=yes, 0=no)")

    plt.title(f"Habit Forecast: {habit_name}")

    plt.legend()

    plt.grid(True)


    plt.show()


# --------------------------------------------------

# MAIN

# --------------------------------------------------

if __name__ == "__main__":

    csv_file = input("Enter CSV file path: ").strip()

    habit = input("Enter habit name (case-sensitive): ").strip()


    ts = load_habit_data(csv_file, habit)


    model, forecast = forecast_habit(ts, days=7)


    risk = habit_risk_score(forecast)


    print("\nšŸ“Š HABIT FORECAST REPORT")

    print("------------------------")

    print(f"Habit: {habit}")

    print(f"Next 7-day average completion: {forecast.mean():.2f}")

    print(f"Risk Level: {risk}")


    plot_forecast(ts, forecast, habit)


Local Password Strength Analyzer

import tkinter as tk

from tkinter import ttk

import math

import re


# ---------------------------

# Heuristics & helpers

# ---------------------------


COMMON_PASSWORDS = {

    "password", "123456", "123456789", "qwerty", "abc123",

    "letmein", "welcome", "admin", "iloveyou", "monkey"

}


SEQUENCES = [

    "abcdefghijklmnopqrstuvwxyz",

    "ABCDEFGHIJKLMNOPQRSTUVWXYZ",

    "0123456789",

    "qwertyuiop", "asdfghjkl", "zxcvbnm"

]


def shannon_entropy(password: str) -> float:

    """Approximate entropy based on character sets used."""

    pool = 0

    if re.search(r"[a-z]", password): pool += 26

    if re.search(r"[A-Z]", password): pool += 26

    if re.search(r"\d", password):    pool += 10

    if re.search(r"[^\w\s]", password): pool += 32  # symbols

    if pool == 0:

        return 0.0

    return len(password) * math.log2(pool)


def has_repeats(password: str) -> bool:

    return bool(re.search(r"(.)\1{2,}", password))  # aaa, 111


def has_sequence(password: str) -> bool:

    p = password

    for seq in SEQUENCES:

        for i in range(len(seq) - 3):

            if seq[i:i+4] in p:

                return True

    return False


def keyboard_walk(password: str) -> bool:

    walks = ["qwerty", "asdf", "zxcv", "poiuy", "lkjhg", "mnbv"]

    p = password.lower()

    return any(w in p for w in walks)


def analyze_password(password: str):

    issues = []

    score = 0


    # Length

    if len(password) < 8:

        issues.append("Too short (minimum 8 characters).")

    else:

        score += min(20, (len(password) - 7) * 3)


    # Character classes

    classes = 0

    classes += bool(re.search(r"[a-z]", password))

    classes += bool(re.search(r"[A-Z]", password))

    classes += bool(re.search(r"\d", password))

    classes += bool(re.search(r"[^\w\s]", password))

    score += classes * 10


    if classes < 3:

        issues.append("Use at least 3 character types (upper/lower/digits/symbols).")


    # Entropy

    ent = shannon_entropy(password)

    score += min(30, int(ent / 3))  # cap contribution


    if ent < 40:

        issues.append("Low entropy. Add length and variety.")


    # Patterns

    if password.lower() in COMMON_PASSWORDS:

        issues.append("Common password detected.")

        score -= 30


    if has_repeats(password):

        issues.append("Repeated characters detected (e.g., 'aaa').")

        score -= 10


    if has_sequence(password):

        issues.append("Sequential pattern detected (e.g., 'abcd', '1234').")

        score -= 10


    if keyboard_walk(password):

        issues.append("Keyboard pattern detected (e.g., 'qwerty').")

        score -= 10


    score = max(0, min(100, score))


    if score >= 80:

        verdict = "Strong"

    elif score >= 60:

        verdict = "Good"

    elif score >= 40:

        verdict = "Weak"

    else:

        verdict = "Very Weak"


    return {

        "score": score,

        "verdict": verdict,

        "entropy": round(ent, 1),

        "issues": issues

    }


# ---------------------------

# GUI

# ---------------------------


class App(tk.Tk):

    def __init__(self):

        super().__init__()

        self.title("Local Password Strength Analyzer")

        self.geometry("520x420")

        self.resizable(False, False)


        ttk.Label(self, text="Enter Password:", font=("Arial", 12)).pack(pady=10)

        self.pw = ttk.Entry(self, show="*", width=40)

        self.pw.pack()


        self.show_var = tk.BooleanVar(value=False)

        ttk.Checkbutton(self, text="Show password", variable=self.show_var,

                        command=self.toggle_show).pack(pady=5)


        ttk.Button(self, text="Analyze", command=self.run).pack(pady=10)


        self.score_lbl = ttk.Label(self, text="Score: —", font=("Arial", 12, "bold"))

        self.score_lbl.pack()


        self.ent_lbl = ttk.Label(self, text="Entropy: — bits")

        self.ent_lbl.pack(pady=5)


        self.verdict_lbl = ttk.Label(self, text="Verdict: —", font=("Arial", 12))

        self.verdict_lbl.pack(pady=5)


        ttk.Label(self, text="Feedback:", font=("Arial", 11, "bold")).pack(pady=8)

        self.feedback = tk.Text(self, height=8, width=60, wrap="word")

        self.feedback.pack(padx=10)


    def toggle_show(self):

        self.pw.config(show="" if self.show_var.get() else "*")


    def run(self):

        pwd = self.pw.get()

        res = analyze_password(pwd)


        self.score_lbl.config(text=f"Score: {res['score']}/100")

        self.ent_lbl.config(text=f"Entropy: {res['entropy']} bits")

        self.verdict_lbl.config(text=f"Verdict: {res['verdict']}")


        self.feedback.delete("1.0", "end")

        if res["issues"]:

            for i in res["issues"]:

                self.feedback.insert("end", f"• {i}\n")

        else:

            self.feedback.insert("end", "No issues found. Great password!")


if __name__ == "__main__":

    App().mainloop()

Image Duplicate Finder (Hash-Based)

import os

import tkinter as tk

from tkinter import filedialog, ttk, messagebox

from PIL import Image, ImageTk

import imagehash



class ImageDuplicateFinder:

    def __init__(self, root):

        self.root = root

        self.root.title("Image Duplicate Finder (Hash-Based)")

        self.root.geometry("900x600")


        self.image_hash_map = {}

        self.duplicates = []


        self.setup_ui()


    # ---------------------------------------------------------

    def setup_ui(self):

        top_frame = tk.Frame(self.root)

        top_frame.pack(fill=tk.X, pady=10)


        tk.Button(top_frame, text="Select Folder", command=self.select_folder).pack(side=tk.LEFT, padx=10)

        tk.Button(top_frame, text="Scan for Duplicates", command=self.scan_duplicates).pack(side=tk.LEFT, padx=10)


        self.result_tree = ttk.Treeview(self.root, columns=("img1", "img2"), show="headings")

        self.result_tree.heading("img1", text="Image 1")

        self.result_tree.heading("img2", text="Duplicate Image")

        self.result_tree.pack(fill="both", expand=True, pady=10)


        self.result_tree.bind("<Double-1>", self.show_preview)


    # ---------------------------------------------------------

    def select_folder(self):

        self.folder_path = filedialog.askdirectory()

        if self.folder_path:

            messagebox.showinfo("Selected Folder", self.folder_path)


    # ---------------------------------------------------------

    def scan_duplicates(self):

        if not hasattr(self, "folder_path"):

            messagebox.showerror("Error", "Please select a folder first!")

            return


        self.image_hash_map = {}

        self.duplicates = []

        self.result_tree.delete(*self.result_tree.get_children())


        supported_ext = (".jpg", ".jpeg", ".png", ".bmp")


        for filename in os.listdir(self.folder_path):

            if filename.lower().endswith(supported_ext):

                full_path = os.path.join(self.folder_path, filename)


                try:

                    img = Image.open(full_path)

                    img_hash = imagehash.average_hash(img)


                    if img_hash in self.image_hash_map:

                        self.duplicates.append((self.image_hash_map[img_hash], full_path))


                    else:

                        self.image_hash_map[img_hash] = full_path


                except Exception as e:

                    print("Error loading:", filename, e)


        # Show results in table

        for dup in self.duplicates:

            self.result_tree.insert("", tk.END, values=dup)


        if not self.duplicates:

            messagebox.showinfo("Result", "No duplicates found!")

        else:

            messagebox.showinfo("Result", f"Found {len(self.duplicates)} duplicate pairs.")


    # ---------------------------------------------------------

    def show_preview(self, event):

        selected = self.result_tree.focus()

        if not selected:

            return


        img1_path, img2_path = self.result_tree.item(selected, "values")

        self.preview_window(img1_path, img2_path)


    # ---------------------------------------------------------

    def preview_window(self, img1_path, img2_path):

        win = tk.Toplevel(self.root)

        win.title("Duplicate Image Preview")

        win.geometry("850x450")


        tk.Label(win, text=f"Image 1: {os.path.basename(img1_path)}", font=("Arial", 10)).pack(pady=5)

        tk.Label(win, text=f"Image 2: {os.path.basename(img2_path)}", font=("Arial", 10)).pack(pady=5)


        frame = tk.Frame(win)

        frame.pack(expand=True)


        # Load images

        img1 = Image.open(img1_path).resize((350, 350))

        img2 = Image.open(img2_path).resize((350, 350))


        img1_tk = ImageTk.PhotoImage(img1)

        img2_tk = ImageTk.PhotoImage(img2)


        left_label = tk.Label(frame, image=img1_tk)

        left_label.image = img1_tk

        left_label.pack(side=tk.LEFT, padx=10)


        right_label = tk.Label(frame, image=img2_tk)

        right_label.image = img2_tk

        right_label.pack(side=tk.RIGHT, padx=10)



# ---------------------------------------------------------

# RUN APP

# ---------------------------------------------------------

root = tk.Tk()

app = ImageDuplicateFinder(root)

root.mainloop()