Metadata-Version: 2.4
Name: ranktube
Version: 0.2.0
Summary: YouTube search CLI and browser UI that ranks results by relevance using YouTube Data API v3. Supports keyword scoring, channel filtering, multiple output modes, and a Streamlit UI with first-run setup.
Author: Manjunath Shetty
License-Expression: MIT
Project-URL: Homepage, https://github.com/mjgit007/ranktube
Project-URL: Repository, https://github.com/mjgit007/ranktube
Project-URL: Bug Tracker, https://github.com/mjgit007/ranktube/issues
Keywords: youtube,search,ranking,cli,relevance,api
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: google-api-python-client>=2.0.0
Requires-Dist: google-auth>=2.0.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: ui
Requires-Dist: streamlit>=1.32.0; extra == "ui"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Provides-Extra: all
Requires-Dist: ranktube[dev,ui]; extra == "all"

# RankTube

Search YouTube and rank results by relevance — not by YouTube's default algorithm.

RankTube is available as a **CLI tool** and a **browser UI**. It queries YouTube using the Data API v3, scores each video against your keywords across title, description, tags, and channel name, then returns a ranked, filtered list. Use it for research, content auditing, or building keyword-monitoring pipelines.

---

## Installation

### CLI only
```bash
pip install ranktube
```
Installs the `ranktube` and `rt` commands.

### CLI + Browser UI
```bash
pip install ranktube[ui]
```
Also installs the `rt-ui` command that opens the browser interface.

### Everything (CLI + UI + dev tools)
```bash
pip install ranktube[all]
```

