Offliner banner

Offliner

8 devlogs
36h 40m 43s

Tired of buffering or losing access to your favorite tracks? Offliner is a robust media archiver built with Python and Flask. It doesn't just download; it cooks your media for the perfect offline experience. Leveraging yt-dlp and FFmpeg, it conver…

Tired of buffering or losing access to your favorite tracks? Offliner is a robust media archiver built with Python and Flask. It doesn’t just download; it cooks your media for the perfect offline experience. Leveraging yt-dlp and FFmpeg, it converts streams into high-quality formats while automatically embedding metadata and album art using Mutagen. It even integrates SponsorBlock to skip non-music segments automatically. With a privacy-first architecture that stores no user data and a slick Dark Mode UI, Offliner lets you take back control of your playlist.

This project uses AI

I used AI (LLMs) as a “pair programmer” to speed up development, specifically for:

  • Frontend Boilerplate: Generating the initial HTML/Bootstrap structure and CSS for the responsive cards and dark mode.
  • Regex & Parsing: Helping with the complex patterns needed to validate URLs and sanitize filenames.
  • Library Documentation: Quickly finding the correct methods for mutagen (ID3 tags) and yt-dlp configuration without digging through pages of docs.
  • Debugging: Troubleshooting FFmpeg conversion errors and threading issues in the download queue.
  • Documentation: Structuring and generating the text for the README.md file.
  • Logic: The core architecture, the integration of SponsorBlock, and the privacy-focused logic (no database) were designed and implemented by me.
Demo Repository

Loading README...

Fede Vitu

I recently had to migrate the live demo of Offliner. The reviewers informed me that hosting on Hugging Face is not allowed under the current deployment guidelines, even though my app is a full-stack project and not just an AI model. Since I cannot afford a paid hosting service that meets the processing requirements of this application, I decided to self-host the demo locally so the voting process can continue.

This new implementation took a massive amount of time, research, and trial and error. To make it work, I had to replace the computer’s operating system with a dedicated server OS, configure all the local networking and port forwarding, set up a custom domain, and properly route everything through Cloudflare to my “offliner” subdomain. I put my absolute best effort into this setup because I really wanted to ensure the project had a functional live demo for the community.

The app is now running 24/7 on an old spare computer at my house. It is powered by an AMD Athlon X2 270 processor with no dedicated GPU, 4GB of DDR3 RAM, and an internet connection with less than 1mb/s of upload speed. Because of these severe hardware and bandwidth constraints, I kindly ask you not to abuse the server. It can handle light testing, but it will crash if it receives too many simultaneous requests.

Please note that if the computer is idle for a while, the hard drive goes into a sleep state. This means your very first download attempt might fail or time out. If that happens, simply try again immediately, and the download will process correctly. This link is strictly for demonstration purposes. If you want to use the app to its full potential, I highly encourage you to clone the repository and run it locally on your own machine.

Attachment
Attachment
0
Fede Vitu

Just shipped a quick hotfix. I found and resolved an annoying bug that was causing some downloads to freeze and get completely stuck right before starting. The queue is now working perfectly again :)

Attachment
0
Fede Vitu

Shipped this project!

Hours: 33.79
Cookies: 🍪 966
Multiplier: 28.59 cookies/hr

I am incredibly proud to finally ship Offliner, a project that evolved from a simple Python script into a fully scalable, enterprise-grade media archiver. Offliner allows users to curate and download media for offline use, featuring intelligent integrations like SponsorBlock to automatically skip non-music segments and native metadata embedding,.

The biggest challenge by far was the deployment phase. Moving from a standard local Flask environment to building a Docker container was a completely new and difficult experience for me. It took a lot of trial and error to correctly containerize the web server, the Redis background workers, and dependencies like FFmpeg. Finding a suitable hosting service that could handle this asynchronous architecture was also tough, but I eventually managed to deploy it successfully on Hugging Face.

I am most proud of the backend architecture and the user experience. I decoupled the heavy downloading tasks from the web server using Redis Queue (RQ), meaning the app handles multiple requests asynchronously without freezing. I also implemented Server-Sent Events (SSE) to feed real-time download progress directly to the frontend, built a robust anti-abuse system with strict rate limits (by IP, download counts, and content duration), and completely redesigned the UI with fully responsive modals and modern toast notifications.

