✨ Fingerprinting audio
This commit is contained in:
		
					parent
					
						
							
								4057d00c46
							
						
					
				
			
			
				commit
				
					
						d8cae5b9c4
					
				
			
		
					 3 changed files with 105 additions and 0 deletions
				
			
		
							
								
								
									
										15
									
								
								app/run.go
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								app/run.go
									
										
									
									
									
								
							|  | @ -24,7 +24,22 @@ func quit() { | ||||||
| 	os.Exit(0) | 	os.Exit(0) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func testFp() { | ||||||
|  | 	fp, err := media.Fingerprint("/home/drj/MyFiles/Videos/WebShows/YouTube/Dolly_Parton_-_Topic/Just_Because_I_m_a_Woman.Dolly_Parton_-_Topic.Fmv-XQerVkM.webm") | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	// fmt.Printf("%+v\n", fp) | ||||||
|  | 	ids, err := media.LookupFingerprint(fp) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Printf("%+v\n", ids) | ||||||
|  | 	quit() | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func Run(step AppStep) { | func Run(step AppStep) { | ||||||
|  | 	testFp() | ||||||
| 	for step < Quit { | 	for step < Quit { | ||||||
| 		switch step { | 		switch step { | ||||||
| 		case Pick: | 		case Pick: | ||||||
|  |  | ||||||
|  | @ -19,6 +19,8 @@ type Config struct { | ||||||
| 	FfEncoder        string            `toml:"ff_encoder"` | 	FfEncoder        string            `toml:"ff_encoder"` | ||||||
| 	AllowedCodecs    []string          `toml:"allowed_codec"` | 	AllowedCodecs    []string          `toml:"allowed_codec"` | ||||||
| 	CodecExt         map[string]string `toml:"codec_ext"` | 	CodecExt         map[string]string `toml:"codec_ext"` | ||||||
|  | 	AcousticIdKey    string            `toml:"acoustic_id_key"` | ||||||
|  | 	AcousticUserKey  string            `toml:"acoustic_user_key"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var config Config | var config Config | ||||||
|  |  | ||||||
							
								
								
									
										88
									
								
								media/fingerprint.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								media/fingerprint.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,88 @@ | ||||||
|  | package media | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"net/http" | ||||||
|  | 	u "net/url" | ||||||
|  | 	"os/exec" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"codeberg.org/danjones000/strip-beats/config" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type FPrint struct { | ||||||
|  | 	Duration    float64 | ||||||
|  | 	Fingerprint string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func Fingerprint(path string) (FPrint, error) { | ||||||
|  | 	pr := FPrint{} | ||||||
|  | 	_, err := exec.LookPath("fpcalc") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return pr, errors.Join(errors.New("Unable to find fpcalc in PATH"), err) | ||||||
|  | 	} | ||||||
|  | 	cmd := exec.Command("fpcalc", "-json", path) | ||||||
|  | 	out, err := cmd.Output() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return pr, errors.Join(errors.New(fmt.Sprintf("Failed to run %s", strings.Join(cmd.Args, " "))), err) | ||||||
|  | 	} | ||||||
|  | 	err = json.Unmarshal(out, &pr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return pr, errors.Join(errors.New("Couldn't parse output from fpcalc"), err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return pr, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type IdResults struct { | ||||||
|  | 	Status  string | ||||||
|  | 	Results []IdResult | ||||||
|  | 	Error   IdError | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type IdResult struct { | ||||||
|  | 	Id         string | ||||||
|  | 	Score      float64 | ||||||
|  | 	Recordings []MbRecording | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type IdError struct { | ||||||
|  | 	Code    int | ||||||
|  | 	Message string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type MbRecording struct { | ||||||
|  | 	Id string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func LookupFingerprint(print FPrint) (IdResults, error) { | ||||||
|  | 	res := IdResults{} | ||||||
|  | 	key := config.GetConfig().AcousticIdKey | ||||||
|  | 	if key == "" { | ||||||
|  | 		return res, errors.New("Missing acoustic_id_key from config") | ||||||
|  | 	} | ||||||
|  | 	url := "https://api.acoustid.org/v2/lookup" | ||||||
|  | 	form := u.Values{ | ||||||
|  | 		"format":      {"json"}, | ||||||
|  | 		"client":      {key}, | ||||||
|  | 		"duration":    {fmt.Sprintf("%.0f", print.Duration)}, | ||||||
|  | 		"fingerprint": {print.Fingerprint}, | ||||||
|  | 		"meta":        {"recordingids"}} | ||||||
|  | 	resp, err := http.PostForm(url, form) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  | 	body, err := io.ReadAll(resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 	json.Unmarshal(body, &res) | ||||||
|  | 	if res.Status == "error" { | ||||||
|  | 		err = errors.New(res.Error.Message) | ||||||
|  | 	} | ||||||
|  | 	return res, err | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue