YouTube-Gast-Zugang (App-Seite): 5 Downloads/Tag ohne Konto #4

Closed
dustin wants to merge 12 commits from feature/youtube-gast-zugang into fix/p0-vollwertigkeit
2 changed files with 67 additions and 4 deletions
Showing only changes of commit 9e2294a480 - Show all commits
+10 -4
View File
@@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'baka_auth.dart'; import 'baka_auth.dart';
import 'gast_zugang.dart';
import 'yt_download_service.dart'; import 'yt_download_service.dart';
/// Ein Treffer der YouTube-Suche über den Baka-Proxy. /// Ein Treffer der YouTube-Suche über den Baka-Proxy.
@@ -44,12 +45,13 @@ String? youtubeVideoId(String url) {
/// Durchsucht YouTube über den Baka-Proxy (`/api/search`, yt-dlp-gestützt) — /// Durchsucht YouTube über den Baka-Proxy (`/api/search`, yt-dlp-gestützt) —
/// dieselbe Anmeldung wie [YtDownloadService]. /// dieselbe Anmeldung wie [YtDownloadService].
class YtSearchService extends ChangeNotifier { class YtSearchService extends ChangeNotifier {
YtSearchService({required this.auth, http.Client? client}) YtSearchService({required this.auth, this.gast, http.Client? client})
: _client = client ?? http.Client(); : _client = client ?? http.Client();
static const proxyUrl = YtDownloadService.proxyUrl; static const proxyUrl = YtDownloadService.proxyUrl;
final BakaAuth auth; final BakaAuth auth;
final GastZugang? gast;
final http.Client _client; final http.Client _client;
bool _laeuft = false; bool _laeuft = false;
@@ -64,7 +66,8 @@ class YtSearchService extends ChangeNotifier {
final q = query.trim(); final q = query.trim();
if (q.isEmpty) return; if (q.isEmpty) return;
if (!auth.istAngemeldet) { final gastAktiv = !auth.istAngemeldet && (gast?.hatToken ?? false);
if (!auth.istAngemeldet && !gastAktiv) {
_treffer = const []; _treffer = const [];
_fehler = 'Bitte zuerst beim Baka-Konto anmelden'; _fehler = 'Bitte zuerst beim Baka-Konto anmelden';
notifyListeners(); notifyListeners();
@@ -80,7 +83,7 @@ class YtSearchService extends ChangeNotifier {
final http.Response antwort; final http.Response antwort;
try { try {
antwort = await _client antwort = await _client
.get(uri, headers: auth.authHeader) .get(uri, headers: gastAktiv ? gast!.gastHeader : auth.authHeader)
.timeout(const Duration(seconds: 20)); .timeout(const Duration(seconds: 20));
} on TimeoutException { } on TimeoutException {
_scheitere('Die Suche braucht zu lange — bitte später erneut versuchen'); _scheitere('Die Suche braucht zu lange — bitte später erneut versuchen');
@@ -92,7 +95,10 @@ class YtSearchService extends ChangeNotifier {
} }
if (antwort.statusCode == 401) { if (antwort.statusCode == 401) {
_scheitere('Anmeldung abgelaufen — bitte neu anmelden'); if (gastAktiv) unawaited(gast!.holeToken());
_scheitere(gastAktiv
? 'Gast-Zugang abgelaufen — bitte erneut versuchen'
: 'Anmeldung abgelaufen — bitte neu anmelden');
return; return;
} }
if (antwort.statusCode != 200) { if (antwort.statusCode != 200) {
+57
View File
@@ -5,6 +5,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:http/testing.dart'; import 'package:http/testing.dart';
import 'package:melo/services/baka_auth.dart'; import 'package:melo/services/baka_auth.dart';
import 'package:melo/services/gast_zugang.dart';
import 'package:melo/services/yt_search_service.dart'; import 'package:melo/services/yt_search_service.dart';
class _MemorySpeicher implements TokenSpeicher { class _MemorySpeicher implements TokenSpeicher {
@@ -200,5 +201,61 @@ void main() {
await dienst.suchen('zweite suche'); await dienst.suchen('zweite suche');
expect(dienst.treffer.single.title, 'Zweites'); expect(dienst.treffer.single.title, 'Zweites');
}); });
test('Mit Gast-Token statt Anmeldung wird trotzdem gesucht', () async {
final speicher = _MemorySpeicher();
speicher.werte['guest_token'] = 'gast-xyz';
final gast = GastZugang(
client: MockClient((_) async => http.Response('', 500)),
speicher: speicher,
);
await gast.laden();
final dienst = YtSearchService(
auth: BakaAuth(
client: MockClient((_) async => http.Response('', 500)),
speicher: _MemorySpeicher()),
gast: gast,
client: MockClient((req) async {
expect(req.headers['X-Guest-Token'], 'gast-xyz');
expect(req.headers.containsKey('Authorization'), isFalse);
return http.Response('[]', 200);
}),
);
await dienst.suchen('roses');
expect(dienst.fehler, isNull);
});
test('401 bei Gast-Zugang holt automatisch einen neuen Gast-Token',
() async {
var tokenAufrufe = 0;
final speicher = _MemorySpeicher();
speicher.werte['guest_token'] = 'alter-token';
final gast = GastZugang(
client: MockClient((_) async {
tokenAufrufe++;
return http.Response(
jsonEncode({'guest_token': 'neuer-token'}), 200);
}),
speicher: speicher,
);
await gast.laden();
final dienst = YtSearchService(
auth: BakaAuth(
client: MockClient((_) async => http.Response('', 500)),
speicher: _MemorySpeicher()),
gast: gast,
client: MockClient((_) async => http.Response('Unauthorized', 401)),
);
await dienst.suchen('roses');
await Future<void>.delayed(Duration.zero);
expect(dienst.fehler, 'Gast-Zugang abgelaufen — bitte erneut versuchen');
expect(tokenAufrufe, 1);
});
}); });
} }