[
  {
    "path": ".github/workflows/main.yml",
    "content": "name: 'Baidu Tieba Auto Sign'\n\non:\n  push:\n    branches:\n      - main\n  schedule:\n    - cron: '5 16,22 * * *'\n\njobs:\n  tieba_sign:\n    runs-on: ubuntu-latest\n    steps:\n      - name: 'Checkout codes'\n        uses: actions/checkout@v2\n      - name: 'Set python'\n        uses: actions/setup-python@v1\n        with:\n          python-version: '3.6'\n      - name: 'Install dependencies'\n        run: python -m pip install --upgrade requests\n      - name: 'Start Sign'\n        env:\n          BDUSS: ${{ secrets.BDUSS }}\n          HOST: ${{ secrets.HOST }}\n          FROM: ${{ secrets.FROM }}\n          TO: ${{ secrets.TO }}\n          AUTH: ${{ secrets.AUTH }}\n        run: python main.py\n"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\npip-wheel-metadata/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n.python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# PEP 582; used by e.g. github.com/David-OConnor/pyflow\n__pypackages__/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n"
  },
  {
    "path": "README.md",
    "content": "# 贴吧签到Github Action版\n\n## 今日签到状态\n\n![Baidu Tieba Auto Sign](https://github.com/gwtak/TieBaSign/workflows/Baidu%20Tieba%20Auto%20Sign/badge.svg)\n\n## 使用说明\n\n1. Fork 本仓库，然后点击你的仓库右上角的 Settings，找到 Secrets 这一项，添加一个库秘密变量。其中 `BDUSS` 存放你的 BDUSS。支持同时添加多个帐户，BDUSS 之间用 `#` 隔开即可。\n\n2. 设置好环境变量后点击你的仓库上方的 `Actions` 选项，第一次打开需要点击 `I understand...` 按钮，确认在 Fork 的仓库上启用 GitHub Actions 。\n\n3. 任意发起一次commit，可以参考下图流程修改readme文件。\n\n- 打开`README.md`，点击修改按钮\n- 修改任意内容，这里在末尾插入了空格。移动到最下面，点击提交。\n\n4. 至此自动签到就搭建完毕了，可以再次点击`Actions`查看工作记录，如果有`Baidu Tieba Auto Sign`则说明workflow创建成功了。点击右侧记录可以查看详细签到情况。\n\n\n\n\n"
  },
  {
    "path": "main.py",
    "content": "# -*- coding:utf-8 -*-\nimport os\nimport requests\nimport hashlib\nimport time\nimport copy\nimport logging\nimport random\n\nimport smtplib\nfrom email.mime.text import MIMEText\n\n\nlogging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\nlogger = logging.getLogger(__name__)\n\n# API_URL\nLIKIE_URL = \"http://c.tieba.baidu.com/c/f/forum/like\"\nTBS_URL = \"http://tieba.baidu.com/dc/common/tbs\"\nSIGN_URL = \"http://c.tieba.baidu.com/c/c/forum/sign\"\n\nENV = os.environ\n\nHEADERS = {\n    'Host': 'tieba.baidu.com',\n    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36',\n}\nSIGN_DATA = {\n    '_client_type': '2',\n    '_client_version': '9.7.8.0',\n    '_phone_imei': '000000000000000',\n    'model': 'MI+5',\n    \"net_type\": \"1\",\n}\n\n# VARIABLE NAME\nCOOKIE = \"Cookie\"\nBDUSS = \"BDUSS\"\nEQUAL = r'='\nEMPTY_STR = r''\nTBS = 'tbs'\nPAGE_NO = 'page_no'\nONE = '1'\nTIMESTAMP = \"timestamp\"\nDATA = 'data'\nFID = 'fid'\nSIGN_KEY = 'tiebaclient!!!'\nUTF8 = \"utf-8\"\nSIGN = \"sign\"\nKW = \"kw\"\n\ns = requests.Session()\n\n\ndef get_tbs(bduss):\n    logger.info(\"获取tbs开始\")\n    headers = copy.copy(HEADERS)\n    headers.update({COOKIE: EMPTY_STR.join([BDUSS, EQUAL, bduss])})\n    try:\n        tbs = s.get(url=TBS_URL, headers=headers, timeout=5).json()[TBS]\n    except Exception as e:\n        logger.error(\"获取tbs出错\" + e)\n        logger.info(\"重新获取tbs开始\")\n        tbs = s.get(url=TBS_URL, headers=headers, timeout=5).json()[TBS]\n    logger.info(\"获取tbs结束\")\n    return tbs\n\n\ndef get_favorite(bduss):\n    logger.info(\"获取关注的贴吧开始\")\n    # 客户端关注的贴吧\n    returnData = {}\n    i = 1\n    data = {\n        'BDUSS': bduss,\n        '_client_type': '2',\n        '_client_id': 'wappc_1534235498291_488',\n        '_client_version': '9.7.8.0',\n        '_phone_imei': '000000000000000',\n        'from': '1008621y',\n        'page_no': '1',\n        'page_size': '200',\n        'model': 'MI+5',\n        'net_type': '1',\n        'timestamp': str(int(time.time())),\n        'vcode_tag': '11',\n    }\n    data = encodeData(data)\n    try:\n        res = s.post(url=LIKIE_URL, data=data, timeout=5).json()\n    except Exception as e:\n        logger.error(\"获取关注的贴吧出错\" + e)\n        return []\n    returnData = res\n    if 'forum_list' not in returnData:\n        returnData['forum_list'] = []\n    if res['forum_list'] == []:\n        return {'gconforum': [], 'non-gconforum': []}\n    if 'non-gconforum' not in returnData['forum_list']:\n        returnData['forum_list']['non-gconforum'] = []\n    if 'gconforum' not in returnData['forum_list']:\n        returnData['forum_list']['gconforum'] = []\n    while 'has_more' in res and res['has_more'] == '1':\n        i = i + 1\n        data = {\n            'BDUSS': bduss,\n            '_client_type': '2',\n            '_client_id': 'wappc_1534235498291_488',\n            '_client_version': '9.7.8.0',\n            '_phone_imei': '000000000000000',\n            'from': '1008621y',\n            'page_no': str(i),\n            'page_size': '200',\n            'model': 'MI+5',\n            'net_type': '1',\n            'timestamp': str(int(time.time())),\n            'vcode_tag': '11',\n        }\n        data = encodeData(data)\n        try:\n            res = s.post(url=LIKIE_URL, data=data, timeout=5).json()\n        except Exception as e:\n            logger.error(\"获取关注的贴吧出错\" + e)\n            continue\n        if 'forum_list' not in res:\n            continue\n        if 'non-gconforum' in res['forum_list']:\n            returnData['forum_list']['non-gconforum'].append(res['forum_list']['non-gconforum'])\n        if 'gconforum' in res['forum_list']:\n            returnData['forum_list']['gconforum'].append(res['forum_list']['gconforum'])\n\n    t = []\n    for i in returnData['forum_list']['non-gconforum']:\n        if isinstance(i, list):\n            for j in i:\n                if isinstance(j, list):\n                    for k in j:\n                        t.append(k)\n                else:\n                    t.append(j)\n        else:\n            t.append(i)\n    for i in returnData['forum_list']['gconforum']:\n        if isinstance(i, list):\n            for j in i:\n                if isinstance(j, list):\n                    for k in j:\n                        t.append(k)\n                else:\n                    t.append(j)\n        else:\n            t.append(i)\n    logger.info(\"获取关注的贴吧结束\")\n    return t\n\n\ndef encodeData(data):\n    s = EMPTY_STR\n    keys = data.keys()\n    for i in sorted(keys):\n        s += i + EQUAL + str(data[i])\n    sign = hashlib.md5((s + SIGN_KEY).encode(UTF8)).hexdigest().upper()\n    data.update({SIGN: str(sign)})\n    return data\n\n\ndef client_sign(bduss, tbs, fid, kw):\n    # 客户端签到\n    logger.info(\"开始签到贴吧：\" + kw)\n    data = copy.copy(SIGN_DATA)\n    data.update({BDUSS: bduss, FID: fid, KW: kw, TBS: tbs, TIMESTAMP: str(int(time.time()))})\n    data = encodeData(data)\n    res = s.post(url=SIGN_URL, data=data, timeout=5).json()\n    return res\n\ndef send_email(sign_list):\n    if ('HOST' not in ENV or 'FROM' not in ENV or 'TO' not in ENV or 'AUTH' not in ENV):\n        logger.error(\"未配置邮箱\")\n        return\n    HOST = ENV['HOST']\n    FROM = ENV['FROM']\n    TO = ENV['TO'].split('#')\n    AUTH = ENV['AUTH']\n    length = len(sign_list)\n    subject = f\"{time.strftime('%Y-%m-%d', time.localtime())} 签到{length}个贴吧\"\n    body = \"\"\"\n    <style>\n    .child {\n      background-color: rgba(173, 216, 230, 0.19);\n      padding: 10px;\n    }\n\n    .child * {\n      margin: 5px;\n    }\n    </style>\n    \"\"\"\n    for i in sign_list:\n        body += f\"\"\"\n        <div class=\"child\">\n            <div class=\"name\"> 贴吧名称: { i['name'] }</div>\n            <div class=\"slogan\"> 贴吧简介: { i['slogan'] }</div>\n        </div>\n        <hr>\n        \"\"\"\n    msg = MIMEText(body, 'html', 'utf-8')\n    msg['subject'] = subject\n    smtp = smtplib.SMTP()\n    smtp.connect(HOST)\n    smtp.login(FROM, AUTH)\n    smtp.sendmail(FROM, TO, msg.as_string())\n    smtp.quit()\n\ndef main():\n    if ('BDUSS' not in ENV):\n        logger.error(\"未配置BDUSS\")\n        return\n    b = ENV['BDUSS'].split('#')\n    for n, i in enumerate(b):\n        logger.info(\"开始签到第\" + str(n) + \"个用户\" + i)\n        tbs = get_tbs(i)\n        favorites = get_favorite(i)\n        for j in favorites:\n            time.sleep(random.randint(1,5))\n            client_sign(i, tbs, j[\"id\"], j[\"name\"])\n        logger.info(\"完成第\" + str(n) + \"个用户签到\")\n    send_email(favorites)\n    logger.info(\"所有用户签到结束\")\n\n\nif __name__ == '__main__':\n    main()\n"
  }
]