package main

import (
	"bufio"
	"fmt"
	"gotest/models"
	"io"
	"os"
	"strconv"
	"strings"

	"time"

	"github.com/gocolly/colly"
)

var OneErr bool

func main() {
	url := "https://p.jisuts.com:999/hls/152/20231112/2054932/plist"
	mc := MyColly{}
	mc.Init()
	mc.Heby(mc.Path+"/video/", mc.Path+"/"+time.Now().Format("05")+".mp4", "cUw5NVBRN0hJRmxTZE5FdA==")
	return
	// mc.ReVisit()
	// return
	//mc.Heby(mc.Path+"/video/", mc.Path+"/"+time.Now().Format("05")+".mp4")
	//return

	// 开始爬取的起始点
	for i := 0; i < 10; i++ {
		strName := ""
		if i < 10 {
			//strName = "0" + fmt.Sprintf("%d", i)
			strName = fmt.Sprintf("%d", i)
		} else {
			strName = fmt.Sprintf("%d", i)
		}
		gotoUrl := url + strName + ".ts"
		fmt.Println(gotoUrl)
		err := mc.Colly.Visit(gotoUrl)
		if err != nil {
			fmt.Println("抓取 失败1次")
			err1 := mc.Colly.Visit(gotoUrl)
			if err1 != nil {
				fmt.Println("抓取 失败2次" + gotoUrl)
				errr := mc.Colly.Visit(gotoUrl)
				if errr != nil {
					fmt.Println("抓取 失败3次保存错误记录" + gotoUrl)
					OneErr = true
					mc.ErrorSave(gotoUrl)
				}

			}
		}
	}

	fmt.Println("完成")
	if !OneErr {
		fmt.Println("没有错误执行合并")
		mc.Heby(mc.Path+"/video/", mc.Path+"/"+time.Now().Format("05")+".mp4", "cUw5NVBRN0hJRmxTZE5FdA==")
	} else {
		fmt.Println("筛选错误抓取")
		mc.ReVisit()
	}
}

type MyColly struct {
	Colly *colly.Collector
	Path  string
}

func (these *MyColly) Init() *MyColly {
	these.Path, _ = os.Getwd()
	fmt.Println(these.Path)
	these.Colly = colly.NewCollector()
	these.Colly.AllowURLRevisit = true //可以重复访问
	//在发起请求前被调用
	these.Colly.OnRequest(func(r *colly.Request) {
		r.Headers.Set("Accept", "*/*")
		r.Headers.Set("Accept-Encoding", "gzip, deflate, br")
		r.Headers.Set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
		r.Headers.Set("Connection", "keep-alive")
		r.Headers.Set("DNT", "1")
		r.Headers.Set("Host", "p.jisuts.com:999")
		r.Headers.Set("Origin", "http://yidian68.com")
		r.Headers.Set("Referer", "http://yidian68.com/")

		r.Headers.Set("Sec-Fetch-Dest", "empty")
		r.Headers.Set("Sec-Fetch-Mode", "cors")
		r.Headers.Set("Sec-Fetch-Site", "cross-site")
		r.Headers.Set("UserAgent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0")
	})
	//请求过程中如果发生错误被调用
	these.Colly.OnError(func(r *colly.Response, err error) {
		fmt.Println("请求过程中如果发生错误被调用" + r.FileName())
	})
	//收到回复后被调用
	these.Colly.OnResponse(func(r *colly.Response) {
		fname := r.FileName()
		if tmp := strings.LastIndex(fname, "."); tmp != -1 {
			s := fname[tmp-3:]
			s = strings.ReplaceAll(s, ".ts", "")
			// 使用strings包中的ContainsAny函数也可以判断字符串中是否包含字母
			if !strings.ContainsAny(s, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") {
				is, _ := strconv.Atoi(s)
				isS := fmt.Sprintf("%d", is)
				if is < 10 {
					isS = "0" + s
				}
				err := r.Save(these.Path + "\\video\\" + isS + ".ts")
				if err != nil {
					fmt.Println(err.Error())
					return
				}
				fmt.Println(isS + ".ts ok 100数")
			} else {
				//fmt.Println("字符串中包含字母")
				s = s[1:]
				fmt.Println(s)
				if !strings.ContainsAny(s, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") {
					is, _ := strconv.Atoi(s)
					err := r.Save(these.Path + "\\video\\" + fmt.Sprintf("%d", is) + ".ts")
					if err != nil {
						fmt.Println(err.Error())
						return
					}
					fmt.Println(s + ".ts ok 10数")
				} else {
					isS := "0" + s[1:]
					err := r.Save(these.Path + "\\video\\" + isS + ".ts")
					if err != nil {
						fmt.Println(err.Error())
						return
					}
					fmt.Println(isS + ".ts ok 个数")
				}
			}

		}

	})
	//在OnResponse之后被调用，如果收到的内容是HTML
	these.Colly.OnHTML("title", func(h *colly.HTMLElement) {

	})
	these.Colly.OnHTML("body", func(h *colly.HTMLElement) {
		//h.ChildAttr() 获取一个元素属性
		//h.ChildAttrs() 获取全部元素属性 返回切片
	})
	these.Colly.OnHTML("a[href]", func(h *colly.HTMLElement) {

	})
	//在OnHTML之后被调用
	these.Colly.OnScraped(func(r *colly.Response) {

	})
	//线程数量限制 超时时间
	these.Colly.Limit(&colly.LimitRule{
		Parallelism: 1,
		Delay:       60 * time.Second,
	})
	return these
}

