Manual info correction, input() using readline

This commit is contained in:
DarkCat09 2023-02-08 14:07:51 +04:00
parent 450421ce0d
commit 9687313cb4
3 changed files with 114 additions and 59 deletions

6
.gitignore vendored
View file

@ -1,5 +1,9 @@
files/ files/
convert/ convert/
tagged/ tagged/
.vscode/
lyrics.txt lyrics.txt
input
__pycache__/
.vscode/
.idea/

View file

@ -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(

View file

@ -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