添加CSV导入工具及数据库操作功能
This commit is contained in:
commit
f42f667764
|
@ -0,0 +1,40 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type ANS string
|
||||||
|
|
||||||
|
const (
|
||||||
|
reset ANS = "\033[0m"
|
||||||
|
red ANS = "\033[31m"
|
||||||
|
green ANS = "\033[32m"
|
||||||
|
yellow ANS = "\033[33m"
|
||||||
|
blue ANS = "\033[34m"
|
||||||
|
purple ANS = "\033[35m"
|
||||||
|
cyan ANS = "\033[36m"
|
||||||
|
white ANS = "\033[37m"
|
||||||
|
)
|
||||||
|
|
||||||
|
func success(content string, arg ...interface{}) {
|
||||||
|
fmt.Printf("%s%s%s\n", green, fmt.Sprintf(content, arg...), reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fatal(content string, arg ...interface{}) {
|
||||||
|
panic(fmt.Sprintf("%s%s%s\n", red, fmt.Sprintf(content, arg...)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func warning(content string, arg ...interface{}) {
|
||||||
|
fmt.Printf("%s%s%s\n", yellow, fmt.Sprintf(content, arg...), reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func log(content string, arg ...interface{}) {
|
||||||
|
fmt.Printf("%s\n", fmt.Sprintf(content, arg...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func input(content string, arg ...interface{}) {
|
||||||
|
fmt.Printf("\n%s%s%s", cyan, fmt.Sprintf(content, arg...), reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tip(content string, arg ...interface{}) {
|
||||||
|
fmt.Printf("\n*%s%s%s", purple, fmt.Sprintf(content, arg...), reset)
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func padToLength(s string, length int, padChar rune) string {
|
||||||
|
if len(s) >= length {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
// 计算需要填充的字符数
|
||||||
|
padding := make([]rune, length-len(s))
|
||||||
|
for i := range padding {
|
||||||
|
padding[i] = padChar
|
||||||
|
}
|
||||||
|
// 将原字符串和填充字符组合起来
|
||||||
|
return s + string(padding)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加密函数
|
||||||
|
func encrypt(key []byte, text string) (string, error) {
|
||||||
|
plaintext := []byte(text)
|
||||||
|
|
||||||
|
// 创建一个新的cipher.Block
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个新的GCM模式的加密器
|
||||||
|
gcm, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个nonce(随机数)
|
||||||
|
nonce := make([]byte, gcm.NonceSize())
|
||||||
|
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加密数据
|
||||||
|
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
|
||||||
|
|
||||||
|
// 返回Base64编码的加密字符串
|
||||||
|
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解密函数
|
||||||
|
func decrypt(key []byte, encryptedText string) (string, error) {
|
||||||
|
// 解码Base64字符串
|
||||||
|
ciphertext, err := base64.StdEncoding.DecodeString(encryptedText)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个新的cipher.Block
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个新的GCM模式的解密器
|
||||||
|
gcm, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分离nonce和实际加密数据
|
||||||
|
nonceSize := gcm.NonceSize()
|
||||||
|
if len(ciphertext) < nonceSize {
|
||||||
|
return "", errors.New("ciphertext too short")
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
|
||||||
|
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(plaintext), nil
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"fmt"
|
||||||
|
"github.com/manifoldco/promptui"
|
||||||
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
|
"golang.org/x/text/transform"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getCsvInfo(dir string) (dataMap []map[string]string, title []string) {
|
||||||
|
fp := fmt.Sprintf("%s/%s/", dir, "csvfile")
|
||||||
|
entries, err := os.ReadDir(fp)
|
||||||
|
if err != nil {
|
||||||
|
panic("当前目录下未找到csvfile文件夹,请自行创建")
|
||||||
|
}
|
||||||
|
var csvFiles []string
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !entry.IsDir() && strings.HasSuffix(strings.ToLower(entry.Name()), ".csv") {
|
||||||
|
csvFiles = append(csvFiles, entry.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
prompt := promptui.Select{
|
||||||
|
Label: "请选择需要导入的csv文件: ",
|
||||||
|
Items: csvFiles,
|
||||||
|
Size: len(csvFiles),
|
||||||
|
}
|
||||||
|
_, f, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
warning("Prompt failed %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fp = fmt.Sprintf("%s/%s", fp, f)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return ReadCsvData(fp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadCsvData(fp string) (dataMap []map[string]string, title []string) {
|
||||||
|
log("正在读取CSV文件,请稍等...")
|
||||||
|
// 打开CSV文件
|
||||||
|
file, err := os.Open(fp)
|
||||||
|
if err != nil {
|
||||||
|
fatal("无法打开文件: %v", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
decoder := simplifiedchinese.GBK.NewDecoder()
|
||||||
|
// 创建CSV读取器
|
||||||
|
reader := csv.NewReader(transform.NewReader(file, decoder))
|
||||||
|
// 可选:设置更宽松的解析选项
|
||||||
|
reader.LazyQuotes = true // 允许非引号包裹的字段中包含引号
|
||||||
|
// 读取所有记录
|
||||||
|
records, err := reader.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
fatal("读取CSV记录出错: %v", err)
|
||||||
|
}
|
||||||
|
if len(records) < 2 {
|
||||||
|
fatal("CSV文件至少需要两行,第一行是标题,第二行是数据")
|
||||||
|
}
|
||||||
|
// 创建map来存储数据
|
||||||
|
dataMap = make([]map[string]string, len(records))
|
||||||
|
title = records[0]
|
||||||
|
for i := 1; i < len(records); i++ {
|
||||||
|
|
||||||
|
dataMap[i-1] = make(map[string]string)
|
||||||
|
for j := 0; j < len(records[i]); j++ { // 假设第一列是唯一标识符
|
||||||
|
dataMap[i-1][title[j]] = records[i][j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log("文件读取完毕")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func desc(video *Video) {
|
||||||
|
var d strings.Builder
|
||||||
|
tip("描述信息,请输入一段描述文字,描述文字越多,生成视频越精彩。")
|
||||||
|
input("请设置描述信息: ")
|
||||||
|
text, _ := reader.ReadString('\n')
|
||||||
|
d.WriteString(fmt.Sprintf("%s ", strings.TrimSpace(text)))
|
||||||
|
d.WriteString("--watermark ")
|
||||||
|
d.WriteString("false ")
|
||||||
|
for {
|
||||||
|
prompt := promptui.Select{
|
||||||
|
Label: "分辨率: ",
|
||||||
|
Items: []string{"480p", "720p"},
|
||||||
|
}
|
||||||
|
_, r, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
warning("Prompt failed %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
d.WriteString("--resolution ")
|
||||||
|
d.WriteString(r)
|
||||||
|
d.WriteString(" ")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
prompt := promptui.Select{
|
||||||
|
Label: "视频时长(秒): ",
|
||||||
|
Items: []string{"5", "10"},
|
||||||
|
}
|
||||||
|
_, r, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
warning("Prompt failed %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
d.WriteString("--dur ")
|
||||||
|
d.WriteString(r)
|
||||||
|
d.WriteString(" ")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
tip("adaptive:根据所上传图片的比例,自动选择最合适的宽高比。")
|
||||||
|
for {
|
||||||
|
prompt := promptui.Select{
|
||||||
|
Label: "视频的宽高比例: ",
|
||||||
|
Items: []string{"adaptive", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21", "1:1"},
|
||||||
|
}
|
||||||
|
_, r, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
warning("Prompt failed %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
d.WriteString("--ratio ")
|
||||||
|
d.WriteString(r)
|
||||||
|
d.WriteString(" ")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
prompt := promptui.Select{
|
||||||
|
Label: "帧率: ",
|
||||||
|
Items: []string{"16", "24"},
|
||||||
|
}
|
||||||
|
_, r, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
warning("Prompt failed %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
d.WriteString("--framepersecond ")
|
||||||
|
d.WriteString(r)
|
||||||
|
d.WriteString(" ")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
prompt := promptui.Select{
|
||||||
|
Label: "是否固定摄像头: ",
|
||||||
|
Items: []string{"false", "true"},
|
||||||
|
}
|
||||||
|
_, r, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
warning("Prompt failed %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
d.WriteString("--camerafixed ")
|
||||||
|
d.WriteString(r)
|
||||||
|
d.WriteString(" ")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
video.Text = d.String()
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DbConnPools = make(map[string]*gorm.DB)
|
||||||
|
|
||||||
|
func setDb() (sql *sql.DB, err error) {
|
||||||
|
db, err = InstanceDb(c.Dns)
|
||||||
|
if err != nil {
|
||||||
|
fatal("数据库连接失败:%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.DB()
|
||||||
|
}
|
||||||
|
|
||||||
|
func InstanceDb(dns string) (*gorm.DB, error) {
|
||||||
|
var (
|
||||||
|
dbConn *gorm.DB
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
if dbConn, ok = DbConnPools[dns]; ok {
|
||||||
|
sqlDB, _ := dbConn.DB()
|
||||||
|
connTest := sqlDB.Ping()
|
||||||
|
if connTest == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := NewDb(&DbConfig{
|
||||||
|
DriverName: "mysql",
|
||||||
|
Dns: dns,
|
||||||
|
Debug: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("s链接失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DbConfig struct {
|
||||||
|
DriverName string
|
||||||
|
Dns string
|
||||||
|
Debug bool
|
||||||
|
MaxIdleConns int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDb(config *DbConfig, opt ...gorm.Option) (gorm *gorm.DB, err error) {
|
||||||
|
gorm, err = config.Conn(opt...)
|
||||||
|
return gorm, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *DbConfig) Conn(opt ...gorm.Option) (*gorm.DB, error) {
|
||||||
|
dial := DriverMysql(m.Dns)
|
||||||
|
|
||||||
|
db, err := gorm.Open(
|
||||||
|
dial,
|
||||||
|
opt...,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sqlDB, _ := db.DB()
|
||||||
|
if m.Debug {
|
||||||
|
db = db.Debug()
|
||||||
|
}
|
||||||
|
sqlDB.SetMaxIdleConns(3) // 设置最大空闲连接数
|
||||||
|
sqlDB.SetMaxOpenConns(10) // 设置最大打开连接数
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DriverMysql(dns string) gorm.Dialector {
|
||||||
|
return mysql.Open(dns + "")
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cutData(data []map[string]string, cut int) chan []map[string]string {
|
||||||
|
lent := (len(data) / cut) + 1
|
||||||
|
batchChan := make(chan []map[string]string, lent)
|
||||||
|
for i := 0; i < len(data); i += cut {
|
||||||
|
if i+cut > len(data) {
|
||||||
|
batchChan <- data[i:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
batchChan <- data[i : i+cut]
|
||||||
|
}
|
||||||
|
return batchChan
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveData(dataChan chan []map[string]string, set *Set, title []string, dir string) {
|
||||||
|
var (
|
||||||
|
wg sync.WaitGroup
|
||||||
|
current int64
|
||||||
|
)
|
||||||
|
|
||||||
|
lent := len(dataChan)
|
||||||
|
wg.Add(lent)
|
||||||
|
for v := range dataChan {
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
warning(fmt.Sprintf("协程弹出"))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
defer func() {
|
||||||
|
atomic.AddInt64(¤t, 1)
|
||||||
|
log("当前进度:%d/%d", current, lent)
|
||||||
|
if current == int64(lent) {
|
||||||
|
close(dataChan)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
query strings.Builder
|
||||||
|
)
|
||||||
|
|
||||||
|
switch set.Op {
|
||||||
|
case Add:
|
||||||
|
query.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES ", c.Table, strings.Join(title, "`,`")))
|
||||||
|
is_start := true
|
||||||
|
for _, item := range v {
|
||||||
|
var dataRaw strings.Builder
|
||||||
|
if !is_start {
|
||||||
|
dataRaw.WriteString(",")
|
||||||
|
} else {
|
||||||
|
is_start = false
|
||||||
|
}
|
||||||
|
dataRaw.WriteString(" (")
|
||||||
|
for _, t := range title {
|
||||||
|
if strings.Contains(item[t], "'") {
|
||||||
|
item[t] = strings.ReplaceAll(item[t], "'", "`")
|
||||||
|
}
|
||||||
|
if strings.Contains(item[t], `"`) {
|
||||||
|
item[t] = strings.ReplaceAll(item[t], `"`, "`")
|
||||||
|
}
|
||||||
|
dataRaw.WriteString(fmt.Sprintf("'%s',", item[t]))
|
||||||
|
}
|
||||||
|
str := dataRaw.String()
|
||||||
|
str = str[:len(str)-1]
|
||||||
|
query.WriteString(str + ")")
|
||||||
|
}
|
||||||
|
query.WriteString(";")
|
||||||
|
raw := query.String()
|
||||||
|
result := db.Exec(raw)
|
||||||
|
if result.Error != nil {
|
||||||
|
warning(fmt.Sprintf("failed to insert user: %v", result.Error))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
warning("数据保存失败:%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
case OverWrite:
|
||||||
|
for _, item := range v {
|
||||||
|
var dataRaw strings.Builder
|
||||||
|
is_start := true
|
||||||
|
dataRaw.WriteString(fmt.Sprintf("SELECT %s From %s WHERE ", strings.Join(title, "`,`"), c.Table))
|
||||||
|
for _, t := range set.OverWriteJudColumns {
|
||||||
|
if strings.Contains(item[t], "'") {
|
||||||
|
item[t] = strings.ReplaceAll(item[t], "'", "`")
|
||||||
|
}
|
||||||
|
if strings.Contains(item[t], `"`) {
|
||||||
|
item[t] = strings.ReplaceAll(item[t], `"`, "`")
|
||||||
|
}
|
||||||
|
if !is_start {
|
||||||
|
dataRaw.WriteString(fmt.Sprintf("'%s',", item[t]))
|
||||||
|
}
|
||||||
|
dataRaw.WriteString(fmt.Sprintf("'%s',", item[t]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
query.WriteString(";")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
success("导入完毕.....")
|
||||||
|
finish(dir)
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 使用方法:
|
||||||
|
# ./genModel.sh usercenter user
|
||||||
|
# ./genModel.sh usercenter user_auth
|
||||||
|
# 再将./genModel下的文件剪切到对应服务的model目录里面,记得改package
|
||||||
|
|
||||||
|
|
||||||
|
#生成的表名
|
||||||
|
tables=$1
|
||||||
|
#表生成的genmodel目录
|
||||||
|
modeldir=./
|
||||||
|
|
||||||
|
# 数据库配置
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gentool --dsn "liucaijun:Sglcj@3374295@tcp(rm-bp15r7sd5q9q47sqy4o.mysql.rds.aliyuncs.com:3306)/datacenter" -outPath ${modeldir} -onlyModel -modelPkgName "model" -tables ${tables}
|
|
@ -0,0 +1,18 @@
|
||||||
|
module ex_pic_to_video
|
||||||
|
|
||||||
|
go 1.23.7
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/manifoldco/promptui v0.9.0
|
||||||
|
golang.org/x/text v0.25.0
|
||||||
|
gorm.io/driver/mysql v1.5.7
|
||||||
|
gorm.io/gorm v1.26.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
|
)
|
|
@ -0,0 +1 @@
|
||||||
|
s1QM2t7N1NQtPksWJpIjU5swReLzUGryqueba8bh/Yj0YQB0zMpxxT/kwjE09zq2ZBcC4TvUr4SHL6WbcT3OT991BATzhZj5s1LJ9oo1ZWFObSZUHhGYiUJ+y92ynZYGMP2kHMrrfNgHkGVpjvcUo8mIbDIJAW6m9XUSYBwdYUZoecXe35g8F71l11ipDdfMDWmOH3DZzy9tzBM=
|
|
@ -0,0 +1,149 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
reader = bufio.NewReader(os.Stdin)
|
||||||
|
)
|
||||||
|
|
||||||
|
var statusMap = map[string]string{
|
||||||
|
"queued": "排队中",
|
||||||
|
"running": "任务运行中",
|
||||||
|
"cancelled": "取消任务",
|
||||||
|
"succeeded": "任务成功",
|
||||||
|
"failed": "任务失败",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Dns string `json:"dns"`
|
||||||
|
Table string `json:"table"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Video struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
c *Conf
|
||||||
|
db *gorm.DB
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log("正在读取配置。。。")
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
panic("获取当前路径失败")
|
||||||
|
}
|
||||||
|
c = getConf(dir)
|
||||||
|
success("读取配置成功!请务必保证网络通畅")
|
||||||
|
sqlc, err := setDb()
|
||||||
|
if err != nil {
|
||||||
|
fatal("数据库连接失败1:%v", err)
|
||||||
|
}
|
||||||
|
defer sqlc.Close()
|
||||||
|
|
||||||
|
do(dir)
|
||||||
|
|
||||||
|
}
|
||||||
|
func do(dir string) {
|
||||||
|
csvData, title := getCsvInfo(dir)
|
||||||
|
set := setOp(title)
|
||||||
|
cutChannel := cutData(csvData, 100)
|
||||||
|
saveData(cutChannel, set, title, dir)
|
||||||
|
finish(dir)
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConf(dir string) *Conf {
|
||||||
|
|
||||||
|
fp := fmt.Sprintf("%s/%s", dir, "import_csv_data")
|
||||||
|
file, err := os.Open(fp)
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
os.Remove(fp)
|
||||||
|
}
|
||||||
|
return cConf(fp)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
content, err := os.ReadFile(fp)
|
||||||
|
if err != nil {
|
||||||
|
fatal("获取配置信息失败")
|
||||||
|
exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pwd string
|
||||||
|
conf = new(Conf)
|
||||||
|
)
|
||||||
|
for {
|
||||||
|
input("请输入访问密码: ")
|
||||||
|
pwd, _ = reader.ReadString('\n')
|
||||||
|
cjson, err := decrypt([]byte(padToLength(strings.TrimSpace(pwd), 16, ' ')), string(content))
|
||||||
|
if err != nil {
|
||||||
|
warning("密码错误")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = json.Unmarshal([]byte(cjson), &conf)
|
||||||
|
if err != nil {
|
||||||
|
warning("配置读取失败")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return conf
|
||||||
|
}
|
||||||
|
|
||||||
|
func cConf(fp string) *Conf {
|
||||||
|
conf := new(Conf)
|
||||||
|
log("进入初始化配置向导")
|
||||||
|
log("----------------------")
|
||||||
|
|
||||||
|
input("请设置DNS: ")
|
||||||
|
k, _ := reader.ReadString('\n')
|
||||||
|
conf.Dns = strings.TrimSpace(k)
|
||||||
|
|
||||||
|
input("请设置数据表: ")
|
||||||
|
t, _ := reader.ReadString('\n')
|
||||||
|
conf.Table = strings.TrimSpace(t)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pwd string
|
||||||
|
)
|
||||||
|
for {
|
||||||
|
input("请设置访问密码(密码长度请小于16位): ")
|
||||||
|
pwd, _ = reader.ReadString('\n')
|
||||||
|
if len(strings.TrimSpace(pwd)) > 16 {
|
||||||
|
warning("密码长度请小于16位")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
cjson, _ := json.Marshal(conf)
|
||||||
|
pad := padToLength(strings.TrimSpace(pwd), 16, ' ')
|
||||||
|
en, e := encrypt([]byte(pad), string(cjson))
|
||||||
|
if e != nil {
|
||||||
|
fatal("设置失败,程序退出:%v", e)
|
||||||
|
exit()
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(fp, []byte(en), 0666); err != nil {
|
||||||
|
fatal("写入失败,程序退出")
|
||||||
|
exit()
|
||||||
|
}
|
||||||
|
return conf
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func exit() {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func finish(dir string) {
|
||||||
|
do(dir)
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/manifoldco/promptui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type opType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
Add opType = 1
|
||||||
|
OverWrite opType = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var opIndex = map[string]opType{
|
||||||
|
"新增": Add,
|
||||||
|
"覆盖(有则改,无则增)": OverWrite,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Set struct {
|
||||||
|
Op opType
|
||||||
|
OverWriteJudColumns []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func setOp(title []string) *Set {
|
||||||
|
var set = new(Set)
|
||||||
|
for {
|
||||||
|
prompt := promptui.Select{
|
||||||
|
Label: "请选择需要执行的操作: ",
|
||||||
|
Items: []string{"新增"}, //, "覆盖(有则改,无则增)"
|
||||||
|
}
|
||||||
|
_, r, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
warning("Prompt failed %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
set.Op = opIndex[r]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if set.Op == OverWrite {
|
||||||
|
selector := append(title, "继续")
|
||||||
|
selector[2] = "继续"
|
||||||
|
for {
|
||||||
|
r := columnSelect(selector)
|
||||||
|
if r != "继续" {
|
||||||
|
set.OverWriteJudColumns = append(set.OverWriteJudColumns, r)
|
||||||
|
selector = removeElement(selector, r)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
|
||||||
|
func columnSelect(selector []string) string {
|
||||||
|
prompt := promptui.Select{
|
||||||
|
Label: "请选择判重字段(可以选择多个,`继续`选项表示选择完了)",
|
||||||
|
Items: selector,
|
||||||
|
Size: len(selector) + 1,
|
||||||
|
}
|
||||||
|
_, r, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
fatal("Prompt failed %v\n", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeElement(slice []string, element string) []string {
|
||||||
|
result := slice[:0] // 创建一个空切片,与原切片共享底层数组
|
||||||
|
for _, v := range slice {
|
||||||
|
if v != element {
|
||||||
|
result = append(result, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
func test() {
|
||||||
|
//key = "236ba4b6-9daa-4755-b22f-2fd274cd223a"
|
||||||
|
//modelEp = "doubao-seedance-1-0-lite-i2v-250428"
|
||||||
|
//desc = "女孩抱着狐狸,女孩睁开眼,温柔地看向镜头,狐狸友善地抱着,镜头缓缓拉出,女孩的头发被风吹动 --resolution 480p --dur 5 --camerafixed false --watermark false"
|
||||||
|
//img = "https://ark-project.tos-cn-beijing.volces.com/doc_image/i2v_foxrgirl.png"
|
||||||
|
}
|
Loading…
Reference in New Issue