YouTube-Tab: Server-User brauchen keine eigene Baka-Anmeldung mehr
Server-User (Dustin, Baka, Tinker) melden sich beim Öffnen des YouTube-Bereichs automatisch im Hintergrund mit ihren Navidrome- Zugangsdaten beim Baka-Konto an (BakaAuth.autoAnmelden) — die manuelle Anmeldung bleibt nur für Gäste sichtbar. Schlägt die Auto-Anmeldung fehl, gibt es einen Rückfallweg zur manuellen Anmeldung, statt den User auszusperren. Login-Buttons vergrößert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcDiyJdVRqh1TtJk5JiabX
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
f0313724d4
commit
f604dc7635
@@ -606,11 +606,32 @@ class _YouTubeBereichState extends State<_YouTubeBereich> {
|
||||
/// Gewählter Datenträger; `null` = Android entscheidet (nur ein Ort da).
|
||||
String? _volume;
|
||||
|
||||
/// Wer am Melo-Server angemeldet ist, braucht keine eigene
|
||||
/// Baka-Anmeldung mehr — nur Gäste (kein Server-Account) sehen sie.
|
||||
bool _serverUser = false;
|
||||
|
||||
/// Die automatische Anmeldung ist fehlgeschlagen (z. B. abweichendes
|
||||
/// Baka-Passwort) — dann bleibt der manuelle Anmelde-Weg als Rückfalloption
|
||||
/// sichtbar, sonst käme so ein User nie mehr an den Dialog heran.
|
||||
bool _autoLoginFehlgeschlagen = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_ladeEinstellungen();
|
||||
_uebernimmAdresse();
|
||||
_pruefeServerUser();
|
||||
}
|
||||
|
||||
Future<void> _pruefeServerUser() async {
|
||||
final nav = context.read<DownloadService>().navidrome;
|
||||
final auth = context.read<BakaAuth>();
|
||||
final ergebnis = await pruefeServerUser(nav, auth);
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_serverUser = ergebnis.serverUser;
|
||||
_autoLoginFehlgeschlagen = ergebnis.autoLoginFehlgeschlagen;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -716,38 +737,54 @@ class _YouTubeBereichState extends State<_YouTubeBereich> {
|
||||
Widget build(BuildContext context) {
|
||||
final auth = context.watch<BakaAuth>();
|
||||
final dienst = context.watch<YtDownloadService>();
|
||||
// Server-User gelten sofort als berechtigt — die Anmeldung passiert für
|
||||
// sie im Hintergrund (_pruefeServerUser). Nur wenn die automatische
|
||||
// Anmeldung nachweislich fehlgeschlagen ist, bleibt der manuelle Weg
|
||||
// als Rückfalloption sichtbar — sonst gäbe es keinen Weg mehr zurück.
|
||||
final zugriffOk =
|
||||
auth.istAngemeldet || (_serverUser && !_autoLoginFehlgeschlagen);
|
||||
|
||||
return ListView(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 24),
|
||||
children: [
|
||||
if (!auth.istAngemeldet) ...[
|
||||
const Text(
|
||||
'Der Downloader läuft über den Baka-Server. Dafür brauchst du '
|
||||
'deine Baka-Anmeldung.',
|
||||
style: TextStyle(color: MeloTheme.text2, fontSize: 13),
|
||||
if (!zugriffOk) ...[
|
||||
Text(
|
||||
_autoLoginFehlgeschlagen
|
||||
? 'Die automatische Anmeldung hat nicht geklappt. Bitte '
|
||||
'manuell beim Baka-Konto anmelden.'
|
||||
: 'Der Downloader läuft über den Baka-Server. Dafür brauchst '
|
||||
'du deine Baka-Anmeldung.',
|
||||
style: const TextStyle(color: MeloTheme.text2, fontSize: 13),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
FilledButton.icon(
|
||||
icon: const Icon(Icons.login),
|
||||
label: const Text('Beim Baka-Konto anmelden'),
|
||||
onPressed: _anmelden,
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: MeloTheme.minTouchTarget + 4,
|
||||
child: FilledButton.icon(
|
||||
icon: const Icon(Icons.login),
|
||||
label: const Text('Beim Baka-Konto anmelden',
|
||||
style: TextStyle(fontSize: 16)),
|
||||
onPressed: _anmelden,
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.verified_user, size: 18, color: MeloTheme.text3),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text('Angemeldet als ${auth.benutzer}',
|
||||
style: const TextStyle(color: MeloTheme.text2, fontSize: 13)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: auth.abmelden,
|
||||
child: const Text('Abmelden'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (!_serverUser) ...[
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.verified_user, size: 18, color: MeloTheme.text3),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text('Angemeldet als ${auth.benutzer}',
|
||||
style: const TextStyle(color: MeloTheme.text2, fontSize: 13)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: auth.abmelden,
|
||||
child: const Text('Abmelden'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
TextField(
|
||||
controller: _url,
|
||||
enabled: !dienst.laeuft,
|
||||
@@ -909,14 +946,19 @@ class _AnmeldeDialogState extends State<_AnmeldeDialog> {
|
||||
),
|
||||
],
|
||||
),
|
||||
actionsPadding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
minimumSize: const Size(88, MeloTheme.minTouchTarget)),
|
||||
onPressed: _verbindet ? null : () => Navigator.pop(context),
|
||||
child: const Text('Abbrechen'),
|
||||
child: const Text('Abbrechen', style: TextStyle(fontSize: 16)),
|
||||
),
|
||||
FilledButton(
|
||||
style: FilledButton.styleFrom(
|
||||
minimumSize: const Size(120, MeloTheme.minTouchTarget)),
|
||||
onPressed: _verbindet ? null : _anmelden,
|
||||
child: const Text('Anmelden'),
|
||||
child: const Text('Anmelden', style: TextStyle(fontSize: 16)),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:provider/provider.dart';
|
||||
import '../library/database.dart';
|
||||
import '../library/library_service.dart';
|
||||
import '../services/baka_auth.dart';
|
||||
import '../services/download_service.dart';
|
||||
import '../services/media_store.dart';
|
||||
import '../services/yt_download_service.dart';
|
||||
import '../services/yt_search_service.dart';
|
||||
@@ -25,6 +26,31 @@ class YoutubeSearchScreen extends StatefulWidget {
|
||||
class _YoutubeSearchScreenState extends State<YoutubeSearchScreen> {
|
||||
final _query = TextEditingController();
|
||||
|
||||
/// Server-User (siehe _YouTubeBereich in downloads_screen.dart) brauchen
|
||||
/// hier keinen Anmelde-Hinweis — die Anmeldung passiert im Hintergrund.
|
||||
bool _serverUser = false;
|
||||
|
||||
/// Die automatische Anmeldung ist fehlgeschlagen — dann bleibt der
|
||||
/// Hinweis auf die manuelle Anmeldung (siehe Download-Tab) sichtbar.
|
||||
bool _autoLoginFehlgeschlagen = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_pruefeServerUser();
|
||||
}
|
||||
|
||||
Future<void> _pruefeServerUser() async {
|
||||
final nav = context.read<DownloadService>().navidrome;
|
||||
final auth = context.read<BakaAuth>();
|
||||
final ergebnis = await pruefeServerUser(nav, auth);
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_serverUser = ergebnis.serverUser;
|
||||
_autoLoginFehlgeschlagen = ergebnis.autoLoginFehlgeschlagen;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_query.dispose();
|
||||
@@ -42,6 +68,8 @@ class _YoutubeSearchScreenState extends State<YoutubeSearchScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
final auth = context.watch<BakaAuth>();
|
||||
final suche = context.watch<YtSearchService>();
|
||||
final zugriffOk =
|
||||
auth.istAngemeldet || (_serverUser && !_autoLoginFehlgeschlagen);
|
||||
|
||||
return SafeArea(
|
||||
child: Column(
|
||||
@@ -69,7 +97,7 @@ class _YoutubeSearchScreenState extends State<YoutubeSearchScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
if (!auth.istAngemeldet)
|
||||
if (!zugriffOk)
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
|
||||
@@ -4,6 +4,8 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'navidrome_service.dart';
|
||||
|
||||
/// Ablage für den Anmelde-Token. Als Schnittstelle, damit Tests ohne die
|
||||
/// Plattform-Kanäle von FlutterSecureStorage auskommen.
|
||||
abstract class TokenSpeicher {
|
||||
@@ -100,6 +102,15 @@ class BakaAuth extends ChangeNotifier {
|
||||
'Anmeldung fehlgeschlagen (${antwort.statusCode})';
|
||||
}
|
||||
|
||||
/// Meldet automatisch an, falls noch nicht angemeldet — für Server-User
|
||||
/// (Dustin, Baka, Tinker), die keine eigene Baka-Anmeldung mehr sehen
|
||||
/// sollen: der Proxy nutzt seine YouTube-Cookies für jeden
|
||||
/// authentifizierten Aufruf ohnehin automatisch.
|
||||
Future<void> autoAnmelden(String benutzer, String passwort) async {
|
||||
if (istAngemeldet || benutzer.isEmpty || passwort.isEmpty) return;
|
||||
await anmelden(benutzer, passwort);
|
||||
}
|
||||
|
||||
Future<void> abmelden() async {
|
||||
_token = null;
|
||||
_benutzer = '';
|
||||
@@ -108,3 +119,20 @@ class BakaAuth extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
/// Prüft, ob ein Server-User verbunden ist, und meldet ihn dann automatisch
|
||||
/// beim Baka-Konto an — geteilte Logik für den YouTube-Bereich
|
||||
/// (downloads_screen.dart) und die YT-Suche (youtube_search_screen.dart).
|
||||
/// Gäste (kein Server-Account) bleiben unangetastet. Schlägt die
|
||||
/// Hintergrund-Anmeldung fehl (falsche/fehlende Zugangsdaten, Server nicht
|
||||
/// erreichbar), meldet [autoLoginFehlgeschlagen] das zurück — sonst bliebe
|
||||
/// so ein User ohne jeden Weg mehr zur manuellen Baka-Anmeldung.
|
||||
Future<({bool serverUser, bool autoLoginFehlgeschlagen})> pruefeServerUser(
|
||||
NavidromeService navidrome, BakaAuth auth) async {
|
||||
await navidrome.ladeGespeicherteZugangsdaten();
|
||||
if (!navidrome.istVerbunden) {
|
||||
return (serverUser: false, autoLoginFehlgeschlagen: false);
|
||||
}
|
||||
await auth.autoAnmelden(navidrome.benutzer, navidrome.passwort);
|
||||
return (serverUser: true, autoLoginFehlgeschlagen: !auth.istAngemeldet);
|
||||
}
|
||||
|
||||
@@ -140,6 +140,12 @@ class NavidromeService {
|
||||
|
||||
bool get istVerbunden => _serverUrl.isNotEmpty && _user.isNotEmpty;
|
||||
|
||||
/// Für die automatische Baka-Anmeldung verbundener Server-User (siehe
|
||||
/// [BakaAuth.autoAnmelden]) — Navidrome- und Baka-Konto teilen sich die
|
||||
/// Zugangsdaten.
|
||||
String get benutzer => _user;
|
||||
String get passwort => _password;
|
||||
|
||||
/// Dekodiert eine Subsonic-JSON-Antwort und wirft [NavidromeException],
|
||||
/// wenn der Server `status:"failed"` meldet (z. B. falsches Passwort) —
|
||||
/// solche Antworten kommen mit HTTP 200 und dürfen nicht als „leer" gelten.
|
||||
|
||||
Reference in New Issue
Block a user