Compare commits
	
		
			5 Commits
		
	
	
		
			dce5236b1f
			...
			efdb203e2c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| efdb203e2c | |||
| 1aaa28d98d | |||
| aa7c0fb106 | |||
| a35f9d05d4 | |||
| 9f34fe4a8a | 
							
								
								
									
										87
									
								
								audible-converter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								audible-converter.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| import configparser | ||||
| from requests import get | ||||
| import os | ||||
| import json | ||||
| import sys | ||||
|  | ||||
| class AudibleBook(object): | ||||
|  | ||||
|     def __init__(self, filePath, activationBytes): | ||||
|         self.filePath = filePath | ||||
|         self.activationBytes = activationBytes | ||||
|         self.metadata = json.loads(os.popen('ffprobe -i {} -show_format \ | ||||
|             -print_format json'.format(filePath)).read())['format']['tags'] | ||||
|         self.chapters = json.loads(os.popen('ffprobe -i {} -print_format json \ | ||||
|             -show_chapters -loglevel error -sexagesimal'.format(self.filePath)) | ||||
|                           .read())['chapters'] | ||||
|  | ||||
|     # getPath() returns path to origonal audible file. | ||||
|     def getPath(self): | ||||
|         return self.filePath | ||||
|  | ||||
|     # getMetadata() returns audio metadata for a given filepath. | ||||
|     def getMetadata(self): | ||||
|         return self.metadata | ||||
|  | ||||
|     # getChapters() returns chapter metadata for a given filepath. | ||||
|     def getChapters(self): | ||||
|         return self.chapters | ||||
|  | ||||
|     # getTitle() returns audiobook title. | ||||
|     def getTitle(self): | ||||
|         return self.getMetadata()['title'] | ||||
|  | ||||
|     def removeDRM(self, fileName): | ||||
|         os.system('ffmpeg -activation_bytes {} -i {} -c copy "{}.m4b"' | ||||
|                   .format(self.activationBytes, self.filePath, fileName)) | ||||
|         print('test') | ||||
|  | ||||
| # getHash() returns the hash of a given file. | ||||
| def getHash(filePath): | ||||
|     with open(filePath, 'rb') as f: | ||||
|         f.seek(653) | ||||
|         data = f.read(20) | ||||
|         f.close() | ||||
|     return data.hex() | ||||
|  | ||||
| # getActivationBytes returns the bytes needed to decrypt a given hash.  | ||||
| def getActivationBytes(filehash): | ||||
|     headers = {'User-Agent': 'audible-converter'} | ||||
|     response = get('https://aax.api.j-kit.me/api/v2/activation/{}'.format(filehash), | ||||
|                    headers=headers) | ||||
|     return json.loads(response.text)['activationBytes'] | ||||
|  | ||||
| # createConfig() creates a config file. | ||||
| def createConfig(configFilePath, filePath): | ||||
|     activationBytes = getActivationBytes(getHash(filePath)) | ||||
|     f = open(configFilePath, 'w') | ||||
|     f.write('activationBytes={}'.format(activationBytes)) | ||||
|     f.close() | ||||
|  | ||||
| configFilePath='./settings.conf' | ||||
| audibleBookPath=sys.argv[1] | ||||
|  | ||||
| # Check if config file exists and creates one if needed. | ||||
| if not os.path.exists(configFilePath): | ||||
|     print('Creating config file') | ||||
|     createConfig(configFilePath, audibleBookPath) | ||||
|      | ||||
| configString = '[Settings]\n' + open(configFilePath).read() | ||||
| configParser = configparser.RawConfigParser() | ||||
| configParser.read_string(configString) | ||||
| activationBytes=configParser.get('Settings', 'activationBytes') | ||||
|      | ||||
| book = AudibleBook(audibleBookPath, activationBytes) | ||||
|  | ||||
| for c in book.getChapters(): | ||||
|     start=c['start'] | ||||
|     end=c['end'] | ||||
|     title=c['tags']['title'] | ||||
|     print(start, end, title) | ||||
|     #os.system('ffmpeg -i {} -acodec copy -vcodec copy -ss {} -t {} OUTFILE-{}.m4a'.format(filePath, start, end, title)) | ||||
|  | ||||
|  | ||||
| print(book.getTitle()) | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -1,5 +1,9 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| cleanString() { | ||||
|      tr -d '"' | ||||
| } | ||||
|  | ||||
| # getHash returns the hash of a given file. | ||||
| function getHash() { | ||||
|     echo $(xxd -p -l20 -s 653 ${1}) | ||||
| @@ -8,7 +12,7 @@ function getHash() { | ||||
| # getActivationBytes returns the bytes needed to decrypt a given hash.  | ||||
| function getActivationBytes() { | ||||
|     json=$(curl -A 'audible-converter' https://aax.api.j-kit.me/api/v2/activation/${1}) | ||||
|     echo $(echo $json | jq '.activationBytes' | tr -d '"') | ||||
|     echo $(echo $json | jq '.activationBytes' | cleanString) | ||||
| } | ||||
|  | ||||
| # createConfig creates a config file. | ||||
| @@ -27,11 +31,11 @@ function checkAudibleFile() { | ||||
| } | ||||
|  | ||||
| function removeDRM() { | ||||
|     ffmpeg -activation_bytes ${2} -i ${1} -c copy "$(basename ${1} | cut -f 1 -d '.').m4b" | ||||
|     ffmpeg -activation_bytes ${2} -i ${1} -c copy "${3}.m4b" | ||||
| } | ||||
|  | ||||
| function getChapterJSON() { | ||||
|     echo $(ffprobe -i ${1} -print_format json -show_chapters -loglevel error -sexagesimal) | ||||
|     echo $(ffprobe -i ${1} -print_format json -show_chapters -loglevel error -sexagesimal | jq '.chapters') | ||||
| } | ||||
|  | ||||
| function getMetadataJSON() { | ||||
| @@ -39,7 +43,11 @@ function getMetadataJSON() { | ||||
| } | ||||
|  | ||||
| function getTitle() { | ||||
|     echo $(echo ${1} | jq '.title') | ||||
|     echo $(echo ${1} | jq '.title' | cleanString) | ||||
| } | ||||
|  | ||||
| function fileSafe() { | ||||
|      sed -e 's/[^A-Za-z0-9._-]/-/g' | tr '[:upper:]' '[:lower:]' | sed -e 's/--/-/g' | ||||
| } | ||||
|  | ||||
| settingsFile='./settings.conf' | ||||
| @@ -57,5 +65,18 @@ fi | ||||
| . $settingsFile | ||||
|  | ||||
| metadataJSON=$(getMetadataJSON $audibleFile) | ||||
| json=$(getMetadataJSON $audibleFile) | ||||
| removeDRM $audibleFile $activationBytes | ||||
| chapterJSON=$(getChapterJSON $audibleFile) | ||||
| name=$(getTitle "${metadataJSON}" | fileSafe) | ||||
|  | ||||
| if [ ! -f "${name}.m4b" ]; then | ||||
|     removeDRM $audibleFile $activationBytes $name | ||||
| fi | ||||
|  | ||||
| mkdir -p $name | ||||
|  | ||||
| data=$(echo "${chapterJSON}" | jq '.[] | "\(.start),\(.end),\(.tags.title)"') | ||||
| echo $data | ||||
| IFS=' ' read -r -a array <<< "$data" | ||||
|  | ||||
|  | ||||
| echo $(echo "${chapterJSON}" | jq '.[] | .start,.end,.tags.title') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user