Skip to main content

flet-media-scanner

A Flet extension for native Android MediaStore integration — save, list, and delete videos in the device Gallery without requiring broad storage permissions.

Built with 100% native Android Kotlin (MediaStore & MediaScannerConnection) and pure Dart Flet service bindings, with zero third-party Flutter plugin dependencies.


Features

  • 📱 Android MediaStore Scoped Storage: Save videos directly to Movies/<Album> without WRITE_EXTERNAL_STORAGE on Android 10+ (API 29+).
  • 🖼️ Instant Gallery Visibility: Media is immediately visible in Google Photos and device Gallery apps via native ContentResolver publishing and MediaScannerConnection.
  • 📋 List & Query: Query videos belonging to your app's custom album.
  • 🗑️ Content URI Deletion: Cleanly delete media using Android content:// URIs.
  • ⚡ Zero Third-Party Dependencies: No external Flutter packages needed.

Requirements

  • Platform: Android only (no-op / unsupported on desktop & iOS)
  • Android: API 21+ (minSdk 21; Scoped Storage optimized for API 29+)
  • Flet: >= 1.0.0
  • Python: >= 3.10

Installation

pip install flet-media-scanner

Or when developing locally in a workspace:

[tool.flet.extensions]
flet_media_scanner = "flet_media_scanner.Extension"

[tool.flet.dev_packages]
flet-media-scanner = "packages/flet-media-scanner"

Setup

Register the extension in your application's pyproject.toml:

[tool.flet.extensions]
flet_media_scanner = "flet_media_scanner.Extension"

Usage

import flet as ft
from flet_media_scanner import MediaScanner, SaveResult

async def main(page: ft.Page):
    # Initialize and register the service
    scanner = MediaScanner()
    page.services.append(scanner)
    page.update()

    # 1. Save a downloaded video to Gallery (Movies/MyVideos folder)
    result: SaveResult = await scanner.save_video(
        file_path="/data/user/0/com.example.app/cache/video.mp4",
        file_name="awesome_video.mp4",
        album="MyVideos",
    )

    if result.success:
        print(f"Saved successfully: {result.content_uri}")
        print(f"Gallery relative path: {result.relative_path}")
    else:
        print(f"Failed to save: {result.error}")

    # 2. List all videos in the custom album
    videos = await scanner.list_videos(album="MyVideos")
    for v in videos:
        print(f"Video: {v['display_name']} | URI: {v['content_uri']}")

    # 3. Delete a video by content URI
    if result.content_uri:
        deleted = await scanner.delete_video(result.content_uri)
        print("Deleted:", deleted)

    # 4. Trigger legacy media scanner for existing public files
    scanned = await scanner.scan_media("/storage/emulated/0/Movies/MyVideos/awesome_video.mp4")
    print("Scanned:", scanned)

ft.run(main)

API Reference

MediaScanner (Service)

Inherits from ft.Service. Must be added to page.services before invoking methods.

await save_video(file_path: str, file_name: str | None = None, album: str = "Vidsaver") -> SaveResult

Copies an app-private cache or temp video file into Android MediaStore.Video.Media (Movies/<album>).

  • file_path (str): Absolute filesystem path to the source video.
  • file_name (str | None): Target file name in the Gallery (defaults to the file basename).
  • album (str): Subdirectory name inside Movies/ (defaults to "Vidsaver").
  • Returns: SaveResult.

await list_videos(album: str = "Vidsaver") -> list[dict]

Queries all videos previously registered in the specified album.

  • album (str): Album subfolder inside Movies/.
  • Returns: List of dictionaries with keys:
    • display_name (str): File name shown in Gallery.
    • content_uri (str): Android content:// URI.
    • mime_type (str): Video MIME type (e.g. video/mp4).
    • relative_path (str): Directory path in storage (e.g. Movies/Vidsaver).
    • size (int): File size in bytes.
    • date_added (int): Unix timestamp added.
    • date_modified (int): Unix timestamp modified.

await delete_video(content_uri: str) -> bool

Deletes a media item from MediaStore using its content:// URI.

  • content_uri (str): Android MediaStore content URI.
  • Returns: True if deleted, False otherwise.

await scan_media(file_path: str) -> bool

Triggers Android native MediaScannerConnection.scanFile to index a file that already resides in public storage.

  • file_path (str): Absolute path to the file.
  • Returns: True if successfully indexed, False otherwise.

SaveResult (Dataclass)

Field Type Description
success bool True if the video was successfully saved and published.
content_uri str Android MediaStore content:// URI for the saved media.
display_name str Display name of the file in the Gallery.
mime_type str MIME type (e.g., video/mp4).
relative_path str Destination relative path (e.g., Movies/Vidsaver).
source_path str Original source path passed into save_video.
size int Size of the saved file in bytes.
error str Error description if success is False.

License

MIT

Metadata

Release files for flet-media-scanner 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flet-media-scanner 1.0.2
File Size Uploaded
flet_media_scanner-1.0.2.tar.gz 11.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for flet-media-scanner 1.0.2
File Interpreter ABI Platform
flet_media_scanner-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 24.6 kB

Release files / flet_media_scanner-1.0.2.tar.gz

Download URL flet_media_scanner-1.0.2.tar.gz
Size 11.8 kB
Tags Source
SHA-256 checksum
How to use checksums
30b9e0466004dceac829c986ba3eced4e8f63a8fee9bc24f311e237e7f996809
BLAKE2b-256 checksum
How to use checksums
b2193379dd7ce9233cc7356aacdddcaf0e510c50aee3ed3506c905108a4bef6a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Release files / flet_media_scanner-1.0.2-py3-none-any.whl

Download URL flet_media_scanner-1.0.2-py3-none-any.whl
Size 12.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
465b0d12e0037b0b6ff4d75227a44ff5ebf6f81e5516ec0e9fd7f92815bd3a3f
BLAKE2b-256 checksum
How to use checksums
d08fbb23bd22348085c141f6e8e5612732af89814645bcbd4a739350e5ef1e47
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Release history Release notifications | RSS feed

This release

1.0.2 This release

2 release files

0.86.5

2 release files

0.86.4

2 release files

0.86.3

2 release files

0.86.2

2 release files

0.86.1

2 release files

0.86.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page