Skip to content

Commit

Permalink
初步完成获取歌曲功能
Browse files Browse the repository at this point in the history
优化稳定性
  • Loading branch information
XiaoMengXinX committed Oct 23, 2021
1 parent 5c1860e commit 52411b0
Show file tree
Hide file tree
Showing 12 changed files with 835 additions and 178 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ log
config.ini
/Music163bot-Go*
/src
/ext
/ext
/cache
*.mp3
*.flac
69 changes: 69 additions & 0 deletions bot/0_init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package bot

import (
"github.com/XiaoMengXinX/Music163Api-Go/utils"
"gorm.io/gorm"
)

var data utils.RequestData
var botName string
var cacheDir = "./cache"

var (
aboutText = `*Music163bot-Go %s*
Github: https://github.com/XiaoMengXinX/Music163bot-Go
\[编译环境] %s
\[程序版本] %s
\[编译哈希] %s
\[编译日期] %s
\[编译系统] %s
\[运行环境] %s`
musicInfo = `「%s」- %s
专辑: %s
#网易云音乐 #%s %.2fkpbs
via @%s`
musicInfoMsg = `%s
专辑: %s
%s %sMB
`
musicInfoNoBr = `%s
专辑: %s
`
rmcacheReportAll = `清除全部数据库成功`
rmcacheReport = `清除 musicid : %s 缓存成功`
searching = `搜索中...`
noResults = `未找到结果`
noCache = `歌曲未缓存`
tapToDownload = `点击上方按钮缓存歌曲`
tapMeToDown = `点我缓存歌曲`
unkonwnError = `未知错误`
alreadyStart = `存在下载任务,请稍候...`
hitCache = `命中缓存,正在发送中...`
sendMeTo = `Send me to...`
uploadFailed = `发送失败 %s`
getUrlFailed = `获取下载链接失败`
fetchInfo = `正在获取歌曲信息...`
fetchInfoFailed = `获取歌曲信息失败`
waitForDown = `等待下载中...`
downloading = `下载中...`
uploading = `下载完成,发送中...`
)

type SongInfo struct {
gorm.Model
MusicID int
SongName string
SongArtists string
SongAlbum string
FileExt string
FileSize string
BitRate int
Duration int
FileID string
ThumbFileID string
FromUserID int64
FromUserName string
FromChatID int64
FromChatName string
}
154 changes: 154 additions & 0 deletions bot/1_downloader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package bot

import (
"fmt"
"github.com/sirupsen/logrus"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"sync"
)

const (
userAgent = `NeteaseMusic/6.5.0.1575377963(164);Dalvik/2.1.0 (Linux; U; Android 9; MIX 2 MIUI/V12.0.1.0.PDECNXM)`
)

// HttpDownloader 下载数据
type HttpDownloader struct {
url string
filename string
contentLength int
acceptRanges bool // 是否支持断点续传
numThreads int // 同时下载线程数
}

// New 新建下载任务
func New(url string, numThreads int) (*HttpDownloader, error) {
var urlSplits = strings.Split(url, "/")
var filename = urlSplits[len(urlSplits)-1]
res, err := http.Head(url)
if err != nil {
return nil, err
}
httpDownload := new(HttpDownloader)
httpDownload.url = url
httpDownload.contentLength = int(res.ContentLength)
httpDownload.numThreads = numThreads
httpDownload.filename = filename
if len(res.Header["Accept-Ranges"]) != 0 && res.Header["Accept-Ranges"][0] == "bytes" {
httpDownload.acceptRanges = true
} else {
httpDownload.acceptRanges = false
}

return httpDownload, nil
}

// Download 下载综合调度
func (h *HttpDownloader) Download() (err error) {
f, err := os.Create(cacheDir + "/" + h.filename)
if err != nil {
return err
}
defer func(f *os.File) {
e := f.Close()
if e != nil {
err = fmt.Errorf("%v", e)
}
}(f)
if h.acceptRanges == false {
resp, err := http.Get(h.url)
if err != nil {
return err
}
err = save2file(cacheDir+"/"+h.filename, 0, resp)
if err != nil {
return err
}
} else {
var wg sync.WaitGroup
for _, ranges := range h.Split() {
wg.Add(1)
go func(start, end int) {
defer wg.Done()
err := h.download(start, end)
if err != nil {
logrus.Errorf("An error occurred while downloading %s: %v", h.url, err)
return
}
}(ranges[0], ranges[1])
}
wg.Wait()
}
return nil
}

