formatter

This commit is contained in:
alexpin 2020-02-25 01:01:10 +02:00
parent f724f0f2a2
commit b6bb470064
10 changed files with 212 additions and 212 deletions

View File

@ -1,102 +1,102 @@
package client package client
import ( import (
"context" "context"
"github.com/chromedp/chromedp" "github.com/chromedp/chromedp"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"time" "time"
config "../models/config" config "../models/config"
utils "../utils" utils "../utils"
) )
// GetMusicUploads - Get all uploads by given music // GetMusicUploads - Get all uploads by given music
func executeClientAction(url string, jsAction string) string { func executeClientAction(url string, jsAction string) string {
dir, err := ioutil.TempDir("", "chromedp-example") dir, err := ioutil.TempDir("", "chromedp-example")
utils.CheckErr(err) utils.CheckErr(err)
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
opts := append(chromedp.DefaultExecAllocatorOptions[:], opts := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.DisableGPU, chromedp.DisableGPU,
chromedp.UserDataDir(dir), chromedp.UserDataDir(dir),
chromedp.Flag("headless", !config.Config.Debug), chromedp.Flag("headless", !config.Config.Debug),
) )
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...) allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel() defer cancel()
ctx, cancel := chromedp.NewContext( ctx, cancel := chromedp.NewContext(
allocCtx, allocCtx,
chromedp.WithLogf(log.Printf), chromedp.WithLogf(log.Printf),
) )
defer cancel() defer cancel()
ctx, cancel = context.WithTimeout(ctx, time.Duration(config.Config.Deadline)*time.Second) ctx, cancel = context.WithTimeout(ctx, time.Duration(config.Config.Deadline)*time.Second)
defer cancel() defer cancel()
var jsOutput string var jsOutput string
jsOutput = runScrapeWithInfo(ctx, jsAction, url) jsOutput = runScrapeWithInfo(ctx, jsAction, url)
return jsOutput return jsOutput
} }
func runScrapeQuiet(ctx context.Context, jsAction string, url string) string { func runScrapeQuiet(ctx context.Context, jsAction string, url string) string {
var jsOutput string var jsOutput string
err := chromedp.Run(ctx, err := chromedp.Run(ctx,
// Navigate to user's page // Navigate to user's page
chromedp.Navigate(url), chromedp.Navigate(url),
// Execute url grabber script // Execute url grabber script
chromedp.EvaluateAsDevTools(utils.ReadFileAsString("scraper.js"), &jsOutput), chromedp.EvaluateAsDevTools(utils.ReadFileAsString("scraper.js"), &jsOutput),
chromedp.EvaluateAsDevTools(jsAction, &jsOutput), chromedp.EvaluateAsDevTools(jsAction, &jsOutput),
// Wait until custom js finishes // Wait until custom js finishes
chromedp.WaitVisible(`video_urls`), chromedp.WaitVisible(`video_urls`),
// Grab url links from our element // Grab url links from our element
chromedp.InnerHTML(`video_urls`, &jsOutput), chromedp.InnerHTML(`video_urls`, &jsOutput),
) )
utils.CheckErr(err) utils.CheckErr(err)
return jsOutput return jsOutput
} }
func runScrapeWithInfo(ctx context.Context, jsAction string, url string) string { func runScrapeWithInfo(ctx context.Context, jsAction string, url string) string {
var jsOutput string var jsOutput string
err := chromedp.Run(ctx, err := chromedp.Run(ctx,
// Navigate to user's page // Navigate to user's page
chromedp.Navigate(url), chromedp.Navigate(url),
// Execute url grabber script // Execute url grabber script
chromedp.WaitReady("video"), chromedp.WaitReady("video"),
chromedp.EvaluateAsDevTools(utils.ReadFileAsString("scraper.js"), &jsOutput), chromedp.EvaluateAsDevTools(utils.ReadFileAsString("scraper.js"), &jsOutput),
chromedp.EvaluateAsDevTools(jsAction, &jsOutput), chromedp.EvaluateAsDevTools(jsAction, &jsOutput),
) )
utils.CheckErr(err) utils.CheckErr(err)
for { for {
err = chromedp.Run(ctx, chromedp.EvaluateAsDevTools("currentState.preloadCount.toString()", &jsOutput)) err = chromedp.Run(ctx, chromedp.EvaluateAsDevTools("currentState.preloadCount.toString()", &jsOutput))
utils.CheckErr(err) utils.CheckErr(err)
if jsOutput != "0" { if jsOutput != "0" {
utils.Logf("\rPreloading... %s items have been founded.", jsOutput) utils.Logf("\rPreloading... %s items have been founded.", jsOutput)
} else { } else {
utils.Logf("\rPreloading...") utils.Logf("\rPreloading...")
} }
err = chromedp.Run(ctx, chromedp.EvaluateAsDevTools("currentState.finished.toString()", &jsOutput)) err = chromedp.Run(ctx, chromedp.EvaluateAsDevTools("currentState.finished.toString()", &jsOutput))
utils.CheckErr(err) utils.CheckErr(err)
if jsOutput == "true" { if jsOutput == "true" {
break break
} }
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
} }
utils.Log("\nRetrieving items...") utils.Log("\nRetrieving items...")
err = chromedp.Run(ctx, err = chromedp.Run(ctx,
// Wait until custom js finishes // Wait until custom js finishes
chromedp.WaitVisible(`video_urls`), chromedp.WaitVisible(`video_urls`),
// Grab url links from our element // Grab url links from our element
chromedp.InnerHTML(`video_urls`, &jsOutput), chromedp.InnerHTML(`video_urls`, &jsOutput),
) )
utils.CheckErr(err) utils.CheckErr(err)
return jsOutput return jsOutput
} }

