Cookies: keep every site of an imported file (no site picker); only the cookies box takes drops on Settings
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
75065f90cd
commit
05f9e794a9
4 files changed
+11
-58
No files matched your search
@@ -337,7 +337,7 @@ shows its version and has "Update now"), so there is nothing to install.
|
|||||||
Sites that refuse guests (Bilibili answers "HTTP Error 412", YouTube may
|
Sites that refuse guests (Bilibili answers "HTTP Error 412", YouTube may
|
||||||
ask to sign in) need cookies: Settings → Player → yt-dlp → Cookies reads
|
ask to sign in) need cookies: Settings → Player → yt-dlp → Cookies reads
|
||||||
them from a browser, or from a cookies.txt or a cookie extension's JSON
|
them from a browser, or from a cookies.txt or a cookie extension's JSON
|
||||||
export (picked or dropped; tick the sites to keep). They stay on this
|
export (picked or dropped; every site in it is kept). They stay on this
|
||||||
computer and are used by its yt-dlp only (your own playback, "through
|
computer and are used by its yt-dlp only (your own playback, "through
|
||||||
me", and a server you host). Cookies log yt-dlp in as you on those
|
me", and a server you host). Cookies log yt-dlp in as you on those
|
||||||
sites: keep the file private, and for YouTube consider a throwaway
|
sites: keep the file private, and for YouTube consider a throwaway
|
||||||
|
|||||||
@@ -501,7 +501,9 @@ class AppShellState extends State<AppShell> with SingleTickerProviderStateMixin
|
|||||||
_selectTab(ShellTab.library);
|
_selectTab(ShellTab.library);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Off on Settings: its own drop targets (cookies) take the files there.
|
||||||
Widget _dropTarget(Widget child) => DropTarget(
|
Widget _dropTarget(Widget child) => DropTarget(
|
||||||
|
enable: _tab != ShellTab.settings,
|
||||||
onDragEntered: (_) => setState(() => _dragging = _onTop),
|
onDragEntered: (_) => setState(() => _dragging = _onTop),
|
||||||
onDragExited: (_) => setState(() => _dragging = false),
|
onDragExited: (_) => setState(() => _dragging = false),
|
||||||
onDragDone: (d) {
|
onDragDone: (d) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:fox_utils/fox_utils.dart' show DesktopDropX, DropTarget;
|
import 'package:fox_utils/fox_utils.dart' show DesktopDropX, DropTarget;
|
||||||
import 'package:signals/signals_flutter.dart';
|
import 'package:signals/signals_flutter.dart';
|
||||||
import 'package:sync_relay_core/core.dart'
|
import 'package:sync_relay_core/core.dart'
|
||||||
show CookieBrowser, CookieFile, NetscapeCookie, YtDlp, YtDlpCookies, cookieBrowsers, cookiesBySite, parseCookies, suggestedCookieSites;
|
show CookieBrowser, CookieFile, NetscapeCookie, YtDlp, YtDlpCookies, cookieBrowsers, parseCookies;
|
||||||
|
|
||||||
import '../controls/player_settings.dart';
|
import '../controls/player_settings.dart';
|
||||||
import '../jellyfin/accounts.dart';
|
import '../jellyfin/accounts.dart';
|
||||||
@@ -461,7 +461,8 @@ class _YtDlpCookieSettingsState extends State<YtDlpCookieSettings> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String get _summary => switch (_source) {
|
String get _summary => switch (_source) {
|
||||||
CookieFile f => '${f.count} cookie${f.count == 1 ? '' : 's'} for ${f.sites.join(', ')}',
|
CookieFile f => '${f.count} cookie${f.count == 1 ? '' : 's'} for '
|
||||||
|
'${f.sites.length <= 3 ? f.sites.join(', ') : '${f.sites.length} sites'}',
|
||||||
CookieBrowser b => 'From ${b.browser}${b.profile.isEmpty ? '' : ' (profile ${b.profile})'}',
|
CookieBrowser b => 'From ${b.browser}${b.profile.isEmpty ? '' : ' (profile ${b.profile})'}',
|
||||||
_ => 'No cookies: yt-dlp visits sites as a guest',
|
_ => 'No cookies: yt-dlp visits sites as a guest',
|
||||||
};
|
};
|
||||||
@@ -494,14 +495,9 @@ class _YtDlpCookieSettingsState extends State<YtDlpCookieSettings> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final bySite = cookiesBySite(all);
|
// Every site in the file: an export is "my logins", not a pick list.
|
||||||
final sites = await showDialog<Set<String>>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => _CookieSitesDialog(bySite: {for (final e in bySite.entries) e.key: e.value.length}),
|
|
||||||
);
|
|
||||||
if (sites == null || sites.isEmpty) return;
|
|
||||||
try {
|
try {
|
||||||
await widget.cookies.saveFile([for (final s in sites) ...?bySite[s]]);
|
await widget.cookies.saveFile(all);
|
||||||
_reload();
|
_reload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_reload('Could not keep the cookies: $e');
|
_reload('Could not keep the cookies: $e');
|
||||||
@@ -586,7 +582,7 @@ class _YtDlpCookieSettingsState extends State<YtDlpCookieSettings> {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'For sites that refuse guests (Bilibili, YouTube asking to sign in). Drop a cookies.txt or a '
|
'For sites that refuse guests (Bilibili, YouTube asking to sign in). Drop a cookies.txt or a '
|
||||||
'cookie-extension JSON export here, or pick one; only the sites you tick are kept, on this computer only. '
|
'cookie-extension JSON export here, or pick one; all of it is kept, on this computer only. '
|
||||||
'Cookies log yt-dlp in as you on those sites. Keep the file private; for YouTube consider a '
|
'Cookies log yt-dlp in as you on those sites. Keep the file private; for YouTube consider a '
|
||||||
'throwaway account (Google may flag accounts used with yt-dlp).',
|
'throwaway account (Google may flag accounts used with yt-dlp).',
|
||||||
style: TextStyle(color: scheme.onSurfaceVariant, fontSize: 12),
|
style: TextStyle(color: scheme.onSurfaceVariant, fontSize: 12),
|
||||||
@@ -598,51 +594,6 @@ class _YtDlpCookieSettingsState extends State<YtDlpCookieSettings> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which sites of an imported cookie file to keep; pops the ticked ones.
|
|
||||||
class _CookieSitesDialog extends StatefulWidget {
|
|
||||||
/// Site -> number of cookies.
|
|
||||||
final Map<String, int> bySite;
|
|
||||||
const _CookieSitesDialog({required this.bySite});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<_CookieSitesDialog> createState() => _CookieSitesDialogState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CookieSitesDialogState extends State<_CookieSitesDialog> {
|
|
||||||
late final _on = {for (final s in widget.bySite.keys) if (suggestedCookieSites.contains(s)) s};
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: const Text('Keep cookies for'),
|
|
||||||
content: SizedBox(
|
|
||||||
width: 380,
|
|
||||||
child: ListView(
|
|
||||||
shrinkWrap: true,
|
|
||||||
children: [
|
|
||||||
for (final e in widget.bySite.entries)
|
|
||||||
CheckboxListTile(
|
|
||||||
dense: true,
|
|
||||||
value: _on.contains(e.key),
|
|
||||||
title: Text(e.key),
|
|
||||||
subtitle: Text('${e.value} cookie${e.value == 1 ? '' : 's'}'),
|
|
||||||
onChanged: (v) => setState(() => v == true ? _on.add(e.key) : _on.remove(e.key)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(onPressed: () => Navigator.pop(context), child: const Text('Cancel')),
|
|
||||||
FilledButton(
|
|
||||||
onPressed: _on.isEmpty ? null : () => Navigator.pop(context, {..._on}),
|
|
||||||
child: const Text('Keep'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Which browser (and profile) yt-dlp reads cookies from.
|
|
||||||
class _CookieBrowserDialog extends StatefulWidget {
|
class _CookieBrowserDialog extends StatefulWidget {
|
||||||
final CookieBrowser? initial;
|
final CookieBrowser? initial;
|
||||||
const _CookieBrowserDialog({this.initial});
|
const _CookieBrowserDialog({this.initial});
|
||||||
|
|||||||
@@ -560,8 +560,8 @@ all three link modes. Nothing is bundled or installed by hand.
|
|||||||
registrable domain by a short rule, with google.com filed under
|
registrable domain by a short rule, with google.com filed under
|
||||||
youtube.com and bilibili's CDNs under bilibili.com). The app: Settings
|
youtube.com and bilibili's CDNs under bilibili.com). The app: Settings
|
||||||
→ Player → yt-dlp → Cookies (a browser and profile, or a file picked or
|
→ Player → yt-dlp → Cookies (a browser and profile, or a file picked or
|
||||||
dropped, then the sites to keep, bilibili.com and youtube.com ticked
|
dropped, kept whole: every site in it; "Remove cookies"; the shell's
|
||||||
when present; "Remove cookies"); its hosted server shares the folder,
|
own drop target is off on Settings so only this box takes the file); its hosted server shares the folder,
|
||||||
so it uses them too. mpv's hook gets the same as `ytdl-raw-options`
|
so it uses them too. mpv's hook gets the same as `ytdl-raw-options`
|
||||||
(`cookies=%N%<path>` / `cookies-from-browser=%N%<spec>`, length-quoted),
|
(`cookies=%N%<path>` / `cookies-from-browser=%N%<spec>`, length-quoted),
|
||||||
re-set before each external link when it changed. The dedicated
|
re-set before each external link when it changed. The dedicated
|
||||||
|
|||||||
Reference in new issue
Block a user