├── assets
├── file.png
├── aliyun.png
├── imooc.png
├── aliyun-ys.gif
├── imooc-ys.gif
├── tcloud-ys.gif
├── imooc-cookie.png
├── aliyun-cookie.png
├── aliyun-install.png
├── cnblog-install.png
├── imooc-install.png
├── tcloud-cookie.png
└── tcloud-install.png
├── XC.BlogTools.Util
├── TagProcessor
│ ├── ITagProcessor.cs
│ └── ImageProcessor.cs
├── XC.BlogTools.Util.csproj
├── EncodingType.cs
├── ClientUploader.cs
└── MimeMapping.cs
├── LICENSE
├── dotnet-aliyun
├── dotnet-aliyun.csproj
└── Program.cs
├── dotnet-imooc
├── dotnet-imooc.csproj
└── Program.cs
├── dotnet-tcloud
├── dotnet-tcloud.csproj
└── Program.cs
├── BlogTools.sln
├── README.md
└── .gitignore
/assets/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/file.png
--------------------------------------------------------------------------------
/assets/aliyun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/aliyun.png
--------------------------------------------------------------------------------
/assets/imooc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/imooc.png
--------------------------------------------------------------------------------
/assets/aliyun-ys.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/aliyun-ys.gif
--------------------------------------------------------------------------------
/assets/imooc-ys.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/imooc-ys.gif
--------------------------------------------------------------------------------
/assets/tcloud-ys.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/tcloud-ys.gif
--------------------------------------------------------------------------------
/assets/imooc-cookie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/imooc-cookie.png
--------------------------------------------------------------------------------
/assets/aliyun-cookie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/aliyun-cookie.png
--------------------------------------------------------------------------------
/assets/aliyun-install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/aliyun-install.png
--------------------------------------------------------------------------------
/assets/cnblog-install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/cnblog-install.png
--------------------------------------------------------------------------------
/assets/imooc-install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/imooc-install.png
--------------------------------------------------------------------------------
/assets/tcloud-cookie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/tcloud-cookie.png
--------------------------------------------------------------------------------
/assets/tcloud-install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/BlogTools/HEAD/assets/tcloud-install.png
--------------------------------------------------------------------------------
/XC.BlogTools.Util/TagProcessor/ITagProcessor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace XC.BlogTools.Util.TagProcessor
4 | {
5 | public interface ITagProcessor
6 | {
7 | ///
8 | /// 处理内容 提取出需要替换的内容列表
9 | ///
10 | ///
11 | ///
12 | List Process(string content);
13 |
14 | ///
15 | /// 替换内容,返回替换后结果
16 | ///
17 | /// 需要替换的字符串
18 | /// 原内容
19 | ///
20 | string Replace(Dictionary repleceDic,string content);
21 | }
22 | }
--------------------------------------------------------------------------------
/XC.BlogTools.Util/XC.BlogTools.Util.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | stulzq
6 | CopyRight 2018 stulzq
7 | https://github.com/stulzq/BlogTools
8 | https://github.com/stulzq/BlogTools.git
9 | git
10 | FileUpload,MarkDown Image Process
11 | https://github.com/stulzq/BlogTools/blob/master/LICENSE
12 | true
13 | 客户端文件上传、MarkDown文件图片处理。
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Zhiqiang Li
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/XC.BlogTools.Util/TagProcessor/ImageProcessor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Text.RegularExpressions;
3 |
4 | namespace XC.BlogTools.Util.TagProcessor
5 | {
6 | public class ImageProcessor:ITagProcessor
7 | {
8 | const string MatchRule= @"!\[.*?\]\((.*?)\)";
9 | public List Process(string content)
10 | {
11 | List result=new List();
12 |
13 | var matchs = Regex.Matches(content, MatchRule, RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
14 |
15 | foreach (Match match in matchs)
16 | {
17 | var val = match.Groups[1].Value;
18 | //只需要解析本地图片
19 | if (!val.StartsWith("http")&& !result.Contains(val))
20 | {
21 | result.Add(val);
22 | }
23 |
24 | }
25 |
26 | return result;
27 | }
28 |
29 | public string Replace(Dictionary repleceDic,string content)
30 | {
31 | foreach (var key in repleceDic.Keys)
32 | {
33 | content = content.Replace(key, repleceDic[key]);
34 | }
35 |
36 | return content;
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/dotnet-aliyun/dotnet-aliyun.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.1
6 | dotnet_aliyun
7 | true
8 | true
9 |
10 | true
11 | stulzq
12 | CopyRight 2018 stulzq
13 | https://github.com/stulzq/BlogTools
14 | https://github.com/stulzq/BlogTools.git
15 | git
16 | 云栖社区
17 | https://github.com/stulzq/BlogTools/blob/master/LICENSE
18 | true
19 | 博文快速多渠道发布工具包,支持博客园、阿里云栖社区、腾讯云+社区、慕课网手记 4种渠道。本工具支持阿里云栖社区。
20 |
21 |
22 |
23 | 7.1
24 |
25 |
26 |
27 | 7.1
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/dotnet-imooc/dotnet-imooc.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.1
6 | dotnet_imooc
7 | true
8 | true
9 |
10 | true
11 | stulzq
12 | CopyRight 2018 stulzq
13 | https://github.com/stulzq/BlogTools
14 | https://github.com/stulzq/BlogTools.git
15 | git
16 | 慕课网手记
17 | https://github.com/stulzq/BlogTools/blob/master/LICENSE
18 | true
19 | 博文快速多渠道发布工具包,支持博客园、阿里云栖社区、腾讯云+社区、慕课网手记 4种渠道。本工具支持慕课网手记。
20 |
21 |
22 |
23 | 7.1
24 |
25 |
26 |
27 | 7.1
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/dotnet-tcloud/dotnet-tcloud.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.1
6 | dotnet_tcloud
7 | true
8 | true
9 |
10 | true
11 | stulzq
12 | CopyRight 2018 stulzq
13 | https://github.com/stulzq/BlogTools
14 | https://github.com/stulzq/BlogTools.git
15 | git
16 | 腾讯云+社区
17 | https://github.com/stulzq/BlogTools/blob/master/LICENSE
18 | true
19 | 博文快速多渠道发布工具包,支持博客园、阿里云栖社区、腾讯云+社区、慕课网手记 4种渠道。本工具支持腾讯云+社区。
20 | 1.0.1
21 | 修复保存文件名后缀不正确
22 |
23 |
24 |
25 | 7.1
26 |
27 |
28 |
29 | 7.1
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/BlogTools.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2026
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-aliyun", "dotnet-aliyun\dotnet-aliyun.csproj", "{ECCDFF26-4032-4F00-9031-A1B2252F0133}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-imooc", "dotnet-imooc\dotnet-imooc.csproj", "{6311B476-94A2-4B1B-A408-80F5FDC71E8E}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-tcloud", "dotnet-tcloud\dotnet-tcloud.csproj", "{F2BA39F2-1540-4933-9096-E7D3991A3D8D}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XC.BlogTools.Util", "XC.BlogTools.Util\XC.BlogTools.Util.csproj", "{90D91C9C-7292-4797-9CCB-AD6C2361E0D3}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{87F91941-9AAC-4A30-B652-9279E4961176}"
15 | ProjectSection(SolutionItems) = preProject
16 | README.md = README.md
17 | EndProjectSection
18 | EndProject
19 | Global
20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 | Debug|Any CPU = Debug|Any CPU
22 | Release|Any CPU = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {ECCDFF26-4032-4F00-9031-A1B2252F0133}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {ECCDFF26-4032-4F00-9031-A1B2252F0133}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {ECCDFF26-4032-4F00-9031-A1B2252F0133}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {ECCDFF26-4032-4F00-9031-A1B2252F0133}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {6311B476-94A2-4B1B-A408-80F5FDC71E8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {6311B476-94A2-4B1B-A408-80F5FDC71E8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {6311B476-94A2-4B1B-A408-80F5FDC71E8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {6311B476-94A2-4B1B-A408-80F5FDC71E8E}.Release|Any CPU.Build.0 = Release|Any CPU
33 | {F2BA39F2-1540-4933-9096-E7D3991A3D8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {F2BA39F2-1540-4933-9096-E7D3991A3D8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {F2BA39F2-1540-4933-9096-E7D3991A3D8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {F2BA39F2-1540-4933-9096-E7D3991A3D8D}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {90D91C9C-7292-4797-9CCB-AD6C2361E0D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {90D91C9C-7292-4797-9CCB-AD6C2361E0D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {90D91C9C-7292-4797-9CCB-AD6C2361E0D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {90D91C9C-7292-4797-9CCB-AD6C2361E0D3}.Release|Any CPU.Build.0 = Release|Any CPU
41 | EndGlobalSection
42 | GlobalSection(SolutionProperties) = preSolution
43 | HideSolutionNode = FALSE
44 | EndGlobalSection
45 | GlobalSection(ExtensibilityGlobals) = postSolution
46 | SolutionGuid = {7A120F70-F758-4D1B-8034-8E3FC6ECA7D4}
47 | EndGlobalSection
48 | EndGlobal
49 |
--------------------------------------------------------------------------------
/XC.BlogTools.Util/EncodingType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace XC.BlogTools.Util
6 | {
7 | ///
8 | /// 获取文件的编码格式
9 | ///
10 | public class EncodingType
11 | {
12 | ///
13 | /// 给定文件的路径,读取文件的二进制数据,判断文件的编码类型
14 | ///
15 | /// 文件路径
16 | /// 文件的编码类型
17 | public static Encoding GetType(string fileName)
18 | {
19 | FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
20 | Encoding r = GetType(fs);
21 | fs.Close();
22 | return r;
23 | }
24 |
25 | ///
26 | /// 通过给定的文件流,判断文件的编码类型
27 | ///
28 | /// 文件流
29 | /// 文件的编码类型
30 | public static Encoding GetType(FileStream fs)
31 | {
32 | Encoding reVal = Encoding.Default;
33 |
34 | var r = new BinaryReader(fs, Encoding.Default);
35 | int i;
36 | int.TryParse(fs.Length.ToString(), out i);
37 | byte[] ss = r.ReadBytes(i);
38 | if (IsUtf8Bytes(ss) || (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF))
39 | {
40 | reVal = Encoding.UTF8;
41 | }
42 | else if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00)
43 | {
44 | reVal = Encoding.BigEndianUnicode;
45 | }
46 | else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41)
47 | {
48 | reVal = Encoding.Unicode;
49 | }
50 | r.Close();
51 | return reVal;
52 |
53 | }
54 |
55 | ///
56 | /// 判断是否是不带 BOM 的 UTF8 格式
57 | ///
58 | ///
59 | ///
60 | private static bool IsUtf8Bytes(byte[] data)
61 | {
62 | int charByteCounter = 1; //计算当前正分析的字符应还有的字节数
63 | foreach (var t in data)
64 | {
65 | var curByte = t; //当前分析的字节.
66 | if (charByteCounter == 1)
67 | {
68 | if (curByte >= 0x80)
69 | {
70 | //判断当前
71 | while (((curByte <<= 1) & 0x80) != 0)
72 | {
73 | charByteCounter++;
74 | }
75 | //标记位首位若为非0 则至少以2个1开始 如:110XXXXX...........1111110X
76 | if (charByteCounter == 1 || charByteCounter > 6)
77 | {
78 | return false;
79 | }
80 | }
81 | }
82 | else
83 | {
84 | //若是UTF-8 此时第一位必须为1
85 | if ((curByte & 0xC0) != 0x80)
86 | {
87 | return false;
88 | }
89 | charByteCounter--;
90 | }
91 | }
92 | if (charByteCounter > 1)
93 | {
94 | throw new Exception("非预期的byte格式");
95 | }
96 | return true;
97 | }
98 |
99 | }
100 | }
--------------------------------------------------------------------------------
/dotnet-aliyun/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.IO;
5 | using System.Threading.Tasks;
6 | using McMaster.Extensions.CommandLineUtils;
7 | using XC.BlogTools.Util;
8 | using XC.BlogTools.Util.TagProcessor;
9 |
10 | namespace dotnet_aliyun
11 | {
12 | [Command(Name = "dotnet-aliyun", Description = "欢迎使用 晓晨博客图片解析快速上传工具-阿里云栖社区,技术支持QQ群 4656606.Github: https://github.com/stulzq/BlogTools")]
13 | [HelpOption("-h|--help")]
14 | class Program
15 | {
16 | static async Task Main(string[] args) => await CommandLineApplication.ExecuteAsync(args);
17 |
18 | [Argument(0, "MarkdownFilePath", "Required.Your mrkdown File Path.")]
19 | [Required]
20 | [FileExists]
21 | public string MarkdownFilePath { get; }
22 |
23 | [Option("-c|--cookie", Description = "Required.Cookie file path.")]
24 | [Required]
25 | [FileExists]
26 | public string CookieFilePath { get; }
27 |
28 | private async Task OnExecuteAsync(CommandLineApplication app)
29 | {
30 | if (app.Options.Count == 1 && (app.Options[0].ShortName == "h"|| app.Options[0].ShortName == "help"))
31 | {
32 | app.ShowHelp();
33 | return 0;
34 | }
35 |
36 | return await Work(MarkdownFilePath, CookieFilePath);
37 | }
38 |
39 |
40 | private async Task Work(string filePath,string cookiePath)
41 | {
42 | string cookie = File.ReadAllText(cookiePath, EncodingType.GetType(cookiePath));
43 |
44 | var fileEncoding = EncodingType.GetType(filePath);
45 | var fileContent = File.ReadAllText(filePath, fileEncoding);
46 | var fileInfo = new FileInfo(filePath);
47 | var fileExtension = fileInfo.Extension;
48 | var fileDir = fileInfo.DirectoryName;
49 |
50 | var imgProc = new ImageProcessor();
51 | var imgList = imgProc.Process(fileContent);
52 |
53 | Console.WriteLine($"提取图片成功,共{imgList.Count}个.");
54 |
55 | var uploader=new ClientUploader("https://yq.aliyun.com");
56 |
57 | var replaceDic=new Dictionary();
58 |
59 | foreach (var img in imgList)
60 | {
61 | string imgPhyPath = Path.Combine(fileDir, img);
62 |
63 | Console.WriteLine($"正在上传图片:{imgPhyPath}");
64 | try
65 | {
66 | var res = await uploader.UploadAsync(imgPhyPath, "/upload/img2", "fileToUpload", new Dictionary()
67 | {
68 | ["Cookie"] = cookie
69 | });
70 |
71 | //校验
72 | res = res.Replace("\r\n", "");
73 | if (!res.StartsWith("https://yqfile.alicdn.com"))
74 | {
75 | Console.WriteLine("Cookie无效!");
76 | return 1;
77 | }
78 |
79 | replaceDic.Add(img, res);
80 |
81 | Console.WriteLine("上传成功!");
82 | }
83 | catch (Exception e)
84 | {
85 | Console.WriteLine($"处理失败!{e.Message}");
86 | return 1;
87 | }
88 | }
89 |
90 | var newContent = imgProc.Replace(replaceDic, fileContent);
91 | string newFileName = filePath.Substring(0, filePath.LastIndexOf('.')) + "-aliyun" + fileExtension;
92 | File.WriteAllText(newFileName, newContent, fileEncoding);
93 |
94 | Console.WriteLine($"处理完成!文件保存在:{newFileName}");
95 |
96 | return 0;
97 | }
98 |
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/dotnet-imooc/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.IO;
5 | using System.Threading.Tasks;
6 | using McMaster.Extensions.CommandLineUtils;
7 | using Newtonsoft.Json.Linq;
8 | using XC.BlogTools.Util;
9 | using XC.BlogTools.Util.TagProcessor;
10 |
11 | namespace dotnet_imooc
12 | {
13 | [Command(Name = "dotnet-imooc",
14 | Description = "欢迎使用 晓晨博客图片解析快速上传工具-慕课网手记,技术支持QQ群 4656606.Github: https://github.com/stulzq/BlogTools")]
15 | [HelpOption("-h|--help")]
16 | class Program
17 | {
18 | static async Task Main(string[] args) => await CommandLineApplication.ExecuteAsync(args);
19 |
20 | [Argument(0, "MarkdownFilePath", "Required.Your mrkdown File Path.")]
21 | [Required]
22 | [FileExists]
23 | public string MarkdownFilePath { get; }
24 |
25 | [Option("-c|--cookie", Description = "Required.Cookie file path.")]
26 | [Required]
27 | [FileExists]
28 | public string CookieFilePath { get; }
29 |
30 | private async Task OnExecuteAsync(CommandLineApplication app)
31 | {
32 | if (app.Options.Count == 1 && (app.Options[0].ShortName == "h" || app.Options[0].ShortName == "help"))
33 | {
34 | app.ShowHelp();
35 | return 0;
36 | }
37 |
38 | return await Work(MarkdownFilePath, CookieFilePath);
39 | }
40 |
41 |
42 | private async Task Work(string filePath, string cookiePath)
43 | {
44 | string cookie = File.ReadAllText(cookiePath, EncodingType.GetType(cookiePath));
45 |
46 | var fileEncoding = EncodingType.GetType(filePath);
47 | var fileContent = File.ReadAllText(filePath, fileEncoding);
48 | var fileInfo = new FileInfo(filePath);
49 | var fileExtension = fileInfo.Extension;
50 | var fileDir = fileInfo.DirectoryName;
51 |
52 | var imgProc = new ImageProcessor();
53 | var imgList = imgProc.Process(fileContent);
54 |
55 | Console.WriteLine($"提取图片成功,共{imgList.Count}个.");
56 |
57 | var uploader = new ClientUploader("https://www.imooc.com");
58 |
59 | var replaceDic = new Dictionary();
60 |
61 | foreach (var img in imgList)
62 | {
63 | string imgPhyPath = Path.Combine(fileDir, img);
64 |
65 | Console.WriteLine($"正在上传图片:{imgPhyPath}");
66 | try
67 | {
68 | var res = await uploader.UploadAsync(imgPhyPath, "/article/ajaxuploadimg", "photo",
69 | new Dictionary()
70 | {
71 | ["Cookie"] = cookie
72 | });
73 |
74 | //校验
75 | var json = JObject.Parse(res);
76 | if (json.Value("result") != 0)
77 | {
78 | Console.WriteLine("Cookie无效!");
79 | return 1;
80 | }
81 |
82 | var httpImgPath = json["data"].Value("imgpath");
83 |
84 | replaceDic.Add(img, httpImgPath);
85 |
86 | Console.WriteLine("上传成功!");
87 | }
88 | catch (Exception e)
89 | {
90 | Console.WriteLine($"处理失败!{e.Message}");
91 | return 1;
92 | }
93 | }
94 |
95 | var newContent = imgProc.Replace(replaceDic, fileContent);
96 | string newFileName = filePath.Substring(0, filePath.LastIndexOf('.')) + "-imooc" + fileExtension;
97 | File.WriteAllText(newFileName, newContent, fileEncoding);
98 |
99 | Console.WriteLine($"处理完成!文件保存在:{newFileName}");
100 |
101 | return 0;
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/dotnet-tcloud/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.IO;
5 | using System.Threading.Tasks;
6 | using McMaster.Extensions.CommandLineUtils;
7 | using Newtonsoft.Json.Linq;
8 | using XC.BlogTools.Util;
9 | using XC.BlogTools.Util.TagProcessor;
10 |
11 | namespace dotnet_tcloud
12 | {
13 | [Command(Name = "dotnet-tcloud",
14 | Description = "欢迎使用 晓晨博客图片解析快速上传工具-腾讯云+社区,技术支持QQ群 4656606.Github: https://github.com/stulzq/BlogTools")]
15 | [HelpOption("-h|--help")]
16 | class Program
17 | {
18 | static async Task Main(string[] args) => await CommandLineApplication.ExecuteAsync(args);
19 |
20 | [Argument(0, "MarkdownFilePath", "Required.Your mrkdown File Path.")]
21 | [Required]
22 | [FileExists]
23 | public string MarkdownFilePath { get; }
24 |
25 | [Option("-c|--cookie", Description = "Required.Cookie file path.")]
26 | [Required]
27 | [FileExists]
28 | public string CookieFilePath { get; }
29 |
30 | [Option("--uin", Description = "Required.")]
31 | [Required]
32 | public string Uin { get; }
33 |
34 | [Option("--csrf", Description = "Required.")]
35 | [Required]
36 | public string Csrf { get; }
37 |
38 | private async Task OnExecuteAsync(CommandLineApplication app)
39 | {
40 | if (app.Options.Count == 1 && (app.Options[0].ShortName == "h" || app.Options[0].ShortName == "help"))
41 | {
42 | app.ShowHelp();
43 | return 0;
44 | }
45 |
46 | return await Work(MarkdownFilePath, CookieFilePath);
47 | }
48 |
49 |
50 | private async Task Work(string filePath, string cookiePath)
51 | {
52 | string cookie = File.ReadAllText(cookiePath, EncodingType.GetType(cookiePath));
53 |
54 | var fileEncoding = EncodingType.GetType(filePath);
55 | var fileContent = File.ReadAllText(filePath, fileEncoding);
56 | var fileInfo = new FileInfo(filePath);
57 | var fileExtension = fileInfo.Extension;
58 | var fileDir = fileInfo.DirectoryName;
59 |
60 | var imgProc = new ImageProcessor();
61 | var imgList = imgProc.Process(fileContent);
62 |
63 | Console.WriteLine($"提取图片成功,共{imgList.Count}个.");
64 |
65 | var uploader = new ClientUploader("https://cloud.tencent.com");
66 |
67 | var replaceDic = new Dictionary();
68 |
69 | foreach (var img in imgList)
70 | {
71 | string imgPhyPath = Path.Combine(fileDir, img);
72 |
73 | Console.WriteLine($"正在上传图片:{imgPhyPath}");
74 | try
75 | {
76 | var res = await uploader.UploadAsync(imgPhyPath, $"/developer/services/ajax/image?action=UploadImage&uin={Uin}&csrfCode={Csrf}", "image",
77 | new Dictionary()
78 | {
79 | ["Cookie"] = cookie
80 | });
81 |
82 | //校验
83 | var json = JObject.Parse(res);
84 | if (json.Value("code") != 0)
85 | {
86 | Console.WriteLine("Cookie或uin、csrf code 无效!");
87 | return 1;
88 | }
89 |
90 | var httpImgPath = json["data"].Value("url");
91 |
92 | replaceDic.Add(img, httpImgPath);
93 |
94 | Console.WriteLine("上传成功!");
95 | }
96 | catch (Exception e)
97 | {
98 | Console.WriteLine($"处理失败!{e.Message}");
99 | return 1;
100 | }
101 | }
102 |
103 | var newContent = imgProc.Replace(replaceDic, fileContent);
104 | string newFileName = filePath.Substring(0, filePath.LastIndexOf('.')) + "-tcloud" + fileExtension;
105 | File.WriteAllText(newFileName, newContent, fileEncoding);
106 |
107 | Console.WriteLine($"处理完成!文件保存在:{newFileName}");
108 |
109 | return 0;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/XC.BlogTools.Util/ClientUploader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.IO;
5 | using System.Net.Http;
6 | using System.Net.Http.Headers;
7 | using System.Threading.Tasks;
8 | using Polly;
9 |
10 | namespace XC.BlogTools.Util
11 | {
12 | ///
13 | /// 客户端文件上传工具类
14 | /// Author:晓晨Master(李志强)
15 | ///
16 | public class ClientUploader
17 | {
18 | public HttpClient Client { get; }
19 |
20 | public ClientUploader()
21 | {
22 | Client=new HttpClient();
23 | }
24 |
25 | public ClientUploader(string baseAddress)
26 | {
27 | Client = new HttpClient(){BaseAddress = new Uri(baseAddress)};
28 | }
29 |
30 | ///
31 | /// 上传文件
32 | ///
33 | /// 文件数据
34 | /// 上传地址
35 | /// 文件名
36 | /// 参数名称
37 | /// 附加http请求header
38 | ///
39 | public async Task UploadAsync(byte[] file,string fileUploadPath,string fileName, string contentName="",Dictionary headers=null)
40 | {
41 | Client.DefaultRequestHeaders.Clear();
42 |
43 | //加入附加header
44 | if (headers != null)
45 | {
46 | foreach (var key in headers.Keys)
47 | {
48 | Client.DefaultRequestHeaders.Add(key,headers[key]);
49 | }
50 | }
51 |
52 | var policy = Policy.Handle().RetryAsync(3, (exception, retryCount) =>
53 | {
54 | Console.WriteLine("上传失败,正在重试 {0},异常:{1}", retryCount, exception.Message);
55 | });
56 |
57 | try
58 | {
59 | var res = await policy.ExecuteAsync(async () =>
60 | {
61 | using (var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
62 | {
63 | var streamContent = new StreamContent(new MemoryStream(file));
64 | streamContent.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(fileName));
65 | content.Add(streamContent, contentName, fileName);
66 |
67 | var result = await Client.PostAsync(fileUploadPath, content);
68 | result.EnsureSuccessStatusCode();
69 | return await result.Content.ReadAsStringAsync();
70 | }
71 | });
72 |
73 | return res;
74 | }
75 | catch (Exception e)
76 | {
77 | Console.WriteLine("上传失败,异常:{0}", e.Message);
78 | throw;
79 | }
80 |
81 | }
82 |
83 | ///
84 | /// 根据文件路径上传文件
85 | ///
86 | /// 文件路径
87 | /// 上传地址
88 | /// 参数名称
89 | /// 附加http请求header
90 | ///
91 | public async Task UploadAsync(string filePath, string fileUploadPath, string contentName = "", Dictionary headers = null)
92 | {
93 | Client.DefaultRequestHeaders.Clear();
94 |
95 | //加入附加header
96 | if (headers != null)
97 | {
98 | foreach (var key in headers.Keys)
99 | {
100 | Client.DefaultRequestHeaders.Add(key, headers[key]);
101 | }
102 | }
103 |
104 | var policy = Policy.Handle().RetryAsync(3, (exception, retryCount) =>
105 | {
106 | Console.WriteLine("上传失败,正在重试 {0},异常:{1}", retryCount, exception.Message);
107 | });
108 |
109 | try
110 | {
111 | var res = await policy.ExecuteAsync(async () =>
112 | {
113 | using (var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
114 | {
115 | var fileInfo = new FileInfo(filePath);
116 | var streamContent = new StreamContent(File.OpenRead(filePath));
117 | streamContent.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(fileInfo.Name));
118 | content.Add(streamContent, contentName, fileInfo.Name);
119 |
120 | var result = await Client.PostAsync(fileUploadPath, content);
121 | result.EnsureSuccessStatusCode();
122 | return await result.Content.ReadAsStringAsync();
123 | }
124 | });
125 |
126 | return res;
127 | }
128 | catch (Exception e)
129 | {
130 | Console.WriteLine("上传失败,异常:{0}", e.Message);
131 | throw;
132 | }
133 |
134 | }
135 | }
136 |
137 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BlogTools
2 |
3 | 博文快速多渠道发布工具包,支持博客园、阿里云栖社区、腾讯云+社区、慕课网手记 4种渠道。
4 |
5 | ## 二.工具的作用
6 |
7 | >本工具只适用于用Markdown写博客或者文章的人群,如果你还不会请花一个小时的时间去熟悉,你就能感受到Markdown给你带来的好处了。
8 |
9 | 使用本工具前,建议先阅读这篇文章:《[如何高效的编写与同步博客](https://www.cnblogs.com/stulzq/p/9043632.html)》
10 |
11 | 我们使用Markdown编写博文,总免不了文章中出现图片,这里的图片有两种类型,一种是放在互联网上的,一种是放在本地的。如果我引用的是互联网上的图片(如 https://xxx.com/xxx.png ),我们在各个渠道发布的时候只需要复制粘贴即可,但是这带来一个问题,如果我们引用图片的网站如果关闭了外链,那我们所发的文章的图片都将会失效,影响文章的质量。如果我们的图片放在本地,那么我们在多个渠道发布的时候,又需要在每个渠道一张张上传图片,岂不是太麻烦,太耗时间了。如果有一个工具能自动解析博文中引用的图片,然后自动上传到对应的渠道,并且把我们博文中引用本地图片的链接改为对应渠道图片的链接,那么我们发布也只用复制粘贴即可,瞬间完成十分高效。
12 |
13 | BlogTools工具包就是为了解决上述问题,它会解析Markdown文件中的图片,然后上传到对于渠道,并且替换本地链接,下面用几张图来表示:
14 |
15 | 1.原文:
16 |
17 | 
18 |
19 | 2.转换为 阿里云栖社区 渠道
20 |
21 | 
22 |
23 | 3.转换为 慕课网手记 渠道
24 |
25 | 
26 |
27 | 主要就是减少你到每个渠道去上传文件的操作。你只需复制转换以后的内容,粘贴到对于的渠道即可完成发布。
28 |
29 | ## 三.各个渠道工具包
30 |
31 | 工具名 | 说明 | 版本号
32 | -------- | :------------ | :------------
33 | dotnet-aliyun | 阿里云栖社区 | [](https://www.nuget.org/packages/dotnet-aliyun/)
34 | dotnet-imooc | 慕课网手记 | [](https://www.nuget.org/packages/dotnet-imooc/)
35 | dotnet-tcloud | 腾讯云+社区 | [](https://www.nuget.org/packages/dotnet-tcloud/)
36 | dotnet-cnblog | 博客园 | [](https://www.nuget.org/packages/dotnet-cnblog/)
37 |
38 | ## 四.安装
39 |
40 | 使用本系列工具需要你的pc具备 .NET Core 2.1版本 SDK 环境或者更高版本。且完全支持跨平台,你可以在.NET Core 支持的任意Linux发行版、Windows、MAC OSX上使用。
41 |
42 | .NET Core SDK 下载地址:https://www.microsoft.com/net/learn/get-started/windows
43 |
44 | ### 1.阿里云栖社区 工具安装
45 |
46 | 打开命令提示符(cmd),输入下面的命令进行安装
47 |
48 | ````shell
49 | dotnet tool install -g dotnet-aliyun
50 | ````
51 | 
52 |
53 | ### 2.慕课网手记 工具安装
54 |
55 | 打开命令提示符(cmd),输入下面的命令进行安装
56 |
57 | ````shell
58 | dotnet tool install -g dotnet-imooc
59 | ````
60 | 
61 |
62 | ### 3.腾讯云+社区 工具安装
63 |
64 | 打开命令提示符(cmd),输入下面的命令进行安装
65 |
66 | ````shell
67 | dotnet tool install -g dotnet-tcloud
68 | ````
69 | 
70 |
71 | ### 4.博客园 工具安装
72 |
73 | 打开命令提示符(cmd),输入下面的命令进行安装
74 |
75 | ````shell
76 | dotnet tool install -g dotnet-cnblog
77 | ````
78 | 
79 |
80 | ## 五.卸载
81 |
82 | 卸载工具的命令格式为:
83 |
84 | ````shell
85 | dotnet tool uninstall -g <工具名称>
86 | ````
87 |
88 | ## 六.使用
89 |
90 | 本工具主要面向写**技术博客**的人员,所以工具在某些细节的地方并未做处理,比如“登录”。需要用户自己登录以后,提取Cookie给工具使用。
91 |
92 | ### 1.阿里云栖社区 工具的使用
93 |
94 | #### (1).使用
95 |
96 | 获取工具的帮助说明,请执行下面的命令,对每个参数都有说明:
97 |
98 | ````shell
99 | dotnet-aliyun -h
100 | ````
101 | 输出:
102 | ````
103 | Usage: dotnet-aliyun [arguments] [options]
104 |
105 | Arguments:
106 | MarkdownFilePath Required.Your mrkdown File Path.
107 |
108 | Options:
109 | -h|--help Show help information
110 | -c|--cookie Required.Cookie file path.
111 | ````
112 |
113 | 使用命令的格式为:
114 |
115 | ````shell
116 | dotnet-aliyun -c
117 | ````
118 |
119 | 例如:
120 |
121 | ````shell
122 | dotnet-aliyun c:\blog\test.md -c c:\blog\cookies\aliyun-cookie.txt
123 | ````
124 | #### (2).Cookie 的提取
125 |
126 | a.使用浏览器登录并访问博客编写的页面:https://yq.aliyun.com/articles/new
127 |
128 | b.打开浏览器的开发者工具并选择 network 选项卡,准备查看上传图片的交互请求。
129 |
130 | c.随便选择一张图片上传
131 |
132 | d.查看这次请求里的Cookie,并保存到文本文件中
133 |
134 | 提取Cookie演示:
135 |
136 | 
137 |
138 | >只复制图中的括号中的数据
139 |
140 | 操作演示:
141 |
142 | 
143 |
144 | ### 2.慕课网手记 工具的使用
145 |
146 | #### (1).使用
147 |
148 | 获取工具的帮助说明,请执行下面的命令,对每个参数都有说明:
149 |
150 | ````shell
151 | dotnet-imooc -h
152 | ````
153 | 输出:
154 | ````
155 | Usage: dotnet-imooc [arguments] [options]
156 |
157 | Arguments:
158 | MarkdownFilePath Required.Your mrkdown File Path.
159 |
160 | Options:
161 | -h|--help Show help information
162 | -c|--cookie Required.Cookie file path.
163 | ````
164 |
165 | 使用命令的格式为:
166 |
167 | ````shell
168 | dotnet-imooc -c
169 | ````
170 |
171 | 例如:
172 |
173 | ````shell
174 | dotnet-imooc c:\blog\test.md -c c:\blog\cookies\imooc-cookie.txt
175 | ````
176 | #### (2).Cookie 的提取
177 |
178 | a.使用浏览器登录并访问博客编写的页面:https://www.imooc.com/article/publish
179 |
180 | b.打开浏览器的开发者工具并选择 network 选项卡,准备查看上传图片的交互请求。
181 |
182 | c.随便选择一张图片上传
183 |
184 | d.查看这次请求里的Cookie,并保存到文本文件中
185 |
186 | 提取Cookie演示:
187 |
188 | 
189 |
190 | >只复制图中的括号中的数据
191 |
192 | 操作演示:
193 |
194 | 
195 |
196 | ### 3.腾讯云+社区 工具的使用
197 |
198 | #### (1).使用
199 |
200 | 获取工具的帮助说明,请执行下面的命令,对每个参数都有说明:
201 |
202 | ````shell
203 | dotnet-tcloud -h
204 | ````
205 | 输出:
206 | ````
207 |
208 | Usage: dotnet-tcloud [arguments] [options]
209 |
210 | Arguments:
211 | MarkdownFilePath Required.Your mrkdown File Path.
212 |
213 | Options:
214 | -h|--help Show help information
215 | -c|--cookie Required.Cookie file path.
216 | --uin Required.
217 | --csrf Required.
218 | ````
219 |
220 | 使用命令的格式为:
221 |
222 | ````shell
223 | dotnet-imooc -c --uin --csrf <跨域验证码>
224 | ````
225 |
226 | 例如:
227 |
228 | ````shell
229 | dotnet-tcloud c:\blog\test.md -c c:\blog\cookies\imooc-cookie.txt --uin 55566677 --csrf 7788991
230 | ````
231 | #### (2).Cookie 的提取
232 |
233 | a.使用浏览器登录并访问博客编写的页面:https://cloud.tencent.com/developer/article/write
234 |
235 | b.打开浏览器的开发者工具并选择 network 选项卡,准备查看上传图片的交互请求。
236 |
237 | c.随便选择一张图片上传
238 |
239 | d.查看这次请求里的Cookie,并保存到文本文件中
240 |
241 | e.根据本次上传图片请求url中的参数提取uin码和csrf码
242 |
243 | 提取Cookie演示:
244 |
245 | 
246 |
247 | >只复制图中的括号中的数据
248 |
249 | 操作演示:
250 |
251 | 
252 |
253 |
254 | ### 4.博客园 工具的使用
255 |
256 | 因博客园工具本系列最早的一个工具,使用方法最简单便捷,无需自己提取cookie,是单独开发。详细的使用说明请移步查看:https://github.com/stulzq/CnBlogPublishTool
257 |
258 | >特殊说明,关于使用js代码 `document.cookie` 获取cookie,经测试腾讯云+社区和慕课网手记可以,阿里云栖社区js获取到的cookie无效,因为必须的cookie项设置为了httponly,js无法获取。
259 |
260 | ## 七.隐私
261 |
262 | 本工具不会收集你的任意数据,且代码完全开源。
263 |
264 | ## 八.贡献代码
265 |
266 | 如果你有问题或者建议,欢迎提交 pull request 贡献代码。
267 |
268 |
269 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
--------------------------------------------------------------------------------
/XC.BlogTools.Util/MimeMapping.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 |
4 | namespace XC.BlogTools.Util
5 | {
6 | public class MimeMapping
7 | {
8 | private static readonly Hashtable MimeMappingTable;
9 |
10 | private static void AddMimeMapping(string extension, string mimeType)
11 | {
12 | MimeMappingTable.Add(extension, mimeType);
13 | }
14 |
15 | public static string GetMimeMapping(string fileName)
16 | {
17 | string text = null;
18 | int num = fileName.LastIndexOf('.');
19 | if (0 < num && num > fileName.LastIndexOf('\\'))
20 | {
21 | text = (string)MimeMappingTable[fileName.Substring(num)];
22 | }
23 |
24 | return text ?? (string) MimeMappingTable[".*"];
25 | }
26 |
27 | static MimeMapping()
28 | {
29 | MimeMappingTable = new Hashtable(190, StringComparer.CurrentCultureIgnoreCase);
30 | AddMimeMapping(".323", "text/h323");
31 | AddMimeMapping(".asx", "video/x-ms-asf");
32 | AddMimeMapping(".acx", "application/internet-property-stream");
33 | AddMimeMapping(".ai", "application/postscript");
34 | AddMimeMapping(".aif", "audio/x-aiff");
35 | AddMimeMapping(".aiff", "audio/aiff");
36 | AddMimeMapping(".axs", "application/olescript");
37 | AddMimeMapping(".aifc", "audio/aiff");
38 | AddMimeMapping(".asr", "video/x-ms-asf");
39 | AddMimeMapping(".avi", "video/x-msvideo");
40 | AddMimeMapping(".asf", "video/x-ms-asf");
41 | AddMimeMapping(".au", "audio/basic");
42 | AddMimeMapping(".application", "application/x-ms-application");
43 | AddMimeMapping(".bin", "application/octet-stream");
44 | AddMimeMapping(".bas", "text/plain");
45 | AddMimeMapping(".bcpio", "application/x-bcpio");
46 | AddMimeMapping(".bmp", "image/bmp");
47 | AddMimeMapping(".cdf", "application/x-cdf");
48 | AddMimeMapping(".cat", "application/vndms-pkiseccat");
49 | AddMimeMapping(".crt", "application/x-x509-ca-cert");
50 | AddMimeMapping(".c", "text/plain");
51 | AddMimeMapping(".css", "text/css");
52 | AddMimeMapping(".cer", "application/x-x509-ca-cert");
53 | AddMimeMapping(".crl", "application/pkix-crl");
54 | AddMimeMapping(".cmx", "image/x-cmx");
55 | AddMimeMapping(".csh", "application/x-csh");
56 | AddMimeMapping(".cod", "image/cis-cod");
57 | AddMimeMapping(".cpio", "application/x-cpio");
58 | AddMimeMapping(".clp", "application/x-msclip");
59 | AddMimeMapping(".crd", "application/x-mscardfile");
60 | AddMimeMapping(".deploy", "application/octet-stream");
61 | AddMimeMapping(".dll", "application/x-msdownload");
62 | AddMimeMapping(".dot", "application/msword");
63 | AddMimeMapping(".doc", "application/msword");
64 | AddMimeMapping(".dvi", "application/x-dvi");
65 | AddMimeMapping(".dir", "application/x-director");
66 | AddMimeMapping(".dxr", "application/x-director");
67 | AddMimeMapping(".der", "application/x-x509-ca-cert");
68 | AddMimeMapping(".dib", "image/bmp");
69 | AddMimeMapping(".dcr", "application/x-director");
70 | AddMimeMapping(".disco", "text/xml");
71 | AddMimeMapping(".exe", "application/octet-stream");
72 | AddMimeMapping(".etx", "text/x-setext");
73 | AddMimeMapping(".evy", "application/envoy");
74 | AddMimeMapping(".eml", "message/rfc822");
75 | AddMimeMapping(".eps", "application/postscript");
76 | AddMimeMapping(".flr", "x-world/x-vrml");
77 | AddMimeMapping(".fif", "application/fractals");
78 | AddMimeMapping(".gtar", "application/x-gtar");
79 | AddMimeMapping(".gif", "image/gif");
80 | AddMimeMapping(".gz", "application/x-gzip");
81 | AddMimeMapping(".hta", "application/hta");
82 | AddMimeMapping(".htc", "text/x-component");
83 | AddMimeMapping(".htt", "text/webviewhtml");
84 | AddMimeMapping(".h", "text/plain");
85 | AddMimeMapping(".hdf", "application/x-hdf");
86 | AddMimeMapping(".hlp", "application/winhlp");
87 | AddMimeMapping(".html", "text/html");
88 | AddMimeMapping(".htm", "text/html");
89 | AddMimeMapping(".hqx", "application/mac-binhex40");
90 | AddMimeMapping(".isp", "application/x-internet-signup");
91 | AddMimeMapping(".iii", "application/x-iphone");
92 | AddMimeMapping(".ief", "image/ief");
93 | AddMimeMapping(".ivf", "video/x-ivf");
94 | AddMimeMapping(".ins", "application/x-internet-signup");
95 | AddMimeMapping(".ico", "image/x-icon");
96 | AddMimeMapping(".jpg", "image/jpeg");
97 | AddMimeMapping(".jfif", "image/pjpeg");
98 | AddMimeMapping(".jpe", "image/jpeg");
99 | AddMimeMapping(".jpeg", "image/jpeg");
100 | AddMimeMapping(".js", "application/x-javascript");
101 | AddMimeMapping(".lsx", "video/x-la-asf");
102 | AddMimeMapping(".latex", "application/x-latex");
103 | AddMimeMapping(".lsf", "video/x-la-asf");
104 | AddMimeMapping(".manifest", "application/x-ms-manifest");
105 | AddMimeMapping(".mhtml", "message/rfc822");
106 | AddMimeMapping(".mny", "application/x-msmoney");
107 | AddMimeMapping(".mht", "message/rfc822");
108 | AddMimeMapping(".mid", "audio/mid");
109 | AddMimeMapping(".mpv2", "video/mpeg");
110 | AddMimeMapping(".man", "application/x-troff-man");
111 | AddMimeMapping(".mvb", "application/x-msmediaview");
112 | AddMimeMapping(".mpeg", "video/mpeg");
113 | AddMimeMapping(".m3u", "audio/x-mpegurl");
114 | AddMimeMapping(".mdb", "application/x-msaccess");
115 | AddMimeMapping(".mpp", "application/vnd.ms-project");
116 | AddMimeMapping(".m1v", "video/mpeg");
117 | AddMimeMapping(".mpa", "video/mpeg");
118 | AddMimeMapping(".me", "application/x-troff-me");
119 | AddMimeMapping(".m13", "application/x-msmediaview");
120 | AddMimeMapping(".movie", "video/x-sgi-movie");
121 | AddMimeMapping(".m14", "application/x-msmediaview");
122 | AddMimeMapping(".mpe", "video/mpeg");
123 | AddMimeMapping(".mp2", "video/mpeg");
124 | AddMimeMapping(".mov", "video/quicktime");
125 | AddMimeMapping(".mp3", "audio/mpeg");
126 | AddMimeMapping(".mpg", "video/mpeg");
127 | AddMimeMapping(".ms", "application/x-troff-ms");
128 | AddMimeMapping(".nc", "application/x-netcdf");
129 | AddMimeMapping(".nws", "message/rfc822");
130 | AddMimeMapping(".oda", "application/oda");
131 | AddMimeMapping(".ods", "application/oleobject");
132 | AddMimeMapping(".pmc", "application/x-perfmon");
133 | AddMimeMapping(".p7r", "application/x-pkcs7-certreqresp");
134 | AddMimeMapping(".p7b", "application/x-pkcs7-certificates");
135 | AddMimeMapping(".p7s", "application/pkcs7-signature");
136 | AddMimeMapping(".pmw", "application/x-perfmon");
137 | AddMimeMapping(".ps", "application/postscript");
138 | AddMimeMapping(".p7c", "application/pkcs7-mime");
139 | AddMimeMapping(".pbm", "image/x-portable-bitmap");
140 | AddMimeMapping(".ppm", "image/x-portable-pixmap");
141 | AddMimeMapping(".pub", "application/x-mspublisher");
142 | AddMimeMapping(".pnm", "image/x-portable-anymap");
143 | AddMimeMapping(".png", "image/png");
144 | AddMimeMapping(".pml", "application/x-perfmon");
145 | AddMimeMapping(".p10", "application/pkcs10");
146 | AddMimeMapping(".pfx", "application/x-pkcs12");
147 | AddMimeMapping(".p12", "application/x-pkcs12");
148 | AddMimeMapping(".pdf", "application/pdf");
149 | AddMimeMapping(".pps", "application/vnd.ms-powerpoint");
150 | AddMimeMapping(".p7m", "application/pkcs7-mime");
151 | AddMimeMapping(".pko", "application/vndms-pkipko");
152 | AddMimeMapping(".ppt", "application/vnd.ms-powerpoint");
153 | AddMimeMapping(".pmr", "application/x-perfmon");
154 | AddMimeMapping(".pma", "application/x-perfmon");
155 | AddMimeMapping(".pot", "application/vnd.ms-powerpoint");
156 | AddMimeMapping(".prf", "application/pics-rules");
157 | AddMimeMapping(".pgm", "image/x-portable-graymap");
158 | AddMimeMapping(".qt", "video/quicktime");
159 | AddMimeMapping(".ra", "audio/x-pn-realaudio");
160 | AddMimeMapping(".rgb", "image/x-rgb");
161 | AddMimeMapping(".ram", "audio/x-pn-realaudio");
162 | AddMimeMapping(".rmi", "audio/mid");
163 | AddMimeMapping(".ras", "image/x-cmu-raster");
164 | AddMimeMapping(".roff", "application/x-troff");
165 | AddMimeMapping(".rtf", "application/rtf");
166 | AddMimeMapping(".rtx", "text/richtext");
167 | AddMimeMapping(".sv4crc", "application/x-sv4crc");
168 | AddMimeMapping(".spc", "application/x-pkcs7-certificates");
169 | AddMimeMapping(".setreg", "application/set-registration-initiation");
170 | AddMimeMapping(".snd", "audio/basic");
171 | AddMimeMapping(".stl", "application/vndms-pkistl");
172 | AddMimeMapping(".setpay", "application/set-payment-initiation");
173 | AddMimeMapping(".stm", "text/html");
174 | AddMimeMapping(".shar", "application/x-shar");
175 | AddMimeMapping(".sh", "application/x-sh");
176 | AddMimeMapping(".sit", "application/x-stuffit");
177 | AddMimeMapping(".spl", "application/futuresplash");
178 | AddMimeMapping(".sct", "text/scriptlet");
179 | AddMimeMapping(".scd", "application/x-msschedule");
180 | AddMimeMapping(".sst", "application/vndms-pkicertstore");
181 | AddMimeMapping(".src", "application/x-wais-source");
182 | AddMimeMapping(".sv4cpio", "application/x-sv4cpio");
183 | AddMimeMapping(".tex", "application/x-tex");
184 | AddMimeMapping(".tgz", "application/x-compressed");
185 | AddMimeMapping(".t", "application/x-troff");
186 | AddMimeMapping(".tar", "application/x-tar");
187 | AddMimeMapping(".tr", "application/x-troff");
188 | AddMimeMapping(".tif", "image/tiff");
189 | AddMimeMapping(".txt", "text/plain");
190 | AddMimeMapping(".texinfo", "application/x-texinfo");
191 | AddMimeMapping(".trm", "application/x-msterminal");
192 | AddMimeMapping(".tiff", "image/tiff");
193 | AddMimeMapping(".tcl", "application/x-tcl");
194 | AddMimeMapping(".texi", "application/x-texinfo");
195 | AddMimeMapping(".tsv", "text/tab-separated-values");
196 | AddMimeMapping(".ustar", "application/x-ustar");
197 | AddMimeMapping(".uls", "text/iuls");
198 | AddMimeMapping(".vcf", "text/x-vcard");
199 | AddMimeMapping(".wps", "application/vnd.ms-works");
200 | AddMimeMapping(".wav", "audio/wav");
201 | AddMimeMapping(".wrz", "x-world/x-vrml");
202 | AddMimeMapping(".wri", "application/x-mswrite");
203 | AddMimeMapping(".wks", "application/vnd.ms-works");
204 | AddMimeMapping(".wmf", "application/x-msmetafile");
205 | AddMimeMapping(".wcm", "application/vnd.ms-works");
206 | AddMimeMapping(".wrl", "x-world/x-vrml");
207 | AddMimeMapping(".wdb", "application/vnd.ms-works");
208 | AddMimeMapping(".wsdl", "text/xml");
209 | AddMimeMapping(".xap", "application/x-silverlight-app");
210 | AddMimeMapping(".xml", "text/xml");
211 | AddMimeMapping(".xlm", "application/vnd.ms-excel");
212 | AddMimeMapping(".xaf", "x-world/x-vrml");
213 | AddMimeMapping(".xla", "application/vnd.ms-excel");
214 | AddMimeMapping(".xls", "application/vnd.ms-excel");
215 | AddMimeMapping(".xof", "x-world/x-vrml");
216 | AddMimeMapping(".xlt", "application/vnd.ms-excel");
217 | AddMimeMapping(".xlc", "application/vnd.ms-excel");
218 | AddMimeMapping(".xsl", "text/xml");
219 | AddMimeMapping(".xbm", "image/x-xbitmap");
220 | AddMimeMapping(".xlw", "application/vnd.ms-excel");
221 | AddMimeMapping(".xpm", "image/x-xpixmap");
222 | AddMimeMapping(".xwd", "image/x-xwindowdump");
223 | AddMimeMapping(".xsd", "text/xml");
224 | AddMimeMapping(".z", "application/x-compress");
225 | AddMimeMapping(".zip", "application/x-zip-compressed");
226 | AddMimeMapping(".*", "application/octet-stream");
227 | }
228 | }
229 | }
--------------------------------------------------------------------------------