2022-11-08 21:23:19 +02:00
|
|
|
import src.fw_api
|
2023-08-12 04:12:50 +03:00
|
|
|
from src.utils import download_track, print_there, track_info_output, indices
|
2022-11-10 02:23:46 +02:00
|
|
|
from src.settings import get_config
|
2022-11-01 12:15:28 +02:00
|
|
|
from loguru import logger
|
2022-11-08 20:02:07 +02:00
|
|
|
from pyfzf.pyfzf import FzfPrompt
|
2022-12-22 12:27:23 +02:00
|
|
|
from shutil import get_terminal_size
|
2023-06-04 13:52:50 +03:00
|
|
|
from shlex import quote
|
2023-08-12 04:12:50 +03:00
|
|
|
from contextlib import suppress
|
2022-11-02 02:05:08 +02:00
|
|
|
import mpv
|
2022-12-08 01:36:45 +02:00
|
|
|
import time
|
2023-01-26 19:03:04 +02:00
|
|
|
import re
|
2023-07-08 12:14:16 +03:00
|
|
|
import requests
|
2022-11-02 02:05:08 +02:00
|
|
|
|
2022-11-08 20:02:07 +02:00
|
|
|
fzf = FzfPrompt()
|
|
|
|
|
2023-03-02 19:58:22 +02:00
|
|
|
if get_config('enable_persistent_cache'):
|
2023-06-13 16:18:07 +03:00
|
|
|
player = mpv.MPV(cache=True,
|
|
|
|
scripts='src/mpv_scripts/mpv_cache.lua:src/mpv_scripts/streamsave.lua',
|
|
|
|
script_opts='streamsave-save_directory=cache,streamsave-dump_mode=continuous,streansave-force_extension=.mkv,streamsave-autostart=no,output_label=overwrite')
|
2023-03-04 02:25:09 +02:00
|
|
|
player.command('script-message', 'streamsave-path', 'cache')
|
2023-03-02 19:58:22 +02:00
|
|
|
else:
|
|
|
|
player = mpv.MPV(cache=True, demuxer_max_bytes=25*1024*1024)
|
2022-12-18 03:02:53 +02:00
|
|
|
player.ytdl = False # Prevent attempts load track with yt-dlp
|
|
|
|
player.volume = get_config('mpv_volume')
|
|
|
|
player.prefetch_playlist = get_config('prefetch_playlist')
|
2022-11-13 04:16:46 +02:00
|
|
|
show_like_button = get_config('show_like_button')
|
2023-07-30 16:33:05 +03:00
|
|
|
share_to_fediverse_token = get_config('share_to_fediverse_token')
|
|
|
|
share_to_fediverse_instance = get_config('share_to_fediverse_instance')
|
2023-06-15 17:43:36 +03:00
|
|
|
shuffle = False
|
2022-11-08 20:02:07 +02:00
|
|
|
|
2023-08-03 18:31:07 +03:00
|
|
|
if get_config('termux_handle_track_switch_by_volume'):
|
|
|
|
import src.android_termux_api
|
|
|
|
|
2022-11-14 22:28:01 +02:00
|
|
|
|
|
|
|
class player_fw_storage:
|
|
|
|
storage = {}
|
2023-08-11 03:12:01 +03:00
|
|
|
menu_ctx = None
|
|
|
|
menu_ctx_args = None
|
2022-11-14 22:28:01 +02:00
|
|
|
|
|
|
|
|
2022-12-08 01:36:45 +02:00
|
|
|
@logger.catch
|
2022-11-18 12:22:55 +02:00
|
|
|
def track_url_to_uuid(listen_url=None):
|
2022-11-18 17:57:25 +02:00
|
|
|
'''Attempt get uuid from track listen url or current playing url'''
|
2023-01-26 19:03:04 +02:00
|
|
|
hex = '[0-9a-fA-F]+'
|
|
|
|
find_uuid = f'{hex}-{hex}-{hex}-{hex}-{hex}'
|
|
|
|
|
2022-11-18 12:22:55 +02:00
|
|
|
if listen_url:
|
2023-01-26 19:03:04 +02:00
|
|
|
uuid = re.findall(find_uuid, listen_url)
|
2022-11-18 12:22:55 +02:00
|
|
|
else:
|
2023-01-26 19:03:04 +02:00
|
|
|
uuid = re.findall(find_uuid, player.stream_open_filename)
|
|
|
|
|
|
|
|
return uuid[0]
|
2022-11-18 12:22:55 +02:00
|
|
|
|
|
|
|
|
2023-07-30 16:33:05 +03:00
|
|
|
def send_listen_activity():
|
|
|
|
try:
|
|
|
|
track = player_fw_storage.storage.get(track_url_to_uuid())
|
|
|
|
except:
|
|
|
|
return
|
|
|
|
if src.fw_api.current_instance.token is not None:
|
|
|
|
track_id = track.get('id')
|
|
|
|
|
|
|
|
if track_id:
|
|
|
|
src.fw_api.record_track_in_history(track_id)
|
|
|
|
else:
|
|
|
|
logger.error("Can't write track to history: No track id")
|
|
|
|
if share_to_fediverse_token != '':
|
|
|
|
fid = track.get('fid')
|
|
|
|
artist = track['artist'].get('name')
|
|
|
|
album = track['album'].get('title')
|
|
|
|
title = track.get('title')
|
|
|
|
tags = track.get('tags')
|
|
|
|
if tags:
|
|
|
|
tags = [f'#{tag}' for tag in tags]
|
|
|
|
tags = ' '.join(tags)
|
|
|
|
if tags == []:
|
|
|
|
tags = ''
|
2023-08-03 11:35:37 +03:00
|
|
|
status_obj = {'spoiler_text': 'funkwlmpv music share',
|
2023-07-30 16:33:05 +03:00
|
|
|
'visibility': 'unlisted',
|
|
|
|
'status': f'🎧 {artist} - {album} - {title}\n{fid}\n#NowPlaying {tags}'}
|
|
|
|
requests.post(f'https://{share_to_fediverse_instance}/api/v1/statuses',
|
|
|
|
json=status_obj,
|
|
|
|
headers={'Authorization': f'Bearer {share_to_fediverse_token}'})
|
2022-12-08 01:36:45 +02:00
|
|
|
|
|
|
|
|
2023-06-11 02:06:44 +03:00
|
|
|
def osd_observer(value):
|
2022-12-20 03:07:08 +02:00
|
|
|
'''Sumulate osd playing message in console'''
|
|
|
|
if value:
|
|
|
|
osd_message = []
|
|
|
|
for i in value.items():
|
|
|
|
if i[0] in ('Artist', 'Album', 'Title'):
|
|
|
|
osd_message.append(i[1])
|
2023-06-11 02:06:44 +03:00
|
|
|
osd_string = ' - '.join(osd_message)
|
2022-12-22 12:27:23 +02:00
|
|
|
term_len = get_terminal_size().columns
|
2023-06-11 02:06:44 +03:00
|
|
|
print_there(0, 0, '\r'+' '*term_len)
|
2022-12-22 13:37:27 +02:00
|
|
|
print_there(0, 0, '\r'+osd_string[:term_len])
|
2023-06-11 02:06:44 +03:00
|
|
|
else:
|
|
|
|
print_there(0, 0, '\rNo metadata...')
|
2022-12-21 22:08:46 +02:00
|
|
|
|
|
|
|
|
2022-12-30 01:43:11 +02:00
|
|
|
@player.event_callback('start-file')
|
2022-12-22 02:23:09 +02:00
|
|
|
@logger.catch
|
2022-12-30 01:43:11 +02:00
|
|
|
def starting_file_handler(value):
|
2022-12-22 02:23:09 +02:00
|
|
|
'''just show loading state'''
|
2022-12-30 01:43:11 +02:00
|
|
|
print_there(0, 0, '\rLoading track...')
|
2022-12-22 02:23:09 +02:00
|
|
|
|
|
|
|
|
2022-12-21 22:08:46 +02:00
|
|
|
@player.property_observer('percent-pos')
|
|
|
|
@logger.catch
|
|
|
|
def universal_observer(_name, value):
|
|
|
|
if value:
|
2022-12-24 18:39:53 +02:00
|
|
|
percent = int(value)
|
2022-12-21 22:08:46 +02:00
|
|
|
if player.audio_bitrate:
|
2022-12-24 18:39:53 +02:00
|
|
|
kbps = int(player.audio_bitrate/1024)
|
2022-12-21 22:08:46 +02:00
|
|
|
else:
|
|
|
|
kbps = '?'
|
2022-12-22 12:27:23 +02:00
|
|
|
if player.file_size:
|
|
|
|
track_size = round(player.file_size/1024/1024, 1)
|
|
|
|
else:
|
|
|
|
track_size = '?'
|
|
|
|
if player.cache_speed:
|
2022-12-30 01:23:26 +02:00
|
|
|
speed_load = player.cache_speed
|
|
|
|
if speed_load >= 3*1024*1024:
|
|
|
|
cache_speed = '| <<<'
|
|
|
|
elif speed_load >= 1*1024*1024:
|
|
|
|
cache_speed = '| <<*'
|
|
|
|
else:
|
|
|
|
cache_speed = '| <=>'
|
2022-12-22 12:27:23 +02:00
|
|
|
else:
|
|
|
|
cache_speed = ''
|
2022-12-24 18:39:53 +02:00
|
|
|
if player.playlist_count > -1:
|
2022-12-30 00:54:36 +02:00
|
|
|
player_pos = f'{player.playlist_pos_1}/{player.playlist_count}'
|
2022-12-24 18:39:53 +02:00
|
|
|
else:
|
|
|
|
player_pos = '-/-'
|
2023-06-11 02:06:44 +03:00
|
|
|
osd_observer(player.filtered_metadata)
|
2022-12-22 12:27:23 +02:00
|
|
|
print_there(2, 2, f'\r'+' '*get_terminal_size().columns)
|
2022-12-24 18:39:53 +02:00
|
|
|
print_there(2, 2, f'\r{player_pos} | {kbps} kbps | {percent}% | {track_size}MB {cache_speed}')
|
2022-12-21 22:08:46 +02:00
|
|
|
time.sleep(1)
|
2022-12-20 03:07:08 +02:00
|
|
|
|
|
|
|
|
2023-06-11 15:10:24 +03:00
|
|
|
def soft_volume_reduce():
|
|
|
|
while player.volume > 10:
|
|
|
|
player.volume = player.volume - 1
|
|
|
|
time.sleep(0.050)
|
|
|
|
|
|
|
|
|
2022-11-08 20:37:43 +02:00
|
|
|
@logger.catch
|
2022-11-14 22:28:01 +02:00
|
|
|
def player_menu(header='', storage={}):
|
2023-08-12 04:12:50 +03:00
|
|
|
for i in player.playlist_filenames:
|
|
|
|
count_same_tracks = indices(player.playlist_filenames, i)
|
|
|
|
while len(count_same_tracks) > 1:
|
|
|
|
with suppress(SystemError):
|
|
|
|
player.playlist_remove(count_same_tracks[-1])
|
|
|
|
count_same_tracks = indices(player.playlist_filenames, i)
|
2022-12-08 01:24:48 +02:00
|
|
|
player_fw_storage.storage.update(storage)
|
2022-11-15 01:02:22 +02:00
|
|
|
player.volume = get_config("mpv_volume")
|
2023-06-15 17:43:36 +03:00
|
|
|
global shuffle
|
2022-11-08 20:02:07 +02:00
|
|
|
while True:
|
|
|
|
try:
|
2022-11-13 04:16:46 +02:00
|
|
|
player_items_menu = ['Next', 'Prev', 'Pause',
|
2023-08-14 09:59:27 +03:00
|
|
|
'Shuffle', 'Download', 'Info', 'Share', 'Jump to']
|
2022-11-29 20:56:33 +02:00
|
|
|
if player.pause:
|
|
|
|
player_items_menu[2] = 'Play'
|
|
|
|
else:
|
|
|
|
player_items_menu[2] = 'Pause'
|
2023-06-15 17:43:36 +03:00
|
|
|
if shuffle:
|
|
|
|
player_items_menu[3] = 'Unshuffle'
|
|
|
|
else:
|
|
|
|
player_items_menu[3] = 'Shuffle'
|
2022-11-13 04:16:46 +02:00
|
|
|
if show_like_button:
|
|
|
|
player_items_menu.append('Like')
|
2023-08-11 03:12:01 +03:00
|
|
|
if player_fw_storage.menu_ctx:
|
|
|
|
player_items_menu.append('Add more tracks')
|
2022-11-13 04:16:46 +02:00
|
|
|
player_items_menu.extend(['Hide artist', 'Exit'])
|
|
|
|
|
2023-06-15 00:52:34 +03:00
|
|
|
select = fzf.prompt(player_items_menu, quote(f"--header=\'{header}\'"))
|
|
|
|
if select == []:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
select = select[0]
|
|
|
|
|
2022-11-08 20:02:07 +02:00
|
|
|
if select == 'Next':
|
2022-12-20 03:33:29 +02:00
|
|
|
try:
|
|
|
|
player.playlist_next()
|
|
|
|
except:
|
|
|
|
print('No more next tracks')
|
2022-11-08 20:02:07 +02:00
|
|
|
elif select == 'Prev':
|
|
|
|
player.playlist_prev()
|
2022-11-29 20:56:33 +02:00
|
|
|
elif select in ('Pause', 'Play'):
|
2023-06-15 17:43:36 +03:00
|
|
|
player.cycle('pause')
|
|
|
|
elif select in ('Shuffle', 'Unshuffle'):
|
|
|
|
if shuffle:
|
|
|
|
shuffle = False
|
|
|
|
player.playlist_unshuffle()
|
2022-11-08 20:02:07 +02:00
|
|
|
else:
|
2023-06-15 17:43:36 +03:00
|
|
|
shuffle = True
|
|
|
|
player.playlist_shuffle()
|
2023-06-21 02:50:45 +03:00
|
|
|
player.playlist_play_index(0)
|
2022-11-08 20:02:07 +02:00
|
|
|
elif select == 'Download':
|
2022-11-18 17:57:25 +02:00
|
|
|
name_downloaded = download_track(player.stream_open_filename)
|
2022-11-08 20:02:07 +02:00
|
|
|
elif select == 'Info':
|
2022-12-08 01:24:48 +02:00
|
|
|
track = player_fw_storage.storage.get(track_url_to_uuid())
|
2023-06-14 17:37:36 +03:00
|
|
|
track['direct_url'] = player.stream_open_filename
|
2023-06-11 00:54:26 +03:00
|
|
|
track_info_output(track)
|
2023-07-30 16:33:05 +03:00
|
|
|
elif select == 'Share':
|
|
|
|
send_listen_activity()
|
2023-08-14 09:59:27 +03:00
|
|
|
elif select == 'Jump to':
|
|
|
|
jump_to_idx = int(fzf.prompt(range(1, len(player.playlist_filenames)+1))[0])
|
|
|
|
jump_to_idx -= 1
|
|
|
|
player.playlist_play_index(jump_to_idx)
|
2022-11-13 04:16:46 +02:00
|
|
|
elif select == 'Like':
|
2022-12-18 03:02:53 +02:00
|
|
|
src.fw_api.favorite_track(
|
|
|
|
player_fw_storage.storage.get(track_url_to_uuid())['id'])
|
2023-08-11 03:12:01 +03:00
|
|
|
elif select == 'Add more tracks':
|
2023-08-12 04:21:52 +03:00
|
|
|
player_fw_storage.menu_ctx(*player_fw_storage.menu_ctx_args)
|
2022-11-08 21:23:19 +02:00
|
|
|
elif select == 'Hide artist':
|
2022-12-08 01:24:48 +02:00
|
|
|
track = player_fw_storage.storage.get(track_url_to_uuid())
|
2023-08-10 22:16:58 +03:00
|
|
|
player.playlist_remove('current')
|
2022-12-18 03:02:53 +02:00
|
|
|
src.fw_api.hide_content(
|
|
|
|
{'target': {'id': track.get('artist').get('id'), 'type': 'artist'}})
|
2022-11-08 20:02:07 +02:00
|
|
|
elif select == 'Exit':
|
2023-06-28 19:33:45 +03:00
|
|
|
shuffle = False
|
2023-06-11 15:10:24 +03:00
|
|
|
soft_volume_reduce()
|
2022-11-08 20:02:07 +02:00
|
|
|
player.playlist_clear()
|
|
|
|
player.stop()
|
2022-12-08 01:24:48 +02:00
|
|
|
player_fw_storage.storage = {}
|
2022-11-08 20:02:07 +02:00
|
|
|
break
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
break
|
|
|
|
|
2022-12-17 03:16:36 +02:00
|
|
|
|
|
|
|
def play_track(track, multi=False):
|
|
|
|
listen_url = src.fw_api.get_audio_file(track['listen_url'], True)
|
|
|
|
player_fw_storage.storage[track_url_to_uuid(listen_url)] = track
|
|
|
|
if multi:
|
|
|
|
player.loadfile(listen_url, 'append-play')
|
|
|
|
else:
|
|
|
|
player.loadfile(listen_url, 'append-play')
|
|
|
|
track_name = track.get('title')
|
|
|
|
player_menu(f"{track_name} playing...", player_fw_storage.storage)
|