{"record":{"id":"39040f58e3780d3b","repo":"fish2018/pansou","slug":"error","errorCode":null,"errorMessage":"链接令牌请求过于频繁","messagePattern":"链接令牌请求过于频繁","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"plugin/ting77/ting77.go","lineNumber":33,"sourceCode":"\n\t\"github.com/PuerkitoBio/goquery\"\n\t\"pansou/model\"\n\t\"pansou/plugin\"\n\t\"pansou/util/json\"\n)\n\nconst (\n\tpluginName       = \"ting77\"\n\tpluginPriority   = 2\n\tdefaultBaseURL   = \"https://sou.77ting.top\"\n\trequestTimeout   = 25 * time.Second\n\tmaxResponseBytes = 4 << 20\n\tmaxTokenRequests = 8\n\ttokenWindow      = 65 * time.Second\n\tbrowserUserAgent = \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\"\n)\n\nvar errRateLimited = errors.New(\"链接令牌请求过于频繁\")\n\nfunc init() {\n\tplugin.RegisterGlobalPlugin(NewTing77Plugin())\n}\n\ntype Ting77Plugin struct {\n\t*plugin.BaseAsyncPlugin\n\tbaseURL      string\n\tlinkCache    sync.Map\n\ttokenMu      sync.Mutex\n\ttokenRequest []time.Time\n}\n\nfunc NewTing77Plugin() *Ting77Plugin {\n\treturn &Ting77Plugin{\n\t\tBaseAsyncPlugin: plugin.NewBaseAsyncPlugin(pluginName, pluginPriority),\n\t\tbaseURL:         defaultBaseURL,\n\t}","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/ting77/ting77.go#L15-L51","documentation":"errRateLimited is ting77's sentinel error meaning the plugin hit its self-imposed token-request budget (maxTokenRequests=8 within a 65s window). resolveLink/fetchLinkToken return it when the site throttles or the budget is exhausted; resolveEntries and the worker loop break out instead of hammering the site.","triggerScenarios":"Requesting more than 8 link tokens within 65 seconds (e.g. resolving many entries at once); the remote ting77 site returning throttle/429 responses during token fetching.","commonSituations":"Bulk-searching songs with many matching entries so each resolveLink consumes budget; repeated searches within a minute; slow site responses causing retries that burn the token budget.","solutions":["Wait ~65 seconds for the token window to reset, then retry","Reduce concurrency / number of entries resolved per search to stay under 8 token requests per window","Increase maxTokenRequests or tokenWindow constants if the site tolerates more traffic","Persist resolved tokens so repeat searches don't re-fetch links"],"exampleFix":"// before\nif errors.Is(lastErr, errRateLimited) {\n    break\n}\n// after\nif errors.Is(lastErr, errRateLimited) {\n    time.Sleep(tokenWindow)\n    // retry resolveEntries once\n    break\n}","handlingStrategy":"retry","validationCode":"// Go\nif tokensUsedInWindow() >= maxTokenRequests { waitUntilWindowReset() }","typeGuard":null,"tryCatchPattern":"if errors.Is(err, errRateLimited) {\n    time.Sleep(tokenWindow)\n    // retry once\n}","preventionTips":["Throttle link-token requests client-side to under 8 per 65s","Cache resolved links to avoid repeated token fetches","Limit entries resolved per search"],"tags":["rate-limit","throttling","go","plugin"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}