Skip to content
Open
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
41 changes: 41 additions & 0 deletions .github/actions/bootstrap/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Bootstrap Workspace
description: >
Installs Flutter, activates melos and bootstraps the melos workspace, so every
package resolves its sibling packages from this repository instead of pub.dev.

# NOTE: the calling job must check the repository out first — a local action
# cannot check out the repository it lives in.

inputs:
flutter-channel:
description: The Flutter channel to install.
required: false
default: stable

runs:
using: composite
steps:
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
cache: true
cache-key: flutter-:os:-:channel:-:version:-:arch:-:hash:-${{ hashFiles('**/pubspec.lock') }}
channel: ${{ inputs.flutter-channel }}
Comment on lines +18 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== action.yml target =="
cat -n .github/actions/bootstrap/action.yml

echo
echo "== workflow/action references in repo (short summary) =="
rg -n "uses:\s*[^#]+@[A-Za-z0-9./_-]+" .github -g '*.yml' -g '*.yaml' || true

echo
echo "== existing full SHA usage in .github =="
python3 - <<'PY'
import pathlib, re
patterns = []
for p in pathlib.Path('.github').glob('**/*.yml'):
    for p2 in pathlib.Path('.github').glob('**/*.yaml'):
        pass
for p in list(pathlib.Path('.github').glob('**/*.yml')) + list(pathlib.Path('.github').glob('**/*.yaml')):
    for i,line in enumerate(p.read_text(errors='replace').splitlines(),1):
        m = re.search(r"\b([0-9a-fA-F]{40})\b", line)
        if m:
            print(f"{p}:{i}:{line.strip()}")
PY

Repository: GetStream/stream-core-flutter

Length of output: 4565


Pin the third-party action to a full commit SHA.

subosito/flutter-action@v2 is a mutable tag, so this workflow can execute unreviewed or compromised code if the tag is moved. Pin an immutable full commit SHA and update it through dependency automation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/actions/bootstrap/action.yml around lines 18 - 23, Update the
“Install Flutter” step’s subosito/flutter-action reference from the mutable v2
tag to a reviewed, immutable full commit SHA, while preserving its existing
inputs and enabling dependency automation to manage future updates.


- name: Install Melos
shell: bash
working-directory: ${{ github.workspace }}
run: flutter pub global activate melos

# Bootstrapping is what writes the melos-managed `pubspec_overrides.yaml`
# files, which are gitignored. Without it, a plain `flutter pub get` in an
# example app resolves the very plugin it is supposed to be testing from
# pub.dev instead of from this checkout.
#
# Invoked through `pub global run` rather than as a bare `melos`, so it does
# not depend on the pub-cache bin directory being on PATH — that differs
# between the ubuntu, macos and windows runners this action is used from.
- name: Bootstrap Workspace
shell: bash
working-directory: ${{ github.workspace }}
run: flutter pub global run melos bootstrap
145 changes: 145 additions & 0 deletions .github/workflows/stream_thumbnail_native_builds.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
name: stream_thumbnail_native_builds

env:
FLUTTER_CHANNEL: stable

on:
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
paths:
- 'packages/stream_thumbnail/**'
- '.github/actions/bootstrap/action.yml'
- '.github/workflows/stream_thumbnail_native_builds.yml'
push:
branches:
- main
paths:
- 'packages/stream_thumbnail/**'
- '.github/actions/bootstrap/action.yml'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- '.github/workflows/stream_thumbnail_native_builds.yml'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: read

jobs:
android:
timeout-minutes: 20
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/stream_thumbnail/example
steps:
- name: Git Checkout
uses: actions/checkout@v6

- name: Bootstrap Workspace
uses: ./.github/actions/bootstrap
with:
flutter-channel: ${{ env.FLUTTER_CHANNEL }}

- name: Build APK
run: flutter build apk --debug

ios:
timeout-minutes: 20
runs-on: macos-latest
defaults:
run:
working-directory: packages/stream_thumbnail/example
steps:
- name: Git Checkout
uses: actions/checkout@v6

- name: Bootstrap Workspace
uses: ./.github/actions/bootstrap
with:
flutter-channel: ${{ env.FLUTTER_CHANNEL }}

- name: Build iOS (no codesign)
run: flutter build ios --debug --no-codesign

macos:
timeout-minutes: 20
runs-on: macos-latest
defaults:
run:
working-directory: packages/stream_thumbnail/example
steps:
- name: Git Checkout
uses: actions/checkout@v6

- name: Bootstrap Workspace
uses: ./.github/actions/bootstrap
with:
flutter-channel: ${{ env.FLUTTER_CHANNEL }}

- name: Build macOS
run: flutter build macos --debug

windows:
timeout-minutes: 20
runs-on: windows-latest
defaults:
run:
working-directory: packages/stream_thumbnail/example
steps:
- name: Git Checkout
uses: actions/checkout@v6

- name: Bootstrap Workspace
uses: ./.github/actions/bootstrap
with:
flutter-channel: ${{ env.FLUTTER_CHANNEL }}

- name: Build Windows
run: flutter build windows --debug

linux:
timeout-minutes: 20
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/stream_thumbnail/example
steps:
- name: Git Checkout
uses: actions/checkout@v6

- name: Install Linux Build Dependencies
run: |
sudo apt-get update
sudo apt-get install -y ninja-build libgtk-3-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libwebp-dev

- name: Bootstrap Workspace
uses: ./.github/actions/bootstrap
with:
flutter-channel: ${{ env.FLUTTER_CHANNEL }}

- name: Build Linux
run: flutter build linux --debug

web:
timeout-minutes: 20
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/stream_thumbnail/example
steps:
- name: Git Checkout
uses: actions/checkout@v6

