Skip to content

Commit c32dd45

Browse files
committed
Initial MusicSubmission testing
1 parent 3dfeece commit c32dd45

5 files changed

Lines changed: 290 additions & 2 deletions

File tree

pythonbits/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# -*- coding: utf-8 -*-
22

33
__title__ = "pythonBits"
4-
__version__ = "3.0.3"
4+
__version__ = "3.1a1"
55
__copyright__ = "Copyright 2018, The pythonBits Authors"
66
__maintainer__ = "mueslo"
77
__license__ = "GPLv3"

pythonbits/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ def parse_args():
2323
"Dead S01\") (optional)"))
2424

2525
cat_map = {'movie': bb.MovieSubmission,
26-
'tv': bb.TvSubmission}
26+
'tv': bb.TvSubmission,
27+
'music': bb.MusicSubmission}
2728
parser.add_argument("-c", "--category", choices=list(cat_map.keys()))
2829
parser.add_argument("-u", "--set-field", nargs=2, action='append',
2930
metavar=('FIELD', 'VALUE'), default=[],

pythonbits/bb.py

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from concurrent.futures.thread import ThreadPoolExecutor
1111

1212
import pymediainfo
13+
import mutagen
1314
import guessit
1415
from unidecode import unidecode
1516
from requests.exceptions import HTTPError
@@ -19,6 +20,7 @@
1920
from .torrent import make_torrent
2021
from . import tvdb
2122
from . import imdb
23+
from . import musicbrainz as mb
2224
from . import imagehosting
2325
from .ffmpeg import FFMpeg
2426
from . import templating as bb
@@ -841,3 +843,202 @@ def _render_description(self):
841843
@form_field('desc')
842844
def _render_form_description(self):
843845
return self['description']
846+
847+
848+
class AudioSubmission(BbSubmission):
849+
default_fields = ("description", "form_tags", "year", "image", "artist",
850+
"title", "format", "bitrate", "media")
851+
852+
def subcategory(self):
853+
return MusicSubmission
854+
855+
856+
class MusicSubmission(AudioSubmission):
857+
default_fields = (AudioSubmission.default_fields + (
858+
'remaster', 'remaster_year', 'remaster_title'))
859+
_form_type = 'Music'
860+
## submit
861+
## type
862+
## artist
863+
## title
864+
# remaster_true (checkbox, special edition info) (!?!?!)
865+
# -> remaster_year
866+
# -> remaster_title (optional)
867+
## year
868+
## scene (checkbox)
869+
## format (select, options: MP3, FLAC, Ogg, AAC, DTS 5.1 Audio, 24bit FLAC)
870+
## bitrate (select, options: 192, V2 (VBR), 256, V0 (VBR), 320, Lossless, Other)
871+
## media (select, options: CD, DVD, Vinyl, Soundboard, DAT, Web)
872+
## image
873+
# album_desc (!!!)
874+
## release_desc (optional)
875+
876+
@form_field('remaster_true', 'checkbox')
877+
def _render_remaster(self):
878+
# todo user input function/module to reduce boilerplating
879+
return bool(
880+
input('Is this a special/remastered edition?').lower() != 'n')
881+
882+
@form_field('remaster_year')
883+
def _render_remaster_year(self):
884+
pass
885+
886+
@form_field('remaster_title')
887+
def _render_remaster_title(self):
888+
pass
889+
890+
@form_field('format')
891+
def _render_format(self):
892+
# MP3, FLAC, Ogg, AAC, DTS 5.1 Audio, 24bit FLAC
893+
choices = ('MP3', 'FLAC', 'Ogg', 'AAC', '24bit FLAC')
894+
895+
tl_format = {
896+
'MP3': 'MP3',
897+
'EasyMP3': 'MP3',
898+
'OggVorbis': 'Ogg',
899+
'OggOpus': 'Ogg',
900+
'FLAC': 'FLAC',
901+
'AAC': 'AAC',
902+
}
903+
904+
tags = self['tags']
905+
format = tl_format[tags['format']]
906+
if format == 'FLAC' and tags['bits_per_sample'] >= 24:
907+
format = '24bit FLAC'
908+
909+
return format
910+
911+
@form_field('bitrate')
912+
def _render_bitrate(self):
913+
# 192, V2(VBR), 256, V0(VBR), 320, Lossless, Other)
914+
format = self['format']
915+
tags = self['tags']
916+
if format == 'MP3':
917+
if tags['encoder_settings'] == '-V 0':
918+
return 'V0(VBR)'
919+
elif tags['encoder_settings'] == '-V 2':
920+
return 'V2(VBR)'
921+
elif tags['bitrate'] == 192000:
922+
return '192'
923+
elif tags['bitrate'] == 256000:
924+
return '256'
925+
elif tags['bitrate'] == 320000:
926+
return '320'
927+
928+
elif 'FLAC' in format:
929+
return 'Lossless'
930+
931+
raise Exception('Unrecognized format/bitrate')
932+
933+
@form_field('media')
934+
def _render_media(self):
935+
media = self['summary']['media']
936+
937+
if len(media) == 1:
938+
return media[0]
939+
940+
raise Exception('Handle this')
941+
942+
def _render_mediainfo_path(self):
943+
assert os.path.isdir(self['path'])
944+
945+
for dp, dns, fns in os.walk(self['path']):
946+
for fn in fns:
947+
full_path = os.path.join(dp, fn)
948+
if os.path.getsize(full_path) > 1 * 2**20:
949+
return full_path
950+
raise Exception('No media file found')
951+
952+
def _render_songlist(self):
953+
return None
954+
955+
def _render_tags(self):
956+
tags = mutagen.File(self['mediainfo_path'], easy=True)
957+
# if type(tags) == mutagen.mp3.MP3:
958+
# tags = mutagen.mp3.MP3(self['mediainfo_path'], ID3=EasyID3)
959+
960+
print(dir(tags.info))
961+
try:
962+
print(tags.info.encoder_settings)
963+
except:
964+
pass
965+
log.debug(type(tags))
966+
log.debug(tags.pprint())
967+
968+
return {'artist': tags.get('albumartist', tags['artist'])[0],
969+
'title': tags['album'][0],
970+
'rid': tags.get('musicbrainz_albumid', [None])[0],
971+
'format': type(tags).__name__,
972+
'bitrate': tags.info.bitrate,
973+
'bits_per_sample': getattr(tags.info, 'bits_per_sample',
974+
None),
975+
'encoder_settings': getattr(tags.info, 'encoder_settings',
976+
None),
977+
}
978+
979+
def _render_summary(self):
980+
# identify self:
981+
# - num tracks todo
982+
# - scan for mb tags
983+
tags = self['tags']
984+
print(tags)
985+
if tags['rid']:
986+
log.info('Found MusicBrainz release in tags')
987+
release = mb.musicbrainzngs.get_release_by_id(
988+
tags['rid'],
989+
includes=['release-groups', 'media'])['release']
990+
rg = mb.musicbrainzngs.get_release_group_by_id(
991+
release['release-group']['id'],
992+
includes=['tags', 'artist-credits'])['release-group']
993+
994+
else:
995+
if self['title_arg']:
996+
query_artist = None
997+
query = self['title_arg']
998+
else:
999+
query_artist = tags['artist']
1000+
query = tags['title']
1001+
rg, release = mb.find_release(query, artist=query_artist)
1002+
1003+
print('rg', rg)
1004+
print('r', release)
1005+
1006+
print(rg.keys())
1007+
return {
1008+
'artist': rg['artist-credit-phrase'],
1009+
'title': rg['title'],
1010+
'year': release['release-event-list'][0]['date'][:4],
1011+
'tags': [t['name'] for t in
1012+
sorted(rg.get('tag-list', []),
1013+
key=lambda t: int(t['count']))][-5:],
1014+
'media': [m['format'] for m in release['medium-list']],
1015+
'cover': mb.get_artwork(rg['id']),
1016+
}
1017+
1018+
@finalize
1019+
@form_field('image')
1020+
def _render_image(self):
1021+
return self['summary']['cover']
1022+
1023+
def _finalize_image(self):
1024+
return ImgurUploader().upload(self['image'])
1025+
1026+
@form_field('year')
1027+
def _render_year(self):
1028+
return self['summary']['year']
1029+
1030+
@form_field('tags')
1031+
def _render_form_tags(self):
1032+
return self['summary']['tags']
1033+
1034+
@form_field('album_desc')
1035+
def _render_description(self):
1036+
return 'album description'
1037+
1038+
@form_field('artist')
1039+
def _render_artist(self):
1040+
return self['summary']['artist']
1041+
1042+
@form_field('title')
1043+
def _render_title(self):
1044+
return self['summary']['title']

pythonbits/musicbrainz.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import (absolute_import, division,
3+
print_function, unicode_literals)
4+
from builtins import * # noqa: F401, F403
5+
6+
import musicbrainzngs
7+
import terminaltables
8+
# from textwrap import wrap
9+
10+
from . import __title__ as appname, __version__ as version, _github as github
11+
12+
13+
musicbrainzngs.set_useragent(appname, version, github)
14+
15+
16+
def get_artwork(release_group_id):
17+
data = musicbrainzngs.get_release_group_image_list(release_group_id)
18+
for image in data["images"]:
19+
if "Front" in image["types"] and image["approved"]:
20+
return image["thumbnails"]["large"]
21+
22+
23+
def find_release_group(release_title, artist=None):
24+
results = musicbrainzngs.search_release_groups(
25+
release_title, artist=artist, limit=10)['release-group-list']
26+
table_data = [('Index', 'Artist', 'Title', 'Type')]
27+
#max_width = table.column_max_width(2)
28+
for i, r in enumerate(results):
29+
#title = '\n'.join(wrap(r['title'], max_width))
30+
table_data.append((i, r['artist-credit-phrase'],
31+
r['title'], r.get('type', '?')))
32+
33+
print(terminaltables.SingleTable(table_data).table)
34+
while True:
35+
choice = raw_input(
36+
"Select the release group (or enter a different query): ")
37+
try:
38+
choice = int(choice)
39+
except ValueError:
40+
if choice != '':
41+
return find_release_group(choice)
42+
continue
43+
44+
try:
45+
choice = results[choice]
46+
except IndexError:
47+
pass
48+
else:
49+
return choice
50+
51+
52+
def find_release(release_title, artist=None):
53+
release_group = find_release_group(release_title, artist=artist)
54+
55+
results = musicbrainzngs.search_releases(
56+
'rgid:'+release_group['id'])['release-list']
57+
58+
table_data = [
59+
('Index', 'Title', '# Tracks', 'Date', 'CC', 'Label', 'Status', 'Format'),
60+
]
61+
62+
for i, r in enumerate(results):
63+
try:
64+
label = r['label-info-list'][0]['label']['name']
65+
except KeyError:
66+
label = '?'
67+
table_data.append((i, r['title'], r['medium-list'][0]['track-count'],
68+
r.get('date', '?'), r.get('country', '?'),
69+
label, r.get('status', '?'),
70+
r['medium-list'][0]['format']))
71+
72+
print(terminaltables.SingleTable(table_data).table)
73+
while True:
74+
choice = raw_input(
75+
"Select the exact release, if known: ")
76+
try:
77+
choice = results[int(choice)]
78+
except (IndexError, ValueError):
79+
if choice == '':
80+
return release_group, None
81+
else:
82+
return release_group, choice
83+

setup.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ def find_version(*file_paths):
4141
"logbook~=1.2",
4242
"pyreadline~=2.1",
4343
"progressbar2~=3.38",
44+
"mutagen~=1.40",
45+
"musicbrainzngs~=0.6",
46+
"terminaltables~=3.1",
4447
],
4548
python_requires=">=3.5,<4.0",
4649
tests_require=['tox', 'pytest', 'flake8', 'pytest-logbook'],

0 commit comments

Comments
 (0)