From c05ab65228e27fa36a9f6236b00a016cb8a0a90d Mon Sep 17 00:00:00 2001 From: nondanee Date: Mon, 2 Dec 2019 01:42:46 +0800 Subject: [PATCH] fix output_path lambda error, support pip (Thanks @lonelyhentai #19) --- README.md | 63 ++++++++++++++++++--------- ncmdump/__init__.py | 1 + app.py => ncmdump/app.py | 80 ++++++++++++++++++++--------------- ncmdump.py => ncmdump/core.py | 29 ++----------- setup.py | 24 +++++++++++ 5 files changed, 117 insertions(+), 80 deletions(-) create mode 100644 ncmdump/__init__.py rename app.py => ncmdump/app.py (57%) rename ncmdump.py => ncmdump/core.py (84%) create mode 100644 setup.py diff --git a/README.md b/README.md index 747a0af..20a6757 100644 --- a/README.md +++ b/README.md @@ -13,40 +13,63 @@ - [JamieDummy/NCM_dump](https://github.com/JamieDummy/NCM_dump): Add GUI - [mnilzg/ncmdump](https://github.com/mnilzg/ncmdump): Speed up with NumPy + +### Contributor + +- [@kalteblau](https://github.com/kalteblau): Validate path & collision +- [@HarrisonXi](https://github.com/HarrisonXi): Add missing identifier +- [@leconio](https://github.com/leconio): handle dict key missing exception +- [@lonelyhentai](https://github.com/lonelyhentai): Add pip support + ## Dependency ``` $ pip install pycryptodome mutagen ``` -## Usage - -### Specify files +## Install ``` -$ python ncmdump.py [file ...] +$ pip install git+https://github.com/nondanee/ncmdump.git ``` -### Traverse working directory -``` -$ python ncmdump.py -``` -### More options -``` -$ python app.py -h -usage: ncmdump [-h] [-f format] [-o output] [-d] [-c | -s] [input [input ...]] +## Usage + +### Execute + +```sh +$ ncmdump -h # equivalent to "python ncmdump/app.py -h" +usage: ncmdump [-h] [-f format] [-o output] [-d] [-c | -r] [input [input ...]] positional arguments: - input ncm file or folder path + input ncm file or folder path optional arguments: - -h, --help show this help message and exit - -f format customize naming format - -o output customize saving folder - -d delete source after conversion - -c overwrite file with the same name - -s skip conversion if file exist + -h show this help message and exit + -f format customize naming format + -o output customize saving folder + -d delete source after conversion + -c overwrite file with the same name + -r auto rename if file name conflicts ``` -> Supported name holder: %artist%, %title%, %album% +> Supported name format holder: `%artist%`, `%title%`, `%album%` + +### Import + +```python +from ncmdump import dump +``` +```python +def dump(input_path, output_path = None, skip = True): + ''' + args: + input_path: a string of input file path + output_path: a string of output file path or a naming function + skip: a boolean controls conversion skipping when output file exists + + returns: + a string of output file path or none if conversion is skipped + ''' +``` \ No newline at end of file diff --git a/ncmdump/__init__.py b/ncmdump/__init__.py new file mode 100644 index 0000000..71dcdf4 --- /dev/null +++ b/ncmdump/__init__.py @@ -0,0 +1 @@ +from .core import dump \ No newline at end of file diff --git a/app.py b/ncmdump/app.py similarity index 57% rename from app.py rename to ncmdump/app.py index 3f74103..f32d2f4 100644 --- a/app.py +++ b/ncmdump/app.py @@ -5,11 +5,15 @@ Created on Fri Sep 28 13:32:51 2018 @author: Nzix """ -import argparse, os, sys, re -import ncmdump +import argparse, os, sys, traceback, re +from .core import dump parser = argparse.ArgumentParser( - prog = 'ncmdump' + prog = 'ncmdump', add_help = False +) +parser.add_argument( + '-h', action = 'help', + help = 'show this help message and exit' ) parser.add_argument( 'input', metavar = 'input', nargs = '*', default = ['.'], @@ -33,8 +37,8 @@ group.add_argument( help = 'overwrite file with the same name' ) group.add_argument( - '-s', dest = 'skip', action = 'store_true', - help = 'skip conversion if file exist' + '-r', dest = 'rename', action = 'store_true', + help = 'auto rename if file name conflicts' ) args = parser.parse_args() @@ -72,39 +76,45 @@ def name_format(path, meta): name += '.' + meta['format'] folder = args.output if args.output else os.path.dirname(path) save = os.path.join(folder, name) - if not (args.cover or args.skip): save = validate_collision(save) + if args.rename: save = validate_collision(save) return save -if args.output: - args.output = os.path.abspath(args.output) - if not os.path.exists(args.output): - print('output does not exist') - exit() - if not os.path.isdir(args.output): - print('output is not a folder') - exit() +def main(): + if args.output: + args.output = os.path.abspath(args.output) + if not os.path.exists(args.output): + print('output does not exist') + exit() + if not os.path.isdir(args.output): + print('output is not a folder') + exit() -files = [] -for path in args.input: - path = os.path.abspath(path) - if not os.path.exists(path): - continue - if os.path.isdir(path): - files += [os.path.join(path, name) for name in os.listdir(path) if os.path.splitext(name)[-1] == '.ncm'] - else: - files += [path] + files = [] + for path in args.input: + path = os.path.abspath(path) + if not os.path.exists(path): + continue + if os.path.isdir(path): + files += [os.path.join(path, name) for name in os.listdir(path) if os.path.splitext(name)[-1] == '.ncm'] + else: + files += [path] + + if sys.version[0] == '2': + files = [path.decode(sys.stdin.encoding) for path in files] -if sys.version[0] == '2': - files = [path.decode(sys.stdin.encoding) for path in files] + if not files: + print('empty input') + exit() -if not files: - print('empty input') - exit() + for path in files: + try: + save = dump(path, name_format, not args.cover) + if save: print(os.path.split(save)[-1]) + if args.delete: os.remove(path) + except KeyboardInterrupt: + exit() + except: + print(traceback.format_exc()) -for path in files: - try: - save = ncmdump.dump(path, name_format, args.skip) - if save: print(os.path.split(save)[-1]) - if args.delete: os.remove(path) - except KeyboardInterrupt: - exit() \ No newline at end of file +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/ncmdump.py b/ncmdump/core.py similarity index 84% rename from ncmdump.py rename to ncmdump/core.py index 48b29e5..12aa492 100644 --- a/ncmdump.py +++ b/ncmdump/core.py @@ -7,7 +7,7 @@ Created on Sun Jul 15 01:05:58 2018 import binascii, struct import base64, json -import os, traceback +import os from Crypto.Cipher import AES from Crypto.Util.Padding import unpad @@ -17,7 +17,7 @@ from mutagen import mp3, flac, id3 def dump(input_path, output_path = None, skip = True): output_path = (lambda path, meta: os.path.splitext(path)[0] + '.' + meta['format']) if not output_path else output_path - output_path = (lambda path, meta: path) if not callable(output_path) else output_path + output_path_generator = (lambda path, meta: output_path) if not callable(output_path) else output_path core_key = binascii.a2b_hex('687A4852416D736F356B496E62617857') meta_key = binascii.a2b_hex('2331346C6A6B5F215C5D2630553C2728') @@ -78,7 +78,7 @@ def dump(input_path, output_path = None, skip = True): f.seek(image_space - image_size, 1) # media data - output_path = output_path(input_path, meta_data) + output_path = output_path_generator(input_path, meta_data) if skip and os.path.exists(output_path): return data = f.read() @@ -128,25 +128,4 @@ def dump(input_path, output_path = None, skip = True): audio['artist'] = '/'.join([artist[0] for artist in meta_data['artist']]) audio.save() - return output_path - -if __name__ == '__main__': - import sys - if len(sys.argv) > 1: - files = sys.argv[1:] - else: - files = [name for name in os.listdir('.') if os.path.splitext(name)[-1] == '.ncm'] - - if sys.version[0] == '2': - files = [path.decode(sys.stdin.encoding) for path in files] - - if not files: - print('please input file path!') - - for path in files: - try: - dump(path) - print(os.path.split(path)[-1]) - except Exception as e: - print(traceback.format_exc()) - pass \ No newline at end of file + return output_path \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..c1b5a6a --- /dev/null +++ b/setup.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +from setuptools import setup, find_packages + +setup( + name = 'ncmdump', + version = '0.1.0', + description = 'netease cloud music copyright protection file dump', + url = 'http://github.com/nondanee/ncmdump', + author = 'nondanee', + author_email = 'iminezn5656@outlook.com', + license = 'MIT', + keywords = ('ncm', 'netease cloud music'), + packages = find_packages(), + platforms = 'any', + zip_safe = False, + python_requires = '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', + install_requires = ['pycryptodome', 'mutagen'], + entry_points = { + 'console_scripts': [ + 'ncmdump=ncmdump.app:main' + ] + } +) \ No newline at end of file