-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
12 changed files
with
835 additions
and
178 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,4 +23,7 @@ log | |
config.ini | ||
/Music163bot-Go* | ||
/src | ||
/ext | ||
/ext | ||
/cache | ||
*.mp3 | ||
*.flac |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.