View File

@ -1,19 +1,19 @@
package client package client
import ( import (
models "../models" models "../models"
config "../models/config" config "../models/config"
"fmt" "fmt"
) )
// GetUserUploads - Get all uploads marked with given hashtag // GetUserUploads - Get all uploads marked with given hashtag
func GetHashtagUploads(hashtagURL string) []models.Upload { func GetHashtagUploads(hashtagURL string) []models.Upload {
jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit) jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit)
actionOutput := executeClientAction(hashtagURL, jsMethod) actionOutput := executeClientAction(hashtagURL, jsMethod)
return models.ParseUploads(actionOutput) return models.ParseUploads(actionOutput)
} }
func GetHashtagUploadsJson(hashtagURL string) string { func GetHashtagUploadsJson(hashtagURL string) string {
jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit) jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit)
return executeClientAction(hashtagURL, jsMethod) return executeClientAction(hashtagURL, jsMethod)
} }

View File

@ -1,19 +1,19 @@
package client package client
import ( import (
models "../models" models "../models"
config "../models/config" config "../models/config"
"fmt" "fmt"
) )
// GetMusicUploads - Get all uploads by given music // GetMusicUploads - Get all uploads by given music
func GetMusicUploads(url string) []models.Upload { func GetMusicUploads(url string) []models.Upload {
jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit) jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit)
actionOutput := executeClientAction(url, jsMethod) actionOutput := executeClientAction(url, jsMethod)
return models.ParseUploads(actionOutput) return models.ParseUploads(actionOutput)
} }
func GetMusicUploadsJson(url string) string { func GetMusicUploadsJson(url string) string {
jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit) jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit)
return executeClientAction(url, jsMethod) return executeClientAction(url, jsMethod)
} }

View File