### Recommended: isolated install with pipx
```bash
pipx install ranktube        # CLI only
pipx install ranktube[ui]    # CLI + UI
```
[pipx](https://pipx.pypa.io/) installs CLI tools in isolated environments and puts them on your PATH automatically.

---

## Getting a YouTube API Key

RankTube requires a **YouTube Data API v3** key. It is free and takes about 5 minutes to set up.

**Step 1 — Open Google Cloud Console**
Go to [console.cloud.google.com](https://console.cloud.google.com/) and sign in with your Google account.

**Step 2 — Create a project**
Click the project dropdown at the top → **New Project** → give it a name (e.g. `ranktube`) → **Create**.

**Step 3 — Enable the YouTube Data API v3**
In the left menu: **APIs & Services → Library** → search for **YouTube Data API v3** → click it → **Enable**.

**Step 4 — Create an API key**
**APIs & Services → Credentials** → **+ Create Credentials → API key** → copy the key shown.

> The free quota is **10,000 units per day** — enough for dozens of searches. Optionally restrict the key to the YouTube Data API v3 in the Credentials page for security.

---

## Quick Start — Browser UI

```bash
rt-ui
```

### Welcome screen (first run only)

The first time you run `rt-ui`, you will see the **Welcome to RankTube** setup screen instead of the main app. This only appears once — until a key is stored locally.

![Welcome screen showing 4-step API key setup instructions]

The screen walks you through:
1. Opening Google Cloud Console
2. Creating a project
3. Enabling YouTube Data API v3
4. Creating and copying your API key

Paste your key into the field at the bottom and click **Save & continue**. The key is saved to `~/.ranktube/config` — you will not be asked again.

### Landing page

After setup, the app opens to the main landing page. On first load (before any search), the main area shows:

- **What RankTube does** — overview of the relevance ranking approach
- **Output modes** — what each of the four formats produces
- **What to do with results** — NotebookLM, Claude/ChatGPT, Fabric, content auditing, JSON pipelines
- **Scoring weights** — how the relevance score is calculated
- **Tips** — guidance on adjusting the min score slider

All search controls are in the **sidebar on the left**.

---

## UI User Guide

### Sidebar controls

#### Keywords
Enter one or more search phrases, separated by commas.

```
machine learning, deep learning, neural networks
```

Each phrase is scored independently — multi-word phrases are kept intact. A caption below the field reminds you to use commas as separators.

#### Channel filter
Choose how to narrow results to a specific creator:

| Option | Behaviour |
|---|---|
| **None** | Search all of YouTube (default) |
| **Channel Name** | Type a display name (e.g. `Khan Academy`) — resolved to a channel ID automatically |
| **Channel ID** | Paste the exact YouTube channel ID (e.g. `UC4a-Gbdigs3jaI_mG1Um6Hg`) — no resolution step |

Only one option is active at a time. Channel Name resolution costs one extra API call.

#### Max Results (Top N)
Leave blank to retrieve all available results (up to the API pagination limit of 500). Enter a number to cap the result count — useful for quick searches or quota conservation.

#### Min Relevance Score
A slider from 0.0 to 1.0, defaulting to **0.1**.

Videos below this threshold are dropped before display. Lower it if you get zero results; raise it to reduce noise. The score is based on keyword match quality only (not views or subscribers).

#### Output Mode
Choose how results are presented:

| Mode | What you get |
|---|---|
| **urls** | Plain list of YouTube URLs — one per line |
| **details** | Rich table with title, channel, views, duration, scores, matched keywords, and clickable URL |
| **json** | Machine-readable JSON array — good for piping into scripts |
| **verbose** | Full detail view with description snippets and separator lines |

#### Search button
Runs the full pipeline: search → enrich → score → filter → display. Results are cached in session — clicking download buttons or adjusting the sidebar does not re-run the search.

---

### Results area

#### urls mode
A code block containing one URL per line, with a **Download URLs (.txt)** button.

#### details / verbose mode
An interactive `st.dataframe` table with columns:

| Column | Description |
|---|---|
| Rank | Position by rank score |
| Title | Video title |
| Channel | Channel name |
| Views | Formatted (e.g. 1.2M) |
| Subscribers | Formatted (e.g. 340K) |
| Duration | mm:ss or h:mm:ss |
| Relevance Score | Keyword match quality (0–1) |
| Rank Score | Final composite score (0–1) |
| Matched Keywords | Which of your phrases matched |
| URL | Clickable link to YouTube |

A **Download Results (.json)** button exports the full data. A collapsed **Raw formatted output** expander shows the plain-text version.

#### json mode
A syntax-highlighted JSON block with a **Download JSON (.json)** button.

---

### Changing your API key

The sidebar shows your stored key in masked form (e.g. `AIza•••...•1234`). To update it, expand the **Change API key** section, enter the new key, and click **Update key**.

---

## Quick Start — CLI

### Basic search
```bash
rt "machine learning"
```

### Multiple keyword phrases
```bash
rt "machine learning, deep learning, transformers"
```

### Limit to top 10 results
```bash
rt "machine learning" --top 10
```

### JSON output
```bash
rt "machine learning" --top 10 --output json
```

### Verbose output with scores and snippets
```bash
rt "machine learning" --top 5 --output verbose
```

### Details output (title, channel, score, matched keywords)
```bash
rt "machine learning" --top 5 --output details
```

### Filter by channel name
```bash
rt "machine learning" --channel "3Blue1Brown" --output verbose
```

### Filter by channel ID
```bash
rt "machine learning" --channel-id UCYO_jab_esuFRV4b17AJtAw --output json
```

### Raise relevance threshold
```bash
rt "machine learning" --min-score 0.5
```

### Pass API key inline
```bash
rt "machine learning" --api-key AIza...
```

---

## CLI Reference

```
rt [-h] [--channel NAME | --channel-id ID]
   [--top N] [--min-score THRESHOLD]
   [--output {urls,details,json,verbose}]
   [--api-key KEY]
   keywords [keywords ...]
```

| Argument | Default | Description |
|---|---|---|
| `keywords` | required | One or more keyword phrases |
| `--channel NAME` | — | Channel display name (auto-resolved to ID) |
| `--channel-id ID` | — | Exact YouTube channel ID (skips resolution) |
| `--top N` | all | Return at most N results |
| `--min-score` | `0.1` | Minimum relevance score (0.0–1.0) |
| `--output` | `urls` | Output format: `urls`, `details`, `json`, `verbose` |
| `--api-key KEY` | env var | Overrides `YOUTUBE_API_KEY` environment variable |

`ranktube` is an alias for `rt`. `--channel` and `--channel-id` are mutually exclusive.

---

## How it works

```
Keywords → YouTube Search API → Raw Videos → Relevance Scorer → Formatted Output
                                                   ↑
                             Channel Filter (optional, resolved by name or ID)
```

1. **Search** — Keywords are joined into a single query and sent to `search.list`. Results are paginated until the requested count is reached or the API is exhausted.
2. **Enrich** — Video IDs are batched to `videos.list` (50 at a time) to fetch tags, duration, and view counts not returned by the search endpoint.
3. **Score** — Each video is scored against the original keywords using a weighted algorithm.
4. **Filter** — Videos below `--min-score` are dropped. Results are sorted by composite rank score descending.
5. **Output** — Printed to stdout (CLI) or rendered in the browser (UI).

### Relevance scoring

| Signal | Weight | Method |
|---|---|---|
| Title token overlap | 40% | Fraction of keyword tokens found in title |
| Description overlap | 25% | First 500 characters only |
| Tags overlap | 20% | Video tags vs keyword tokens |
| Exact phrase bonus | 10% | Multi-word phrase appears literally in title or description |
| Channel name overlap | 5% | Channel title tokens vs keyword tokens |

### Rank score (final ordering)

| Signal | Weight |
|---|---|
| Relevance score | 60% |
| View count (log-normalised, 10M ref) | 25% |
| Subscriber count (log-normalised, 10M ref) | 15% |

---

## What to do with results

**Research & learning**
- Upload the URL list to [NotebookLM](https://notebooklm.google.com/) — it ingests YouTube URLs directly for deep concept research and Q&A across multiple videos.
- Paste URLs into [Claude](https://claude.ai/) or ChatGPT to summarise, compare, or extract key concepts across the set.
- Feed URLs to [Fabric](https://github.com/danielmiessler/fabric) (`yt` + `extract_wisdom` pattern) for automated transcript analysis.

**Content creation**
- Audit what's already covered in your niche before recording.
- Export as JSON and load into a spreadsheet to track competitor channels over time.

**Developer / automation**
- The JSON output pipes directly into any downstream script or data pipeline.
- Use the `ranktube` CLI in cron jobs or CI workflows to build scheduled keyword-monitoring reports.

---

## API Quota

| Operation | Cost |
|---|---|
| `search.list` (per page of 50 results) | 100 units |
| `videos.list` (per batch of 50 video IDs) | 1 unit |
| Free daily quota | 10,000 units |

Fetching 100 results costs ~102 units. Fetching 500 results costs ~1,010 units — well within the free tier.

---

## Project Structure

```
ranktube/
├── pyproject.toml           # Package metadata, dependencies, entry points
├── requirements.txt         # Annotated dependency list
├── src/ranktube/
│   ├── cli.py               # Argument parsing and pipeline orchestration
│   ├── api.py               # YouTube API client and pagination
│   ├── resolver.py          # Channel name → channel ID resolution
│   ├── scorer.py            # Relevance scoring engine (ScoredVideo dataclass)
│   ├── formatter.py         # Output formatting (urls / details / json / verbose)
│   └── ui.py                # Streamlit browser UI
└── tests/
    ├── test_scorer.py        # Unit tests — scoring engine
    ├── test_resolver.py      # Mocked tests — channel resolution
    └── test_api.py           # Mocked tests — API client
```

---

## Dependencies

| Package | Used for |
|---|---|
| `google-api-python-client` | YouTube Data API v3 (`search.list`, `videos.list`) |
| `google-auth` | API key authentication |
| `python-dotenv` | Loads `YOUTUBE_API_KEY` from `.env` file |
| `streamlit` *(ui extra)* | Browser UI — widgets, tables, download buttons |

---

## Running Tests

```bash
pip install ranktube[dev]
pytest tests/ -v
```

All tests run without a live API key — all API calls are fully mocked.

---

## Publishing a new version

```bash
# 1. Bump version in pyproject.toml
# 2. Rebuild
rm -rf dist/ && python -m build
# 3. Upload
twine upload dist/*
```
