Library / SDK
sharatsachin/ytplaylist-len avatar
sharatsachin/ytplaylist-len

ytplaylist-len: turning a YouTube playlist into a finish date

A small web app to get the lengths of playlists on YouTube

917 stars126 forksPythonLicense varies

At a glance

What is it?
ytplaylist-len is a small FastAPI web app that reads a YouTube playlist or video and reports its total duration at different playback speeds, with a watch schedule calculator that turns hours per week into a real finish date. It is a single service with Redis caching, MongoDB analytics and 27 locales, and the author is not looking for contributions.
Who is it for?
ytplaylist-len suits anyone who wants to know how long a course playlist actually takes and when they will finish it, and it is a readable reference for a small FastAPI service that mixes caching, internationalisation and server rendered templates. It does not suit a team that needs an API to depend on, since the project is a web app rather than a published library, and it does not suit anyone who cannot supply a YouTube Data API key.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 101 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The core question is how long a playlist takes, not what is in it

ytplaylist-len is a small web app for getting the lengths of playlists on YouTube, hosted at ytplaylist-len.sharats.dev. The pitch in the project's own words is to analyze YouTube playlists and videos with ease, get detailed information about video durations and playlist lengths, and plan your watch schedule.

That is a narrower purpose than a YouTube client, and the narrowness is the point. The app exists because knowing a playlist has forty videos is not the same as knowing it is eleven hours long, and neither tells you whether you will get through it before the course deadline.

The feature list sets the scope. Multiple playlists and individual videos can be analyzed in one request, up to five. Total duration is calculated at 1.25x, 1.50x, 1.75x, 2.00x and custom speeds. Specific video ranges within a playlist can be analyzed, up to 500 videos.

The most interesting feature is the watch schedule calculator, where you enter hours per day and which days of the week you watch, and get back a real finish date and a progress ring. That is the piece that turns a duration into a plan.

Two side features sit alongside it. There is a YouTube thumbnail downloader at /thumbnails and a YouTube timestamp link generator at /timestamp, both small utilities that share the same parsing machinery rather than existing as separate applications.

The API key is spread across the clock to dodge quota limits

Underneath, the app talks to the YouTube Data API v3, and the interesting engineering detail is in the environment configuration rather than the UI.

The .env file takes several values.

code
APIS=your_youtube_api_key
REDIS_URL=redis://localhost:6379
MONGO_URL=mongodb://localhost:27017
BASE_URL=https://ytplaylist-len.sharats.dev

The APIS variable is plural and accepts multiple API keys separated by a semicolon. The documented behaviour is that the app time-slices between them based on the current hour to spread quota load. That is a pragmatic response to the fact that the YouTube Data API quota is a fixed daily allowance per project, and that a popular playlist analysis will exhaust a single key quickly.

Time-slicing by hour means the key used at any moment depends on the clock, so different requests hit different keys. The offline test suite names the helper that implements this, pick_api_key, alongside extract_video_id and parse, which tells you the selection logic is factored into a testable function rather than buried in a request handler.

The rest of the stack is conventional for a Python web service. FastAPI with the standard extras, uvicorn and gunicorn for serving, python-dotenv for configuration, Jinja2 for templates, aiohttp for async HTTP, redis for playlist caching, pymongo for analytics, isodate for duration parsing and markdown-it-py for the blog.

The Redis cache has a 24 hour TTL and the YouTube API calls run in parallel asynchronously, which is the right pairing for the workload. A playlist's duration does not change often, so caching it for a day removes most of the quota pressure, and issuing the per-video detail calls concurrently keeps the response time down.

Running it locally, and the tests that need no API key

The setup path is conventional Python.

code
git clone https://github.com/sharatsachin/ytplaylist-len.git
cd ytplaylist-len
pip install -r requirements.txt

After creating the .env file with the values above, the app runs with the FastAPI development server.

code
fastapi dev app.py

Then you open http://localhost:8000. The repository also ships a Procfile, which is what the Render hosting target consumes.

The test setup is worth a look, because it is split deliberately into offline and online halves. The offline tests need no YouTube API key.

code
pip install -r requirements-dev.txt
pytest

According to the documentation, the offline tests cover URL and ID parsing through get_id and get_item_ids, the utility helpers extract_video_id, parse and pick_api_key, and the playlist range and video-order logic using mocked API responses.

The online tests run against the real API when a key is present.

code
pytest --run-online

They fetch a known public video and that video's channel uploads playlist, or a playlist you set through YOUTUBE_TEST_PLAYLIST_ID, exercise call_youtube_api and run end-to-end ItemList and Playlist flows. The documentation notes these consume a small amount of API quota, around 5 to 15 units per run, and gives optional overrides YOUTUBE_TEST_VIDEO_ID and YOUTUBE_TEST_PLAYLIST_ID.

Splitting the suite this way is the right approach for a project with a metered upstream dependency. The offline tests are fast and free and cover the parsing logic where bugs are most likely, and the online tests are opt-in so a normal test run does not silently consume quota or fail because a key expired.

Internationalisation as twenty-seven JSON files and one registry entry

The app supports 27 languages, with URL prefixes such as /es/, /fr/, /ja/, /ta/ and /bn/, and hreflang alternates for search engines.

The structure makes adding a language a four step process, and the documentation is unusually blunt about how little work it is. Copy locales/en.json to locales/xx.json, translate the values while keeping the keys unchanged, add a LocaleInfo entry to SUPPORTED_LOCALES in src/i18n.py, and restart the app. The documentation states that the URL prefix routing and hreflang alternates then work automatically.