- name: Bootstrap Workspace
uses: ./.github/actions/bootstrap
with:
flutter-channel: ${{ env.FLUTTER_CHANNEL }}

- name: Build Web
run: flutter build web
15 changes: 14 additions & 1 deletion melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,26 @@ scripts:
- Note: you can also rely on your IDEs Dart Analysis / Issues window.

generate:all:
run: melos run generate:dart && melos run generate:flutter
run: melos run generate:dart && melos run generate:flutter && melos run generate:pigeon
description: Build all generated files for Dart & Flutter packages in this project.

generate:icons:
run: melos exec -c 1 --file-exists="stream_icons.yaml" -- "dart run \$MELOS_ROOT_PATH/scripts/generate_icons.dart"
description: Generate icon font and Dart classes from SVG files.

generate:pigeon:
run: |
melos exec -c 1 --file-exists="pigeons/messages.dart" -- "
dart run pigeon --input pigeons/messages.dart --swift_out=ios/\$MELOS_PACKAGE_NAME/Sources/\$MELOS_PACKAGE_NAME/Messages.g.swift &&
dart run pigeon --input pigeons/messages.dart --swift_out=macos/\$MELOS_PACKAGE_NAME/Sources/\$MELOS_PACKAGE_NAME/Messages.g.swift &&
dart format lib/src/messages.g.dart
"
description: |
Generate Pigeon platform-channel bindings for packages with a pigeons/messages.dart
schema. Swift output is generated once per Darwin platform (iOS, macOS) since SwiftPM
forbids a target's source path from escaping its own package root, so the two
platforms can't share one generated file in place.

check:barrels:
run: melos exec -c 1 --file-exists="check_barrels.yaml" -- "dart run \$MELOS_ROOT_PATH/scripts/check_barrels.dart"
description: Validate the public-barrel contract for packages with a check_barrels.yaml config.
Expand Down
38 changes: 38 additions & 0 deletions packages/stream_thumbnail/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
## Upcoming

### ✨ Features

- Added macOS support, sharing the same `AVAssetImageGenerator` + `libwebp` approach
as iOS.
- Added Windows support, via Media Foundation for decoding and WIC for JPEG/PNG
encoding. `StreamThumbnailFormat.webp` and `headers` (for authenticated remote
videos) are not yet supported on Windows.
- Added Linux support, via FFmpeg for decoding and jpeg/png encoding, and `libwebp`
for WebP — the only platform besides Android with full format support, including
`headers` for authenticated remote videos.

### 💥 BREAKING CHANGES

- `thumbnailFiles` now fails fast: if any video fails to produce a thumbnail, the call
throws instead of silently omitting that video from the returned list.
- `thumbnailFiles` now throws an `ArgumentError` when `thumbnailPath` names a file rather
than a directory and more than one video was given. That combination pointed every
video in the batch at the same output path.

### 🐞 Fixed

- Fixed a crash on iOS where a failed `thumbnailData` call returned `null` instead of an
error, causing the Dart side to crash casting `null` to `Uint8List`.
- Native errors now surface as typed `PlatformException`s on all platforms instead of a
generic `Exception` wrapping a raw Android stack trace.
- Unified the platform-channel implementation: Android previously acknowledged a call
immediately and delivered the real result via a separate reverse invocation; it now
replies once with the actual result, like iOS and web.

### 🔧 Internal

- Migrated the Android/iOS platform channel to Pigeon-generated, type-safe messaging
and rewrote the iOS plugin in Swift (previously Objective-C). The public Dart API is
unchanged; web keeps its separate hand-written implementation, since Pigeon does not
support it.

## 0.1.0

* Initial release.
10 changes: 7 additions & 3 deletions packages/stream_thumbnail/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

## Introduction

A Flutter plugin for creating a thumbnail image from a video. Give it a local file path or a video URL and it returns the thumbnail as bytes or as a saved image file. Works on Android, iOS, and web.
A Flutter plugin for creating a thumbnail image from a video. Give it a local file path or a video URL and it returns the thumbnail as bytes or as a saved image file. Works on Android, iOS, macOS, Windows, Linux, and web.

Windows requires the [Media Feature Pack](https://support.microsoft.com/en-us/topic/media-feature-pack-list-for-windows-n-editions-c1c6bfba-4bf7-4be6-ae13-8608318bf3d4) for decoding (present by default outside of "N"/"KN" Windows editions), and doesn't yet support `StreamThumbnailFormat.webp` or `headers` for authenticated remote videos.

Linux requires FFmpeg and libwebp development packages on the build machine, e.g. on Debian/Ubuntu: `libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libwebp-dev`.

## Installation

Expand Down Expand Up @@ -62,9 +66,9 @@ Every method accepts the same options:
| Option | Description |
| --------------- | ------------------------------------------------------------------------------- |
| `video`(s) | Path to a local video file or a video URL. |
| `headers` | HTTP headers sent when fetching a remote video. |
| `headers` | HTTP headers sent when fetching a remote video. Not supported on Windows. |
| `thumbnailPath` | Output path (file variants only). Defaults to the video's folder or cache dir. |
| `imageFormat` | `JPEG`, `PNG`, or `WEBP`. Defaults to `PNG`. WebP on iOS is backed by `libwebp`.|
| `imageFormat` | `JPEG`, `PNG`, or `WEBP`. Defaults to `PNG`. WebP on iOS/macOS is backed by `libwebp`; not yet supported on Windows.|
| `maxHeight` / `maxWidth` | Max size in pixels, or `0` to keep the source resolution. |
| `timeMs` | Capture position in milliseconds. |
| `quality` | Output quality, `0`–`100` (ignored for PNG). |
Loading
Loading