Skip to content

Commit

Permalink
Merge branch 'release/v0.6.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
gee1k committed Jun 27, 2019
2 parents fdf1737 + a649682 commit 85a3ee2
Show file tree
Hide file tree
Showing 32 changed files with 837 additions and 124 deletions.
122 changes: 62 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,99 +1,101 @@
# uPic

> 图片(文件)上传
# ☁️ 简洁的 Mac 图床客户端 uPic

<p align="center">
<img src="./screenshot/logo.png" alt="">
</p>
<p align="center">
<a href="https://github.com/gee1k/uPic/releases">
<img src="https://img.shields.io/github/downloads/gee1k/uPic/total.svg?style=flat-square" alt="">
<div style="display: flex;justify-content: center;">
<a href="https://github.com/gee1k/uPic/stargazers">
<img src="https://img.shields.io/github/stars/gee1k/uPic.svg?style=popout-square" alt="">
</a> <a href="https://github.com/gee1k/uPic/releases" style="margin: 0 5px;">
<img src="https://img.shields.io/github/downloads/gee1k/uPic/total.svg?style=popout-square" alt="">
</a> <a href="https://github.com/gee1k/uPic/releases/latest">
<img src="https://img.shields.io/github/release/gee1k/uPic.svg?style=popout-square" alt="">
</a>
<a href="https://github.com/gee1k/uPic/releases/latest">
<img src="https://img.shields.io/github/release/gee1k/uPic.svg?style=flat-square" alt="">
</a>
</p>
</div>

## 📑 简介

> **uPic 是一款 Mac 端的图床(文件)上传客户端**
> 可将图片、各种文件上传到配置好的指定提供商的对象存储中。
> 然后快速获取可供互联网访问的文件 URL
## ⚒ 上传方式
## 💡 特点

**uPic支持选择文件上传、拖拽文件上传、复制文件上传、截图上传。支持菜单栏显示实时进度**
无论是本地文件、或者屏幕截图都可自动上传,菜单栏显示实时上传进度。上传完成后文件链接自动复制到剪切板,让你无论是在写博客、灌水聊天都能快速插入图片。
连接格式可以是普通 URL、HTML 或者 Markdown,仍由你掌控。

### 1.选择文件上传
点击菜单栏 `选择文件上传`即可打开 Finder 选择需要上传的文件。
![selectFile](./screenshot/selectFile.gif)
## 📤 上传方式

### 2.复制上传
将需要上传的文件复制到剪切板,然后点击菜单栏中的`上传已拷贝的文件`即可上传。
![paste](./screenshot/paste.gif)
为了满足你可能遇到的各种需求,uPic 提供了多种上传方式

### 3.拖拽上传
只需要将当前图床所支持格式的文件拖到菜单栏的 uPic 图标上即可上传。
![drag](./screenshot/drag.gif)
- ✅ 选择文件上传
- ✅ 复制文件上传
- ✅ 拖拽文件上传
- ✅ 截图上传

### 4.截图上传
点击菜单栏 `截图上传`会激活截图操作,拉框选择要截图的范围即可自动上传。
![screenshot](./screenshot/screenshot.gif)
#### 🖥 选择文件上传

> 除了复制上传以外,所有上传方式均可以在`偏好设置`中设置全局快捷键。
> 设置好全局快捷键之后可以在任何时候通过快捷键激活对应的上传操作
![选择文件上传](./screenshot/selectFile.gif)

![shortcuts](./screenshot/shortcuts.png)
#### ⌨️ 复制文件上传

## 💻 图床配置
![复制文件上传](./screenshot/paste.gif)

**`偏好设置`中可配置图床,同一类型图床可配置多个,已满足多个云储存位置**
#### 🖱 拖拽文件上传

![hosts](./screenshot/hosts.png)
![拖拽文件上传](./screenshot/drag.gif)

配置好的图床可以在菜单栏`图床`栏看到,并选择您接下来要上传到的图床。
#### 🖱 截图上传

![default-host](./screenshot/default-host.png)
![截图上传](./screenshot/screenshot.gif)

