{"id":42513302,"url":"https://github.com/foyoux/pilk","last_synced_at":"2026-01-28T14:16:55.553Z","repository":{"id":57452736,"uuid":"444274373","full_name":"foyoux/pilk","owner":"foyoux","description":"python silk codec bindings 支持微信语音编解码","archived":false,"fork":false,"pushed_at":"2025-01-08T10:57:00.000Z","size":425,"stargazers_count":135,"open_issues_count":5,"forks_count":21,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-30T16:32:08.600Z","etag":null,"topics":["decode","encode","media","python","qq","silk","tencent","voice","wechat"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/foyoux.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-04T03:32:10.000Z","updated_at":"2025-08-24T06:44:17.000Z","dependencies_parsed_at":"2024-06-19T09:16:31.375Z","dependency_job_id":"35549e34-4021-4281-81ef-e80a82f2fac8","html_url":"https://github.com/foyoux/pilk","commit_stats":{"total_commits":33,"total_committers":2,"mean_commits":16.5,"dds":0.06060606060606055,"last_synced_commit":"4e9b5059a7d100d4eac705b30ef48e0697ce6354"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/foyoux/pilk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foyoux%2Fpilk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foyoux%2Fpilk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foyoux%2Fpilk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foyoux%2Fpilk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foyoux","download_url":"https://codeload.github.com/foyoux/pilk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foyoux%2Fpilk/sbom","scorecard":{"id":408311,"data":{"date":"2025-08-11","repo":{"name":"github.com/foyoux/pilk","commit":"b64925623956f8cc6fd3d49fe9662b8756147d02"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/started_notify.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v0.0.1 not signed: https://api.github.com/repos/foyoux/pilk/releases/56353523","Warn: release artifact v0.0.1 does not have provenance: https://api.github.com/repos/foyoux/pilk/releases/56353523"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}}]},"last_synced_at":"2025-08-18T21:57:38.758Z","repository_id":57452736,"created_at":"2025-08-18T21:57:38.758Z","updated_at":"2025-08-18T21:57:38.758Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28846058,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T13:02:32.985Z","status":"ssl_error","status_checked_at":"2026-01-28T13:02:04.945Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decode","encode","media","python","qq","silk","tencent","voice","wechat"],"created_at":"2026-01-28T14:16:55.441Z","updated_at":"2026-01-28T14:16:55.539Z","avatar_url":"https://github.com/foyoux.png","language":"C","readme":"# pilk\n\npython silk codec binding 支持微信语音编解码\n\npilk: python + silk\n\n关联项目: [weixin-wxposed-silk-voice](https://github.com/foyoux/weixin-wxposed-silk-voice)\n\n## 安装\n\n[![python version](https://img.shields.io/pypi/pyversions/pilk)](https://pypi.org/project/pilk/)  [![downloads](https://static.pepy.tech/personalized-badge/pilk?period=total\u0026units=international_system\u0026left_color=black\u0026right_color=orange\u0026left_text=Downloads)](https://pepy.tech/project/pilk)\n\n```bash\npip install pilk\n```\n\n## 介绍与说明\n\n[**SILK**](https://en.wikipedia.org/wiki/SILK) 是一种语音编码格式，由 [**Skype**](https://en.wikipedia.org/wiki/Skype_Technologies)\n公司研发，网上可找到的最新版本是 2012 发布的。\n\n**SILK** 原始代码已上传到 [Release](https://github.com/foyoux/pilk/releases/tag/v0.0.1) , 包含规范文档\n\n**Tencent** 系语音支持来自 [silk-v3-decoder](https://github.com/kn007/silk-v3-decoder)\n\n[Release ](https://github.com/foyoux/pilk/releases/tag/v0.0.1)\n中也包含 [silk-v3-decoder](https://github.com/kn007/silk-v3-decoder) 重编译的 **x64-win**\n版本，支持中文，[源代码](https://github.com/foyoux/silk-codec)\n\n### **SILK** 编码格式 和 **Tencent** 系语音的关系：\n\n\u003e 此处 **Tencent** 系语音，仅以微信语音为例\n\n1. 标准 **SILK** 文件以 `b'#!SILK_V3'` 开始，以 `b'\\xFF\\xFF'` 结束，中间为语音数据\n2. 微信语音文件在标准 **SILK** 文件的开头插入了 `b'\\x02'`，去除了结尾的 `b'\\xFF\\xFF'`，中间不变\n\n\u003e 已下统称为语音文件\n\n### 语音数据\n\n语音数据分为很多个独立 **frame**，每个 **frame** 开头两字节存储剩余 **frame** 数据的大小，每个 **frame** 默认存储 **20ms** 的音频数据\n\n据此可写出获取 **语音文件** 持续时间(duration) 的函数（此函数 **pilk** 中已包含）\n\n```python\ndef get_duration(silk_path: str, frame_ms: int = 20) -\u003e int:\n    \"\"\"获取 silk 文件持续时间，单位：ms\"\"\"\n    with open(silk_path, 'rb') as silk:\n        tencent = False\n        if silk.read(1) == b'\\x02':\n            tencent = True\n        silk.seek(0)\n        if tencent:\n            silk.seek(10)\n        else:\n            silk.seek(9)\n        i = 0\n        while True:\n            size = silk.read(2)\n            if len(size) != 2:\n                break\n            i += 1\n            size = size[0] + size[1] * 16\n            silk.seek(silk.tell() + size)\n        return i * frame_ms\n```\n\n根据 **SILK** 格式规范，**frame_ms** 可为 `20, 40, 60, 80, 100`\n\n## 快速入门\n\n\u003e 详情请在 IDE 中查看 API 文档注释\n\n在使用 **pilk** 之前，你还需清楚 **音频文件 `mp3, aac, m4a, flac, wav, ...`** 与 **语音文件** 之间的转换是借助 [**PCM raw\ndata**](https://en.wikipedia.org/wiki/Pulse-code_modulation) 完成的\n\n具体转换关系：音频文件 ⇔ PCM ⇔ 语音文件\n\n1. 音(视)频文件 ➜ PCM\n   \u003e 借助 ffmpeg，你当然需要先有 [ffmpeg](https://www.ffmpeg.org/download.html)\n    ```bat\n    ffmpeg -y -i \u003c音(视)频输入文件\u003e -vn -ar \u003c采样率\u003e -ac 1 -f s16le \u003cPCM输出文件\u003e\n    ```\n    1. `-y`: 可加可不加，表示 \u003cPCM输出文件\u003e 已存在时不询问，直接覆盖\n    2. `-i`: 没啥好说的，固定的，后接 \u003c音(视)频输入文件\u003e\n    3. `-vn`: 表示不处理视频数据，建议添加，虽然不加也不会处理视频数据（视频数据不存在转PCM的说法），但可能会打印警告\n    4. `-ar`: 设置采样率，可选的值是 [8000, 12000, 16000, 24000, 32000, 44100, 48000], 这里你可以直接理解为声音质量\n    5. `-ac`: 设置声道数，在这里必须为 **1**，这是由 **SILK** 决定的\n    6. `-f`: 表示强制转换为指定的格式，一般来说必须为 **s16le**, 表示 `16-bit short integer Little-Endian data`\n    7. example1: `ffmpeg -y -i mv.mp4 -vn -ar 44100 -ac 1 -f s16le mv.pcm`\n    8. example2: `ffmpeg -y -i music.mp3 -ar 44100 -ac 1 -f s16le music.pcm`\n\n\n2. PCM ➜ 音频文件\n    ```bat\n    ffmpeg -y -f s16le -ar \u003c采样率\u003e -ac \u003c声道数\u003e -i \u003cPCM输入文件\u003e \u003c音频输出文件\u003e\n    ```\n    1. `-f`: 这里必须为 `s16le`, 同样也是由 **SILK** 决定的\n    2. `-ar`: 同上\n    3. `-ac`: 含义同上，值随意\n    4. `\u003c音频输出文件\u003e`: 扩展名要准确，没有指定格式时，**ffmpeg** 会根据给定的输出文件扩展名来判断需要输出的格式\n    5. example3: `ffmpeg -y -f s16le -ar 16000 -i test.pcm test.mp3`\n\n\u003e ffmpeg 也可以使用 python ffmpeg binding 替换，推荐 [PyAV](https://github.com/PyAV-Org/PyAV) 大家自行研究，这里不再啰嗦。\n\n讲完了 音频文件 ⇔ PCM，接下来就是用 **pilk** 进行 PCM ⇔ 语音文件 互转\n\n### silk 编码\n\n```python\nimport pilk\n\n# pcm_rate 参数必须和 使用 ffmpeg 转 音频 到 PCM 文件时，使用的 `-ar` 参数一致\n# pcm_rate 参数必须和 使用 ffmpeg 转 音频 到 PCM 文件时，使用的 `-ar` 参数一致\n# pcm_rate 参数必须和 使用 ffmpeg 转 音频 到 PCM 文件时，使用的 `-ar` 参数一致\nduration = pilk.encode(\"test.pcm\", \"test.silk\", pcm_rate=44100, tencent=True)\n\nprint(\"语音时间为:\", duration)\n```\n\n### silk 解码\n\n```python\nimport pilk\n\n# pcm_rate 参数必须和 使用 ffmpeg 转 音频 到 PCM 文件时，使用的 `-ar` 参数一致\nduration = pilk.decode(\"test.silk\", \"test.pcm\")\n\nprint(\"语音时间为:\", duration)\n```\n\n## 使用 Python 转任意媒体文件到 SILK\n\n使用 [pudub](https://github.com/jiaaro/pydub) 依赖 [ffmpeg](https://www.ffmpeg.org/)\n\n```python\nimport os, pilk\nfrom pydub import AudioSegment\n\n\ndef convert_to_silk(media_path: str) -\u003e str:\n    \"\"\"将输入的媒体文件转出为 silk, 并返回silk路径\"\"\"\n    media = AudioSegment.from_file(media_path)\n    pcm_path = os.path.basename(media_path)\n    pcm_path = os.path.splitext(pcm_path)[0]\n    silk_path = pcm_path + '.silk'\n    pcm_path += '.pcm'\n    media.export(pcm_path, 's16le', parameters=['-ar', str(media.frame_rate), '-ac', '1']).close()\n    pilk.encode(pcm_path, silk_path, pcm_rate=media.frame_rate, tencent=True)\n    return silk_path\n```\n\n使用 [pyav](https://github.com/PyAV-Org/PyAV) **推荐**\n\n```python\nimport os\n\nimport av\n\nimport pilk\n\n\ndef to_pcm(in_path: str) -\u003e tuple[str, int]:\n    \"\"\"任意媒体文件转 pcm\"\"\"\n    out_path = os.path.splitext(in_path)[0] + '.pcm'\n    with av.open(in_path) as in_container:\n        in_stream = in_container.streams.audio[0]\n        sample_rate = in_stream.codec_context.sample_rate\n        with av.open(out_path, 'w', 's16le') as out_container:\n            out_stream = out_container.add_stream(\n                'pcm_s16le',\n                rate=sample_rate,\n                layout='mono'\n            )\n            try:\n               for frame in in_container.decode(in_stream):\n                  frame.pts = None\n                  for packet in out_stream.encode(frame):\n                     out_container.mux(packet)\n            except:\n               pass\n    return out_path, sample_rate\n\n\ndef convert_to_silk(media_path: str) -\u003e str:\n    \"\"\"任意媒体文件转 silk, 返回silk路径\"\"\"\n    pcm_path, sample_rate = to_pcm(media_path)\n    silk_path = os.path.splitext(pcm_path)[0] + '.silk'\n    pilk.encode(pcm_path, silk_path, pcm_rate=sample_rate, tencent=True)\n    os.remove(pcm_path)\n    return silk_path\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoyoux%2Fpilk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoyoux%2Fpilk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoyoux%2Fpilk/lists"}