That last point is the one worth pausing on. Hand-maintaining hreflang alternates across 27 locales for every page is the kind of thing that quietly rots, so generating them from the locale registry is the right call. The src/i18n.py module is described as a locale loader plus translator factory, and locales/ holds 27 JSON translation files.

The templates show how the pages are composed. base.html carries the shared layout, the SEO tags and JSON-LD, home.html holds the playlist calculator, the schedule calculator, an FAQ block and a HowTo block, thumbnails.html and timestamp.html are the utility pages, and templates/blog/ holds the blog list and post templates.

There is also a blog, with content/blog/en/ holding Markdown posts with YAML frontmatter and src/blog.py as the loader. That is a content marketing surface rather than a functional requirement, and it is worth naming as such, because it is the part of the codebase a reader evaluating the core calculation logic can safely ignore.

Where the app stops and what to build instead

The limits are structural, and they come from the same design decisions that make the app pleasant.

The first is that it needs a YouTube Data API key, and the project does not describe any unauthenticated fallback. Every calculation depends on metadata the API returns. For a personal instance that is a five minute setup with a free quota. For anyone trying to run this at a scale that exhausts the daily allowance, the multiple-key time-slicing helps but does not create quota that does not exist.

The second is the range and count limits: up to five playlists or videos per request, up to 500 videos per playlist range. These are the kind of caps that exist to keep a single request inside an acceptable latency and quota envelope, and they mean the tool is not a bulk data pipeline.

The third is the biggest one for anyone thinking of depending on it. This is a web application, not a library. The package name, the structure and the Procfile all point to a deployable service rather than something you add to your requirements.txt. The code is small and readable enough to fork, and the documentation says as much in the contributing section, but there is no importable API.

The alternative approach for the same underlying question is to skip the server entirely. A script that calls the YouTube Data API directly and prints the durations is a hundred lines of Python, needs no Redis, no MongoDB, no template engine and no locale registry. The trade is that you lose the schedule calculator, the 27 languages, the caching and the shared links that the hosted version gives you for free.

Maintenance state and the invitation to fork rather than contribute

The last push was on 2026-07-14, and the repository has no GitHub releases, so there is no version history to consult and no tag to pin. The topics list only onrender-deploy and webapp, which matches the shape of the project, a single deployed service rather than a distributed library.

The contributing section is the most informative paragraph in the documentation, and it says something specific. The author states plainly that he is not looking for contributions to the repository and will not be actively watching it, while inviting people to fork it and make their own changes.

That is unusual and worth taking at face value. It is a finished personal project rather than a community project, and the correct expectation to set is that you will be maintaining your own fork. There is no maintainer responsiveness to plan around, but there is also no roadmap to wait for.

The licence field on the repository says unknown, and unlike most of the projects with a stated licence, this one does not point at an Apache, MIT or BSD file. The root contains a requirements.txt, a Procfile and the source, but no licence file is listed among the top level entries. For a fork, that gap is the first thing to resolve, since without an explicit licence grant you do not have permission to redistribute the code even though it is public. This is not legal advice, and the practical step is to ask the author or to treat the code as unusable for redistribution until the terms are clear.

Everything else about the project reads as a small, well organised FastAPI service: Python 3.13, a separate templates and static tree, a client-side reactive schedule calculator in static/js/schedule.js, inline form validation in form_validation.js, and a pytest.ini at the root.

Editorial conclusion

ytplaylist-len suits anyone who wants to know how long a course playlist actually takes and when they will finish it, and it is a readable reference for a small FastAPI service that mixes caching, internationalisation and server rendered templates. It does not suit a team that needs an API to depend on, since the project is a web app rather than a published library, and it does not suit anyone who cannot supply a YouTube Data API key. Before adopting or forking it, read the caching and key selection code in src/playlist.py and src/utils.py, because the quota spreading behaviour across multiple keys is the part that decides whether it keeps working as your quota grows.

Frequently asked questions

What does ytplaylist-len do?

It is a FastAPI web app that analyzes YouTube playlists and videos to report their total duration, calculates that duration at 1.25x, 1.50x, 1.75x, 2.00x and custom playback speeds, and uses a watch schedule calculator to turn hours per day and chosen weekdays into a finish date.

How do I run ytplaylist-len locally?

Clone the repository, run pip install -r requirements.txt, create a .env file with APIS, REDIS_URL, MONGO_URL and BASE_URL, then start it with fastapi dev app.py and open http://localhost:8000.

Can I run the ytplaylist-len tests without a YouTube API key?

Yes. The offline suite runs with pytest after pip install -r requirements-dev.txt and covers URL and ID parsing, utility helpers including pick_api_key, and playlist range logic with mocked API responses. The live tests need a key and run with pytest --run-online.

How does ytplaylist-len handle YouTube API quota?

It caches playlist data in Redis with a 24 hour TTL and issues API calls in parallel asynchronously. You can also supply multiple API keys in the APIS variable separated by a semicolon, and the app time-slices between them based on the current hour to spread quota load.

Is ytplaylist-len accepting contributions?

No. The contributing section states that the author is not looking for contributions and will not be actively watching the repository, and invites people to fork it and make their own changes instead.

Official sources

  1. Issues
  2. Project website
  3. README
  4. sharatsachin/ytplaylist-len on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sharatsachin-ytplaylist-len.svg)](https://hysenlabs.com/projects/sharatsachin-ytplaylist-len)

Was this useful?