## 📝 输出格式
## 📦 图床、对象存储

**支持多种输出格式,以快速帮你实现的不同需求。**
- [smms](https://sm.ms/)
- [又拍云 USS](https://www.upyun.com/products/file-storage)
- [七牛云 KODO](https://www.qiniu.com/products/kodo)
- [阿里云 OSS](https://www.aliyun.com/product/oss/)
- [腾讯云 COS](https://cloud.tencent.com/product/cos)
- [自定义上传接口](https://blog.svend.cc/upic/tutorials/custom)
- ...

![output](./screenshot/output.png)
#### ⚙️ 配置图床

## 支持图床服务
**`偏好设置`中可配置图床。支持同一类型图床可配置多个实例**

**以下是现有和未来计划加入支持的图床**
![图床配置](./screenshot/hosts.png)

- [x] [~~smms~~](https://sm.ms/)
#### 🔦 选择图床

- [x] [~~又拍云 USS~~](https://www.upyun.com/products/file-storage)
**配置好的图床可以在菜单栏`图床`中看到,并选择您接下来要上传到的图床**

- [x] [~~七牛云 KODO~~](https://www.qiniu.com/products/kodo)
![图床](./screenshot/default-host.png)

- [x] [~~腾讯云 COS~~](https://cloud.tencent.com/product/cos)
## 🧰 更多功能

- [x] [~~阿里云 OSS~~](https://www.aliyun.com/product/oss)
**除了以上这些最基本的功能以外,uPic 还提供了一系列小功能让你使用起来更方便更顺心**

- ...
### ⌨︎ 全局快捷键

# ⚙ 开发
![快捷键](./screenshot/shortcuts.png)

- 1.克隆代码到本地

`https://github.com/gee1k/uPic.git`

- 2.安装依赖,本项目依赖使用 [Cocoapods](https://cocoapods.org/) 管理,请先确保已有 Cocoapods 环境
### 🕦 上传历史

```sh
# 进入项目目录
cd uPic
# 安装依赖
pod install
```
![上传历史](./screenshot/history.png)

- 3.依赖安装完成之后,可编译测试一下是否通过
### 📢 更多功能等待你发现

# ✉️ 联系我
...

- `Email`: `[email protected]`
# 💌 联系我

- `Email`: [email protected]
- `微信`: `JSW5297` (请备注一下 uPic)
- `Telegram`: [gee1k](https://t.me/gee1k)
- `项目地址`: [Github](https://github.com/gee1k/uPic)

# 📝 使用手册

**编写中...敬请期待**


# ❤️ 赞助

Expand Down
24 changes: 24 additions & 0 deletions uPic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
16068C7822AECB34004D39B7 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16068C7722AECB34004D39B7 /* PreferencesWindowController.swift */; };
16068C7C22AECD9F004D39B7 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16068C7B22AECD9F004D39B7 /* Constants.swift */; };
160CAA2522B1ED6F00D04FBD /* PreferenceKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 160CAA2422B1ED6F00D04FBD /* PreferenceKey.swift */; };
161C3BE122C483380092114F /* CustomUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161C3BE022C4831B0092114F /* CustomUploader.swift */; };
161C3BE322C483560092114F /* CustomHostConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161C3BE222C483560092114F /* CustomHostConfig.swift */; };
161C3BE522C4870C0092114F /* CustomConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161C3BE422C4870B0092114F /* CustomConfigView.swift */; };
161C3BE722C49BE90092114F /* RequestMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161C3BE622C49BE90092114F /* RequestMethods.swift */; };
1623611B22AB935300E4025C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1623611D22AB935300E4025C /* InfoPlist.strings */; };
1623612322AB951E00E4025C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1623612522AB951E00E4025C /* Localizable.strings */; };
162E5D4822C096FD001FAA46 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 162E5D4722C096FD001FAA46 /* Assets.xcassets */; };
Expand Down Expand Up @@ -91,6 +95,10 @@
16068C7722AECB34004D39B7 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
16068C7B22AECD9F004D39B7 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
160CAA2422B1ED6F00D04FBD /* PreferenceKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceKey.swift; sourceTree = "<group>"; };
161C3BE022C4831B0092114F /* CustomUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomUploader.swift; sourceTree = "<group>"; };
161C3BE222C483560092114F /* CustomHostConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomHostConfig.swift; sourceTree = "<group>"; };
161C3BE422C4870B0092114F /* CustomConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomConfigView.swift; sourceTree = "<group>"; };
161C3BE622C49BE90092114F /* RequestMethods.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestMethods.swift; sourceTree = "<group>"; };
1623611822AB92DB00E4025C /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Main.strings"; sourceTree = "<group>"; };
1623611C22AB935300E4025C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
1623611E22AB935F00E4025C /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -206,6 +214,16 @@
path = PreferencesWindow;
sourceTree = "<group>";
};
161C3BDF22C4830A0092114F /* Custom */ = {
isa = PBXGroup;
children = (
161C3BE022C4831B0092114F /* CustomUploader.swift */,
161C3BE222C483560092114F /* CustomHostConfig.swift */,
161C3BE622C49BE90092114F /* RequestMethods.swift */,
);
path = Custom;
sourceTree = "<group>";
};
163632ED22B2745A00805E7F /* Basic */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -272,6 +290,7 @@
isa = PBXGroup;
children = (
1662AC7022C0AC52003AC924 /* AliyunConfigView.swift */,
161C3BE422C4870B0092114F /* CustomConfigView.swift */,
1660FCBE22C1211800372950 /* TencentConfigView.swift */,
166B4A5222B9CB4D001288ED /* UpYunConfigView.swift */,
1690E7E322BF111500FC81F8 /* QiniuConfigView.swift */,
Expand All @@ -289,6 +308,7 @@
167D7F4C22B4D43B00DD0A7A /* HostSaveKey.swift */,
167D7F4A22B4D31300DD0A7A /* HostType.swift */,
68BBB87F2C3AEBDF2C914131 /* Aliyun */,
161C3BDF22C4830A0092114F /* Custom */,
1690E7E522BF113700FC81F8 /* Qiniu */,
167D7F4E22B4DB2500DD0A7A /* Smms */,
1660FCB522C11A9F00372950 /* Tencent */,
Expand Down Expand Up @@ -589,8 +609,10 @@
16A6DC5822AA375700813706 /* AppDelegate.swift in Sources */,
1602ED9722ADEFB200AA8638 /* BaseUploader.swift in Sources */,
163632F322B2751D00805E7F /* BoolType.swift in Sources */,
161C3BE722C49BE90092114F /* RequestMethods.swift in Sources */,
163632EF22B2749000805E7F /* NSTextFieldCell+VerticallyCentered.swift in Sources */,
164745EB22B618D700F9575D /* HostPreferencesViewController.swift in Sources */,
161C3BE322C483560092114F /* CustomHostConfig.swift in Sources */,
1660FCBD22C11C7800372950 /* TencentRegion.swift in Sources */,
167D7F4922B4D2F500DD0A7A /* HostConfig.swift in Sources */,
164C3A0222B2AB22003ADE39 /* ConfigNotifier.swift in Sources */,
Expand All @@ -612,6 +634,7 @@
160CAA2522B1ED6F00D04FBD /* PreferenceKey.swift in Sources */,
169F073722AF4549008E8525 /* AdvancedPreferencesViewController.swift in Sources */,
16068C7522AEC1D1004D39B7 /* PreferencesViewController.swift in Sources */,
161C3BE122C483380092114F /* CustomUploader.swift in Sources */,
169F073A22AF4549008E8525 /* AboutPreferencesViewController.swift in Sources */,
1690E7E722BF174300FC81F8 /* QiniuHostConfig.swift in Sources */,
1675516222ABF80300D3EB6F /* NSDragingInfoExt.swift in Sources */,
Expand All @@ -620,6 +643,7 @@
169F073922AF4549008E8525 /* GeneralPreferencesViewController.swift in Sources */,
167D7F4D22B4D43B00DD0A7A /* HostSaveKey.swift in Sources */,
16068C7C22AECD9F004D39B7 /* Constants.swift in Sources */,
161C3BE522C4870C0092114F /* CustomConfigView.swift in Sources */,
68BBB6E5FFBB050D05107413 /* AliyunHostConfig.swift in Sources */,
68BBB3EF25C92DCAE216A4DF /* AliyunUploader.swift in Sources */,
1660FCBC22C11C7500372950 /* TencentUtil.swift in Sources */,
Expand Down
7 changes: 7 additions & 0 deletions uPic.xcodeproj/xcshareddata/xcschemes/uPic.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@
ReferencedContainer = "container:uPic.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<EnvironmentVariables>
<EnvironmentVariable
key = "CG_PDF_VERBOSE"
value = "1"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
Expand Down
13 changes: 7 additions & 6 deletions uPic/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
setupStatusBar()
}

func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
func applicationWillTerminate(_ notification: Notification) {
NSStatusBar.system.removeStatusItem(statusItem)
}

func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
return true
}

}
Expand Down Expand Up @@ -91,13 +95,10 @@ extension AppDelegate {

extension AppDelegate {

@objc func showPreference() {
self.preferencesWindowController.showWindow(self)
}

/* 选择文件 */
@objc func selectFile() {

NSApp.activate(ignoringOtherApps: true)
let fileExtensions = BaseUploader.getFileExtensions()

let openPanel = NSOpenPanel()
Expand Down
6 changes: 3 additions & 3 deletions uPic/Assets.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"info": {
"version": 1,
"author": "xcode"
"info" : {
"version" : 1,
"author" : "xcode"
}
}
21 changes: 21 additions & 0 deletions uPic/Assets.xcassets/host_icon_-1.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "itmis_customer.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions uPic/Basic/String+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ extension String {
func urlSafeBase64() -> String {
return self.replacingOccurrences(of: "+", with: "-").replacingOccurrences(of: "/", with: "_")
}

//将原始的url编码为合法的url
func urlEncoded() -> String {
let encodeUrlString = self.addingPercentEncoding(withAllowedCharacters:
.urlQueryAllowed)
return encodeUrlString ?? ""
}

//将编码后的url转换回原始的url
func urlDecoded() -> String {
return self.removingPercentEncoding ?? ""
}

// 字符串增强
var lastPathComponent: String {
Expand Down
2 changes: 1 addition & 1 deletion uPic/General/Managers/ConfigManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ extension ConfigManager {

public var historyLimit: Int {
get {
let defaultLimit = 10
let defaultLimit = 6
let limit = Defaults[.historyLimit]
if (limit == nil || limit == 0) {
return defaultLimit
Expand Down
13 changes: 7 additions & 6 deletions uPic/Models/Aliyun/AliyunUploader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,23 @@ class AliyunUploader: BaseUploader {

var headers = HTTPHeaders()
headers.add(HTTPHeader.contentType("application/x-www-form-urlencoded;charset=utf-8"))


AF.upload(multipartFormData: { (multipartFormData: MultipartFormData) in



func multipartFormDataGen(multipartFormData: MultipartFormData) {
multipartFormData.append(key.data(using: .utf8)!, withName: "key")
multipartFormData.append(accessKey.data(using: .utf8)!, withName: "OSSAccessKeyId")
multipartFormData.append(policy.data(using: .utf8)!, withName: "policy")
multipartFormData.append(signature.data(using: .utf8)!, withName: "Signature")

if fileUrl != nil {
multipartFormData.append(fileUrl!, withName: "file", fileName: fileName, mimeType: mimeType)
} else {
multipartFormData.append(fileData!, withName: "file", fileName: fileName, mimeType: mimeType)
}
}


}, to: url, headers: headers).validate().uploadProgress { progress in
AF.upload(multipartFormData: multipartFormDataGen, to: url, headers: headers).validate().uploadProgress { progress in
super.progress(percent: progress.fractionCompleted * 100)
}.response(completionHandler: { response -> Void in
switch response.result {
Expand Down
Loading

0 comments on commit 85a3ee2

Please sign in to comment.