| import { useEffect, useState } from 'react' |
| import { useAtom } from 'jotai' |
| import { Switch } from '@headlessui/react' |
| import { toast } from 'react-hot-toast' |
| import { hashAtom, voiceAtom } from '@/state' |
| import { |
| Dialog, |
| DialogContent, |
| DialogDescription, |
| DialogFooter, |
| DialogHeader, |
| DialogTitle |
| } from '@/components/ui/dialog' |
| import { Button } from './ui/button' |
| import { Input } from './ui/input' |
| import { ChunkKeys, parseCookies, extraCurlFromCookie, randomIP, encodeHeadersToCookie } from '@/lib/utils' |
| import { ExternalLink } from './external-link' |
| import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard' |
|
|
| export function Settings() { |
| const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 }) |
| const [loc, setLoc] = useAtom(hashAtom) |
| const [curlValue, setCurlValue] = useState(extraCurlFromCookie(parseCookies(document.cookie, ChunkKeys))) |
| const [enableTTS, setEnableTTS] = useAtom(voiceAtom) |
|
|
| useEffect(() => { |
| if (isCopied) { |
| toast.success('复制成功') |
| } |
| }, [isCopied]) |
|
|
| if (loc === 'settings') { |
| return ( |
| <Dialog open onOpenChange={() => setLoc('')} modal> |
| <DialogContent> |
| <DialogHeader> |
| <DialogTitle>设置你的用户信息</DialogTitle> |
| <DialogDescription> |
| 请使用 Edge 浏览器 |
| <ExternalLink |
| href="https://www.bing.com/turing/captcha/challenge" |
| > |
| 打开并登录 Bing |
| </ExternalLink> |
| ,然后再打开 |
| <ExternalLink href="https://www.bing.com/turing/captcha/challenge">Challenge 接口</ExternalLink> |
| 右键 》检查。打开开发者工具,在网络里面找到 Create 接口 》右键复制》复制为 cURL(bash),粘贴到此处,然后保存。 |
| <div className="h-2" /> |
| 图文示例: |
| <ExternalLink href="https://github.com/weaigc/bingo#如何获取%20BING_HEADER">如何获取 BING_HEADER</ExternalLink> |
| </DialogDescription> |
| </DialogHeader> |
| <div className="flex gap-4"> |
| |
| </div> |
| <Input |
| value={curlValue} |
| placeholder="在此填写用户信息,格式: curl 'https://www.bing.com/turing/captcha/challenge' ..." |
| onChange={e => setCurlValue(e.target.value)} |
| /> |
| <Button variant="ghost" className="bg-[#F5F5F5] hover:bg-[#F2F2F2]" onClick={() => copyToClipboard(btoa(curlValue))}> |
| 转成 BING_HEADER 并复制 |
| </Button> |
| |
| <DialogFooter className="items-center"> |
| <Button |
| variant="secondary" |
| className="bg-[#c7f3ff] hover:bg-[#fdc7ff]" |
| onClick={() => { |
| let headerValue = curlValue |
| if (headerValue) { |
| try { |
| headerValue = atob(headerValue) |
| } catch (e) {} |
| if (!/^\s*curl ['"]https:\/\/www\.bing\.com\/turing\/captcha\/challenge['"]/.test(headerValue)) { |
| toast.error('格式不正确') |
| return |
| } |
| const maxAge = 86400 * 30 |
| encodeHeadersToCookie(headerValue).forEach(cookie => document.cookie = `${cookie}; Max-Age=${maxAge}; Path=/; SameSite=None; Secure`) |
| } else { |
| [...ChunkKeys, 'BING_COOKIE', 'BING_UA', 'BING_IP'].forEach(key => document.cookie = `${key}=; Path=/; SameSite=None; Secure`) |
| } |
| |
| toast.success('保存成功') |
| setLoc('') |
| setTimeout(() => { |
| location.href = './' |
| }, 2000) |
| }} |
| > |
| 保存 |
| </Button> |
| </DialogFooter> |
| </DialogContent> |
| </Dialog> |
| ) |
| } else if (loc === 'voice') { |
| return ( |
| <Dialog open onOpenChange={() => setLoc('')} modal> |
| <DialogContent> |
| <DialogHeader> |
| <DialogTitle>语音设置</DialogTitle> |
| <DialogDescription> |
| 目前仅支持 PC 端 Edge 及 Chrome 浏览器 |
| </DialogDescription> |
| </DialogHeader> |
| |
| <div className="flex gap-2"> |
| 启用语音回答 |
| <Switch |
| checked={enableTTS} |
| className={`${enableTTS ? 'bg-blue-600' : 'bg-gray-200'} relative inline-flex h-6 w-11 items-center rounded-full`} |
| onChange={(checked: boolean) => setEnableTTS(checked)} |
| > |
| <span |
| className={`${enableTTS ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition`} |
| /> |
| </Switch> |
| </div> |
| |
| <DialogFooter className="items-center"> |
| <Button |
| variant="secondary" |
| onClick={() => { |
| toast.success('保存成功') |
| setLoc('') |
| setTimeout(() => { |
| location.href = './' |
| }, 2000) |
| }} |
| > |
| 保存 |
| </Button> |
| </DialogFooter> |
| </DialogContent> |
| </Dialog> |
| ) |
| } |
| return null |
| } |
|
|