Please note: The live link provided is simply a demo to showcase the functionality. It is running on limited hardware and is not intended or provisioned to be a server for massive bulk downloads.

Fede Vitu

This is the biggest update since I started the project. I have spent a huge amount of time and effort refactoring the entire application because I didn’t want Offliner to be just another “personal script”, I wanted to build it with a scalable, enterprise-grade architecture.

I completely split the application logic. The web server is now lightweight, while heavy download tasks are offloaded to background workers using Redis Queue (RQ). This makes the app truly asynchronous and scalable,,you could technically run multiple worker nodes to handle hundreds of simultaneous downloads without freezing the UI.

Key Technical Improvements:

  • I rewrote logic.py, optimizing ~2700 lines down to ~2400 efficient lines and switching to native yt-dlp metadata embedding for stability.
  • Implemented Server-Sent Events (SSE) to stream the download progress to the user instantly (no more guessing if it’s stuck!).
  • I added a real-time validator for Netscape Cookies.
  • I included a Dockerfile and start.sh so it can be deployed anywhere with a single command.

It was a challenging refactor, but the app is now robust, faster, and ready for the real worldd 🚀

0
Fede Vitu

I have implemented a major redesign of the user interface to improve accessibility and responsiveness across all devices. The Download Settings menu has been moved from the navigation bar to the main body of the page and now opens in a fully responsive modal window instead of a side panel, offering a cleaner and more organized layout.

I also added a “Paste” button that integrates with the system clipboard to instantly paste URLs and trigger the search automatically. The notification system was completely overhauled with modern “Toast” alerts that feature entrance and exit animations, context-aware styling, and a visual progress bar indicating the auto-dismiss time.

On the visual side, the top bar is now fixed with a blur effect, and I fixed several CSS issues to ensure the content adapts vertically on small screens without overflowing. Finally, I included a legal disclaimer footer to clarify the terms of use regarding content distribution and copyright.

Attachment
Attachment
Attachment
0
Fede Vitu

I have been working heavily on the core stability of the application to ensure it is easy to maintain in the long run. My main focus was implementing a comprehensive anti-abuse system that allows configuring limits via environment variables, restricting downloads by quantity, duration, and frequency per IP to protect the server.

I also refactored the interface to use a unified design for both videos and playlists, making the result containers more compact to reduce scrolling. On the backend, I optimized FFmpeg commands for faster processing, added support for parsing full Spotify albums, and fixed specific bugs like WAV metadata visibility. Finally, I streamlined the download logic to force a choice between audio or video, preventing previous conflicts and ensuring a reliable experience.

Attachment
0
Fede Vitu

I realized that sometimes you want a video, and sometimes just the audio, but changing the global settings every time is annoying. So, I added Per-Download Customization! You can now choose the format and type for each item individually without touching the main recipe.
Other spicy updates:

  • Modern Formats: I swapped out the old AVI/FLAC containers for MKV and WEBM. FFmpeg processes them much faster and they play nicer with modern players.
  • Transparency: Search results now feature a SponsorBlock badge that shows exactly how many minutes of “filler” (intros, promos) you are saving per video. ⏱️
    The app feels much more flexible now!
Attachment
0
Fede Vitu

No more copy-pasting! Search is here 🔎
I got tired of switching tabs to copy URLs from YouTube, so I decided to build a search engine directly into Offliner.
New stuff:

  • Integrated Search: You can now query YouTube and YouTube Music directly from the dashboard to find your ingredients faster.
  • Automatic Cleanup: Implemented a backend logic to wipe the temporary directory after processing. No more storage clutter!
  • Code Refactor: Cleaned up the Flask templates to make the frontend modular and easier to maintain.
Attachment
0
Fede Vitu

Say hello to Offliner. I wanted a tool to keep my media library organized without relying on sketchy websites.
I’ve just finished the main UI using Bootstrap with a custom Dark Mode (essential for late-night coding). I also implemented a robust configuration panel where you can toggle specific filters like “Music Offtopic” or “Interactions”.
Best part? The backend is completely stateless, no databases, no tracking. It processes your request in-memory and hands you the file. Clean and simple.

Attachment
1

Comments

RespectableDot
RespectableDot about 2 months ago

Nice