@ -3,17 +3,17 @@ package client
import ( import (
models "../models" models "../models"
config "../models/config" config "../models/config"
"fmt" "fmt"
) )
// GetUserUploads - Get all uploads by user // GetUserUploads - Get all uploads by user
func GetUserUploads(username string) []models.Upload { func GetUserUploads(username string) []models.Upload {
jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit) jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit)
actionOutput := executeClientAction(`https://www.tiktok.com/@`+username, jsMethod) actionOutput := executeClientAction(`https://www.tiktok.com/@`+username, jsMethod)
return models.ParseUploads(actionOutput) return models.ParseUploads(actionOutput)
} }
func GetUserUploadsJson(username string) string { func GetUserUploadsJson(username string) string {
jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit) jsMethod := fmt.Sprintf("bootstrapIteratingVideos(%d)", config.Config.Limit)
return executeClientAction(`https://www.tiktok.com/@`+username, jsMethod) return executeClientAction(`https://www.tiktok.com/@`+username, jsMethod)
} }

View File

@ -1,57 +1,57 @@
package config package config
import ( import (
"flag" "flag"
"fmt" "fmt"
"os" "os"
) )
// Config - Runtime configuration // Config - Runtime configuration
var Config struct { var Config struct {
URL string URL string
OutputPath string OutputPath string
BatchFilePath string BatchFilePath string
Debug bool Debug bool
MetaData bool MetaData bool
Quiet bool Quiet bool
Deadline int Deadline int
Limit int Limit int
JSONOnly bool JSONOnly bool
} }
// GetConfig - Returns Config object // GetConfig - Returns Config object
func GetConfig() { func GetConfig() {
outputPath := flag.String("output", "./downloads", "Output path") outputPath := flag.String("output", "./downloads", "Output path")
batchFilePath := flag.String("batch-file", "", "File containing URLs/Usernames to download, one value per line. Lines starting with '#', are considered as comments and ignored.") batchFilePath := flag.String("batch-file", "", "File containing URLs/Usernames to download, one value per line. Lines starting with '#', are considered as comments and ignored.")
debug := flag.Bool("debug", false, "Enables debug mode") debug := flag.Bool("debug", false, "Enables debug mode")
metadata := flag.Bool("metadata", false, "Write video metadata to a .json file") metadata := flag.Bool("metadata", false, "Write video metadata to a .json file")
quiet := flag.Bool("quiet", false, "Supress output") quiet := flag.Bool("quiet", false, "Supress output")
deadline := flag.Int("deadline", 1500, "Sets the timout for scraper logic in seconds (used as a workaround for 'context deadline exceeded' error)") deadline := flag.Int("deadline", 1500, "Sets the timout for scraper logic in seconds (used as a workaround for 'context deadline exceeded' error)")
limit := flag.Int("limit", 0, "Sets the videos count limit (useful when there too many videos from the user or by hashtag)") limit := flag.Int("limit", 0, "Sets the videos count limit (useful when there too many videos from the user or by hashtag)")
jsonOnly := flag.Bool("json", false, "Just get JSON data from scraper (without video downloading)") jsonOnly := flag.Bool("json", false, "Just get JSON data from scraper (without video downloading)")
flag.Parse() flag.Parse()
args := flag.Args() args := flag.Args()
if len(args) < 1 && *batchFilePath == "" { if len(args) < 1 && *batchFilePath == "" {
fmt.Println("Usage: tiktok-dl [OPTIONS] TIKTOK_USERNAME|TIKTOK_URL") fmt.Println("Usage: tiktok-dl [OPTIONS] TIKTOK_USERNAME|TIKTOK_URL")
fmt.Println(" or: tiktok-dl [OPTIONS] -batch-file path/to/users.txt") fmt.Println(" or: tiktok-dl [OPTIONS] -batch-file path/to/users.txt")
os.Exit(2) os.Exit(2)
} }
if len(args) > 0 { if len(args) > 0 {
Config.URL = flag.Args()[len(args)-1] Config.URL = flag.Args()[len(args)-1]
} else { } else {
Config.URL = "" Config.URL = ""
} }
Config.OutputPath = *outputPath Config.OutputPath = *outputPath
Config.BatchFilePath = *batchFilePath Config.BatchFilePath = *batchFilePath
Config.Debug = *debug Config.Debug = *debug
Config.MetaData = *metadata Config.MetaData = *metadata
Config.Quiet = *quiet Config.Quiet = *quiet
if *jsonOnly { if *jsonOnly {
Config.Quiet = true Config.Quiet = true
} }
Config.Deadline = *deadline Config.Deadline = *deadline
Config.Limit = *limit Config.Limit = *limit
Config.JSONOnly = *jsonOnly; Config.JSONOnly = *jsonOnly
} }

