SkillAgentSearch skills...

Turron

A search system that analyzes short video snippets (2–5 secs) and finds highly accurate matches using keyframe-based perceptual hashing; Selfhosted Video Shazam;

Install / Use

/learn @Fl1s/Turron

README

<a id="readme-top"></a>

<!-- PROJECT SHIELDS --> <p align="center">

[![Contributors][contributors-shield]][contributors-url] [![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![Apache 2.0 License][license-shield]][license-url]

</p> <!-- PROJECT LOGO --> <div align="center"> <p align="center"> <img width="480" height="480" alt="turron-logo-readme" src="https://github.com/user-attachments/assets/d0ba8800-3067-4f7c-a554-19aac4833c7b" /> </p>

https://github.com/user-attachments/assets/8bf90c7a-ce68-4d38-a140-e363fc421395

https://github.com/user-attachments/assets/5651a9fb-029d-4126-b192-ba42ca269a5d

https://github.com/user-attachments/assets/db4aef2f-349c-499e-bcb6-a3aac1d57e1a

<p align="center"> . <a href="#quickstart"><strong>Quickstart</strong></a> </p>

· <a href="https://github.com/fl1s/turron/issues/new?labels=bug">Report Bug</a> · <a href="https://github.com/fl1s/turron/issues/new?labels=enhancement">Request Feature</a>

</p> </div> <!-- SKILL ICONS --> <p align="center"> <img src="https://skillicons.dev/icons?i=java,spring,postgres,kafka,docker,kubernetes,prometheus,grafana,gradle,postman,git" /> </p> <!-- TABLE OF CONTENTS --> <details> <summary>Table of Contents</summary> <ol> <li> <a href="#about-the-project">About</a> <ul> <li><a href="#microservices">Microservices</a></li> <li><a href="#built-with">Built With</a></li> </ul> </li> <li> <a href="#getting-started">Getting Started</a> <ul> <li><a href="#prerequisites">Prerequisites</a></li> <li><a href="#installation">Installation</a></li> </ul> </li> <li><a href="#usage">Usage</a></li> <li><a href="#ci-cd">CI/CD</a></li> <li><a href="#monitoring">Monitoring</a></li> <li><a href="#roadmap">Roadmap</a></li> <li><a href="#contributing">Contributing</a></li> <li><a href="#license">License</a></li> <li><a href="#contact">Contact</a></li> </ol> </details> <!-- ABOUT THE PROJECT -->

About The Project

A video recognition system that works like Shazam — but for video. It analyzes short snippets (2–5 seconds), breaks them into keyframes, and uses perceptual hashing to identify the exact or near-exact source, even if the clip has been edited or altered. This preserves the full context of the snippet and enables reliable tracking of original video content.

Key features:

  • Upload full video snippets, not just images — automatic extraction of keyframes for context-aware matching.
  • Accurate source identification via perceptual hashing tolerant to modifications.
  • Optimized for quick, precise matching of short video fragments.
  • Scalable microservices architecture built to handle heavy traffic without performance loss.
<p align="right">(<a href="#readme-top">back to top</a>)</p>

Microservices

Turron is structured into 6 microservices, each with bounded responsibilities:

  • Eureka Server: Manages service discovery using Netflix Eureka with @DiscoveryClient.

  • Upload Service: Accepts short videos via REST API, stores them in MinIO, and sends processing tasks to Kafka.

    <img width="900" alt="upload-service" src="https://github.com/user-attachments/assets/21d8f136-0eab-40de-9be3-21d73094c03a" />
  • Frame Extraction Service: Extracts 5-10 keyframes from videos using FFmpeg, normalizes orientation for robustness, and forwards frames to Kafka for hashing.

<img width="900" alt="extraction-first" src="https://github.com/user-attachments/assets/6d6e7850-062d-45bb-81b2-ddde60c6a0fb" />

...

<img width="900" alt="extraction-third" src="https://github.com/user-attachments/assets/3effd378-634a-41c2-b0c2-2cd770780647" />
  • Hashing Service: Computes pHashes for keyframes and stores it in database. <img width="1130" alt="hashing-first" src="https://github.com/user-attachments/assets/db3dfc52-741a-41ea-bdba-6ca57b2c4ef1" />

... <img width="1269" alt="hashing-third" src="https://github.com/user-attachments/assets/5bbfea23-7659-4613-b427-4298cd9dfe6b" />

  • Search Service: Matches snippet videos to source videos using perceptual hash comparisons with sliding-window Hamming distance, storing results in database. <img width="999" alt="cleanup" src="https://github.com/user-attachments/assets/635f377e-6233-4a19-9e22-5d8541cbd4f0" />
<img width="1232" alt="another snippet bc previous is cleaned up" src="https://github.com/user-attachments/assets/8d11e6ca-143b-463b-be5e-10450c162156" />
  • API Gateway: Centralized REST API endpoint managing requests, authentication, and response aggregation.
<p align="right">(<a href="#readme-top">back to top</a>)</p>

Built With

  • [![Java][Java]][Java-url] [![Gradle][Gradle]][Gradle-url] [![Spring Boot][Spring]][Spring-url] [![PostgreSQL][PostgreSQL]][PostgreSQL-url] [![Kafka][Kafka]][Kafka-url]
  • [![Docker][Docker]][Docker-url] [![Kubernetes][Kubernetes]][Kubernetes-url] [![Prometheus][Prometheus]][Prometheus-url] [![Grafana][Grafana]][Grafana-url]
<p align="right">(<a href="#readme-top">back to top</a>)</p>

<a id="quickstart"></a>

Quickstart

  1. Clone the repository:
    git clone https://github.com/fl1s/turron.git
    
  2. Navigate to the project directory:
    cd turron
    
  3. Create .env.dev file from the .env.example:
    cd .config/secrets
    
    bash / zsh / powerShell
    cp .env.example .env.dev
    
    cmd
    copy .env.example .env.dev
    
  4. Start the dev environment with Docker Compose:
    docker-compose --env-file .config/secrets/.env.dev up
    
  5. Verify services are running:
    docker ps
    
  6. Go to the <a href="#api">API Endpoints</a>
<!-- GETTING STARTED -->

Getting Started (advanced)

Set up Turron locally using Docker Compose for the dev environment or deploy to Kubernetes for production.

Prerequisites

Ensure you have the following installed:

  • Java 21
  • Gradle
  • Docker and Docker Compose
  • kubectl (for prod environment)
  • PostgreSQL, Kafka, MinIO (or use Docker Compose)
    java --version
    gradle --version
    docker --version
    

Installation

  1. Clone the repository:
    git clone https://github.com/fl1s/turron.git
    
  2. Navigate to the project directory:
    cd turron
    
  3. Build all microservices with Gradle:
    cd microservice-name
    ./gradlew clean build
    
  4. Start the dev environment with Docker Compose:
    docker-compose up -d
    
  5. Verify services are running:
    docker ps
    
<p align="right">(<a href="#readme-top">back to top</a>)</p> <!-- API ENDPOINTS -->

<a id="api"></a>

API Endpoints

Upload snippet-video

POST {{api-gateway}}/api/v1/upload/snippet

Form Data:

| Field | Description | Type | |-------|----------------|------------| | file | MP4 video file | file (mp4) |

Response:

{
  "snippetId": "..."
}

Upload source-video

POST {{api-gateway}}/api/v1/upload/source

Form Data:

| Field | Description | Type | |-------|----------------|------------| | file | MP4 video file | file (mp4) |

Response:

{
  "sourceId": "..."
}

Find best-match

GET {{api-gateway}}/api/v1/search/best-match/:snippetId

Path Parameter:

| Parameter | Description | Type | |-----------|------------------|--------| | snippetId | Snippet video ID | string |

Response:

{
  "downloadUrl": "..."
}

CI/CD

This project uses GitHub Actions.

The .github/workflows/build.yml workflow runs on every push and pull request to the main branch. It performs the following steps:

  1. Checks out the repository
  2. Sets up Java 21 using the Temurin distribution
  3. Caches Gradle dependencies to speed up builds
  4. Builds each service defined in the job matrix:
    • eureka-server
    • upload-service
    • extraction-service
    • hashing-service
    • search-service
    • api-gateway
  5. Authenticates to GitHub Container Registry (GHCR)
  6. Builds and pushes Docker images using a composite action located at .github/actions/docker-build-push

Each Docker image is tagged with:

  • latest
  • a short Git commit SHA
  • a date-based tag in YYYYMMDD format
<!-- MONITORING -->

Monitoring

Our project includes out-of-the-box monitoring setup using Prometheus and Grafana.

How it works

  • Each microservice exposes metrics via Spring Boot Actuator on the /actuator/prometheus endpoint.
  • Prometheus scrapes these endpoints regularly to collect metrics.
  • Grafana connects to Prometheus as a data source to visualize metrics on dashboards.

Prometheus configuration

Prometheus config is located at:
monitoring/prometheus/prometheus.yml

Folder structure

  • monitoring/prometheus/ — Prometheus config files
  • monitoring/grafana/ — Grafana dashboards and config files

Getting started

  1. Start Prometheus using the config from monitoring/prometheus/prometheus.yml(it's already configured in docker-compose).
  2. Start Grafana and add Prometheus as a data source (http://localhost:9090).
  3. Create your dashboards in Grafana or import community dashboards for Spring Boot metrics.
  4. Access your dashboards to monitor service health, performance, and custom metrics.

Cloudflare (optional)

  1. In Zero Trust you need to go to Network -> Tunnels, then create a new tunnel with the name of your domain.
  2. Get the token and put its value in the field CLOUDFLARED_TUNNEL_TOKEN in .config/secrets/.env.prod.
  3. In published application routes, set root route to nginx:80.
  4. Also, don't forget to set the minio subdomain (s3.yourdomain) and route to nginx:80.
  5. In `Additi
View on GitHub
GitHub Stars69
CategoryContent
Updated19d ago
Forks5

Languages

Java

Security Score

100/100

Audited on Mar 13, 2026

No findings