Skip to content

CopyCat bridges the gap between Zurg and Local Storage through a clean web interface. https://discord.gg/Dy5xNzEHKw

License

Notifications You must be signed in to change notification settings

Woahai321/copy-cat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

25 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

CopyCat Logo Nuxt FastAPI Docker Vue Python GitHub Actions

What is it? Why? Interface Quick Start Deployment Configuration Technical Support


😸 What is CopyCat?

CopyCat is a self-hosted media management tool for digital libraries. It bridges the gap between Cloud Storage (such as Zurg or Rclone mounts) and Local Storage (HDD/NAS).

CopyCat provides a web interface to scan, organize, and copy media files across different storage locations.

πŸ—οΈ Why I built this?

CopyCat was born out of a desire to simplify a cumbersome workflow.

My setup involved managing 300TB of media in Zurg alongside 16TB of local storage. I often wanted to bring specific content "offline" to my local drives to ensure it was always ready to go. My manual process was painful:

  1. Add a torrent hash to Real-Debrid via DMM or SeerrBridge.
  2. Remote desktop into the host machine (often from a phone).
  3. Manually copy folders from the Zurg directory to the local drive.

Remote desktopping from a phone is a "pain," and I felt there could be a cleaner way. CopyCat provides that solution.

😻 Interface Overview

CopyCat Dashboard


πŸ“Έ View More Screenshots

Media Library

Browse content through a categorized interface. Filter by movies or TV shows, view metadata, and select items for transfer.

Media Library

Media Library View

Copy Wizard

Prefer a traditional view? The Copy Wizard offers a familiar file explorer interface, allowing you to manually navigate directory structures and define precise destinations for your transfers.

Copy Wizard

File Explorer & Copy Wizard

Transfer Queue

Monitor active transfers in real-time. View detailed progress, transfer speeds, and manage your queue with priority controls to ensure your most important media is ready when you are.

Transfer Queue

Live Transfer Queue


😸 Quick Start (Docker Command)

Run CopyCat with this single Docker command:

Warning

Configuration Required: You MUST replace /path/to/source, /path/to/destination, and JWT_SECRET_KEY with your actual paths and a secure secret.

docker run -d --name copycat -p 4222:3000 -p 4223:8000 -v "$(pwd)/data":/data -v /path/to/source:/mnt/source:ro -v /path/to/destination:/mnt/destination -e JWT_SECRET_KEY=change_this_to_secure_random_string ghcr.io/woahai321/copy-cat:main

Tip

Access the App: The Web Interface is at http://localhost:4222 and the API at http://localhost:4223. Login with admin / changeme.


😽 Deployment

Deployment Instructions

CopyCat is deployed using Docker.

1. Requirements

  • A machine running Docker & Docker Compose.
  • A Source Path (e.g., /mnt/zurg or any folder with media).
  • A Destination Path (e.g., /mnt/media where you want files to go).

2. Setup

Clone the repo and configure your environment:

git clone https://github.com/woahai321/copy-cat.git
cd copy-cat
cp .env.example .env

3. Configure

Edit .env to match your paths:

# Where your media is getting READ from (ReadOnly recommended)
SOURCE_PATH=/mnt/zurg

# Where you want your media COPIED to
DESTINATION_PATH=/mnt/local/media

# Security: Set a strong random password!
JWT_SECRET_KEY=change_me_to_something_secure

[!CAUTION] Production Security: Ensure the JWT_SECRET_KEY is a unique, randomly generated string. Do not use the default value in public deployments.

4. Launch

docker-compose up -d

5. Login

  • Web Interface: http://localhost:4222
  • Backend API: http://localhost:4223/api/docs
  • User: admin
  • Password: changeme

Need more help? Check out the Deployment Guide or Configuration Reference.

πŸ™€ Technical Overview

graph TD
    %% Theme - Cyberpunk Purple
    classDef purple fill:#2e1065,stroke:#7c3aed,color:#fff,rx:5,ry:5,stroke-width:2px;
    classDef light fill:#5b21b6,stroke:#8b5cf6,color:#fff,rx:5,ry:5,stroke-width:2px;
    classDef accent fill:#7c3aed,stroke:#a78bfa,color:#fff,rx:5,ry:5,stroke-width:2px;
    classDef external fill:#0f172a,stroke:#334155,color:#94a3b8,rx:5,ry:5,stroke-dasharray: 5 5;

    subgraph "External Ecosystem"
        Cloud[(Zurg/Rclone)]:::external
        Trakt[Trakt.tv API]:::external
        TMDB[TMDB/Fanart]:::external
    end

    subgraph "Host Infrastructure"
        Mount[Filesystem Mount]:::purple
        LocalDest[(Local/NAS Storage)]:::purple
    end

    subgraph "CopyCat Core"
        direction TB
        
        subgraph Pipeline ["1. Ingestion Engine"]
            Watcher[File Watcher]:::light
            Scanner[Recursive Scanner]:::light
            Regex{Regex Parsing}:::accent
            Matcher[Media Matcher]:::light
        end

        subgraph Data ["2. Persistence Layer"]
            DB[(SQLite Database)]:::purple
            ImgCache[Image/Asset Cache]:::purple
        end

        subgraph Backend ["3. Application Server"]
            API[FastAPI REST Layer]:::light
            Auth{JWT Auth}:::accent
            WS[WebSocket Manager]:::accent
            Scheduler[Task Scheduler]:::light
        end
        
        subgraph Execution ["4. Transfer Engine"]
            Queue[Job Queue]:::light
            WorkerPool[Worker Thread Pool]:::accent
            IO[IO Stream Manager]:::light
        end
    end

    subgraph "Presentation"
        UI[Nuxt.js Frontend]:::purple
        Store[Pinia State]:::light
    end

    %% Data Flow Relationships
    Cloud ==> Mount
    Mount -.-> Scanner
    
    Scanner --> Regex
    Regex --> Matcher
    Matcher <--> Trakt
    Matcher <--> TMDB
    Matcher --> DB
    Matcher --> ImgCache

    UI <--> API
    API <--> DB
    API --> WS
    WS -.->|Real-time Events| UI
    
    UI -- "Dispatch Copy" --> API
    API --> Queue
    Queue --> WorkerPool
    WorkerPool --> IO
    
    IO -- "Read Stream" --> Mount
    IO -- "Write Stream" --> LocalDest
    IO -- "Progress Events" --> WS
Loading
  1. Ingestion Layer: The system mounts your cloud storage (Zurg/Rclone) to the local filesystem, making it accessible as standard files.
  2. Processing Layer: The Scanner Engine recursively reads files, cleaning filenames with Regex and enriching them with metadata/posters via the Trakt API.
  3. Persistence Layer: All library data is structured and stored in a SQLite Database, while images are cached locally for offline performance.
  4. Application Layer: The FastAPI Backend serves data to the Nuxt Frontend, ensuring a reactive, real-time user experience via WebSockets.
  5. Execution Layer: When you initiate a copy, the Queue Manager spawns optimized workers to stream data from Source to Destination efficiently.

😺 Documentation

😺 Support CopyCat's Development

If CopyCat saves you time, consider sponsoring:

➑️ GitHub Sponsors

Thank you.

🐱 Contributing

Welcome! See Developer Guide for Nuxt + FastAPI setup.

🐱 License

MIT License

Star History

Star History Chart