diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..52aa089
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,3 @@
+language: go
+install:
+ - go get github.com/tanaikech/goodls
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..a6b90f8
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright (c) 2018 Kanshi TANAIKE
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7b95645
--- /dev/null
+++ b/README.md
@@ -0,0 +1,87 @@
+goodls
+=====
+
+
+[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENCE)
+
+
+# Overview
+This is a CLI tool to download shared files from Google Drive.
+
+# Demo
+![](images/demo.gif)
+
+The image used for this demonstration was created by [k3-studio](https://k3-studio.deviantart.com/art/Chromatic-spiral-416032436)
+
+
+# Description
+We have already known that the shared files on Google Drive can be downloaded without the authorization. But when the size of file becomes large (about 40MB), it requires a little ingenuity to download the file. It requires to access 2 times to Google Drive. At 1st access, it retrieves a cookie and a code for downloading. At 2nd access, the file is downloaded using the cookie and code. I created this process as a CLI tool. This tool has the following features.
+
+- Use suitable process for size and type of file.
+- Retrieve filename and mimetype from response header.
+- Can download all shared files except for project files.
+
+# How to Install
+Download an executable file of goodls from [the release page](https://github.com/tanaikech/goodls/releases) and import to a directory with path.
+
+or
+
+Use go get.
+
+~~~bash
+$ go get -u github.com/tanaikech/goodls
+~~~
+
+# Usage
+You can use this just after you download or install goodls. You are not required to do like OAuth2 process.
+
+~~~bash
+$ goodls -u [URL of shared file on Google Drive]
+~~~
+
+- **Help**
+ - ``$ goodls --help``
+- **Options**
+ - ``-e``
+ - Extension of output file. This is for only Google Docs (Spreadsheet, Document, Presentation). Default is ``pdf``.
+ - Sample :
+ - ``$ goodls -u https://docs.google.com/document/d/#####/edit?usp=sharing -e txt``
+ - ``-f``
+ - Filename of file which is output. When this was not used, the original filename on Google Drive is used.
+ - Sample :
+ - ``$ goodls -u https://docs.google.com/document/d/#####/edit?usp=sharing -e txt -f sample.txt``
+- **URL is like below.**
+ - In the case of Google Docs (Spreadsheet, Document, Slides)
+ - ``https://docs.google.com/spreadsheets/d/#####/edit?usp=sharing``
+ - ``https://docs.google.com/document/d/#####/edit?usp=sharing``
+ - ``https://docs.google.com/presentation/d/#####/edit?usp=sharing``
+ - In the case of except for Google Docs
+ - ``https://drive.google.com/file/d/#####/view?usp=sharing``
+
+**When you download shared files from Google Drive, please confirm whether the files are shared.**
+
+# Q&A
+- I want to download **shared projects** from user's Google Drive.
+ - You can download **shared projects** using [ggsrun](https://github.com/tanaikech/ggsrun).
+ - ggsrun can also download **shared files** from other user's Google Drive using Drive API which needs the access token.
+
+-----
+
+
+# Licence
+[MIT](LICENCE)
+
+
+# Author
+[Tanaike](https://tanaikech.github.io/about/)
+
+If you have any questions and commissions for me, feel free to tell me.
+
+
+# Update History
+* v1.0.0 (January 10, 2018)
+
+ 1. Initial release.
+
+
+[TOP](#TOP)
diff --git a/doc.go b/doc.go
new file mode 100644
index 0000000..9309815
--- /dev/null
+++ b/doc.go
@@ -0,0 +1,29 @@
+/*
+Package main (doc.go) :
+This is a CLI tool to download shared files from Google Drive.
+
+We have already known that the shared files on Google Drive can be downloaded without the authorization. But when the size of file becomes large (about 40MB), it requires a little ingenuity to download the file. It requires to access 2 times to Google Drive. At 1st access, it retrieves a cookie and a code for downloading. At 2nd access, the file is downloaded using the cookie and code. I created this process as a CLI tool. This tool has the following features.
+
+- Use suitable process for size and type of file.
+- Retrieve filename and mimetype from response header.
+- Can download all shared files except for project files.
+
+---------------------------------------------------------------
+
+# How to Install
+Download an executable file of goodls from https://github.com/tanaikech/goodls/releases
+
+or
+
+Use go get.
+
+$ go get -u github.com/tanaikech/goodls
+
+# Usage
+You can use this just after you download or install goodls. You are not required to do like OAuth2 process.
+
+$ goodls -u [URL of shared file on Google Drive]
+
+---------------------------------------------------------------
+*/
+package main
diff --git a/goodls.go b/goodls.go
new file mode 100644
index 0000000..f35878b
--- /dev/null
+++ b/goodls.go
@@ -0,0 +1,226 @@
+// Package main (goodls.go) :
+package main
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "mime"
+ "net/http"
+ "net/http/cookiejar"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ "github.com/urfave/cli"
+)
+
+const (
+ appname = "goodls"
+ anyurl = "https://drive.google.com/uc?export=download"
+ docutl = "https://docs.google.com/"
+)
+
+// para : Structure for each parameter
+type para struct {
+ Client *http.Client
+ Code string
+ ContentType string
+ Ext string
+ Filename string
+ Id string
+ Kind string
+ Url string
+ WorkDir string
+}
+
+// saveFile : Save retrieved data as a file.
+func (p *para) saveFile(res *http.Response) error {
+ var err error
+ p.ContentType = res.Header["Content-Type"][0]
+ err = p.getFilename(res)
+ if err = p.getFilename(res); err != nil {
+ return err
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ return err
+ }
+ ioutil.WriteFile(filepath.Join(p.WorkDir, p.Filename), body, 0777)
+ fmt.Printf("{\"Filename\": \"%s\", \"Type\": \"%s\", \"MimeType\": \"%s\", \"FileSize\": %d}\n", p.Filename, p.Kind, p.ContentType, len(body))
+ defer res.Body.Close()
+ return nil
+}
+
+// getFilename : Retrieve filename from header.
+func (p *para) getFilename(s *http.Response) error {
+ if len(s.Header["Content-Disposition"]) > 0 {
+ _, para, err := mime.ParseMediaType(s.Header["Content-Disposition"][0])
+ if err != nil {
+ return err
+ }
+ if p.Filename == "" {
+ p.Filename = para["filename"]
+ }
+ } else {
+ return errors.New(fmt.Sprintf("File ID [ %s ] is not shared, while the file is existing.\n", p.Id))
+ }
+ return nil
+}
+
+// downloadLargeFile : When a large size of file is downloaded, this method is used.
+func (p *para) downloadLargeFile() error {
+ fmt.Println("Now downloading.")
+ res, err := p.fetch(p.Url + "&confirm=" + p.Code)
+ if err != nil {
+ return err
+ }
+ if res.StatusCode != 200 && p.Kind != "file" {
+ return errors.New(fmt.Sprintf("Error: This error occurs when it downloads a large file of Google Docs.\nMessage: %+v", res))
+ }
+ p.saveFile(res)
+ return nil
+}
+
+// checkCookie : When a large size of file is downloaded, a code for downloading is retrieved at here.
+func (p *para) checkCookie(rawCookies string) {
+ header := http.Header{}
+ header.Add("Cookie", rawCookies)
+ request := http.Request{Header: header}
+ for _, e := range request.Cookies() {
+ if strings.Contains(e.Name, "download_warning_") {
+ cookie, _ := request.Cookie(e.Name)
+ p.Code = cookie.Value
+ break
+ }
+ }
+}
+
+// fetch : Fetch data from Google Drive
+func (p *para) fetch(url string) (*http.Response, error) {
+ req, err := http.NewRequest("get", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ res, err := p.Client.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ return res, nil
+}
+
+// checkUrl : Parse inputted URL.
+func (p *para) checkUrl(s string) error {
+ r := regexp.MustCompile(`google\.com\/(\w.+)\/d\/(\w.+)\/`)
+ if r.MatchString(s) {
+ res := r.FindAllStringSubmatch(s, -1)
+ p.Kind = res[0][1]
+ p.Id = res[0][2]
+ if p.Kind == "file" {
+ p.Url = anyurl + "&id=" + p.Id
+ } else {
+ if p.Kind == "presentation" {
+ p.Url = docutl + p.Kind + "/d/" + p.Id + "/export/" + p.Ext
+ } else {
+ p.Url = docutl + p.Kind + "/d/" + p.Id + "/export?format=" + p.Ext
+ }
+ }
+ } else {
+ return errors.New("Error: URL is wrong.")
+ }
+ return nil
+}
+
+// download : Main method of download.
+func (p *para) download(url string) error {
+ var err error
+ err = p.checkUrl(url)
+ if err != nil {
+ return err
+ }
+ jar, err := cookiejar.New(nil)
+ if err != nil {
+ return err
+ }
+ p.Client = &http.Client{Jar: jar}
+ res, err := p.fetch(p.Url)
+ if err != nil {
+ return err
+ }
+ if res.StatusCode == 200 {
+ if len(res.Header["Set-Cookie"]) == 0 {
+ return p.saveFile(res)
+ } else {
+ p.checkCookie(res.Header["Set-Cookie"][0])
+ if len(p.Code) == 0 && p.Kind == "file" {
+ return errors.New(fmt.Sprintf("File ID [ %s ] is not shared, while the file is existing.\n", p.Id))
+ } else if len(p.Code) == 0 && p.Kind != "file" {
+ return p.saveFile(res)
+ } else {
+ return p.downloadLargeFile()
+ }
+ }
+ } else {
+ return errors.New(fmt.Sprintf("File ID [ %s ] cannot be downloaded as [ %s ].\n", p.Id, p.Ext))
+ }
+ return nil
+}
+
+// handler : Initialize of "para".
+func handler(c *cli.Context) {
+ if c.String("url") == "" {
+ createHelp().Run(os.Args)
+ return
+ }
+ var err error
+ workdir, err := filepath.Abs(".")
+ if err != nil {
+ log.Fatal(err)
+ }
+ p := ¶{
+ Ext: c.String("extension"),
+ Filename: c.String("filename"),
+ WorkDir: workdir,
+ }
+ err = p.download(c.String("url"))
+ if err != nil {
+ fmt.Printf("Error: %v\n", err)
+ os.Exit(1)
+ }
+ return
+}
+
+// createHelp : Create help document.
+func createHelp() *cli.App {
+ a := cli.NewApp()
+ a.Name = appname
+ a.Author = "tanaike [ https://github.com/tanaikech/" + appname + " ] "
+ a.Email = "tanaike@hotmail.com"
+ a.Usage = "Download shared files on Google Drive."
+ a.Version = "1.0.0"
+ a.Flags = []cli.Flag{
+ cli.StringFlag{
+ Name: "url, u",
+ Usage: "URL of shared file on Google Drive. This is a required parameter.",
+ },
+ cli.StringFlag{
+ Name: "extension, e",
+ Usage: "Extension of output file. This is for only Google Docs (Spreadsheet, Document, Presentation).",
+ Value: "pdf",
+ },
+ cli.StringFlag{
+ Name: "filename, f",
+ Usage: "Filename of file which is output. When this was not used, the original filename on Google Drive is used.",
+ },
+ }
+ return a
+}
+
+// main : Main of this script
+func main() {
+ a := createHelp()
+ a.Action = handler
+ a.Run(os.Args)
+}
diff --git a/images/demo.gif b/images/demo.gif
new file mode 100644
index 0000000..3c91f8b
Binary files /dev/null and b/images/demo.gif differ