import 'dart:convert'; import 'package:html/parser.dart' as html_parser; import 'package:http/http.dart' as http; class ScrapedRecipe { final String title; final List ingredients; final List instructions; final double? proteinGrams; ScrapedRecipe({ required this.title, required this.ingredients, required this.instructions, this.proteinGrams, }); } class RecipeScraperService { Future extractFromUrl(String url) async { final response = await http.get(Uri.parse(url)); if (response.statusCode != 200) return null; final document = html_parser.parse(response.body); final scriptTags = document.querySelectorAll('script[type="application/ld+json"]'); for (final tag in scriptTags) { try { final data = jsonDecode(tag.text); if (data is Map && data['@type'] == 'Recipe') { return _parseJsonLd(data); } else if (data is List) { final recipe = data.firstWhere((e) => e['@type'] == 'Recipe', orElse: () => null); if (recipe != null) return _parseJsonLd(recipe); } } catch (_) { continue; } } return null; } ScrapedRecipe _parseJsonLd(Map json) { return ScrapedRecipe( title: json['name'] ?? 'Untitled Recipe', ingredients: List.from(json['recipeIngredient'] ?? []), instructions: (json['recipeInstructions'] as List? ?? []) .map((step) => step is Map ? step['text']?.toString() ?? '' : step.toString()) .toList(), proteinGrams: double.tryParse( json['nutrition']?['proteinContent'] ?.toString() .replaceAll(RegExp(r'[^0-9.]'), '') ?? '', ), ); } }