Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: CI

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable

- name: Vet
run: make vet

- name: Build
run: make build

- name: Unit tests
run: make test

- name: Functional smoke test (offline, no API quota)
run: ./yrank -top-search "fitness" -local-test -o csv | head -3
31 changes: 31 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
55 changes: 55 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
version: 2

before:
hooks:
- go mod tidy

builds:
- id: yrank
main: .
binary: yrank
env:
- CGO_ENABLED=0
ldflags:
- -s -w -X main.version={{.Version}}
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm64

archives:
- id: default
name_template: >-
{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}
format_overrides:
- goos: windows
formats: [zip]

checksum:
name_template: "checksums.txt"

changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
- "^chore:"

# Publish a Homebrew formula to a tap repo on each tagged release.
# Requires a github.com/fedir/homebrew-tap repository and a HOMEBREW_TAP_TOKEN
# secret with write access to it.
brews:
- name: yrank
repository:
owner: fedir
name: homebrew-tap
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
homepage: "https://github.com/fedir/yrank"
description: "Rank YouTube playlist, channel or search-result videos by engagement metrics."
license: "GPL-3.0"
test: |
assert_match "yrank", shell_output("#{bin}/yrank -version")
14 changes: 12 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ refactor: extract pagination logic
## Commands

```bash
make build # compile → ./yrank binary
make build # compile → ./yrank binary (injects version via -ldflags)
make test # go test -race ./...
make vet # go vet ./...
make clean # remove binary and coverage artifacts
make clean # remove binary, coverage artifacts and dist/
make snapshot # local GoReleaser snapshot (no publish; needs goreleaser)

# Run a single test
go test -race -run TestName ./youtube/...
Expand All @@ -31,8 +32,17 @@ go test -race -run TestName ./youtube/...
# Run with local fixtures (no API quota consumed)
./yrank -p PLiVdPopzGBsV7TgjAw9GH43Ck9QCxrw5w -local-test
./yrank -p PLiVdPopzGBsV7TgjAw9GH43Ck9QCxrw5w -local-test -strategy all -o csv

# Print version (overridden at build time via -ldflags -X main.version=...)
./yrank -version
```

## CI & releases

- `.github/workflows/ci.yml` — runs `make vet`, `make build`, `make test` and an offline `-local-test` smoke test on every push/PR to `master`.
- `.github/workflows/release.yml` — on a `v*` tag push, runs GoReleaser (`.goreleaser.yaml`): cross-compiles linux/darwin/windows × amd64/arm64, publishes a GitHub release with checksums + changelog, and updates the `fedir/homebrew-tap` formula (needs the `HOMEBREW_TAP_TOKEN` secret).
- `main.go` declares `var version = "dev"`; `-version`/`-V` print it. The Makefile and GoReleaser inject the real version through `-ldflags "-X main.version=..."`.

## Configuration

Copy `.env.example` to `.env` and set your YouTube Data API v3 key:
Expand Down
17 changes: 14 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
BINARY := yrank
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
LDFLAGS := -ldflags "-s -w -X main.version=$(VERSION)"

.PHONY: build test vet clean coverage install
.PHONY: build test vet clean coverage install release snapshot

build:
go build -o $(BINARY) .
go build $(LDFLAGS) -o $(BINARY) .

test:
go test -race ./...
Expand All @@ -15,7 +17,16 @@ coverage:
go test -race -coverprofile=coverage.txt ./... && go tool cover -func=coverage.txt

install:
go install .
go install $(LDFLAGS) .

# Build and publish a release for the current tag (used by CI on tag push).
release:
goreleaser release --clean

# Build a local snapshot (no publish) to verify the release config.
snapshot:
goreleaser release --snapshot --clean

clean:
rm -f $(BINARY) coverage.txt
rm -rf dist
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
# yrank = Youtube Rank analyzer

[![Build Status](https://travis-ci.org/fedir/yrank.svg?branch=master)](https://travis-ci.org/fedir/yrank)
[![CI](https://github.com/fedir/yrank/actions/workflows/ci.yml/badge.svg)](https://github.com/fedir/yrank/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/fedir/yrank/branch/master/graph/badge.svg)](https://codecov.io/gh/fedir/yrank)

Ranks videos in a YouTube playlist or channel by engagement metrics, so you can prioritise what to watch — especially useful for large conference playlists.

## Installation

Go 1.26+ is required.
Pre-built binaries for Linux, macOS and Windows (amd64/arm64) are attached to every
[GitHub release](https://github.com/fedir/yrank/releases).

Homebrew:

```bash
brew install fedir/tap/yrank
```

With Go 1.26+:

```bash
go install github.com/fedir/yrank@latest
Expand Down Expand Up @@ -51,6 +60,7 @@ The key is also read directly from the environment if set there.
| `-m` | `0` (all) | Maximum number of results to return |
| `-local-test` | `false` | Use local `testdata/` fixtures instead of live API calls (no quota consumed) |
| `-d` | `false` | Debug mode — prints API URLs and IDs |
| `-version` / `-V` | — | Print version and exit |

Exactly one input source — `-p`, `-c`, or `-top-search` — must be given; they are mutually exclusive.

Expand Down Expand Up @@ -198,3 +208,24 @@ score = views / age_days
* [Squeezie — Concepts originaux](sample_output/squeezie_concepts_originaux_positive_interest.md)
* [Squeezie — Full channel](sample_output/squeezie_channel_positive_interest.md)
* [FOSDEM 2020](sample_output/fosdem2020_positive_interest.md)

## Releases

Releases are fully automated with [GoReleaser](https://goreleaser.com/). Pushing a
`v*` tag triggers the [release workflow](.github/workflows/release.yml), which
cross-compiles binaries (linux/darwin/windows × amd64/arm64), publishes a GitHub
release with checksums and a changelog, and updates the Homebrew tap.

```bash
git tag v1.2.3
git push origin v1.2.3
```

Build a local snapshot to test the release config without publishing:

```bash
make snapshot # requires goreleaser installed locally
```

The `Homebrew` formula update requires a `HOMEBREW_TAP_TOKEN` repository secret with
write access to `fedir/homebrew-tap`.
7 changes: 7 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,16 @@ func cliParameters() (cid, pid, topSearch, output, sorting, strategy, from, weig
outFlag = flag.String("out", "", "Write output to file atomically (safer than shell redirection)")
localTestFlag = flag.Bool("local-test", false, "Use local testdata/ fixtures instead of live API calls")
dbg = flag.Bool("d", false, "Debug mode")
showVersion = flag.Bool("version", false, "Print version and exit")
showVersionV = flag.Bool("V", false, "Print version and exit (alias of -version)")
)
flag.Parse()

if *showVersion || *showVersionV {
fmt.Printf("yrank %s\n", version)
os.Exit(0)
}

sources := 0
for _, s := range []string{*playlistID, *channelID, *searchFlag} {
if s != "" {
Expand Down
3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import (
"github.com/fedir/yrank/youtube"
)

// version is overridden at build time via -ldflags "-X main.version=...".
var version = "dev"

func main() {
c := configuration()
cid, pid, topSearch, of, sorting, strategy, from, weightsRaw, outFile, m, d, localTest := cliParameters()
Expand Down
Loading