View File

@ -1,16 +1,16 @@
package utils package utils
import ( import (
res "../resources" res "../resources"
"fmt" "fmt"
"strings" "strings"
) )
// GetHashtagFromURL - Get's tag name from passed url // GetHashtagFromURL - Get's tag name from passed url
func GetHashtagFromURL(str string) string { func GetHashtagFromURL(str string) string {
if match := strings.Contains(str, "/tag/"); match { if match := strings.Contains(str, "/tag/"); match {
return strings.Split(str, "/tag/")[1] return strings.Split(str, "/tag/")[1]
} }
panic(fmt.Sprintf(res.ErrorCouldNotRecogniseURL, str)) panic(fmt.Sprintf(res.ErrorCouldNotRecogniseURL, str))
} }

View File

@ -1,36 +1,36 @@
package workflows package workflows
import ( import (
client "../client" client "../client"
config "../models/config" config "../models/config"
utils "../utils" utils "../utils"
"fmt" "fmt"
"strings" "strings"
) )
// CanUseDownloadHashtag - Test's if this workflow can be used for parameter // CanUseDownloadHashtag - Test's if this workflow can be used for parameter
func CanUseDownloadHashtag(url string) bool { func CanUseDownloadHashtag(url string) bool {
match := strings.Contains(url, "/tag/") match := strings.Contains(url, "/tag/")
return match return match
} }
// DownloadHashtag - Download videos marked with given hashtag // DownloadHashtag - Download videos marked with given hashtag
func DownloadHashtag(url string) { func DownloadHashtag(url string) {
uploads := client.GetHashtagUploads(url) uploads := client.GetHashtagUploads(url)
uploadCount := len(uploads) uploadCount := len(uploads)
hashtag := utils.GetHashtagFromURL(url) hashtag := utils.GetHashtagFromURL(url)
downloadDir := fmt.Sprintf("%s/%s", config.Config.OutputPath, hashtag) downloadDir := fmt.Sprintf("%s/%s", config.Config.OutputPath, hashtag)
utils.InitOutputDirectory(downloadDir) utils.InitOutputDirectory(downloadDir)
for index, upload := range uploads { for index, upload := range uploads {
downloadVideo(upload, downloadDir) downloadVideo(upload, downloadDir)
utils.Logf("\r[%d/%d] Downloaded", index+1, uploadCount) utils.Logf("\r[%d/%d] Downloaded", index+1, uploadCount)
} }
utils.Log() utils.Log()
} }
func GetHashtagJson(url string) { func GetHashtagJson(url string) {
uploads := client.GetHashtagUploads(url) uploads := client.GetHashtagUploads(url)
fmt.Printf("%s", uploads) fmt.Printf("%s", uploads)
} }

View File

