├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── -------.md │ └── bug--.md ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── codeql-analysis.yml │ ├── gitee-sync.yml │ └── release.yaml ├── .gitignore ├── .vscode └── launch.json ├── EXAMPLE.md ├── FAQ.md ├── FRAMEWORK.md ├── INSTALL.md ├── LICENSE ├── Makefile ├── README.md ├── TEMPLATE.md ├── UPDATE.md ├── admin.txt ├── bot.go ├── bot ├── .github │ └── dependabot.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── app.go ├── bot │ ├── bot.go │ ├── login.go │ ├── module.go │ ├── moduleid.go │ └── moduleinfo.go ├── config │ └── config.go ├── go.mod ├── go.sum ├── internal │ └── encryption │ │ ├── config.go │ │ └── t544 │ │ ├── data.go │ │ ├── encryption.go │ │ ├── encryption_amd64.s │ │ ├── encryption_generic.go │ │ ├── t544.go │ │ ├── t544_stub.go │ │ ├── t544_test.go │ │ └── transform.go ├── modules │ └── logging │ │ └── log.go └── utils │ ├── fs.go │ ├── log.go │ └── net.go ├── cmd ├── hook_other.go ├── hook_windows.go ├── main.go └── play.go ├── go.mod ├── go.sum ├── image_pool ├── local_pool │ └── pool.go ├── lolicon_pool │ ├── api.go │ ├── error.go │ ├── persist.go │ └── pool.go ├── model.go └── pool.go ├── internal ├── test │ └── test.go └── test_concern │ └── concern.go ├── logging └── log.go ├── lsp ├── acfun │ ├── acfun.go │ ├── acfun.pb.go │ ├── acfun.proto │ ├── acfun_test.go │ ├── apiChannelList.go │ ├── apiChannelList_test.go │ ├── concern.go │ ├── concern_test.go │ ├── config.go │ ├── config_test.go │ ├── init.go │ ├── keyset.go │ ├── keyset_test.go │ ├── livePage.go │ ├── livePage_test.go │ ├── model.go │ ├── stateManager.go │ └── stateManager_test.go ├── bilibili │ ├── README.md │ ├── XRelationStat.go │ ├── XSpaceAccInfo.go │ ├── XSpaceAccInfo_test.go │ ├── XWebInterfaceNav.go │ ├── XWebInterfaceNav_test.go │ ├── bilibili.go │ ├── bilibili.pb.go │ ├── bilibili.proto │ ├── bilibili_test.go │ ├── card_extension.go │ ├── card_extension_test.go │ ├── concern.go │ ├── concern_emit_fresher.go │ ├── concern_fresher.go │ ├── concern_test.go │ ├── config.go │ ├── config_test.go │ ├── dynamicHistory.go │ ├── dynamicHistory_test.go │ ├── dynamicNew.go │ ├── dynamicNew_test.go │ ├── feedList.go │ ├── feedList_test.go │ ├── getAttentionList.go │ ├── getAttentionList_test.go │ ├── init.go │ ├── keyset.go │ ├── keyset_test.go │ ├── login.go │ ├── login_test.go │ ├── model.go │ ├── model_test.go │ ├── relation.go │ ├── relation_test.go │ ├── spaceHistory.go │ ├── spaceHistory_test.go │ ├── stateManager.go │ └── stateManager_test.go ├── buntdb │ ├── buntdb.go │ ├── buntdb_test.go │ ├── errors.go │ ├── key.go │ ├── key_test.go │ ├── option.go │ ├── option_test.go │ ├── shortcut.go │ └── shortcut_test.go ├── cfg │ ├── config.go │ └── logger.go ├── command.go ├── commandRunetime_test.go ├── commandRuntime.go ├── command_test.go ├── concern │ ├── callback.go │ ├── callback_test.go │ ├── concern.go │ ├── concern_ext.go │ ├── config.go │ ├── config_at.go │ ├── config_filter.go │ ├── config_notify.go │ ├── config_test.go │ ├── errors.go │ ├── hook.go │ ├── hook_test.go │ ├── identity.go │ ├── identity_test.go │ ├── json.go │ ├── keyset.go │ ├── keyset_test.go │ ├── registry.go │ ├── registry_test.go │ ├── stateManager.go │ └── stateManager_test.go ├── concern_type │ ├── type.go │ └── type_test.go ├── cron.go ├── douyu │ ├── betard.go │ ├── concern.go │ ├── concern_test.go │ ├── config.go │ ├── config_test.go │ ├── douyu.go │ ├── douyu.pb.go │ ├── douyu.proto │ ├── douyu_test.go │ ├── errors.go │ ├── init.go │ ├── keyset.go │ ├── keyset_test.go │ ├── model.go │ ├── model_test.go │ ├── stateManager.go │ └── stateManager_test.go ├── groupCommand.go ├── huya │ ├── concern.go │ ├── concern_test.go │ ├── config.go │ ├── config_test.go │ ├── errors.go │ ├── huya.go │ ├── init.go │ ├── keyset.go │ ├── keyset_test.go │ ├── model.go │ ├── model_test.go │ ├── roomPage.go │ ├── stateManager.go │ └── stateManager_test.go ├── iCommand.go ├── iCommand_test.go ├── messageContext.go ├── migration_v1.go ├── migration_v1_test.go ├── migrations.go ├── mmsg │ ├── at.go │ ├── ctx.go │ ├── cut.go │ ├── image.go │ ├── image_test.go │ ├── logger.go │ ├── poke.go │ ├── target.go │ ├── target_test.go │ ├── type.go │ ├── typed.go │ ├── typed_test.go │ ├── writer.go │ └── writer_test.go ├── module.go ├── notify.go ├── notify_test.go ├── parser │ ├── parser.go │ └── parser_test.go ├── permission │ ├── errors.go │ ├── errors_test.go │ ├── keyset.go │ ├── keyset_test.go │ ├── permission.go │ ├── permission_test.go │ ├── stateManager.go │ └── stateManager_test.go ├── privateCommand.go ├── stateManager.go ├── stateManager_test.go ├── status.go ├── status_test.go ├── template │ ├── README.md │ ├── default │ │ ├── .keep │ │ ├── command.group.checkin.tmpl │ │ ├── command.group.help.tmpl │ │ ├── command.group.lsp.tmpl │ │ ├── command.private.help.tmpl │ │ ├── command.private.ping.tmpl │ │ ├── notify.group.acfun.live.tmpl │ │ ├── notify.group.bilibili.live.tmpl │ │ ├── notify.group.douyu.live.tmpl │ │ ├── notify.group.huya.live.tmpl │ │ ├── trigger.group.member_in.tmpl │ │ ├── trigger.group.member_out.tmpl │ │ ├── trigger.group.poke.tmpl │ │ ├── trigger.private.group_invited.tmpl │ │ ├── trigger.private.new_friend_added.tmpl │ │ └── trigger.private.poke.tmpl │ ├── error.go │ ├── exec.go │ ├── funcs.go │ ├── funcs_cast_ext.go │ ├── funcs_cmp_ext.go │ ├── funcs_date_ext.go │ ├── funcs_default_ext.go │ ├── funcs_dict_ext.go │ ├── funcs_ext.go │ ├── funcs_hash_ext.go │ ├── funcs_json_ext.go │ ├── funcs_list_ext.go │ ├── funcs_request_ext.go │ ├── funcs_strings_ext.go │ ├── helper.go │ ├── loader.go │ ├── logger.go │ ├── option.go │ ├── sort.go │ ├── template.go │ └── template_test.go ├── twitcasting │ ├── concern.go │ ├── config.go │ ├── live.go │ └── notify.go ├── version.go ├── version │ ├── errors.go │ ├── helper.go │ ├── migration.go │ ├── migration_test.go │ ├── version.go │ └── version_test.go ├── version_test.go ├── weibo │ ├── concern.go │ ├── concern_test.go │ ├── containerGetIndex.go │ ├── containerGetIndex_test.go │ ├── freshCookie.go │ ├── freshCookie_test.go │ ├── init.go │ ├── keyset.go │ ├── keyset_test.go │ ├── model.go │ ├── model_test.go │ ├── stateManager.go │ ├── stateManager_test.go │ ├── weibo.go │ ├── weibo.pb.go │ └── weibo.proto └── youtube │ ├── concern.go │ ├── concern_test.go │ ├── config.go │ ├── config_test.go │ ├── fetchInfo.go │ ├── fetchInfo_test.go │ ├── init.go │ ├── keyset.go │ ├── keyset_test.go │ ├── model.go │ ├── model_test.go │ ├── stateManager.go │ ├── stateManager_test.go │ ├── youtube.go │ ├── youtube.pb.go │ └── youtube.proto ├── miraigo ├── .github │ └── workflows │ │ ├── codeql-analysis.yml │ │ ├── go.yml │ │ └── goimports.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── binary │ ├── jce │ │ ├── reader.go │ │ ├── reader_test.go │ │ ├── structs.go │ │ ├── structs_tobytes.go │ │ ├── writer.go │ │ └── writer_test.go │ ├── pool.go │ ├── reader.go │ ├── tea.go │ ├── tea_test.go │ ├── utils.go │ ├── writer.go │ └── writer_test.go ├── client │ ├── _c2c_decoders.go │ ├── builders.go │ ├── c2c_processor.go │ ├── c2c_switch.go │ ├── client.go │ ├── decoders.go │ ├── entities.go │ ├── events.go │ ├── face.go │ ├── global.go │ ├── group_file.go │ ├── group_info.go │ ├── group_msg.go │ ├── guild.go │ ├── guild_eventflow.go │ ├── guild_msg.go │ ├── http_api.go │ ├── image.go │ ├── internal │ │ ├── auth │ │ │ ├── auth.go │ │ │ ├── device.go │ │ │ ├── pow.go │ │ │ ├── protocoltype_string.go │ │ │ └── qimei.go │ │ ├── highway │ │ │ ├── bdh.go │ │ │ ├── frame.go │ │ │ └── highway.go │ │ ├── intern │ │ │ └── string.go │ │ ├── network │ │ │ ├── conn.go │ │ │ ├── packet.go │ │ │ ├── request.go │ │ │ ├── response.go │ │ │ └── transport.go │ │ ├── oicq │ │ │ ├── ecdh.go │ │ │ └── oicq.go │ │ └── tlv │ │ │ └── decoder.go │ ├── log.go │ ├── logger.go │ ├── loginerror_string.go │ ├── model_show.go │ ├── multimsg.go │ ├── network.go │ ├── notify.go │ ├── offline_file.go │ ├── online_push.go │ ├── packet.go │ ├── pb │ │ ├── channel │ │ │ ├── GuildChannelBase.pb.go │ │ │ ├── GuildChannelBase.proto │ │ │ ├── GuildFeedCloudMeta.pb.go │ │ │ ├── GuildFeedCloudMeta.proto │ │ │ ├── GuildFeedCloudRead.pb.go │ │ │ ├── GuildFeedCloudRead.proto │ │ │ ├── GuildWriter.pb.go │ │ │ ├── GuildWriter.proto │ │ │ ├── MsgResponsesSvr.pb.go │ │ │ ├── MsgResponsesSvr.proto │ │ │ ├── common.pb.go │ │ │ ├── common.proto │ │ │ ├── msgpush.pb.go │ │ │ ├── msgpush.proto │ │ │ ├── oidb0xf62.pb.go │ │ │ ├── oidb0xf62.proto │ │ │ ├── servtype.pb.go │ │ │ ├── servtype.proto │ │ │ ├── synclogic.pb.go │ │ │ ├── synclogic.proto │ │ │ ├── unknown.pb.go │ │ │ └── unknown.proto │ │ ├── cmd0x346 │ │ │ ├── cmd0x346.pb.go │ │ │ └── cmd0x346.proto │ │ ├── cmd0x352 │ │ │ ├── cmd0x352.pb.go │ │ │ └── cmd0x352.proto │ │ ├── cmd0x388 │ │ │ ├── cmd0x388.pb.go │ │ │ └── cmd0x388.proto │ │ ├── cmd0x3f6 │ │ │ ├── cmd0x3f6.pb.go │ │ │ └── cmd0x3f6.proto │ │ ├── cmd0x6ff │ │ │ ├── smbcmd0x519.pb.go │ │ │ ├── smbcmd0x519.proto │ │ │ ├── subcmd0x501.pb.go │ │ │ └── subcmd0x501.proto │ │ ├── data.pb.go │ │ ├── data.proto │ │ ├── exciting │ │ │ ├── group.pb.go │ │ │ └── group.proto │ │ ├── faceroam │ │ │ ├── faceroam.pb.go │ │ │ └── faceroam.proto │ │ ├── highway │ │ │ ├── bdhExtInfo.pb.go │ │ │ └── bdhExtInfo.proto │ │ ├── longmsg │ │ │ ├── longmsg.pb.go │ │ │ └── longmsg.proto │ │ ├── msf │ │ │ ├── register_proxy.pb.go │ │ │ └── register_proxy.proto │ │ ├── msg │ │ │ ├── TextMsgExt.pb.go │ │ │ ├── TextMsgExt.proto │ │ │ ├── head.pb.go │ │ │ ├── head.proto │ │ │ ├── msg.pb.go │ │ │ ├── msg.proto │ │ │ ├── objmsg.pb.go │ │ │ ├── objmsg.proto │ │ │ ├── report.pb.go │ │ │ └── report.proto │ │ ├── msgtype0x210 │ │ │ ├── subMsgType0x27.pb.go │ │ │ └── subMsgType0x27.proto │ │ ├── multimsg │ │ │ ├── multimsg.pb.go │ │ │ └── multimsg.proto │ │ ├── notify │ │ │ ├── group0x857.pb.go │ │ │ └── group0x857.proto │ │ ├── oidb │ │ │ ├── oidb.pb.go │ │ │ ├── oidb.proto │ │ │ ├── oidb0x5eb.pb.go │ │ │ ├── oidb0x5eb.proto │ │ │ ├── oidb0x6d6.pb.go │ │ │ ├── oidb0x6d6.proto │ │ │ ├── oidb0x6d7.pb.go │ │ │ ├── oidb0x6d7.proto │ │ │ ├── oidb0x6d8.pb.go │ │ │ ├── oidb0x6d8.proto │ │ │ ├── oidb0x6d9.pb.go │ │ │ ├── oidb0x6d9.proto │ │ │ ├── oidb0x769.pb.go │ │ │ ├── oidb0x769.proto │ │ │ ├── oidb0x88d.pb.go │ │ │ ├── oidb0x88d.proto │ │ │ ├── oidb0x8a7.pb.go │ │ │ ├── oidb0x8a7.proto │ │ │ ├── oidb0x8fc.pb.go │ │ │ ├── oidb0x8fc.proto │ │ │ ├── oidb0x990.pb.go │ │ │ ├── oidb0x990.proto │ │ │ ├── oidb0xD79.pb.go │ │ │ ├── oidb0xD79.proto │ │ │ ├── oidb0xb77.pb.go │ │ │ ├── oidb0xb77.proto │ │ │ ├── oidb0xbcb.pb.go │ │ │ ├── oidb0xbcb.proto │ │ │ ├── oidb0xe07.pb.go │ │ │ ├── oidb0xe07.proto │ │ │ ├── oidb0xe5b.pb.go │ │ │ ├── oidb0xe5b.proto │ │ │ ├── oidb0xeac.pb.go │ │ │ ├── oidb0xeac.proto │ │ │ ├── oidb0xeb7.pb.go │ │ │ ├── oidb0xeb7.proto │ │ │ ├── oidb0xec4.pb.go │ │ │ └── oidb0xec4.proto │ │ ├── profilecard │ │ │ ├── accountsearch.pb.go │ │ │ ├── accountsearch.proto │ │ │ ├── busi.pb.go │ │ │ ├── busi.proto │ │ │ ├── gate.pb.go │ │ │ └── gate.proto │ │ ├── pttcenter │ │ │ ├── shortvideo.pb.go │ │ │ └── shortvideo.proto │ │ ├── qweb │ │ │ ├── app.pb.go │ │ │ ├── app.proto │ │ │ ├── protocol.pb.go │ │ │ └── protocol.proto │ │ ├── richmedia │ │ │ ├── tts.pb.go │ │ │ └── tts.proto │ │ ├── structmsg │ │ │ ├── structmsg.pb.go │ │ │ └── structmsg.proto │ │ └── web │ │ │ ├── WebSsoBody.pb.go │ │ │ └── WebSsoBody.proto │ ├── private_msg.go │ ├── ptt.go │ ├── qidian.go │ ├── recall.go │ ├── richmsg.go │ ├── security.go │ ├── sign.go │ ├── statistics.go │ ├── sync.go │ ├── system_msg.go │ ├── tlv_decoders.go │ ├── translate.go │ ├── upload_file.go │ └── web.go ├── go.mod ├── go.sum ├── internal │ ├── generator │ │ ├── c2c_switcher │ │ │ └── c2c_switcher.go │ │ └── jce_gen │ │ │ └── main.go │ ├── proto │ │ ├── dynamic.go │ │ ├── dynamic_test.go │ │ └── wrapper.go │ └── tlv │ │ ├── t.go │ │ ├── t1.go │ │ ├── t100.go │ │ ├── t104.go │ │ ├── t106.go │ │ ├── t107.go │ │ ├── t108.go │ │ ├── t109.go │ │ ├── t10a.go │ │ ├── t112.go │ │ ├── t116.go │ │ ├── t124.go │ │ ├── t128.go │ │ ├── t141.go │ │ ├── t142.go │ │ ├── t143.go │ │ ├── t144.go │ │ ├── t145.go │ │ ├── t147.go │ │ ├── t154.go │ │ ├── t16.go │ │ ├── t166.go │ │ ├── t16a.go │ │ ├── t16e.go │ │ ├── t174.go │ │ ├── t177.go │ │ ├── t17a.go │ │ ├── t17c.go │ │ ├── t18.go │ │ ├── t187.go │ │ ├── t188.go │ │ ├── t191.go │ │ ├── t193.go │ │ ├── t194.go │ │ ├── t197.go │ │ ├── t198.go │ │ ├── t1b.go │ │ ├── t1d.go │ │ ├── t1f.go │ │ ├── t2.go │ │ ├── t202.go │ │ ├── t33.go │ │ ├── t35.go │ │ ├── t400.go │ │ ├── t401.go │ │ ├── t511.go │ │ ├── t516.go │ │ ├── t521.go │ │ ├── t525.go │ │ ├── t52d.go │ │ ├── t536.go │ │ ├── t544.go │ │ ├── t545.go │ │ ├── t8.go │ │ └── tlv.go ├── message │ ├── elements.go │ ├── elementtype_string.go │ ├── face.go │ ├── face_config_json.zip │ ├── forward.go │ ├── generate.go │ ├── image.go │ ├── marketface.go │ ├── message.go │ ├── message_guild.go │ ├── message_test.go │ ├── pack.go │ └── source.go ├── topic │ ├── elements.go │ └── feed.go ├── utils │ ├── group.go │ ├── http.go │ ├── string.go │ ├── string_test.go │ ├── sys.go │ ├── tcping.go │ ├── tcping_test.go │ ├── ttl.go │ └── waiter.go └── wrapper │ └── codec.go ├── msg-marker └── marker.go ├── proxy_pool ├── local_proxy_pool │ ├── local.go │ └── local_test.go ├── proxyPool.go └── py │ └── pyPool.go ├── requests ├── fake_useragent.go ├── fake_useragent_0.2.0.json ├── fake_useragent_test.go ├── json.go └── requests.go ├── utils ├── blockCache │ ├── blockCache.go │ ├── blockCache_test.go │ ├── fnv.go │ └── fnv_test.go ├── emitQueue.go ├── emitQueue_test.go ├── expirable │ ├── expirable.go │ └── expirable_test.go ├── hackedBot.go ├── hackedBot_test.go ├── helper.go ├── helper_test.go ├── image.go ├── image_test.go ├── logger.go ├── miraigo.go ├── miraigo_test.go └── msgstringer │ ├── logger.go │ ├── stringer.go │ └── stringer_test.go └── warn ├── warn_other.go └── warn_windows.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://afdian.net/@sora233'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-------.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 希望添加新功能 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **描述一下您的想法** 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug--.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug反馈 3 | about: 向DDBOT反馈一个BUG,帮助DDBOT变得更好 4 | title: "[BUG]" 5 | labels: bug, question 6 | assignees: '' 7 | 8 | --- 9 | 10 | **详细描述** 11 | 在这里描述一下BUG发生时的情况,以及您做了什么操作导致BUG发生。 12 | 13 | **正常情况应该是怎样的** 14 | 在这里描述一下如果没有BUG,正常情况应该是怎样的。 15 | 16 | **截图** 17 | 如果有截图,可以放一下,请注意保护个人隐私。 18 | 19 | **如果是私有部署** 20 | 操作系统版本: 21 | BOT版本: 22 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "21:00" 8 | open-pull-requests-limit: 10 9 | reviewers: 10 | - Sora233 11 | ignore: 12 | - dependency-name: github.com/aliyun/alibaba-cloud-sdk-go 13 | versions: 14 | - 1.61.885 15 | - 1.61.888 16 | - 1.61.902 17 | - 1.61.905 18 | - 1.61.913 19 | - 1.61.946 20 | - 1.61.950 21 | - 1.61.957 22 | - 1.61.962 23 | - 1.61.968 24 | - 1.61.971 25 | - 1.61.976 26 | - 1.61.977 27 | - 1.61.979 28 | -------------------------------------------------------------------------------- /.github/workflows/gitee-sync.yml: -------------------------------------------------------------------------------- 1 | name: Mirror GitHub Auto Queried Repos to Gitee 2 | on: 3 | push: 4 | branches: 5 | - 'develop' 6 | - 'master' 7 | jobs: 8 | run: 9 | name: Sync-GitHub-to-Gitee 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Mirror the Github repos to Gitee. 13 | uses: Yikun/hub-mirror-action@master 14 | with: 15 | src: github/Sora233 16 | dst: gitee/sora233 17 | dst_key: ${{ secrets.GITEE_PRIVATE_KEY }} 18 | dst_token: ${{ secrets.GITEE_TOKEN }} 19 | static_list: "DDBOT" 20 | force_update: true -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | release: 5 | types: [ created ] 6 | 7 | jobs: 8 | releases-matrix: 9 | name: Release Go Binary 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | goos: [ linux, windows, darwin ] 14 | goarch: [ "386", amd64, arm, arm64 ] 15 | exclude: 16 | - goos: darwin 17 | goarch: arm 18 | - goos: darwin 19 | goarch: "386" 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Set env 23 | run: | 24 | echo BUILD_TIME=$(date --rfc-3339=seconds) >> ${GITHUB_ENV} 25 | echo Tags=${GITHUB_REF##*/} >> ${GITHUB_ENV} 26 | - uses: wangyoucao577/go-release-action@v1.22 27 | with: 28 | github_token: ${{ secrets.GITHUB_TOKEN }} 29 | goos: ${{ matrix.goos }} 30 | goarch: ${{ matrix.goarch }} 31 | goversion: "https://go.dev/dl/go1.20.2.linux-amd64.tar.gz" 32 | ldflags: -w -s -X "github.com/Sora233/DDBOT/lsp.BuildTime=${{ env.BUILD_TIME }}" -X github.com/Sora233/DDBOT/lsp.CommitId=${{ github.sha }} -X github.com/Sora233/DDBOT/lsp.Tags=${{ env.Tags }} 33 | project_path: "./cmd" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /logs 3 | /miraigo-logs 4 | application.yaml 5 | device.json 6 | Sora233-MiraiGo 7 | .lsp.db 8 | .lsp.db.lock 9 | DDBOT 10 | /.coverage.out 11 | /coverage.html 12 | /qrcode.png 13 | /qq-logs 14 | /session.token 15 | /dist/ 16 | /template 17 | /version*.json -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Package", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${fileDirname}", 13 | "env": { 14 | "GOOS": "windows", 15 | "GOARCH": "amd64" 16 | }, 17 | "args": [ 18 | 19 | ] 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD_TIME := $(shell date --rfc-3339=seconds) 2 | COMMIT_ID := $(shell git rev-parse HEAD) 3 | 4 | LDFLAGS = -X "github.com/Sora233/DDBOT/lsp.BuildTime='"$(BUILD_TIME)"'" -X "github.com/Sora233/DDBOT/lsp.CommitId='"$(COMMIT_ID)"'" 5 | 6 | SRC := $(shell find . -type f -name '*.go') lsp/template/default/* 7 | PROTO := $(shell find . -type f -name '*.proto') 8 | COV := .coverage.out 9 | TARGET := DDBOT 10 | 11 | $(COV): $(SRC) 12 | go test ./... -coverprofile=$(COV) 13 | 14 | 15 | $(TARGET): $(SRC) go.mod go.sum 16 | go build -ldflags '$(LDFLAGS)' -o $(TARGET) github.com/Sora233/DDBOT/cmd 17 | 18 | build: $(TARGET) 19 | 20 | proto: $(PROTO) 21 | protoc --go_out=. $(PROTO) 22 | 23 | test: $(COV) 24 | 25 | coverage: $(COV) 26 | go tool cover -func=$(COV) | grep -v 'pb.go' 27 | 28 | report: $(COV) 29 | go tool cover -html=$(COV) 30 | 31 | clean: 32 | - rm -rf $(TARGET) $(COV) 33 | -------------------------------------------------------------------------------- /admin.txt: -------------------------------------------------------------------------------- 1 | 2022717137 2 | 872654135270991 -------------------------------------------------------------------------------- /bot/.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /bot/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | application.yaml 4 | device.json 5 | 6 | logs/ 7 | 8 | /MiraiGo-Template -------------------------------------------------------------------------------- /bot/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:buster as builder 2 | 3 | ENV GOPROXY=https://goproxy.cn 4 | 5 | WORKDIR /app 6 | 7 | COPY . . 8 | 9 | RUN CGO_ENABLED=0 \ 10 | GOOS=linux \ 11 | GOARCH=amd64 \ 12 | go build -o MiraiGo . 13 | 14 | FROM debian:buster as runner 15 | 16 | WORKDIR /app 17 | 18 | COPY --from=builder /app/MiraiGo . 19 | 20 | ENTRYPOINT ["./MiraiGo"] -------------------------------------------------------------------------------- /bot/README.md: -------------------------------------------------------------------------------- 1 | **修改过的Miraigo-Template,并不与上游兼容** 2 | 3 | 登陆代码大部分参考 [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) -------------------------------------------------------------------------------- /bot/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | 7 | "github.com/Sora233/MiraiGo-Template/bot" 8 | "github.com/Sora233/MiraiGo-Template/config" 9 | "github.com/Sora233/MiraiGo-Template/utils" 10 | 11 | _ "github.com/Sora233/MiraiGo-Template/modules/logging" 12 | ) 13 | 14 | func init() { 15 | utils.WriteLogToFS() 16 | config.Init() 17 | } 18 | 19 | func main() { 20 | // 快速初始化 21 | bot.Init() 22 | 23 | // 初始化 Modules 24 | bot.StartService() 25 | 26 | // 登录 27 | bot.Login() 28 | 29 | // 刷新好友列表,群列表 30 | bot.RefreshList() 31 | 32 | ch := make(chan os.Signal, 1) 33 | signal.Notify(ch, os.Interrupt, os.Kill) 34 | <-ch 35 | bot.Stop() 36 | } 37 | -------------------------------------------------------------------------------- /bot/bot/moduleid.go: -------------------------------------------------------------------------------- 1 | package bot 2 | 3 | import "strings" 4 | 5 | // ModuleID 模块ID 6 | // 请使用 小写 并用 _ 代替空格 7 | // Example: 8 | // - logiase.autoreply 9 | type ModuleID string 10 | 11 | // Namespace - 获取一个 Module 的 Namespace 12 | func (id ModuleID) Namespace() string { 13 | lastDot := strings.LastIndex(string(id), ".") 14 | if lastDot < 0 { 15 | return "" 16 | } 17 | return string(id)[:lastDot] 18 | } 19 | 20 | // Name - 获取一个 Module 的 Name 21 | func (id ModuleID) Name() string { 22 | if id == "" { 23 | return "" 24 | } 25 | parts := strings.Split(string(id), ".") 26 | return parts[len(parts)-1] 27 | } 28 | -------------------------------------------------------------------------------- /bot/bot/moduleinfo.go: -------------------------------------------------------------------------------- 1 | package bot 2 | 3 | // ModuleInfo 模块信息 4 | type ModuleInfo struct { 5 | // ID 模块的名称 6 | // 应全局唯一 7 | ID ModuleID 8 | 9 | // Instance 返回 Module 10 | Instance Module 11 | } 12 | 13 | func (mi ModuleInfo) String() string { 14 | return string(mi.ID) 15 | } 16 | -------------------------------------------------------------------------------- /bot/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | type Config struct { 9 | *viper.Viper 10 | } 11 | 12 | // GlobalConfig 默认全局配置 13 | var GlobalConfig = &Config{ 14 | viper.New(), 15 | } 16 | 17 | // Init 使用 ./application.yaml 初始化全局配置 18 | func Init() { 19 | GlobalConfig.SetConfigName("application") 20 | GlobalConfig.SetConfigType("yaml") 21 | GlobalConfig.AddConfigPath(".") 22 | GlobalConfig.AddConfigPath("./config") 23 | 24 | err := GlobalConfig.ReadInConfig() 25 | if err != nil { 26 | logrus.WithField("config", "GlobalConfig").WithError(err).Fatal("unable to read global config") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /bot/internal/encryption/config.go: -------------------------------------------------------------------------------- 1 | package encryption 2 | 3 | var T544Signer = map[string]func(int64, []byte) []byte{} 4 | -------------------------------------------------------------------------------- /bot/internal/encryption/t544/encryption.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 2 | 3 | package t544 4 | 5 | import ( 6 | "encoding/binary" 7 | "hash/crc32" 8 | "io" 9 | ) 10 | 11 | var crc32Table = func() (tab crc32.Table) { 12 | f, err := cryptoZip.Open("crc32.bin") 13 | if err != nil { 14 | panic(err) 15 | } 16 | data, err := io.ReadAll(f) 17 | if err != nil { 18 | panic(err) 19 | } 20 | for i := range tab { 21 | tab[i] = binary.LittleEndian.Uint32(data[i*4 : (i+1)*4]) 22 | } 23 | return 24 | }() 25 | 26 | //go:noescape 27 | func tencentCrc32(tab *crc32.Table, b []byte) uint32 28 | 29 | //go:noescape 30 | func sub_a([]byte, []uint32) 31 | 32 | //go:noescape 33 | func sub_b([]byte, []uint32) 34 | 35 | //go:noescape 36 | func sub_c(*[16][16]byte, []byte) 37 | 38 | //go:noescape 39 | func sub_d(*[16]byte, []byte) 40 | 41 | //go:noescape 42 | func sub_e(*[256][6]byte, []byte) 43 | 44 | //go:noescape 45 | func sub_f(*[16]byte, *[15]uint32, *[16][16]byte) (w [44]uint32) 46 | 47 | //go:noescape 48 | func sub_aa(int, *[16][2][16][16]byte, *[16]byte, []byte) byte 49 | 50 | // transformInner see com/tencent/mobileqq/dt/model/FEBound 51 | // 52 | //go:noescape 53 | func transformInner(*[0x15]byte, *[32][16]byte) 54 | 55 | //go:noescape 56 | func initState(*state, []byte, []byte, uint64) 57 | 58 | func (c *state) init(key []byte, data []byte, counter uint64, nr uint8) { 59 | c.nr = nr 60 | c.p = 0 61 | initState(c, key, data, counter) 62 | } 63 | 64 | //go:noescape 65 | func refreshState(c *state) 66 | -------------------------------------------------------------------------------- /bot/internal/encryption/t544/t544_stub.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 2 | 3 | package t544 4 | 5 | func init() { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /bot/internal/encryption/t544/t544_test.go: -------------------------------------------------------------------------------- 1 | package t544 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/hex" 6 | "testing" 7 | ) 8 | 9 | func TestT544(t *testing.T) { 10 | r := hex.EncodeToString(sign(0, []byte{})) 11 | if r != "0c05d28b405bce1595c70ffa694ff163d4b600f229482e07de32c8000000003525382c00000000" { 12 | t.Fatal(r) 13 | } 14 | } 15 | 16 | func TestCrash(t *testing.T) { 17 | brand := make([]byte, 4096) 18 | for i := 1; i <= 1024; i++ { 19 | rand.Reader.Read(brand) 20 | sign(123, brand) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bot/internal/encryption/t544/transform.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 2 | 3 | package t544 4 | 5 | type transformer struct { 6 | encode [32][16]byte 7 | decode [32][16]byte 8 | } 9 | 10 | func (ts *transformer) transformEncode(bArr *[0x15]byte) { 11 | transformInner(bArr, &ts.encode) 12 | } 13 | 14 | func (ts *transformer) transformDecode(bArr *[0x15]byte) { 15 | transformInner(bArr, &ts.decode) 16 | } 17 | 18 | var ts = transformer{ 19 | encode: readData[[32][16]byte]("encode.bin"), 20 | decode: readData[[32][16]byte]("decode.bin"), 21 | } 22 | -------------------------------------------------------------------------------- /bot/utils/fs.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | 7 | "github.com/sirupsen/logrus" 8 | ) 9 | 10 | // ReadFile 读取文件 11 | // 读取失败返回 nil 12 | func ReadFile(path string) []byte { 13 | bytes, err := ioutil.ReadFile(path) 14 | if err != nil { 15 | logrus.WithError(err).WithField("util", "ReadFile").Errorf("unable to read '%s'", path) 16 | return nil 17 | } 18 | return bytes 19 | } 20 | 21 | // FileExist 判断文件是否存在 22 | func FileExist(path string) (bool, error) { 23 | _, err := os.Stat(path) 24 | if err == nil { 25 | return true, nil 26 | } 27 | if os.IsNotExist(err) { 28 | return false, nil 29 | } 30 | return true, err 31 | } 32 | -------------------------------------------------------------------------------- /bot/utils/log.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "path" 5 | "time" 6 | 7 | rotatelogs "github.com/lestrrat-go/file-rotatelogs" 8 | "github.com/rifflock/lfshook" 9 | "github.com/sirupsen/logrus" 10 | ) 11 | 12 | // GetModuleLogger - 提供一个为 Module 使用的 logrus.Entry 13 | // 包含 logrus.Fields 14 | func GetModuleLogger(name string) *logrus.Entry { 15 | return logrus.WithField("module", name) 16 | } 17 | 18 | // WriteLogToFS 将日志转储至文件 19 | // 请务必在 init() 阶段调用此函数 20 | // 否则会出现日志缺失 21 | // 日志存储位置 ./logs 22 | func WriteLogToFS() { 23 | WriteLogToPath("logs") 24 | } 25 | 26 | // WriteLogToPath 将日志转储至文件 27 | // 请务必在 init() 阶段调用此函数 28 | // 否则会出现日志缺失 29 | // 日志存储位置 p 30 | func WriteLogToPath(p string) { 31 | writer, err := rotatelogs.New( 32 | path.Join(p, "%Y-%m-%d.log"), 33 | rotatelogs.WithMaxAge(7*24*time.Hour), 34 | rotatelogs.WithRotationTime(24*time.Hour), 35 | ) 36 | if err != nil { 37 | logrus.WithError(err).Error("unable to write logs") 38 | return 39 | } 40 | logrus.AddHook(lfshook.NewHook(writer, &logrus.JSONFormatter{})) 41 | } 42 | -------------------------------------------------------------------------------- /bot/utils/net.go: -------------------------------------------------------------------------------- 1 | package utils 2 | -------------------------------------------------------------------------------- /cmd/hook_other.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package main 5 | 6 | func exitHook(func()) error { 7 | return nil 8 | } 9 | -------------------------------------------------------------------------------- /cmd/hook_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package main 5 | 6 | import ( 7 | "syscall" 8 | "time" 9 | ) 10 | 11 | const ( 12 | CTRL_C_EVENT = uint32(0) 13 | CTRL_BREAK_EVENT = uint32(1) 14 | CTRL_CLOSE_EVENT = uint32(2) 15 | CTRL_LOGOFF_EVENT = uint32(5) 16 | CTRL_SHUTDOWN_EVENT = uint32(6) 17 | ) 18 | 19 | var ( 20 | kernel32 = syscall.NewLazyDLL("kernel32.dll") 21 | procSetConsoleCtrlHandler = kernel32.NewProc("SetConsoleCtrlHandler") 22 | ) 23 | 24 | func exitHook(f func()) error { 25 | n, _, err := procSetConsoleCtrlHandler.Call( 26 | syscall.NewCallback(func(controlType uint32) uint { 27 | f() 28 | time.Sleep(time.Second * 1) 29 | switch controlType { 30 | case CTRL_CLOSE_EVENT: 31 | return 1 32 | default: 33 | return 0 34 | } 35 | }), 36 | 1) 37 | 38 | if n == 0 { 39 | return err 40 | } 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /cmd/play.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func play() { 4 | } 5 | -------------------------------------------------------------------------------- /image_pool/lolicon_pool/error.go: -------------------------------------------------------------------------------- 1 | package lolicon_pool 2 | 3 | import "fmt" 4 | 5 | var ( 6 | ErrNotFound = fmt.Errorf("没有符合条件的图片") 7 | ErrAPIKeyError = fmt.Errorf("APIKEY 不存在或被封禁") 8 | ErrQuotaExceed = fmt.Errorf("达到调用额度限制") 9 | ) 10 | -------------------------------------------------------------------------------- /image_pool/model.go: -------------------------------------------------------------------------------- 1 | package image_pool 2 | 3 | import "errors" 4 | 5 | var ErrNotInit = errors.New("not init") 6 | -------------------------------------------------------------------------------- /image_pool/pool.go: -------------------------------------------------------------------------------- 1 | package image_pool 2 | 3 | type Image interface { 4 | Content() ([]byte, error) 5 | } 6 | 7 | type Option map[string]interface{} 8 | 9 | type OptionFunc func(option Option) Option 10 | 11 | func NumOption(num int) OptionFunc { 12 | return func(option Option) Option { 13 | option["num"] = num 14 | return option 15 | } 16 | } 17 | 18 | type Pool interface { 19 | Get(...OptionFunc) ([]Image, error) 20 | } 21 | -------------------------------------------------------------------------------- /lsp/acfun/acfun.go: -------------------------------------------------------------------------------- 1 | package acfun 2 | 3 | import ( 4 | jsoniter "github.com/json-iterator/go" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | var json = jsoniter.ConfigCompatibleWithStandardLibrary 10 | 11 | const ( 12 | Site = "acfun" 13 | BaseHost = "https://live.acfun.cn" 14 | ) 15 | 16 | var BasePath = map[string]string{ 17 | PathApiChannelList: BaseHost, 18 | } 19 | 20 | func APath(path string) string { 21 | if strings.HasPrefix(path, "/") { 22 | return BasePath[path] + path 23 | } else { 24 | return BasePath[path] + "/" + path 25 | } 26 | } 27 | 28 | func LiveUrl(uid int64) string { 29 | return "https://live.acfun.cn/live/" + strconv.FormatInt(uid, 10) 30 | } 31 | -------------------------------------------------------------------------------- /lsp/acfun/acfun.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package acfun; 3 | 4 | option go_package = "lsp/acfun"; 5 | 6 | message ApiChannelListResponse { 7 | message ChannelListData { 8 | message LiveListItem { 9 | // bool disableDanmakuShow = 1; 10 | // string requestId = 2; 11 | // string groupId = 3; 12 | // int32 action = 4; 13 | // int32 href = 5; 14 | message User { 15 | int32 action = 1; 16 | string id = 2; 17 | string name = 3; 18 | int64 fanCountValue = 4; 19 | string fanCount = 5; 20 | string headUrl = 6; 21 | } 22 | User user = 6; 23 | repeated string coverUrls = 7; 24 | string title = 8; 25 | int64 createTime = 9; 26 | int64 authorId = 10; 27 | string liveId = 11; 28 | } 29 | int64 result = 1; 30 | string requestId = 2; 31 | repeated LiveListItem liveList = 3; 32 | int32 count = 4; 33 | string pcursor = 5; 34 | int32 totalCount = 6; 35 | } 36 | 37 | ChannelListData channelListData = 1; 38 | } 39 | 40 | message LivePageResponse { 41 | message LiveInfo { 42 | message User { 43 | string headUrl = 1; 44 | int32 fanCountValue = 2; 45 | string name = 3; 46 | } 47 | User user = 1; 48 | } 49 | LiveInfo liveInfo = 1; 50 | } 51 | -------------------------------------------------------------------------------- /lsp/acfun/acfun_test.go: -------------------------------------------------------------------------------- 1 | package acfun 2 | 3 | import ( 4 | "github.com/Sora233/DDBOT/internal/test" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func TestAcfun(t *testing.T) { 10 | assert.NotEmpty(t, APath(PathApiChannelList)) 11 | assert.NotEmpty(t, APath("api/channel/list")) 12 | assert.NotEmpty(t, LiveUrl(test.UID1)) 13 | } 14 | -------------------------------------------------------------------------------- /lsp/acfun/apiChannelList.go: -------------------------------------------------------------------------------- 1 | package acfun 2 | 3 | import ( 4 | "github.com/Sora233/DDBOT/proxy_pool" 5 | "github.com/Sora233/DDBOT/requests" 6 | "github.com/Sora233/DDBOT/utils" 7 | "time" 8 | ) 9 | 10 | const ( 11 | PathApiChannelList = "/api/channel/list" 12 | ) 13 | 14 | type ApiChannelListRequest struct { 15 | Count int32 `json:"count"` 16 | PCursor string `json:"pcursor"` 17 | // and maybe filter ... 18 | } 19 | 20 | func ApiChannelList(count int32, pcursor string) (*ApiChannelListResponse, error) { 21 | st := time.Now() 22 | defer func() { 23 | ed := time.Now() 24 | logger.WithField("FuncName", utils.FuncName()).Tracef("cost %v", ed.Sub(st)) 25 | }() 26 | url := APath(PathApiChannelList) 27 | params, err := utils.ToParams(&ApiChannelListRequest{ 28 | Count: count, 29 | PCursor: pcursor, 30 | }) 31 | if err != nil { 32 | return nil, err 33 | } 34 | var opts []requests.Option 35 | opts = append(opts, 36 | requests.ProxyOption(proxy_pool.PreferNone), 37 | requests.AddUAOption(), 38 | requests.TimeoutOption(time.Second*10), 39 | ) 40 | apiChannelListResp := new(ApiChannelListResponse) 41 | err = requests.Get(url, params, &apiChannelListResp, opts...) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return apiChannelListResp, nil 46 | } 47 | -------------------------------------------------------------------------------- /lsp/acfun/apiChannelList_test.go: -------------------------------------------------------------------------------- 1 | package acfun 2 | 3 | import ( 4 | localutils "github.com/Sora233/DDBOT/utils" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestApiChannelList(t *testing.T) { 11 | var resp *ApiChannelListResponse 12 | var err error 13 | localutils.Retry(5, time.Second, func() bool { 14 | resp, err = ApiChannelList(100, "") 15 | return err == nil 16 | }) 17 | assert.Nil(t, err) 18 | assert.NotNil(t, resp) 19 | } 20 | -------------------------------------------------------------------------------- /lsp/acfun/config.go: -------------------------------------------------------------------------------- 1 | package acfun 2 | 3 | import "github.com/Sora233/DDBOT/lsp/concern" 4 | 5 | type GroupConcernConfig struct { 6 | concern.IConfig 7 | } 8 | 9 | func NewGroupConcernConfig(g concern.IConfig) *GroupConcernConfig { 10 | return &GroupConcernConfig{g} 11 | } 12 | -------------------------------------------------------------------------------- /lsp/acfun/init.go: -------------------------------------------------------------------------------- 1 | package acfun 2 | 3 | import ( 4 | "github.com/Sora233/DDBOT/lsp/concern" 5 | ) 6 | 7 | func init() { 8 | concern.RegisterConcern(NewConcern(concern.GetNotifyChan())) 9 | } 10 | -------------------------------------------------------------------------------- /lsp/acfun/keyset.go: -------------------------------------------------------------------------------- 1 | package acfun 2 | 3 | import localdb "github.com/Sora233/DDBOT/lsp/buntdb" 4 | 5 | type extraKey struct{} 6 | 7 | func (e *extraKey) UserInfoKey(keys ...interface{}) string { 8 | return localdb.AcfunUserInfoKey(keys...) 9 | } 10 | 11 | func (e *extraKey) LiveInfoKey(keys ...interface{}) string { 12 | return localdb.AcfunLiveInfoKey(keys...) 13 | } 14 | 15 | func (e *extraKey) NotLiveKey(keys ...interface{}) string { 16 | return localdb.AcfunNotLiveKey(keys...) 17 | } 18 | 19 | func (e *extraKey) UidFirstTimestamp(keys ...interface{}) string { 20 | return localdb.AcfunUidFirstTimestampKey(keys...) 21 | } 22 | -------------------------------------------------------------------------------- /lsp/acfun/keyset_test.go: -------------------------------------------------------------------------------- 1 | package acfun 2 | 3 | import "testing" 4 | 5 | func TestExtraKeySet(t *testing.T) { 6 | var e extraKey 7 | e.LiveInfoKey() 8 | e.NotLiveKey() 9 | e.UserInfoKey() 10 | e.UidFirstTimestamp() 11 | } 12 | -------------------------------------------------------------------------------- /lsp/acfun/livePage.go: -------------------------------------------------------------------------------- 1 | package acfun 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "github.com/Sora233/DDBOT/proxy_pool" 7 | "github.com/Sora233/DDBOT/requests" 8 | "github.com/Sora233/DDBOT/utils" 9 | "regexp" 10 | "time" 11 | ) 12 | 13 | var livePageRegex = regexp.MustCompile("