func (these *MyColly) ErrorSave(str string) {
	// 打开文件，如果文件不存在则创建，以追加模式打开
	file, err := os.OpenFile("error.txt", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		fmt.Println("打开文件失败:", err)
		return
	}
	defer file.Close()

	// 要追加的内容
	content := str + "\n"

	// 将内容追加到文件中
	_, err = file.WriteString(content)
	if err != nil {
		fmt.Println("追加内容失败:", err)
		return
	}
	fmt.Println("内容追加成功！")
}

func (these *MyColly) Heby(filePath, result, key string) bool {
	folderPath := these.Path + "/video/"
	// 获取文件夹下的所有文件
	files, err := os.ReadDir(folderPath)
	if err != nil {
		fmt.Println("读取文件夹失败:", err)
		return false
	}

	// 计数文件数量
	fileCount := 0
	for _, file := range files {
		if !file.IsDir() {
			fileCount++
		}
	}

	for i := 0; i < fileCount; i++ {
		tn := ""
		if i < 10 {
			tn = filePath + "0" + fmt.Sprintf("%d", i)
		} else {
			tn = filePath + fmt.Sprintf("%d", i)
		}
		// 打开源视频文件

		sourceFile, err := os.Open(tn + ".ts")
		if err != nil {
			fmt.Println("打开源视频文件失败:", err)
			these.ErrorSave("打开源视频文件失败:" + tn)
			return false
		}
		defer sourceFile.Close()
		// 打开目标视频文件，如果文件不存在则创建，以追加模式打开
		targetFile, err := os.OpenFile(result, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			fmt.Println("打开目标视频文件失败:", err)
			return false
		}
		defer targetFile.Close()
		if key == "" {
			// 将源视频文件的内容追加到目标视频文件中
			_, err = io.Copy(targetFile, sourceFile)
			if err != nil {
				fmt.Println("追加视频文件内容失败:", err)
				return false
			}

			fmt.Println("视频文件追加成功！")
		} else {
			bs, err := io.ReadAll(sourceFile)
			if err != nil {
				fmt.Println("视频文件转byte失败:", err)
				return false
			}
			en := models.Encryption{}
			strs := en.AesDecrypt(string(bs), key)
			_, err = io.Copy(targetFile, strings.NewReader(strs))
			if err != nil {
				fmt.Println("追加视频文件内容失败:", err)
				return false
			}
		}
	}
	os.RemoveAll(these.Path + "/video/")
	return true
}
func (these *MyColly) TxtToList() []string {
	strs := []string{}
	// 打开txt文件
	file, err := os.Open("error.txt")
	if err != nil {
		fmt.Println("打开文件失败:", err)
		return nil
	}
	defer file.Close()

	// 创建一个Scanner来读取文件内容
	scanner := bufio.NewScanner(file)

	// 逐行读取文件内容
	for scanner.Scan() {
		line := scanner.Text()
		strs = append(strs, line)
	}

	// 检查是否有错误发生
	if err := scanner.Err(); err != nil {
		fmt.Println("读取文件失败:", err)

		return nil
	}
	return strs
}
func (these *MyColly) ReVisit() {
	result := []string{}
	strs := these.TxtToList()
	if len(strs) != 0 {
		os.RemoveAll("error.txt")
		for _, v := range strs {
			err := these.Colly.Visit(v)
			if err != nil {
				result = append(result, v)
			} else {
				fmt.Println("重新抓取成功" + v)
			}
		}
		if len(result) != 0 {
			for _, v := range result {
				these.ErrorSave(v)
			}

		}
	}
}
