Skip to content

Instantly share code, notes, and snippets.

@AhmedAbouelkher
Last active October 29, 2023 08:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AhmedAbouelkher/c9594848523ad88abe9998bca4777839 to your computer and use it in GitHub Desktop.
Save AhmedAbouelkher/c9594848523ad88abe9998bca4777839 to your computer and use it in GitHub Desktop.
Golang Script to extract file direct download link for Google Drive files with any size.

Golang Script to extract file direct download link for Google Drive files with any size without encountering the dump Google Drive can't scan this file for viruses webpage.

package main
import (
"context"
"encoding/base64"
"flag"
"fmt"
"net/http"
"net/url"
"os"
"regexp"
"strings"
"golang.org/x/net/html"
"google.golang.org/api/drive/v2"
"google.golang.org/api/option"
)
var (
ctx = context.Background()
)
func main() {
var shareUri string
flag.StringVar(&shareUri, "u", "", "share uri")
flag.Parse()
if shareUri == "" {
panic("share uri is required")
}
fmt.Print(`
-----------------------------------------------
You are using a beta version of this tool.
The tool is not meant to be distributed or used in production.
The tool is provided as is, without any warranty.
Version: 0.0.2
By: Ahmed Mahmoud
-----------------------------------------------
`)
apiKey := os.Getenv("GOOGLE_API_KEY")
if apiKey == "" {
panic(`
GOOGLE_API_KEY is required, You can get an API key from https://console.developers.google.com/apis/credentials
After creating the API key, make sure to enable the following APIs:
- Google Drive API
Then export the API key as an environment variable:
Example: export GOOGLE_API_KEY=your-api-key
`)
}
valid := ValidateShareUrl(shareUri)
if !valid {
panic("invalid share uri: " + shareUri)
}
fileId, err := ExtractFileId(shareUri)
if err != nil {
panic(err)
}
srv, err := drive.NewService(ctx, option.WithAPIKey(apiKey))
if err != nil {
panic("Unable to retrieve Drive client: %v" + err.Error())
}
file, err := srv.Files.Get(fileId).Do()
if err != nil {
panic(err)
}
client := http.DefaultClient
downloadUrl, err := GenerateDownloadUrl(client, file)
if err != nil {
panic(err)
}
fmt.Println("Download URL: " + downloadUrl)
}
func ValidateShareUrl(shareUri string) bool {
regexPattern := `https:\/\/drive\.google\.com\/file\/d\/[a-zA-Z0-9_-]+\/view`
match, _ := regexp.MatchString(regexPattern, shareUri)
return match
}
func ExtractFileId(shareUri string) (string, error) {
u, err := url.Parse(shareUri)
if err != nil {
return "", err
}
if u.Host != "drive.google.com" {
return "", fmt.Errorf("invalid share uri: %s", shareUri)
}
s := strings.Split(shareUri, "d/")
if len(s) != 2 {
return "", fmt.Errorf("invalid share uri: %s", shareUri)
}
ss := strings.Split(s[1], "/")
if len(ss) < 1 {
return "", fmt.Errorf("invalid share uri: %s", shareUri)
}
return ss[0], nil
}
func DecodeBase64(s string) string {
s = strings.Trim(s, " ")
s = strings.Trim(s, "\"")
d, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return ""
}
return string(d)
}
func GenerateDownloadUrl(client *http.Client, file *drive.File) (string, error) {
fileSize := file.FileSize
fileId := file.Id
// check if file size is larger than 100MB
if fileSize < 100*(1<<20) {
// simple download
// https://drive.google.com/uc?export=download&id=file-id
downloadUrl := fmt.Sprintf("https://drive.google.com/uc?export=download&id=%s", fileId)
return downloadUrl, nil
}
// large file download, more complicated download
// Example: https://drive.google.com/u/0/uc?id=XXXXXXXXBKPx3G5_UZWA79g79ncqEfQ&export=download
scanFailedUrl := fmt.Sprintf("https://drive.google.com/uc?export=download&id=%s", fileId)
res, err := client.Get(scanFailedUrl)
if err != nil {
return "", err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to open download url: %s", scanFailedUrl)
}
// check content type, must be html
contentType := res.Header.Get("Content-Type")
if contentType != "text/html; charset=utf-8" {
return "", fmt.Errorf("download page content type is not html: %s", contentType)
}
downloadPage, err := html.Parse(res.Body)
if err != nil {
return "", err
}
// TODO: Check if the page is "Google Drive Quota Exceeded or Limit Reached"
formElem := GetElementByID(downloadPage, "download-form")
if formElem == nil {
return "", fmt.Errorf("form element was not found in the download page")
}
formAction := GetAttribute(formElem, "action")
if formAction == "" {
return "", fmt.Errorf("form action was not found in the download page")
}
return formAction, nil
}
func GetElementByID(n *html.Node, id string) *html.Node {
if n.Type == html.ElementNode {
if attr := GetAttribute(n, "id"); attr == id {
return n
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
if n := GetElementByID(c, id); n != nil {
return n
}
}
return nil
}
func GetAttribute(n *html.Node, key string) string {
for _, attr := range n.Attr {
if attr.Key == key {
return attr.Val
}
}
return ""
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment