generated from bing/readnotes
Compare commits
2 Commits
dc9d8b6e94
...
a724d602a5
Author | SHA1 | Date |
---|---|---|
|
a724d602a5 | |
|
9c3ee32098 |
|
@ -19,3 +19,5 @@
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
go/bin
|
go/bin
|
||||||
|
|
||||||
|
build/
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -7,6 +7,7 @@ require (
|
||||||
github.com/bogem/id3v2/v2 v2.1.4
|
github.com/bogem/id3v2/v2 v2.1.4
|
||||||
github.com/coreos/go-oidc/v3 v3.1.0
|
github.com/coreos/go-oidc/v3 v3.1.0
|
||||||
github.com/gin-gonic/gin v1.8.1
|
github.com/gin-gonic/gin v1.8.1
|
||||||
|
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20241129212102-9c50ad6b591e
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -198,6 +198,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20241129212102-9c50ad6b591e h1:8AnObPi8WmIgjwcidUxaREhXMSpyUJeeSrIkZTXdabw=
|
||||||
|
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20241129212102-9c50ad6b591e/go.mod h1:DvXTE/K/RtHehxU8/GtDs4vFtfw64jJ3PaCnFri8CRg=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(ogg2mp3)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
|
# 手动指定 Vorbis 和 MP3Lame 库的路径
|
||||||
|
set(VORBIS_INCLUDE_DIRS /usr/include)
|
||||||
|
set(VORBIS_LIBRARIES /usr/lib/x86_64-linux-gnu/libvorbisfile.so /usr/lib/x86_64-linux-gnu/libvorbis.so /usr/lib/x86_64-linux-gnu/libogg.so)
|
||||||
|
set(MP3LAME_INCLUDE_DIRS /usr/include)
|
||||||
|
set(MP3LAME_LIBRARIES /usr/lib/x86_64-linux-gnu/libmp3lame.so)
|
||||||
|
|
||||||
|
# 包含头文件目录
|
||||||
|
include_directories(${VORBIS_INCLUDE_DIRS})
|
||||||
|
include_directories(${MP3LAME_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# 添加源文件
|
||||||
|
set(SOURCES ogg2mp3.cpp)
|
||||||
|
|
||||||
|
# 创建静态库
|
||||||
|
add_library(ogg2mp3 STATIC ${SOURCES})
|
||||||
|
|
||||||
|
# 链接库
|
||||||
|
target_link_libraries(ogg2mp3 ${VORBIS_LIBRARIES} ${MP3LAME_LIBRARIES})
|
|
@ -0,0 +1,97 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/build -logg2mp3 -lvorbisfile -lvorbis -logg -lmp3lame -lstdc++
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ogg2mp3.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
_ "github.com/ianlancetaylor/cgosymbolizer" // cgo 错误跟踪
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertOggToMp3(src string, dst string) C.int {
|
||||||
|
input := C.CString(src)
|
||||||
|
defer C.free(unsafe.Pointer(input))
|
||||||
|
output := C.CString(dst)
|
||||||
|
defer C.free(unsafe.Pointer(output))
|
||||||
|
return C.convertOggToMp3(input, output)
|
||||||
|
}
|
||||||
|
// listOggFiles 遍历指定文件夹,返回所有 OGG 文件的路径列表
|
||||||
|
func listOggFiles(dir string) ([]string, error) {
|
||||||
|
var oggFiles []string
|
||||||
|
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !info.IsDir() && strings.HasSuffix(strings.ToLower(info.Name()), ".ogg") {
|
||||||
|
oggFiles= append(oggFiles, path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return oggFiles, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertOggFilesToMp3 将指定文件夹下的所有 OGG 文件转换为 MP3
|
||||||
|
func convertOggFilesToMp3(files []string, outputDir string) {
|
||||||
|
for _, file := range files {
|
||||||
|
outputFile := filepath.Join(outputDir, strings.TrimSuffix(filepath.Base(file), ".ogg")+".mp3")
|
||||||
|
if n := convertOggToMp3(file, outputFile); n != 0 {
|
||||||
|
log.Printf("Error converting %s to %s: %d", file, outputFile, n)
|
||||||
|
} else {
|
||||||
|
log.Printf("Successfully converted %s to %s", file, outputFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var rootCmd = &cobra.Command{Use: "main"}
|
||||||
|
var convertCmd = &cobra.Command{
|
||||||
|
Use: "file [input.ogg] [output.mp3]",
|
||||||
|
Short: "Convert OGG to MP3",
|
||||||
|
Args: cobra.ExactArgs(2),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
input := C.CString(args[0])
|
||||||
|
defer C.free(unsafe.Pointer(input))
|
||||||
|
output := C.CString(args[1])
|
||||||
|
defer C.free(unsafe.Pointer(output))
|
||||||
|
if n := C.convertOggToMp3(input, output); n != 0 {
|
||||||
|
log.Fatalf("Error converting OGG to MP3: %d", n)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var convertDirCmd = &cobra.Command{
|
||||||
|
Use: "dir [inputDir] [outputDir]",
|
||||||
|
Short: "Convert all OGG files in a directory to MP3",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
inputDir := args[0]
|
||||||
|
outputDir := inputDir + "_mp3"
|
||||||
|
if len(args) == 2 {
|
||||||
|
outputDir = args[1]
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(outputDir); os.IsNotExist(err) {
|
||||||
|
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||||
|
log.Fatalf("Error creating output directory: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oggFiles, err := listOggFiles(inputDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error listing OGG files: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
convertOggFilesToMp3(oggFiles, outputDir)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCmd.AddCommand(convertCmd, convertDirCmd)
|
||||||
|
rootCmd.Execute()
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vorbis/vorbisfile.h>
|
||||||
|
#include <lame/lame.h>
|
||||||
|
#include "ogg2mp3.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OGG_FILE_ERROR 1
|
||||||
|
#define MP3_FILE_ERROR 2
|
||||||
|
#define OGG_DECODE_ERROR 3
|
||||||
|
#define MP3_ENCODE_ERROR 4
|
||||||
|
|
||||||
|
int convertOggToMp3(const char* oggFilePath, const char* mp3FilePath) {
|
||||||
|
// 打开 OGG 文件
|
||||||
|
FILE* oggFile = fopen(oggFilePath, "rb");
|
||||||
|
if (!oggFile) {
|
||||||
|
return OGG_FILE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开 MP3 文件
|
||||||
|
FILE* mp3File = fopen(mp3FilePath, "wb");
|
||||||
|
if (!mp3File) {
|
||||||
|
fclose(oggFile);
|
||||||
|
return MP3_FILE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化 OGG 解码器
|
||||||
|
OggVorbis_File vf;
|
||||||
|
if (ov_open(oggFile, &vf, NULL, 0) < 0) {
|
||||||
|
fclose(oggFile);
|
||||||
|
fclose(mp3File);
|
||||||
|
return OGG_DECODE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取音频信息
|
||||||
|
vorbis_info* vi = ov_info(&vf, -1);
|
||||||
|
|
||||||
|
// 初始化 LAME 编码器
|
||||||
|
lame_t lame = lame_init();
|
||||||
|
lame_set_in_samplerate(lame, vi->rate);
|
||||||
|
lame_set_num_channels(lame, vi->channels);
|
||||||
|
lame_set_VBR(lame, vbr_default);
|
||||||
|
lame_init_params(lame);
|
||||||
|
|
||||||
|
// 缓冲区
|
||||||
|
const int BUFFER_SIZE = 4096;
|
||||||
|
short int pcm_buffer[BUFFER_SIZE * vi->channels];
|
||||||
|
unsigned char mp3_buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
int read, write;
|
||||||
|
int current_section;
|
||||||
|
|
||||||
|
// 读取 OGG 数据并编码为 MP3
|
||||||
|
while ((read = ov_read(&vf, (char*)pcm_buffer, sizeof(pcm_buffer), 0, 2, 1, ¤t_section)) > 0) {
|
||||||
|
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read / (2 * vi->channels), mp3_buffer, BUFFER_SIZE);
|
||||||
|
fwrite(mp3_buffer, write, 1, mp3File);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结束编码
|
||||||
|
write = lame_encode_flush(lame, mp3_buffer, BUFFER_SIZE);
|
||||||
|
fwrite(mp3_buffer, write, 1, mp3File);
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
lame_close(lame);
|
||||||
|
ov_clear(&vf);
|
||||||
|
fclose(mp3File);
|
||||||
|
// fclose(oggFile);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
int convertOggToMp3(const char* oggFilePath, const char* mp3FilePath);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
BIN
go/uiweb/uiweb
BIN
go/uiweb/uiweb
Binary file not shown.
Loading…
Reference in New Issue