Skip to content

Commit 13efcce

Browse files
committed
Fix Google drive file upload problem
1 parent 219abc2 commit 13efcce

File tree

8 files changed

+198
-58
lines changed

8 files changed

+198
-58
lines changed

Readme-zh-CN.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
萌咖大佬写了一个 [非常好的版本](https://github.com/MoeClub/OneList/tree/master/OneDriveUploader) ,可惜并没有开源,而且已经好久都没有更新了。这个项目作为从 [DownloadBot](https://github.com/gaowanliang/DownloadBot) 中独立出来的一个简易上传工具,旨在用更轻量化的方式让在各种平台都能快速的向各个网络硬盘上传数据。
44

5-
- 支持 OneDrive 国际版, 个人版(家庭版),世纪互联,Google Drive(测试版,下面的命令并未完全支持).
5+
- 支持 OneDrive 国际版, 个人版(家庭版),世纪互联,Google Drive.
66
- 支持上传文件和文件夹到指定目录,并保持上传前的目录结构.
77
- 支持命令参数使用, 方便外部程序调用.
88
- 支持自定义上传分块大小.
@@ -24,15 +24,15 @@ LightUploader -a "url" -l zh-CN
2424
# OneDrive 个人版(家庭版)
2525
LightUploader -a "url" -v 1
2626
# OneDrive 中国版(世纪互联),并使用中文语言包
27-
LightUploader -a "url" -v 2
27+
LightUploader -a "url" -v 2 -l zh-CN
2828

2929
# 在浏览器地址栏中获取以 http://loaclhost 开头的整个url内容
3030
# 将获取的完整url内容替换命令中的 url 三个字母
3131
# 每次产生的 url 只能用一次, 重试请重新获取 url
3232
# 此操作将会自动初始化的配置文件
3333

3434
# Google Drive
35-
LightUploader -a "url" -v 3
35+
LightUploader -v 3
3636
```
3737

3838
## 使用

Readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ MoeClub wrote a [very good version](https://github.com/MoeClub/OneList/tree/mast
55

66
## Features
77

8-
- Supports OneDrive Business, Personal (Home) versions, 21vianet (CN) version, Google Drive (Beta).
8+
- Supports OneDrive Business, Personal (Home) versions, 21vianet (CN) version, Google Drive.
99
- Support for uploading files and folders to specified directories, keeping the directory structure as it was before the upload.
1010
- Supports the use of command parameters for external applications.
1111
- Support for customising the upload chunk size.
@@ -40,7 +40,7 @@ LightUploader -a "url" -v 2 -l zh-CN
4040
# This action will automatically initialise the configuration file
4141

4242
# Google Drive
43-
LightUploader -a "url" -v 3
43+
LightUploader -v 3
4444

4545
```
4646

googledrive/gdUpload.go

Lines changed: 167 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@ import (
66
"io/ioutil"
77
"log"
88
httpLocal "main/graph/net/http"
9+
"math"
910
"net/http"
1011
"os"
1112
"path"
1213
"path/filepath"
14+
"strconv"
1315
"strings"
16+
"sync"
1417
"time"
1518
"unsafe"
1619

20+
"google.golang.org/api/googleapi"
21+
1722
"golang.org/x/net/context"
1823
"golang.org/x/oauth2"
1924
"golang.org/x/oauth2/google"
@@ -22,6 +27,21 @@ import (
2227

2328
// refs https://developers.google.com/drive/v3/web/quickstart/go
2429

30+
var chunkSize = 10 * 1024 * 1024
31+
32+
func changeChunkSize(block int) {
33+
chunkSize = block * 1024 * 1024
34+
}
35+
36+
var wg sync.WaitGroup
37+
var threads = 3
38+
var pool = make(chan struct{}, threads)
39+
40+
func changeThread(thread int) {
41+
threads = thread
42+
pool = make(chan struct{}, threads)
43+
}
44+
2545
// getClient uses a Context and Config to retrieve a Token
2646
// then generate a Client. It returns the generated Client.
2747
func getClient(file string, ctx context.Context, config *oauth2.Config) *http.Client {
@@ -82,7 +102,7 @@ func tokenCacheFile() string {
82102

83103
// tokenFromFile retrieves a Token from a given file path.
84104
// It returns the retrieved Token and any read error encountered.
85-
func tokenFromFile(file string, Thread int, BlockSize int, Language string, TimeOut int, BotKey string, UserID string) (*oauth2.Token, error) {
105+
func tokenFromFile(c *oauth2.Config, file string, Thread int, BlockSize int, Language string, TimeOut int, BotKey string, UserID string) (*oauth2.Token, error) {
86106
//搜尋路徑,有token檔就開啟並Decode,沒有就回傳nil
87107
f, err := os.Open(file)
88108
if err != nil {
@@ -92,14 +112,19 @@ func tokenFromFile(file string, Thread int, BlockSize int, Language string, Time
92112
ts := &httpLocal.Certificate{}
93113
err = json.NewDecoder(f).Decode(ts) //Decode錯誤也會回傳err
94114
oauth2Token := ts.Other.(map[string]interface{})
95-
expiry, _ := time.ParseInLocation("2021-04-29T16:27:54.2042271+08:00", oauth2Token["expiry"].(string), time.Local)
115+
expiry, _ := time.Parse(time.RFC3339, oauth2Token["expiry"].(string))
96116
t := &oauth2.Token{
97117
AccessToken: oauth2Token["access_token"].(string),
98118
TokenType: oauth2Token["token_type"].(string),
99119
RefreshToken: oauth2Token["refresh_token"].(string),
100120
Expiry: expiry,
101121
}
102122
defer f.Close()
123+
f, err = os.OpenFile(file, os.O_WRONLY|os.O_TRUNC, 0666)
124+
defer f.Close()
125+
// log.Printf("%+v\n", t)
126+
updatedToken, err := c.TokenSource(context.TODO(), t).Token()
127+
// log.Printf("%+v\n", updatedToken)
103128
data := httpLocal.Certificate{
104129
Drive: "GoogleDrive",
105130
RefreshToken: ts.RefreshToken,
@@ -110,17 +135,23 @@ func tokenFromFile(file string, Thread int, BlockSize int, Language string, Time
110135
TimeOut: TimeOut,
111136
BotKey: BotKey,
112137
UserID: UserID,
113-
Other: ts.Other,
138+
Other: updatedToken,
114139
}
115-
json.NewEncoder(f).Encode(data)
116-
return t, err
140+
err = json.NewEncoder(f).Encode(data)
141+
if err != nil {
142+
log.Fatalf("Unable to cache oauth token: %v", err)
143+
}
144+
changeThread(Thread)
145+
changeChunkSize(BlockSize)
146+
return updatedToken, err
117147
}
118148

119149
// saveToken uses a file path to create a file and store the
120150
// token in it.
151+
121152
func saveToken(file string, token *oauth2.Token, lang string) {
122153
//fmt.Printf("Saving credential file to: %s\n", file)
123-
f, err := os.Create(file)
154+
f, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
124155
if err != nil {
125156
log.Fatalf("Unable to cache oauth token: %v", err)
126157
}
@@ -140,7 +171,46 @@ func saveToken(file string, token *oauth2.Token, lang string) {
140171
json.NewEncoder(f).Encode(data)
141172
}
142173

143-
func UploadAllFile(pathname string, folderIDList []string, srv *drive.Service, startTime int64, username string, sendMsg func(text string), locText func(text string) string) error {
174+
func byte2Readable(bytes float64) string {
175+
const kb float64 = 1024
176+
const mb float64 = kb * 1024
177+
const gb float64 = mb * 1024
178+
var readable float64
179+
var unit string
180+
_bytes := bytes
181+
182+
if _bytes >= gb {
183+
// xx GB
184+
readable = _bytes / gb
185+
unit = "GB"
186+
} else if _bytes < gb && _bytes >= mb {
187+
// xx MB
188+
readable = _bytes / mb
189+
unit = "MB"
190+
} else {
191+
// xx KB
192+
readable = _bytes / kb
193+
unit = "KB"
194+
}
195+
return strconv.FormatFloat(readable, 'f', 2, 64) + " " + unit
196+
}
197+
198+
func UploadAllFile(pathname string, folderIDList []string, srv *drive.Service, startTime int64, username string, sendMsg func() (func(text string), string, string, func(string, string, string) func(string)), locText func(text string) string) (func(string), error) {
199+
200+
filePath := path.Base(pathname)
201+
temps, _botKey, iUserID, BotSend := sendMsg()
202+
var iSendMsg func(string)
203+
tip := "`" + filePath + "`" + locText("startUploadGoogleDrive")
204+
if _botKey != "" && iUserID != "" {
205+
iSendMsg = BotSend(_botKey, iUserID, tip)
206+
}
207+
temp := func(text string) {
208+
temps(text)
209+
if _botKey != "" && iUserID != "" {
210+
iSendMsg(text)
211+
}
212+
}
213+
temp(tip)
144214

145215
rd, err := ioutil.ReadDir(pathname)
146216
if err != nil {
@@ -156,11 +226,9 @@ func UploadAllFile(pathname string, folderIDList []string, srv *drive.Service, s
156226
defer f.Close()
157227
//log.Println("file", fi.Name(), fullName)
158228
//上傳檔案,create要給定檔案名稱,要傳進資料夾就加上Parents參數給定folderID的array,media傳入我們要上傳的檔案,最後Do
159-
_, err = srv.Files.Create(&drive.File{Name: fullName, Parents: tempFolderIDList}).Media(f).Do()
160-
if err != nil {
161-
log.Panicf("Unable to create file: %v", err)
162-
}
163-
sendMsg(fmt.Sprintf(locText("googleDriveUploadTip"), username, fullName, time.Now().Unix()-startTime))
229+
230+
uploadFile(srv, pathname, fullName, tempFolderIDList, f, sendMsg, locText, username)
231+
// sendMsg(fmt.Sprintf(locText("googleDriveUploadTip"), username, fullName, time.Now().Unix()-startTime))
164232
}
165233
_, foldName := filepath.Split(pathname)
166234
//log.Println(foldName)
@@ -182,13 +250,13 @@ func UploadAllFile(pathname string, folderIDList []string, srv *drive.Service, s
182250
tempFolderIDList = folderIDList
183251
}
184252
tempFolderIDList = append(tempFolderIDList, createFolder.Id)
185-
err := UploadAllFile(fullDir, tempFolderIDList, srv, startTime, username, sendMsg, locText)
253+
_, err := UploadAllFile(fullDir, tempFolderIDList, srv, startTime, username, sendMsg, locText)
186254
if err != nil {
187255
log.Panic("read dir fail:", err)
188-
return err
256+
return nil, err
189257
}
190258
//log.Println("folder", fi.Name(), fullDir)
191-
sendMsg(fmt.Sprintf(locText("googleDriveUploadTip"), username, fullDir, time.Now().Unix()-startTime))
259+
// sendMsg(fmt.Sprintf(locText("googleDriveUploadTip"), username, fullDir, time.Now().Unix()-startTime))
192260
} else {
193261
fullName := pathname + "/" + fi.Name()
194262
var tempFolderIDList []string
@@ -203,15 +271,93 @@ func UploadAllFile(pathname string, folderIDList []string, srv *drive.Service, s
203271
defer f.Close()
204272
//log.Println("file", fi.Name(), fullName)
205273
//上傳檔案,create要給定檔案名稱,要傳進資料夾就加上Parents參數給定folderID的array,media傳入我們要上傳的檔案,最後Do
206-
_, err = srv.Files.Create(&drive.File{Name: fi.Name(), Parents: tempFolderIDList}).Media(f).Do()
274+
// _, err = srv.Files.Create(&drive.File{Name: fi.Name(), Parents: tempFolderIDList}).Media(f, googleapi.ChunkSize(chunkSize)).Do()
275+
uploadFile(srv, fullName, fi.Name(), tempFolderIDList, f, sendMsg, locText, username)
207276
if err != nil {
208277
log.Panicf("Unable to create file: %v", err)
209278
}
210-
sendMsg(fmt.Sprintf(locText("googleDriveUploadTip"), username, fullName, time.Now().Unix()-startTime))
279+
// sendMsg(fmt.Sprintf(locText("googleDriveUploadTip"), username, fullName, time.Now().Unix()-startTime))
211280
//log.Printf("file: %+v", driveFile)
212281
}
213282
}
214-
return nil
283+
wg.Wait()
284+
return temp, nil
285+
}
286+
287+
func FileSizeFormat(bytes int64, forceBytes bool) string {
288+
if forceBytes {
289+
return fmt.Sprintf("%v B", bytes)
290+
}
291+
292+
units := []string{"B", "KB", "MB", "GB", "TB", "PB"}
293+
294+
var i int
295+
value := float64(bytes)
296+
297+
for value > 1000 {
298+
value /= 1000
299+
i++
300+
}
301+
return fmt.Sprintf("%.1f %s", value, units[i])
302+
}
303+
304+
func MeasureTransferRate() func(int64) string {
305+
start := time.Now()
306+
307+
return func(bytes int64) string {
308+
seconds := int64(time.Now().Sub(start).Seconds())
309+
if seconds < 1 {
310+
return fmt.Sprintf("%s/s", FileSizeFormat(bytes, false))
311+
}
312+
bps := bytes / seconds
313+
return fmt.Sprintf("%s/s", FileSizeFormat(bps, false))
314+
}
315+
}
316+
317+
func uploadFile(srv *drive.Service, filePath string, filename string, tempFolderIDList []string, f *os.File, sendMsg func() (func(text string), string, string, func(string, string, string) func(string)), locText func(text string) string, username string) {
318+
wg.Add(1)
319+
pool <- struct{}{}
320+
startTime := time.Now().Unix()
321+
go func() {
322+
defer wg.Done()
323+
defer func() {
324+
<-pool
325+
}()
326+
temps, _botKey, iUserID, botSend := sendMsg()
327+
var iSendMsg func(string)
328+
tip := "`" + filePath + "`" + locText("startToUpload1")
329+
if _botKey != "" && iUserID != "" {
330+
iSendMsg = botSend(_botKey, iUserID, tip)
331+
}
332+
temp := func(text string) {
333+
temps(text)
334+
if _botKey != "" && iUserID != "" {
335+
iSendMsg(text)
336+
}
337+
}
338+
fi, err := os.Stat(filePath)
339+
if err != nil {
340+
fi, err = os.Stat(filename)
341+
if err != nil {
342+
log.Panicln(err)
343+
}
344+
}
345+
getRate := MeasureTransferRate()
346+
size := fi.Size()
347+
// log.Println(byte2Readable(float64(size)))
348+
349+
showProgress := func(current, total int64) {
350+
temp(fmt.Sprintf(locText("googleDriveUploadTip1"), username, filePath, byte2Readable(float64(size)), byte2Readable(float64(current)), int(math.Ceil(float64(current)/float64(chunkSize))), int(math.Ceil(float64(size)/float64(chunkSize))), getRate(current), time.Now().Unix()-startTime))
351+
}
352+
353+
_, err = srv.Files.Create(&drive.File{Name: filename, Parents: tempFolderIDList}).Media(f, googleapi.ChunkSize(chunkSize)).ProgressUpdater(showProgress).Do()
354+
if err != nil {
355+
log.Panicln(err)
356+
}
357+
358+
defer temp("close")
359+
}()
360+
215361
}
216362

217363
/*func main() {
@@ -266,7 +412,8 @@ func CreateNewInfo(code string, lang string) string {
266412

267413
func Upload(infoPath string, filePath string, sendMsg func() (func(text string), string, string, func(string, string, string) func(string)), locText func(text string) string, Thread int, BlockSize int, Language string, TimeOut int, BotKey string, UserID string) {
268414
ctx, config := gdInit()
269-
tok, _ := tokenFromFile(infoPath, Thread, BlockSize, Language, TimeOut, BotKey, UserID)
415+
infoPath, _ = filepath.Abs(infoPath)
416+
tok, _ := tokenFromFile(config, infoPath, Thread, BlockSize, Language, TimeOut, BotKey, UserID)
270417
client := config.Client(ctx, tok)
271418
srv, err := drive.New(client)
272419
username := strings.ReplaceAll(filepath.Base(infoPath), ".json", "")
@@ -280,26 +427,12 @@ func Upload(infoPath string, filePath string, sendMsg func() (func(text string),
280427
if err != nil {
281428
log.Panic(err)
282429
}
283-
filePath = path.Base(filePath)
284-
temps, _botKey, iUserID, BotSend := sendMsg()
285-
var iSendMsg func(string)
286-
tip := "`" + filePath + "`" + locText("startUploadGoogleDrive")
287-
if _botKey != "" && iUserID != "" {
288-
iSendMsg = BotSend(_botKey, iUserID, tip)
289-
}
290-
temp := func(text string) {
291-
temps(text)
292-
if _botKey != "" && iUserID != "" {
293-
iSendMsg(text)
294-
}
295-
}
296-
temp(tip)
297430

298431
if err != nil {
299432
log.Fatalf("Unable to retrieve drive Client %v", err)
300433

301434
}
302-
_ = UploadAllFile(filePath, nil, srv, time.Now().Unix(), username, temp, locText)
435+
temp, _ := UploadAllFile(filePath, nil, srv, time.Now().Unix(), username, sendMsg, locText)
303436
temp(locText("uploadGoogleDriveComplete"))
304437
err = os.Chdir(oldDir)
305438
if err != nil {

i18n.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ package main
22

33
import (
44
"fmt"
5-
"github.com/BurntSushi/toml"
6-
"github.com/nicksnyder/go-i18n/v2/i18n"
7-
"golang.org/x/text/language"
85
"io/ioutil"
96
"log"
107
"net/http"
@@ -13,6 +10,10 @@ import (
1310
"path/filepath"
1411
"regexp"
1512
"time"
13+
14+
"github.com/BurntSushi/toml"
15+
"github.com/nicksnyder/go-i18n/v2/i18n"
16+
"golang.org/x/text/language"
1617
)
1718

1819
var bundle *i18n.Bundle
@@ -118,6 +119,7 @@ func (loc *Loc) init(locLanguage string) {
118119
}
119120
}
120121
dir, err = os.Executable()
122+
// log.Println(dir)
121123
dropErr(err)
122124
dir = filepath.Dir(dir)
123125
rd, err := ioutil.ReadDir(dir)

0 commit comments

Comments
 (0)