@ -1,36 +1,36 @@
package workflows package workflows
import ( import (
client "../client" client "../client"
config "../models/config" config "../models/config"
utils "../utils" utils "../utils"
"fmt" "fmt"
"regexp" "regexp"
) )
// CanUseDownloadMusic - Check's if DownloadMusic can be used for parameter // CanUseDownloadMusic - Check's if DownloadMusic can be used for parameter
func CanUseDownloadMusic(url string) bool { func CanUseDownloadMusic(url string) bool {
match, _ := regexp.MatchString(".com\\/music\\/.+", url) match, _ := regexp.MatchString(".com\\/music\\/.+", url)
return match return match
} }
// DownloadMusic - Download all videos by given music // DownloadMusic - Download all videos by given music
func DownloadMusic(url string) { func DownloadMusic(url string) {
uploads := client.GetMusicUploads(url) uploads := client.GetMusicUploads(url)
uploadCount := len(uploads) uploadCount := len(uploads)
for index, upload := range uploads { for index, upload := range uploads {
username := utils.GetUsernameFromString(upload.Uploader) username := utils.GetUsernameFromString(upload.Uploader)
downloadDir := fmt.Sprintf("%s/%s", config.Config.OutputPath, username) downloadDir := fmt.Sprintf("%s/%s", config.Config.OutputPath, username)
utils.InitOutputDirectory(downloadDir) utils.InitOutputDirectory(downloadDir)
downloadVideo(upload, downloadDir) downloadVideo(upload, downloadDir)
utils.Logf("\r[%d/%d] Downloaded", index+1, uploadCount) utils.Logf("\r[%d/%d] Downloaded", index+1, uploadCount)
} }
utils.Log() utils.Log()
} }
func GetMusicJson(url string) { func GetMusicJson(url string) {
uploads := client.GetMusicUploadsJson(url) uploads := client.GetMusicUploadsJson(url)
fmt.Printf("%s", uploads) fmt.Printf("%s", uploads)
} }

View File

@ -31,5 +31,5 @@ func DownloadUser(username string) {
func GetUserVideosJson(username string) { func GetUserVideosJson(username string) {
uploads := client.GetUserUploadsJson(username) uploads := client.GetUserUploadsJson(username)
fmt.Printf("%s", uploads) fmt.Printf("%s", uploads)
} }

View File

@ -1,44 +1,44 @@
package workflows package workflows
import ( import (
client "../client" client "../client"
models "../models" models "../models"
config "../models/config" config "../models/config"
utils "../utils" utils "../utils"
"fmt" "fmt"
"regexp" "regexp"
) )
// CanUseDownloadSingleVideo - Check's if DownloadSingleVideo can be used for parameter // CanUseDownloadSingleVideo - Check's if DownloadSingleVideo can be used for parameter
func CanUseDownloadSingleVideo(url string) bool { func CanUseDownloadSingleVideo(url string) bool {
match, _ := regexp.MatchString("\\/@.+\\/video\\/[0-9]+", url) match, _ := regexp.MatchString("\\/@.+\\/video\\/[0-9]+", url)
return match return match
} }
// DownloadSingleVideo - Downloads single video // DownloadSingleVideo - Downloads single video
func DownloadSingleVideo(url string) { func DownloadSingleVideo(url string) {
username := utils.GetUsernameFromString(url) username := utils.GetUsernameFromString(url)
upload := client.GetVideoDetails(url) upload := client.GetVideoDetails(url)
downloadDir := fmt.Sprintf("%s/%s", config.Config.OutputPath, username) downloadDir := fmt.Sprintf("%s/%s", config.Config.OutputPath, username)
utils.InitOutputDirectory(downloadDir) utils.InitOutputDirectory(downloadDir)
downloadVideo(upload, downloadDir) downloadVideo(upload, downloadDir)
utils.Log("[1/1] Downloaded\n") utils.Log("[1/1] Downloaded\n")
} }
// DownloadVideo - Downloads one video // DownloadVideo - Downloads one video
func downloadVideo(upload models.Upload, downloadDir string) { func downloadVideo(upload models.Upload, downloadDir string) {
uploadID := upload.GetUploadID() uploadID := upload.GetUploadID()
downloadPath := fmt.Sprintf("%s/%s.mp4", downloadDir, uploadID) downloadPath := fmt.Sprintf("%s/%s.mp4", downloadDir, uploadID)
if utils.CheckIfExists(downloadPath) { if utils.CheckIfExists(downloadPath) {
return return
} }
utils.DownloadFile(downloadPath, upload.URL) utils.DownloadFile(downloadPath, upload.URL)
if config.Config.MetaData { if config.Config.MetaData {
metadataPath := fmt.Sprintf("%s/%s.json", downloadDir, uploadID) metadataPath := fmt.Sprintf("%s/%s.json", downloadDir, uploadID)
upload.WriteToFile(metadataPath) upload.WriteToFile(metadataPath)
} }
} }