Manual info correction, input() using readline
This commit is contained in:
parent
450421ce0d
commit
9687313cb4
3 changed files with 114 additions and 59 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,5 +1,9 @@
|
||||||
files/
|
files/
|
||||||
convert/
|
convert/
|
||||||
tagged/
|
tagged/
|
||||||
.vscode/
|
|
||||||
lyrics.txt
|
lyrics.txt
|
||||||
|
input
|
||||||
|
|
||||||
|
__pycache__/
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
|
@ -11,7 +11,7 @@ import mimetypes
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
from typing import Optional
|
from typing import Optional, Any
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -51,6 +51,16 @@ class ParseResult(TypedDict):
|
||||||
cover_mime: Optional[str]
|
cover_mime: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
parsed = ParseResult(
|
||||||
|
title='', artist='',
|
||||||
|
album='', year=0,
|
||||||
|
track_no=0, tracks=0,
|
||||||
|
lyrics='',
|
||||||
|
cover=None,
|
||||||
|
cover_mime=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ParseError(Exception):
|
class ParseError(Exception):
|
||||||
|
|
||||||
def __init__(self, parsing_obj: str) -> None:
|
def __init__(self, parsing_obj: str) -> None:
|
||||||
|
@ -58,10 +68,13 @@ class ParseError(Exception):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
f'Unable to parse {parsing_obj}'
|
f'Unable to parse {parsing_obj}'
|
||||||
)
|
)
|
||||||
|
self.parsing_obj = parsing_obj
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|
||||||
|
global parsed
|
||||||
|
|
||||||
copy = int(sys.argv[1]) == 1
|
copy = int(sys.argv[1]) == 1
|
||||||
file = sys.argv[2]
|
file = sys.argv[2]
|
||||||
|
|
||||||
|
@ -76,34 +89,64 @@ def main() -> None:
|
||||||
print('Title:', title)
|
print('Title:', title)
|
||||||
correct = input().strip()
|
correct = input().strip()
|
||||||
|
|
||||||
parsed: Optional[ParseResult] = None
|
|
||||||
|
|
||||||
if correct == '!--':
|
if correct == '!--':
|
||||||
parsed = manual_info_input()
|
manual_info_input()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
if correct != '':
|
if correct != '':
|
||||||
title = correct.lower()
|
title = correct.lower()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
url = search_azurl(title)
|
url = search_azurl(title)
|
||||||
print(url)
|
print(url)
|
||||||
parsed = parse_azlyrics(url)
|
parse_azlyrics(url)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
|
||||||
print(err)
|
print(err)
|
||||||
print(
|
|
||||||
'In most cases, this error means '
|
if isinstance(err, ParseError) \
|
||||||
'the script have received some incorrect data, '
|
and err.parsing_obj == 'edit':
|
||||||
'so you should enter song info manually.'
|
pass
|
||||||
)
|
|
||||||
parsed = manual_info_input()
|
else:
|
||||||
|
print(
|
||||||
|
'In most cases, this error means that '
|
||||||
|
'the script have received some incorrect data, '
|
||||||
|
'so you should enter song info manually.'
|
||||||
|
)
|
||||||
|
|
||||||
|
manual_info_input(False)
|
||||||
|
|
||||||
#print(parsed)
|
#print(parsed)
|
||||||
tagmp3(file, parsed, copy)
|
tagmp3(file, parsed, copy)
|
||||||
|
|
||||||
|
|
||||||
|
def input(msg: str = '', def_: Any = '') -> str:
|
||||||
|
|
||||||
|
subprocess.call(
|
||||||
|
(
|
||||||
|
f'read -e -r -i "{def_}" -p "{msg}" input; '
|
||||||
|
'echo -n "$input" >./input'
|
||||||
|
),
|
||||||
|
shell=True,
|
||||||
|
executable='bash',
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open('./input', 'rt', encoding='utf-8') as f:
|
||||||
|
return f.read() \
|
||||||
|
.removesuffix('\n') \
|
||||||
|
.removesuffix('\r')
|
||||||
|
except Exception:
|
||||||
|
return def_
|
||||||
|
|
||||||
|
|
||||||
def input_num(msg: str, def_: int = 0) -> int:
|
def input_num(msg: str, def_: int = 0) -> int:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return int(input(msg))
|
return int(input(msg, def_))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return def_
|
return def_
|
||||||
|
|
||||||
|
@ -149,17 +192,15 @@ def search_azurl(title: str) -> str:
|
||||||
'https://searx.dc09.ru/search',
|
'https://searx.dc09.ru/search',
|
||||||
params={
|
params={
|
||||||
'q': f'{title} site:azlyrics.com',
|
'q': f'{title} site:azlyrics.com',
|
||||||
'category_general': 1,
|
|
||||||
'language': 'ru-RU',
|
'language': 'ru-RU',
|
||||||
'time_range': '',
|
|
||||||
'safesearch': 0,
|
'safesearch': 0,
|
||||||
'theme': 'simple',
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
soup = BeautifulSoup(page.text, 'html.parser')
|
soup = BeautifulSoup(page.text, 'html.parser')
|
||||||
link = soup.select_one(
|
link = soup.select_one(
|
||||||
'div#urls>article>h3>a[href*="azlyrics.com/lyrics/"]'
|
'div#urls>article>h3>a'
|
||||||
|
'[href*="azlyrics.com/lyrics/"]'
|
||||||
)
|
)
|
||||||
|
|
||||||
if link is None:
|
if link is None:
|
||||||
|
@ -168,16 +209,9 @@ def search_azurl(title: str) -> str:
|
||||||
return str(link.get('href'))
|
return str(link.get('href'))
|
||||||
|
|
||||||
|
|
||||||
def parse_azlyrics(link: str) -> ParseResult:
|
def parse_azlyrics(link: str) -> None:
|
||||||
|
|
||||||
result = ParseResult(
|
global parsed
|
||||||
title='', artist='',
|
|
||||||
album='', year=0,
|
|
||||||
track_no=0, tracks=0,
|
|
||||||
lyrics='',
|
|
||||||
cover=None,
|
|
||||||
cover_mime=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
print('Please wait...')
|
print('Please wait...')
|
||||||
|
|
||||||
|
@ -192,19 +226,23 @@ def parse_azlyrics(link: str) -> ParseResult:
|
||||||
)
|
)
|
||||||
if lyrics is None:
|
if lyrics is None:
|
||||||
raise ParseError('song lyrics')
|
raise ParseError('song lyrics')
|
||||||
result['lyrics'] = lyrics.get_text().strip()
|
parsed['lyrics'] = lyrics.get_text().strip()
|
||||||
|
|
||||||
artist_elem = soup.select_one(f'{LYRICS_ROW}>.lyricsh>h2')
|
lyrics_file = Path('.') / 'lyrics.txt'
|
||||||
if artist_elem is None:
|
with lyrics_file.open('wt', encoding='utf-8') as f:
|
||||||
raise ParseError('artist name')
|
f.write(parsed['lyrics'])
|
||||||
result['artist'] = artist_elem.get_text() \
|
|
||||||
.removesuffix(' Lyrics') \
|
|
||||||
.strip()
|
|
||||||
|
|
||||||
title_elem = soup.select_one(f'{LYRICS_ROW}>b')
|
title_elem = soup.select_one(f'{LYRICS_ROW}>b')
|
||||||
if title_elem is None:
|
if title_elem is None:
|
||||||
raise ParseError('song title')
|
raise ParseError('song title')
|
||||||
result['title'] = title_elem.get_text().strip('" ')
|
parsed['title'] = title_elem.get_text().strip('" ')
|
||||||
|
|
||||||
|
artist_elem = soup.select_one(f'{LYRICS_ROW}>.lyricsh>h2')
|
||||||
|
if artist_elem is None:
|
||||||
|
raise ParseError('artist name')
|
||||||
|
parsed['artist'] = artist_elem.get_text() \
|
||||||
|
.removesuffix(' Lyrics') \
|
||||||
|
.strip()
|
||||||
|
|
||||||
album_blocks = soup.select('.songinalbum_title')
|
album_blocks = soup.select('.songinalbum_title')
|
||||||
album = None
|
album = None
|
||||||
|
@ -223,8 +261,8 @@ def parse_azlyrics(link: str) -> ParseResult:
|
||||||
if album_re is None:
|
if album_re is None:
|
||||||
raise ParseError('album name')
|
raise ParseError('album name')
|
||||||
|
|
||||||
result['album'] = album_re[1]
|
parsed['album'] = album_re[1]
|
||||||
result['year'] = int(album_re[2])
|
parsed['year'] = int(album_re[2])
|
||||||
|
|
||||||
cover = album.select_one('img.album-image')
|
cover = album.select_one('img.album-image')
|
||||||
|
|
||||||
|
@ -235,8 +273,8 @@ def parse_azlyrics(link: str) -> ParseResult:
|
||||||
cover_url = BASEURL + cover_url
|
cover_url = BASEURL + cover_url
|
||||||
|
|
||||||
req = session.get(cover_url)
|
req = session.get(cover_url)
|
||||||
result['cover'] = req.content
|
parsed['cover'] = req.content
|
||||||
result['cover_mime'] = req.headers.get(
|
parsed['cover_mime'] = req.headers.get(
|
||||||
'Content-Type', 'image/jpeg'
|
'Content-Type', 'image/jpeg'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -246,14 +284,14 @@ def parse_azlyrics(link: str) -> ParseResult:
|
||||||
tracklist = tracklist_elem.select(
|
tracklist = tracklist_elem.select(
|
||||||
'.listalbum-item'
|
'.listalbum-item'
|
||||||
)
|
)
|
||||||
result['tracks'] = len(tracklist)
|
parsed['tracks'] = len(tracklist)
|
||||||
|
|
||||||
current_url = re.search(
|
current_url = re.search(
|
||||||
r'/(lyrics/.+?\.html)',
|
r'/(lyrics/.+?\.html)',
|
||||||
link,
|
link,
|
||||||
)
|
)
|
||||||
|
|
||||||
result['track_no'] = 0
|
parsed['track_no'] = 0
|
||||||
if current_url is not None:
|
if current_url is not None:
|
||||||
for i, track in enumerate(tracklist):
|
for i, track in enumerate(tracklist):
|
||||||
|
|
||||||
|
@ -263,23 +301,32 @@ def parse_azlyrics(link: str) -> ParseResult:
|
||||||
|
|
||||||
track_href = str(track_url.get('href'))
|
track_href = str(track_url.get('href'))
|
||||||
if current_url[0] in track_href:
|
if current_url[0] in track_href:
|
||||||
result['track_no'] = (i + 1)
|
parsed['track_no'] = (i + 1)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
print('Succesfully parsed')
|
||||||
|
print('Title:', parsed['title'])
|
||||||
|
print('Artist:', parsed['artist'])
|
||||||
|
print('Album:', parsed['album'])
|
||||||
|
print('Track:', parsed['track_no'], '/', parsed['tracks'])
|
||||||
|
print('Correct something?')
|
||||||
|
|
||||||
return result
|
if input('[y/N] ').lower == 'y':
|
||||||
|
manual_info_input(False)
|
||||||
|
else:
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
def manual_info_input() -> ParseResult:
|
def manual_info_input(overwrite_lyrics: bool = True) -> None:
|
||||||
|
|
||||||
result = ParseResult(
|
global parsed
|
||||||
title=input('Song title: '),
|
|
||||||
artist=input('Artist name: '),
|
parsed['title'] = input('Song title: ', parsed['title'])
|
||||||
album=input('Album name: '),
|
parsed['artist'] = input('Artist name: ', parsed['artist'])
|
||||||
year=input_num('Release year: '),
|
parsed['album'] = input('Album name: ', parsed['album'])
|
||||||
track_no=input_num('Track #'),
|
parsed['year'] = input_num('Release year: ', parsed['year'])
|
||||||
tracks=input_num('Tracks in album: '),
|
parsed['track_no'] = input_num('Track #', parsed['track_no'])
|
||||||
lyrics='', cover=None, cover_mime=None,
|
parsed['tracks'] = input_num('Tracks in album: ', parsed['tracks'])
|
||||||
)
|
|
||||||
|
|
||||||
editor = os.getenv('EDITOR', 'nano')
|
editor = os.getenv('EDITOR', 'nano')
|
||||||
print('Now, paste the lyrics into a text editor')
|
print('Now, paste the lyrics into a text editor')
|
||||||
|
@ -292,8 +339,10 @@ def manual_info_input() -> ParseResult:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
lyrics_file = Path('.') / 'lyrics.txt'
|
lyrics_file = Path('.') / 'lyrics.txt'
|
||||||
with lyrics_file.open('wt') as f:
|
|
||||||
f.write('\n')
|
if overwrite_lyrics or not lyrics_file.exists():
|
||||||
|
with lyrics_file.open('wt') as f:
|
||||||
|
f.write('\n')
|
||||||
|
|
||||||
subprocess.call([
|
subprocess.call([
|
||||||
editor,
|
editor,
|
||||||
|
@ -302,14 +351,14 @@ def manual_info_input() -> ParseResult:
|
||||||
|
|
||||||
print('Reading file...')
|
print('Reading file...')
|
||||||
with open('lyrics.txt', 'rt', encoding='utf-8') as f:
|
with open('lyrics.txt', 'rt', encoding='utf-8') as f:
|
||||||
result['lyrics'] = f.read().strip()
|
parsed['lyrics'] = f.read().strip()
|
||||||
print('Done')
|
print('Done')
|
||||||
|
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
logging.exception(err)
|
logging.exception(err)
|
||||||
|
|
||||||
cover = input('Insert an album cover? [Y/n] ')
|
cover = input('Insert an album cover? [Y/n] ')
|
||||||
if cover.lower() not in ('n','н'):
|
if cover.lower() != 'n':
|
||||||
try:
|
try:
|
||||||
print(
|
print(
|
||||||
'Download the cover and enter its path:',
|
'Download the cover and enter its path:',
|
||||||
|
@ -319,16 +368,16 @@ def manual_info_input() -> ParseResult:
|
||||||
cover_file = Path(input().strip())
|
cover_file = Path(input().strip())
|
||||||
|
|
||||||
with cover_file.open('rb') as f:
|
with cover_file.open('rb') as f:
|
||||||
result['cover'] = f.read()
|
parsed['cover'] = f.read()
|
||||||
|
|
||||||
result['cover_mime'] = (
|
parsed['cover_mime'] = (
|
||||||
mimetypes.guess_type(cover_file)[0]
|
mimetypes.guess_type(cover_file)[0]
|
||||||
or 'image/jpeg'
|
or 'image/jpeg'
|
||||||
)
|
)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logging.exception(err)
|
logging.exception(err)
|
||||||
|
|
||||||
return result
|
print()
|
||||||
|
|
||||||
|
|
||||||
def tagmp3(
|
def tagmp3(
|
||||||
|
|
|
@ -20,3 +20,5 @@ echo
|
||||||
|
|
||||||
find "$directory" -type f -name "*.mp3" -exec \
|
find "$directory" -type f -name "*.mp3" -exec \
|
||||||
python3 ./.id3tag_helper.py "$copy_arg" {} \;
|
python3 ./.id3tag_helper.py "$copy_arg" {} \;
|
||||||
|
|
||||||
|
rm -f ./input
|
||||||
|
|
Reference in a new issue