yt_extractor 0.1.0 copy "yt_extractor: ^0.1.0" to clipboard
yt_extractor: ^0.1.0 copied to clipboard

PlatformAndroid

A Flutter plugin that wraps the NewPipe Extractor. Extract YouTube (and other service) streams, audio, video, metadata, search, comments, channels, playlists and trending content — without any API keys.

example/lib/main.dart

import 'package:flutter/material.dart';

import 'src/browse_screen.dart';
import 'src/extractor.dart';
import 'src/log.dart';
import 'src/search_screen.dart';
import 'src/stream_screen.dart';
import 'widgets/section_header.dart';

void main() => runApp(const YtExtractorExampleApp());

/// Demo app for the `yt_extractor` plugin: search, browse kiosks and play
/// streams.
class YtExtractorExampleApp extends StatelessWidget {
  const YtExtractorExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'yt_extractor demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.red),
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.red,
          brightness: Brightness.dark,
        ),
      ),
      onGenerateRoute: (settings) {
        if (settings.name == StreamScreen.route) {
          return MaterialPageRoute<void>(
            builder: (_) => StreamScreen(url: settings.arguments as String),
          );
        }
        return null;
      },
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final TextEditingController _controller = TextEditingController();
  String _status = 'Initializing…';
  bool _ready = false;

  static const List<String> _quickSearches = [
    'Lofi hip hop',
    'Dua Lipa',
    'MKBHD',
  ];

  @override
  void initState() {
    super.initState();
    _init();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  Future<void> _init() async {
    try {
      Log.info('HomePage', 'initializing extractor');
      await extractor.init();
      Log.info('HomePage', 'extractor ready');
      if (!mounted) return;
      setState(() {
        _status = 'Ready';
        _ready = true;
      });
    } catch (e) {
      Log.error('HomePage', 'init failed', e);
      if (!mounted) return;
      setState(() => _status = 'Init failed: $e');
    }
  }

  void _search(String query) {
    if (query.trim().isEmpty) return;
    Log.debug('HomePage', 'searching for "$query"');
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (_) => SearchScreen(query: query.trim()),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Scaffold(
      body: SafeArea(
        child: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            Row(
              children: [
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'yt_extractor',
                        style: theme.textTheme.headlineMedium?.copyWith(
                          fontWeight: FontWeight.w800,
                        ),
                      ),
                      const SizedBox(height: 4),
                      Text(
                        'NewPipe Extractor, wrapped for Flutter.',
                        style: theme.textTheme.bodySmall,
                      ),
                    ],
                  ),
                ),
                Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 12,
                    vertical: 6,
                  ),
                  decoration: BoxDecoration(
                    color: _ready
                        ? Colors.green.withValues(alpha: 0.15)
                        : Colors.orange.withValues(alpha: 0.15),
                    borderRadius: BorderRadius.circular(20),
                  ),
                  child: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Icon(
                        _ready ? Icons.check_circle : Icons.hourglass_top,
                        size: 16,
                        color: _ready ? Colors.green : Colors.orange,
                      ),
                      const SizedBox(width: 6),
                      Text(_status, style: theme.textTheme.labelSmall),
                    ],
                  ),
                ),
              ],
            ),
            const SizedBox(height: 24),
            TextField(
              controller: _controller,
              textInputAction: TextInputAction.search,
              onSubmitted: (query) {
                if (query.trim().isNotEmpty) _search(query);
              },
              decoration: InputDecoration(
                hintText: 'Search YouTube',
                prefixIcon: const Icon(Icons.search),
                suffixIcon: IconButton(
                  icon: const Icon(Icons.arrow_forward),
                  onPressed: () => _search(_controller.text),
                ),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(28),
                ),
              ),
            ),
            const SizedBox(height: 8),
            Wrap(
              spacing: 8,
              children: [
                for (final query in _quickSearches)
                  ActionChip(
                    label: Text(query),
                    onPressed: () => _search(query),
                  ),
              ],
            ),
            const SectionHeader('Browse'),
            Card(
              child: Column(
                children: [
                  ListTile(
                    leading: const Icon(Icons.local_fire_department),
                    title: const Text('Trending & kiosks'),
                    subtitle: const Text('Popular videos, music and more'),
                    trailing: const Icon(Icons.chevron_right),
                    onTap: () {
                      Navigator.of(context).push(
                        MaterialPageRoute<void>(
                          builder: (_) => const BrowseScreen(),
                        ),
                      );
                    },
                  ),
                  const Divider(height: 1),
                  ListTile(
                    leading: const Icon(Icons.play_circle_outline),
                    title: const Text('Try a known stream'),
                    subtitle: const Text(
                      'Rick Astley – Never Gonna Give You Up',
                    ),
                    trailing: const Icon(Icons.chevron_right),
                    onTap: () {
                      Navigator.of(context).pushNamed(
                        StreamScreen.route,
                        arguments:
                            'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
                      );
                    },
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
150
points
16
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin that wraps the NewPipe Extractor. Extract YouTube (and other service) streams, audio, video, metadata, search, comments, channels, playlists and trending content — without any API keys.

Repository (GitHub)
View/report issues
Contributing

Topics

#youtube #music #extractor #streaming #media

License

MIT (license)

Dependencies

equatable, flutter

More

Packages that depend on yt_extractor

Packages that implement yt_extractor