mirror of
https://github.com/mirarr-app/mirarr.git
synced 2025-05-17 11:05:56 +08:00
added tmdb url handling
This commit is contained in:
@ -24,6 +24,40 @@
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<!-- Deep linking for movies -->
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https"
|
||||
android:host="www.themoviedb.org"
|
||||
android:pathPrefix="/movie" />
|
||||
</intent-filter>
|
||||
<!-- Deep linking for TV shows -->
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https"
|
||||
android:host="www.themoviedb.org"
|
||||
android:pathPrefix="/tv" />
|
||||
</intent-filter>
|
||||
<!-- Custom URI scheme for movies -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="themoviedb"
|
||||
android:host="movie" />
|
||||
</intent-filter>
|
||||
<!-- Custom URI scheme for TV shows -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="themoviedb"
|
||||
android:host="tv" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
|
110
lib/functions/url_parser.dart
Normal file
110
lib/functions/url_parser.dart
Normal file
@ -0,0 +1,110 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:Mirarr/functions/fetchers/fetch_movie_details.dart';
|
||||
import 'package:Mirarr/functions/fetchers/fetch_serie_details.dart';
|
||||
import 'package:Mirarr/functions/regionprovider_class.dart';
|
||||
import 'package:Mirarr/moviesPage/functions/on_tap_movie_desktop.dart';
|
||||
import 'package:Mirarr/seriesPage/function/on_tap_serie_desktop.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:Mirarr/moviesPage/functions/on_tap_movie.dart';
|
||||
import 'package:Mirarr/seriesPage/function/on_tap_serie.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class TMDBUrlParser {
|
||||
static bool isTMDBMovieUrl(String url) {
|
||||
return url.startsWith('https://www.themoviedb.org/movie/') ||
|
||||
url.startsWith('themoviedb://movie/');
|
||||
}
|
||||
|
||||
static bool isTMDBTVUrl(String url) {
|
||||
return url.startsWith('https://www.themoviedb.org/tv/') ||
|
||||
url.startsWith('themoviedb://tv/');
|
||||
}
|
||||
|
||||
static Future<String> _getMovieTitle(
|
||||
int movieId, BuildContext context) async {
|
||||
final region =
|
||||
Provider.of<RegionProvider>(context, listen: false).currentRegion;
|
||||
final responseData = await fetchMovieDetails(movieId, region);
|
||||
return responseData['title'];
|
||||
}
|
||||
|
||||
static int? parseMovieId(String url) {
|
||||
try {
|
||||
// Remove the base URL part
|
||||
String path = url.replaceAll('https://www.themoviedb.org/movie/', '');
|
||||
path = path.replaceAll('themoviedb://movie/', '');
|
||||
|
||||
// Split by dash to separate ID and title
|
||||
List<String> parts = path.split('-');
|
||||
|
||||
// First part is the ID
|
||||
return int.parse(parts[0]);
|
||||
} catch (e) {
|
||||
debugPrint('Error parsing TMDB movie ID: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<String> _getSerieTitle(
|
||||
int serieId, BuildContext context) async {
|
||||
final region =
|
||||
Provider.of<RegionProvider>(context, listen: false).currentRegion;
|
||||
final responseData = await fetchSerieDetails(serieId, region);
|
||||
return responseData['name'];
|
||||
}
|
||||
|
||||
static int? parseSerieId(String url) {
|
||||
try {
|
||||
// Remove the base URL part
|
||||
String path = url.replaceAll('https://www.themoviedb.org/tv/', '');
|
||||
path = path.replaceAll('themoviedb://tv/', '');
|
||||
|
||||
// Split by dash to separate ID and title
|
||||
List<String> parts = path.split('-');
|
||||
|
||||
// First part is the ID
|
||||
int serieId = int.parse(parts[0]);
|
||||
|
||||
return serieId;
|
||||
} catch (e) {
|
||||
debugPrint('Error parsing TMDB TV URL: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> handleUrl(String url, BuildContext context) async {
|
||||
// Ensure we're on the main thread and the context is valid
|
||||
if (!context.mounted) return;
|
||||
|
||||
if (isTMDBMovieUrl(url)) {
|
||||
final movieId = parseMovieId(url);
|
||||
if (movieId != null) {
|
||||
try {
|
||||
final movieTitle = await _getMovieTitle(movieId, context);
|
||||
if (context.mounted) {
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
onTapMovie(movieTitle, movieId, context);
|
||||
} else {
|
||||
onTapMovieDesktop(movieTitle, movieId, context);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching movie title: $e');
|
||||
}
|
||||
}
|
||||
} else if (isTMDBTVUrl(url)) {
|
||||
final serieId = parseSerieId(url);
|
||||
if (serieId != null) {
|
||||
final serieTitle = await _getSerieTitle(serieId, context);
|
||||
if (context.mounted) {
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
onTapSerie(serieTitle, serieId, context);
|
||||
} else {
|
||||
onTapSerieDesktop(serieTitle, serieId, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import 'package:Mirarr/functions/themeprovider_class.dart';
|
||||
import 'package:Mirarr/functions/regionprovider_class.dart';
|
||||
import 'package:Mirarr/functions/url_parser.dart';
|
||||
import 'package:Mirarr/widgets/check_updates.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
@ -7,9 +8,12 @@ import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:Mirarr/moviesPage/mainPage.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:app_links/app_links.dart';
|
||||
import 'dart:io';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await dotenv.load(fileName: ".env");
|
||||
@ -39,13 +43,61 @@ void main() async {
|
||||
);
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
class MyApp extends StatefulWidget {
|
||||
const MyApp({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MyApp> createState() => _MyAppState();
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
late AppLinks _appLinks;
|
||||
bool _isInitialized = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_initAppLinks();
|
||||
}
|
||||
|
||||
Future<void> _initAppLinks() async {
|
||||
if (!_isInitialized && !Platform.isLinux) {
|
||||
_appLinks = AppLinks();
|
||||
|
||||
// Handle initial URI if the app was launched from a link
|
||||
try {
|
||||
final uri = await _appLinks.getInitialAppLink();
|
||||
if (uri != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
if (navigatorKey.currentContext != null) {
|
||||
await TMDBUrlParser.handleUrl(
|
||||
uri.toString(), navigatorKey.currentContext!);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error handling initial app link: $e');
|
||||
}
|
||||
|
||||
// Handle incoming links while the app is running
|
||||
_appLinks.uriLinkStream.listen((uri) async {
|
||||
if (uri != null && navigatorKey.currentContext != null) {
|
||||
await TMDBUrlParser.handleUrl(
|
||||
uri.toString(), navigatorKey.currentContext!);
|
||||
}
|
||||
}, onError: (err) {
|
||||
debugPrint('Error handling app links: $err');
|
||||
});
|
||||
|
||||
_isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<ThemeProvider>(builder: (context, themeProvider, child) {
|
||||
return MaterialApp(
|
||||
navigatorKey: navigatorKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Mirarr',
|
||||
theme: themeProvider.currentTheme,
|
||||
|
@ -6,11 +6,15 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <gtk/gtk_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) gtk_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin");
|
||||
gtk_plugin_register_with_registrar(gtk_registrar);
|
||||
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
|
||||
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
gtk
|
||||
screen_retriever
|
||||
url_launcher_linux
|
||||
window_manager
|
||||
|
16
pubspec.lock
16
pubspec.lock
@ -1,6 +1,14 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
app_links:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: app_links
|
||||
sha256: "3ced568a5d9e309e99af71285666f1f3117bddd0bd5b3317979dccc1a40cada4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.5.1"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -216,6 +224,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
gtk:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: gtk
|
||||
sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
hive:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -27,6 +27,7 @@ dependencies:
|
||||
cupertino_icons: ^1.0.2
|
||||
provider: ^6.1.2
|
||||
shared_preferences: ^2.0.15
|
||||
app_links: ^3.5.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -6,12 +6,15 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <app_links/app_links_plugin_c_api.h>
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
AppLinksPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("AppLinksPluginCApi"));
|
||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||
ScreenRetrieverPluginRegisterWithRegistrar(
|
||||
|
@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
app_links
|
||||
connectivity_plus
|
||||
screen_retriever
|
||||
url_launcher_windows
|
||||
|
Reference in New Issue
Block a user