{"id":22366677,"url":"https://github.com/archertrister/electron-publisher-custom","last_synced_at":"2026-05-06T00:37:00.049Z","repository":{"id":97916086,"uuid":"403908182","full_name":"ArcherTrister/electron-publisher-custom","owner":"ArcherTrister","description":"electron自定义发布程序","archived":false,"fork":false,"pushed_at":"2022-11-30T15:32:55.000Z","size":88,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-31T17:07:58.252Z","etag":null,"topics":["custom","electron","npm","publish"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ArcherTrister.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2021-09-07T08:53:26.000Z","updated_at":"2022-11-29T15:41:54.000Z","dependencies_parsed_at":null,"dependency_job_id":"b57650fe-8184-4a84-aa19-04368d5990ff","html_url":"https://github.com/ArcherTrister/electron-publisher-custom","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArcherTrister%2Felectron-publisher-custom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArcherTrister%2Felectron-publisher-custom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArcherTrister%2Felectron-publisher-custom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArcherTrister%2Felectron-publisher-custom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ArcherTrister","download_url":"https://codeload.github.com/ArcherTrister/electron-publisher-custom/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245689364,"owners_count":20656414,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["custom","electron","npm","publish"],"created_at":"2024-12-04T18:15:00.681Z","updated_at":"2025-10-17T01:25:59.493Z","avatar_url":"https://github.com/ArcherTrister.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# electron-publisher-custom\n\n先吐槽一番，实在不想要这个名字！！！！！！！！！！！！！！\n\n不过我已经尽力了，issue 不被采纳，可能是我撇脚的英语吧 😂😂😂\n\n[详情](https://github.com/electron-userland/electron-builder/issues/6098)\n\nWebPack 打包暂未实现，请忽略掉\n\n# Plan\n\n1. 增加是否强制更新参数\n2. 增加更新说明参数\n3. 增加上传 auth\n\n## 使用方式\n\n### 安装\n\n### ①【npm 版本大于等于 7】\n\n- 克隆本项目\n\n\u003e git clone https://github.com/ArcherTrister/electron-publisher-custom\n\n\u003e git clone https://gitee.com/ArcherTrister/electron-publisher-custom\n\n- 全局 link\n\n在本项目根目录下运行\n\n\u003e npm link\n\n或直接执行 **package** 中的脚本 link\n\n- 项目 link\n\n转到自己项目根目录下运行\n\n\u003e npm link electron-publisher-custom --save\n\n### ②【需注意 link 目录层级】\n\n- 克隆本项目\n\n\u003e git clone https://github.com/ArcherTrister/electron-publisher-custom\n\n\u003e git clone https://gitee.com/ArcherTrister/electron-publisher-custom\n\n- 项目 link\n\n转到自己项目根目录下运行\n\n\u003e npm link ../../electron-publisher-custom\n\n### ③ 【推荐】\n\n- npm 安装\n\n\u003e npm install github:ArcherTrister/electron-publisher-custom\n\nor\n\n\u003e npm install git+https://github.com/ArcherTrister/electron-publisher-custom.git\n\nor\n\n\u003e npm install git+https://gitee.com/ArcherTrister/electron-publisher-custom.git\n\n### ④\n\n～～ - 修改 tsconfig 中 outFile 配置为 **electron-publisher-custom.js**，将生成的文件放到项目 **buildResourcesDir** 下 ～～\n\n- 检查`node_modules`文件夹下刚刚安装的`electron-publisher-custom`包，如果这个包的依赖没有安装成功，在此包文件夹下执行 `npm i` or `yarn` 安装一下依赖\n- 在 build 文件夹下创建`electron-publisher-custom.js`文件，并拷贝下面代码到此文件\n\n```javascript\n// build/electron-publisher-custom.js\nconst CustomPublisher = require(\"electron-publisher-custom\");\nmodule.exports = CustomPublisher;\n```\n\n### 配置\n\npackage.json\n\n```json\n  \"scripts\": {\n    \"dist:win:ia32\": \"electron-builder -w --ia32 -p always\"\n  },\n  \"build\": {\n    \"publish\": [\n      {\n        \"provider\": \"custom\",\n        \"url\": \"http://localhost:port\",\n        \"updaterPath\": \"/upload\"\n      }\n    ],\n  }\n\n```\n\n```\n\n  // 需注意，打包脚本需使用 -p 参数才能应用自定义发布\n  // eg: electron-builder -w --ia32 -p always\n  // channel 为空，则使用默认值 `latest`\n  // version - channel\n  // eg: \"version\": \"1.0.0\" \"version\": \"1.0.0-beta\" | \"version\": \"1.0.0-latest\" | \"version\": \"1.0.0-latest_xxx\"\n  // updaterPath 为空，则使用默认值 `/upload`\n  // updaterPath 如需自定义请确认以 / 开头\n  // 最终上传路由 `{updaterPath}/{productName|name}/{version}/{platform}/{arch}/{channel}`\n\n```\n\n### 后端示例\n\n```csharp\n\n        /// \u003csummary\u003e\n        /// Electron Uploader\n        /// \u003c/summary\u003e\n        /// \u003cparam name=\"appName\"\u003eApplication Name\u003c/param\u003e\n        /// \u003cparam name=\"version\"\u003e\u003c/param\u003e\n        /// \u003cparam name=\"platform\"\u003e\u003c/param\u003e\n        /// \u003cparam name=\"arch\"\u003e\u003c/param\u003e\n        /// \u003cparam name=\"channel\"\u003e\u003c/param\u003e\n        /// \u003creturns\u003e\u003c/returns\u003e\n        [HttpPost(\"/upload/{appName}/{version}/{platform}/{arch}/{channel}\", Name = \"ElectronUploader\")]\n        [DisableRequestSizeLimit]\n        public async Task\u003cIActionResult\u003e ElectronUploader(string appName, string version, string platform, string arch, string channel)\n        {\n            // TODO: token 限制上传 etc.\n\n            Request.Headers.TryGetValue(\"X-File-Name\", out StringValues hFileName);\n            var fileName = StringValues.IsNullOrEmpty(hFileName) ? throw new System.ArgumentNullException(\"Request Header item X-File-Name value is null!\") : hFileName.ToString();\n\n            var filePath = Path.Combine(_webHostEnvironment.ContentRootPath, \"Apps\", appName, platform, version, arch, fileName);\n            if (System.IO.File.Exists(filePath))\n            {\n                return Ok(\"文件已存在！\");\n            }\n            var dir = Path.GetDirectoryName(filePath);\n            if (!System.IO.Directory.Exists(dir))\n            {\n                Directory.CreateDirectory(dir);\n            }\n            using (var targetStream = System.IO.File.Create(filePath))\n            {\n                await Request.Body.CopyToAsync(targetStream);\n            }\n            // string[] fileTypes = new string[] { \".dmg\",\".zip\",\".deb\",\".exe\",\".pkg\" };\n            var fileType = Path.GetExtension(fileName);\n            if (fileTypes.Contains(fileType))\n            {\n                VersionInfo versionInfo = new()\n                {\n                    AppName = appName,\n                    Version = new Version(version),\n                    Arch = arch,\n                    Platform = platform,\n                    Channel = channel,\n                    FileName = fileName,\n                    FileType = fileType,\n                    Size = Request.Body.Length,\n                    Hash = GetHash(Request.Body.ToBytes(), \"sha512\", \"base64\"),\n                    ReleaseDate = DateTime.Now\n                };\n                versionDic.Add(versionInfo.Id, versionInfo);\n            }\n            return Ok();\n        }\n\n        /// \u003csummary\u003e\n        /// Mac App Check Updater\n        /// \u003c/summary\u003e\n        /// \u003cparam name=\"appName\"\u003e\u003c/param\u003e\n        /// \u003cparam name=\"platform\"\u003e\u003c/param\u003e\n        /// \u003cparam name=\"arch\"\u003e\u003c/param\u003e\n        /// \u003cparam name=\"channel\"\u003e\u003c/param\u003e\n        /// \u003creturns\u003e\u003c/returns\u003e\n        [HttpGet(\"/update/{appName}/{platform}/{arch}/{channel}-mac.yml\", Name = \"ElectronUpdaterMac\")]\n        public async Task\u003cIActionResult\u003e ElectronUpdaterMac(string appName, string platform, string arch, string channel)\n        {\n            // TODO: token 限制访问 etc.\n            var versionInfo = versionDic.Values?.Where(p =\u003e p.AppName.Equals(appName, StringComparison.OrdinalIgnoreCase)\n            \u0026\u0026 p.Platform.Equals(platform, StringComparison.OrdinalIgnoreCase) \u0026\u0026 p.Arch.Equals(arch, StringComparison.OrdinalIgnoreCase)).OrderByDescending(p=\u003ep.Version).FirstOrDefault();\n            if (versionInfo != null)\n            {\n                var downloadPath = $\"/download/{appName}/{versionInfo.Version}/{platform}/{arch}/{channel}/{versionInfo.FileName}\";\n                var latestMacYml = $\"version: {versionInfo.Version}\"+\n                                $\"\\nfiles:\"+\n                                $\"\\n  - url: {downloadPath}\"+\n                                $\"\\n    sha512: {versionInfo.Hash}\"+\n                                $\"\\n    size: {versionInfo.Size}\"+\n                                $\"\\npath: {downloadPath}\"+\n                                $\"\\nsha512: {versionInfo.Hash}\"+\n                                $\"\\nreleaseDate: '{versionInfo.ReleaseDate}'\";\n                return Content(await Task.FromResult(latestMacYml));\n            }\n            return NotFound();\n        }\n\n        /// \u003csummary\u003e\n        /// Electron Downloader\n        /// \u003c/summary\u003e\n        /// \u003cparam name=\"appName\"\u003e\u003c/param\u003e\n        /// \u003cparam name=\"platform\"\u003e\u003c/param\u003e\n        /// \u003cparam name=\"arch\"\u003e\u003c/param\u003e\n        /// \u003cparam name=\"channel\"\u003e\u003c/param\u003e\n        /// \u003creturns\u003e\u003c/returns\u003e\n        [HttpGet(\"/download/{appName}/{platform}/{arch}/{channel}/{filename?}\", Name = \"ElectronDownloader\")]\n        public async Task\u003cIActionResult\u003e ElectronDownloader(string appName, string platform, string arch, string channel)\n        {\n            var versionInfo = versionDic.Values?.Where(p =\u003e p.AppName.Equals(appName, StringComparison.OrdinalIgnoreCase)\n            \u0026\u0026 p.Platform.Equals(platform, StringComparison.OrdinalIgnoreCase) \u0026\u0026 p.Arch.Equals(arch, StringComparison.OrdinalIgnoreCase)).OrderByDescending(p =\u003e p.Version).FirstOrDefault();\n            if (versionInfo != null)\n            {\n                var filePath = Path.Combine(_webHostEnvironment.ContentRootPath, \"Apps\", appName, platform, versionInfo.Version.ToString(), arch, versionInfo.FileName);\n                return File(filePath, MediaTypeNames.Application.Octet, versionInfo.FileName);\n            }\n            return NotFound();\n        }\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farchertrister%2Felectron-publisher-custom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farchertrister%2Felectron-publisher-custom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farchertrister%2Felectron-publisher-custom/lists"}