Metadata-Version: 2.5
Name: watchbudget
Version: 0.1.0
Summary: Plan sequential viewing with playback speeds, breaks, and a time budget.
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# watchbudget

Work out how much of a playlist fits into tonight.
Zero runtime dependencies. Python 3.10+. MIT licensed.

## Install and run

~~~console
python -m pip install watchbudget
watchbudget 45m 45m --speed 1.5 --break 10m
watchbudget 20:00 35:00 15:00 --speed 1.25 --break 5m --budget 45m --json
~~~

The first command reports a full viewing time of 1:10:00: 60 minutes of
accelerated content and one 10-minute break.

For local installation, use **python -m pip install .**. The CLI is also
available as **python -m watchbudget**.

## Python

~~~python
from watchbudget import plan, parse_duration, format_duration

result = plan(["20m", "35m", "15m"], speed="1.25", break_duration="5m", budget="45m")
assert result.fits_count == 1
assert result.fitted_seconds == 960
assert format_duration(result.remaining_seconds) == "0:29:00"
assert parse_duration("1:30") == 90
assert parse_duration("1h 20m") == 4800
~~~

## Rules and API

- Plain numbers mean seconds. Strings accept seconds, M:SS, H:MM:SS or units
  h/m/s, for example 1h20m, 30s, 2.5m. A two-field 1:30 means 90 seconds.
- Seconds fields and the middle field of H:MM:SS must be below 60.
- Breaks occur only between episodes that are watched, never after the final
  episode. Playback speed does not shorten breaks.
- The planner takes the longest consecutive prefix. It does not skip a long
  episode to fit later short ones.
- Empty playlists and zero-length episodes are allowed through the Python API.
  Durations and budgets must be non-negative; speed must be positive.
- Arithmetic uses Fraction, with decimal inputs interpreted exactly as written.
  Use decimal strings when exact input precision matters.

**plan(durations, *, speed=1, break_duration=0, budget=None)** returns a
ViewingPlan with episode_count, fits_count, total_seconds, fitted_seconds and
remaining_seconds. Times are Fraction objects; remaining_seconds is None for an
unlimited budget. **as_dict()** produces JSON-ready values with exact rational
seconds plus H:MM:SS display strings. Display strings round upward to the next
whole second; planning decisions always use exact time.

Exit status is 0 on success, including when no episode fits, or 2 for invalid
input. The tool accepts supplied durations; it does not fetch videos or inspect
media files.

## Development

~~~console
python -m pip install -e .
python -m unittest discover -s tests -v
~~~
