-
Notifications
You must be signed in to change notification settings - Fork 0
/
abc-go.go
170 lines (146 loc) · 5.96 KB
/
abc-go.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package main
import (
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"regexp"
"sync"
ffmpeg_go "github.com/u2takey/ffmpeg-go"
)
func main() {
var wg = sync.WaitGroup{}
var folder string
var getchecksum, getactivationbytes, recursive, deletefiles bool
//this is the flag section of the program, pretty self explnetory.
flag.StringVar(&folder, "folder", ".", "Specify the name of the folder you wish to convert.")
flag.BoolVar(&getchecksum, "checksum", false, "Get the checksum of all AAX audible Files in a directory. Does not convert audio files.")
flag.BoolVar(&getactivationbytes, "activationbytes", false, "Get the activation bytes of your audible AAX files. Does not convert any audio files.")
flag.BoolVar(&recursive, "recursive", false, "Recursivly go through sub folders, default is false.")
flag.BoolVar(&deletefiles, "deletefiles", false, "Delete files once the conversion is complete. Understand, this does not care if the file was a lost pet, or an mp3 file. if its in the folder it WILL be deleted.")
flag.Parse()
var foldertoconvertfrom string = folder
var filenameregex = regexp.MustCompile(`(\.\w*$)`)
var regexforendslash = regexp.MustCompile("/$")
var regexAAX = regexp.MustCompile(".[a,A]{2}[x,X]$")
var regexisaudiofile = regexp.MustCompile("(?i).(?:wav|mp3|m4a|ogg|flac|aiff|aac|wma|alac|mp4)$")
// This gets your personal activation bytes from the file activation_bytes.txt file from the same
// folder as your program folder. this is legacy code, now it gets the activation code automaticly
/* activaitonfile, _ := os.Open("activation_bytes.txt")
reader := bufio.NewReader(activaitonfile)
line, _, err := reader.ReadLine()
if err == io.EOF {
log.Fatal(err)
}
activationbytes := line
*/
// Checks the folder you pass to the executable and adds a trailing slash if needed
// If you pass it a . it sets it as current working directory
if foldertoconvertfrom == "." || len(foldertoconvertfrom) == 0 {
currentdir, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
foldertoconvertfrom = currentdir + "/"
}
if !regexforendslash.MatchString(foldertoconvertfrom) {
foldertoconvertfrom = foldertoconvertfrom + "/"
}
// Iterates over a folder and gets all files from it, adding it to file.Name()
files, err := os.ReadDir(foldertoconvertfrom)
if err != nil {
log.Fatal(err)
}
// for eatch file in files
// splits it into two parts, the first being the file name, second is the file extention...//
// but only if we did not get asked for activationbytes or checksum value, if they were true skip this section
if !getchecksum && !getactivationbytes {
for _, file := range files {
fullfileName := file.Name()
justFileName := filenameregex.Split(file.Name(), 2)
wg.Add(1)
if regexAAX.MatchString(file.Name()) {
activationkey := getactivationkey(fullfileName, foldertoconvertfrom)
go convertaax(justFileName, foldertoconvertfrom, fullfileName, deletefiles, &wg, activationkey)
}
if regexisaudiofile.MatchString(file.Name()) {
go convertgenericaudio(justFileName, foldertoconvertfrom, fullfileName, deletefiles, &wg)
}
}
wg.Wait()
}
if getactivationbytes || getchecksum {
for _, file := range files {
fullFileName := file.Name()
if regexAAX.MatchString(file.Name()) {
checksum := getaaxchecksum(fullFileName, foldertoconvertfrom)
if getchecksum {
fmt.Println(checksum)
}
if getactivationbytes {
activaitonkey := getactivationkey(fullFileName, foldertoconvertfrom)
fmt.Println(activaitonkey)
}
}
}
}
}
// runs ffmpeg with the given options and coverts from any audio file to an m4a file,
// with the file extenion m4b
// which is the standard for audio books.
func getaaxchecksum(fullFilename string, foldertoconvertfrom string) string {
aaxfile, err := os.Open(foldertoconvertfrom + fullFilename)
if err != nil {
fmt.Println("error opening file")
}
// this sets the size of checksumbytes to 20 bytes long (which is the size of the aax file checksum)
checksumbytes := make([]byte, 20)
// jumps to the 653rd byte of the aax file and reads in the next 20 bytes
aaxfile.Seek(653, 0)
aaxfile.Read(checksumbytes)
// takes the raw binarydata and converts it to hex encoding
var checksum string = string(hex.EncodeToString(checksumbytes))
return checksum
}
func convertgenericaudio(justFileName []string, foldertoconvertfrom string, fullfilename string, deletefiles bool, wg *sync.WaitGroup) {
ffmpeg_go.Input(foldertoconvertfrom+fullfilename).
Output(foldertoconvertfrom+justFileName[0]+".m4b", ffmpeg_go.KwArgs{"c:a": "aac", "c:v": "copy", "af": "dynaudnorm"}).
OverWriteOutput().Run()
if deletefiles == true {
os.Remove(foldertoconvertfrom + fullfilename)
}
wg.Done()
}
func convertaax(justFileName []string, foldertoconvertfrom string, fullfilename string, deletefiles bool, wg *sync.WaitGroup, activationbytes string) {
ffmpeg_go.Input(foldertoconvertfrom+fullfilename, ffmpeg_go.KwArgs{"activation_bytes": activationbytes}).
Output(foldertoconvertfrom+justFileName[0]+".m4b", ffmpeg_go.KwArgs{"vn": "", "c:a": "copy"}).
OverWriteOutput().Run()
if deletefiles == true {
os.Remove(foldertoconvertfrom + fullfilename)
}
wg.Done()
}
// this function takes the checksum we found in getaaxchecksum and makes an API call to get the decryption bytes
func getactivationkey(fullFileName string, foldertoconvertfrom string) string {
checksum := getaaxchecksum(fullFileName, foldertoconvertfrom)
resp, err := http.Get("https://aax.api.j-kit.me/api/v2/activation/" + checksum)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
resp.Header.Set("User-Agent:", "abc-go/1.1")
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
// reads in the https responce data and makes a maped string list
var apiresponce map[string]interface{}
json.Unmarshal(body, &apiresponce)
// sets activationkey to the responded api's "activationBytes"
activationkey := fmt.Sprintf("%v", apiresponce["activationBytes"])
return activationkey
}