// Split 下载文件分段
func (h *HttpDownloader) Split() [][]int {
var ranges [][]int
blockSize := h.contentLength / h.numThreads
for i := 0; i < h.numThreads; i++ {
var start = i * blockSize
var end = (i+1)*blockSize - 1
if i == h.numThreads-1 {
end = h.contentLength - 1
}
ranges = append(ranges, []int{start, end})
}
return ranges
}

// 多线程下载
func (h *HttpDownloader) download(start, end int) (err error) {
req, err := http.NewRequest("GET", h.url, nil)
if err != nil {
return err
}
req.Header.Set("Range", fmt.Sprintf("bytes=%v-%v", start, end))
req.Header.Set("User-Agent", userAgent)

resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer func(Body io.ReadCloser) {
e := Body.Close()
if e != nil {
err = fmt.Errorf("%v", err)
}
}(resp.Body)
err = save2file(cacheDir+"/"+h.filename, int64(start), resp)
if err != nil {
return err
}
return nil
}

// 保存文件
func save2file(filename string, offset int64, resp *http.Response) error {
f, err := os.OpenFile(filename, os.O_WRONLY, 0660)
if err != nil {
return err
}
_, err = f.Seek(offset, 0)
if err != nil {
return err
}
defer func(f *os.File) {
e := f.Close()
if e != nil {
err = fmt.Errorf("%v", e)
}
}(f)
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
_, err = f.Write(content)
if err != nil {
return err
}
return nil
}
83 changes: 83 additions & 0 deletions bot/1_pic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package bot

import (
"bufio"
"bytes"
"fmt"
"github.com/nfnt/resize"
"github.com/sirupsen/logrus"
"image"
"image/draw"
"image/jpeg"
"image/png"
"io/ioutil"
"os"
)

func resizeImg(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}

buffer, err := ioutil.ReadAll(bufio.NewReader(file))
if err != nil {
return "", err
}

var img image.Image

img, err = jpeg.Decode(bytes.NewReader(buffer))
if err != nil {
img, err = png.Decode(bytes.NewReader(buffer))
if err != nil {
return "", fmt.Errorf("Image decode error %s", filePath)
}
}
err = file.Close()
if err != nil {
return "", err
}

width := img.Bounds().Dx()
height := img.Bounds().Dy()
widthNew := 320
heightNew := 320

var m image.Image
if width/height >= widthNew/heightNew {
m = resize.Resize(uint(widthNew), uint(height)*uint(widthNew)/uint(width), img, resize.Lanczos3)
} else {
m = resize.Resize(uint(width*heightNew/height), uint(heightNew), img, resize.Lanczos3)
}

newImag := image.NewNRGBA(image.Rect(0, 0, 320, 320))
if m.Bounds().Dx() > m.Bounds().Dy() {
draw.Draw(newImag, image.Rectangle{
Min: image.Point{Y: (320 - m.Bounds().Dy()) / 2},
Max: image.Point{X: 320, Y: 320},
}, m, m.Bounds().Min, draw.Src)
} else {
draw.Draw(newImag, image.Rectangle{
Min: image.Point{X: (320 - m.Bounds().Dx()) / 2},
Max: image.Point{X: 320, Y: 320},
}, m, m.Bounds().Min, draw.Src)
}

out, err := os.Create(filePath + ".resize.jpg")
if err != nil {
return "", fmt.Errorf("Create image file error %s", err)
}
defer func(out *os.File) {
err := out.Close()
if err != nil {
logrus.Errorln(err)
}
}(out)

err = jpeg.Encode(out, newImag, nil)
if err != nil {
logrus.Fatal(err)
}
return filePath + ".resize.jpg", nil
}
50 changes: 50 additions & 0 deletions bot/1_tools.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package bot

import (
"fmt"
"github.com/XiaoMengXinX/Music163Api-Go/types"
"github.com/sirupsen/logrus"
"os"
"sort"
)

func init() {
dirExists(cacheDir)
}

func in(target string, str_array []string) bool {
sort.Strings(str_array)
index := sort.SearchStrings(str_array, target)
if index < len(str_array) && str_array[index] == target {
return true
}
return false
}

func parseArtist(songDetail types.SongDetailData) string {
var artists string
for i, ar := range songDetail.Ar {
if i == 0 {
artists = ar.Name
} else {
artists = fmt.Sprintf("%s/%s", artists, ar.Name)
}
}
return artists
}

func dirExists(path string) bool {
_, err := os.Stat(path)
if err == nil {
return true
}
if os.IsNotExist(err) {
err := os.Mkdir(path, os.ModePerm)
if err != nil {
logrus.Errorf("mkdir %v failed: %v\n", path, err)
}
return false
}
logrus.Errorf("Error: %v\n", err)
return false
}
Loading

0 comments on commit 52411b0

Please sign in to comment.