feat: Load language file in lang/ instead of the ini file.
This commit is contained in:
parent
e84607b8e8
commit
9e2e09e5fd
@ -20,6 +20,7 @@ steps:
|
||||
- echo "current git commit is $version"
|
||||
- echo $version > /mnt/botamusique/testing-version
|
||||
- sed -i "s/version = 'git'/version = '$version'/" mumbleBot.py
|
||||
- ./lang/translate.py
|
||||
- rm -rf .git*
|
||||
- rm -rf web
|
||||
- mkdir /tmp/botamusique
|
||||
|
@ -6,7 +6,8 @@ import json
|
||||
import re
|
||||
import pymumble_py3 as pymumble
|
||||
|
||||
from constants import tr, commands
|
||||
from constants import tr_cli as tr
|
||||
from constants import commands
|
||||
import interface
|
||||
import media.system
|
||||
import util
|
||||
|
@ -195,159 +195,3 @@ list_webinterface_user = webuserlist
|
||||
add_webinterface_user = webuseradd
|
||||
remove_webinterface_user = webuserdel
|
||||
change_user_password = password
|
||||
|
||||
[strings]
|
||||
current_volume = Current volume: {volume}.
|
||||
current_ducking_volume = Volume on ducking: {volume}.
|
||||
change_volume = Volume set to {volume} by {user}.
|
||||
change_ducking_volume = Volume on ducking set to {volume} by {user}.
|
||||
bad_command = {command}: command not found.
|
||||
bad_parameter = {command}: invalid parameter.
|
||||
error_executing_command = {command}: Command failed with error: {error}.
|
||||
not_admin = You are not an admin!
|
||||
not_playing = Nothing is playing right now.
|
||||
no_file = File not found.
|
||||
wrong_pattern = Invalid regex: {error}.
|
||||
file_added = Added {item}.
|
||||
file_deleted = Deleted {item} from the library.
|
||||
multiple_file_added = Multiple items added:
|
||||
multiple_file_deleted = Multiple items deleted from the library:
|
||||
multiple_file_found = Found:
|
||||
page_instruction = Page {current}/{total}. Use <i>!{command} {{page}}</i> to navigate.
|
||||
records_omitted = ...
|
||||
bad_url = Bad URL requested.
|
||||
preconfigurated_radio = Preconfigurated Radio available:
|
||||
unable_download = Unable to download <b>{item}</b>. Removed from the library.
|
||||
unable_play = Unable to play <b>{item}</b>. Removed from the library.
|
||||
which_command = Do you mean <br /> {commands}
|
||||
multiple_matches = File not found! Possible candidates:
|
||||
queue_contents = Items on the playlist:
|
||||
queue_empty = Playlist is empty!
|
||||
invalid_index = Invalid index <i>{index}</i>. Use '!queue' to see your playlist.
|
||||
now_playing = Playing {item}
|
||||
radio = Radio
|
||||
file = File
|
||||
url_from_playlist = URL
|
||||
url = URL
|
||||
radio_item = <a href="{url}"><b>{title}</b></a> <i>from</i> {name} <i>added by</i> {user}
|
||||
file_item = <b>{artist} - {title}</b> <i>added by</i> {user}
|
||||
url_from_playlist_item = <a href="{url}"><b>{title}</b></a> <i>from playlist</i> <a href="{playlist_url}">{playlist}</a> <i>added by</i> {user}
|
||||
url_item = <a href="{url}"><b>{title}</b></a> <i>added by</i> {user}
|
||||
not_in_my_channel = You're not in my channel, command refused!
|
||||
pm_not_allowed = Private message aren't allowed.
|
||||
too_long = <b>{song}</b> is too long, removed from playlist!
|
||||
download_in_progress = Download of <b>{item}</b> in progress...
|
||||
removing_item = Removed entry {item} from playlist.
|
||||
user_ban = You are banned, not allowed to do that!
|
||||
url_ban = This url is banned!
|
||||
rb_query_result = This is the result of your query, send !rbplay 'ID' to play a station:
|
||||
rb_play_empty = Please specify a radio station ID!
|
||||
paused = Music paused.
|
||||
stopped = Music stopped.
|
||||
cleared = Playlist emptied.
|
||||
database_dropped = Database dropped. All records have gone.
|
||||
new_version_found = <h2>Update Available!</h2> Version {new_version} of botamusique is available! <hr />
|
||||
<h3>Changelog</h3> {changelog} <hr /> Send <i>!update</i> to update!
|
||||
update_successful = <h2>botamusique v{version} Installed!</h2><hr />
|
||||
<h3>Changelog</h3> {changelog} <hr /> Visit <a href="https://github.com/azlux/botamusique">our github repo</a> for more details!
|
||||
start_updating = Start updating...
|
||||
file_missed = Music file '{file}' missed! This item has been removed from the playlist.
|
||||
unknown_mode = Unknown playback mode '{mode}'. It should be one of <i>one-shot</i>, <i>repeat</i>, <i>random</i>.
|
||||
current_mode = Current playback mode is <i>{mode}</i>.
|
||||
change_mode = Playback mode set to <i>{mode}</i> by {user}.
|
||||
repeat = Repeat {song} for {n} times.
|
||||
yt_result = Youtube query result: {result_table} Use <i>!sl {{indexes}}</i> to play the item you want. <br />
|
||||
<i>!ytquery -n</i> for the next page.
|
||||
yt_no_more = No more results!
|
||||
yt_query_error = Unable to query youtube!
|
||||
playlist_fetching_failed = Unable to fetch the playlist!
|
||||
cache_refreshed = Cache refreshed!
|
||||
added_tags = Added tags <i>{tags}</i> to <b>{song}</b>.
|
||||
added_tags_to_all = Added tags <i>{tags}</i> to songs on the playlist.
|
||||
removed_tags = Removed tags <i>{tags}</i> from <b>{song}</b>.
|
||||
removed_tags_from_all = Removed tags <i>{tags}</i> from songs on the playlist.
|
||||
cleared_tags = Removed all tags from <b>{song}</b>.
|
||||
cleared_tags_from_all = Removed all tags from songs on the playlist.
|
||||
shortlist_instruction = Use <i>!sl {indexes}</i> to play the item you want.
|
||||
auto_paused = Use <i>!play</i> to resume music!
|
||||
webpage_address= Your own address to access the web interface is <a href="{address}">{address}</a>
|
||||
web_user_list = Following users has the privilege to access the web interface: <br /> {users}
|
||||
user_password_set = Your password has been updated.
|
||||
command_disabled = {command}: command disabled!
|
||||
|
||||
help = <h3>Commands</h3>
|
||||
<b>Control</b>
|
||||
<ul>
|
||||
<li> <b>!<u>w</u>eb</b> - get the URL of the web interface, if enabled. </li>
|
||||
<li> <b>!play </b> (or <b>!p</b>) [{num}] [{start_from}] - resume from pausing / start to play (the num-th song is num if given) </li>
|
||||
<li> <b>!<u>pa</u>use </b> - pause </li>
|
||||
<li> <b>!<u>st</u>op </b> - stop playing </li>
|
||||
<li> <b>!<u>sk</u>ip </b> - jump to the next song </li>
|
||||
<li> <b>!<u>la</u>st </b> - jump to the last song </li>
|
||||
<li> <b>!<u>v</u>olume </b> {volume} - get or change the volume (from 0 to 100) </li>
|
||||
<li> <b>!<u>m</u>ode </b> [{mode}] - get or set the playback mode, {mode} should be one of <i>one-shot</i> (remove
|
||||
item once played), <i>repeat</i> (looping through the playlist), <i>random</i> (randomize the playlist),
|
||||
<i>autoplay</i> (randomly grab something from the music library).</li>
|
||||
<li> <b>!duck </b> on/off - enable or disable ducking function </li>
|
||||
<li> <b>!duckv </b> - set the volume of the bot when ducking is activated </li>
|
||||
<li> <b>!<u>duckt</u>hres </b> - set the threshold of volume to activate ducking (3000 by default) </li>
|
||||
<li> <b>!<u>o</u>ust </b> - stop playing and go to default channel </li>
|
||||
</ul>
|
||||
<b>Playlist</b>
|
||||
<ul>
|
||||
<li> <b>!<u>n</u>ow </b> (or <b>!np</b>) - display the current song </li>
|
||||
<li> <b>!<u>q</u>ueue </b> - display items in the playlist </li>
|
||||
<li> <b>!<u>t</u>ag </b> {tags} - add all items with tags {tags}, tags separated by ",". </li>
|
||||
<li> <b>!file </b>(or <b>!f</b>) {path/folder/keyword} - add a single file to the playlist by its path or keyword in its path. </li>
|
||||
<li> <b>!<u>filem</u>atch </b>(or <b>!fm</b>) {pattern} - add all files that match regex {pattern} </li>
|
||||
<li> <b>!<u>ur</u>l </b> {url} - add Youtube or SoundCloud music </li>
|
||||
<li> <b>!<u>playl</u>ist </b> {url} [{offset}] - add all items in a Youtube or SoundCloud playlist, and start with the {offset}-th item </li>
|
||||
<li> <b>!<u>rad</u>io </b> {url} - append a radio {url} to the playlist </li>
|
||||
<li> <b>!<u>rbq</u>uery </b> {keyword} - query http://www.radio-browser.info for a radio station </li>
|
||||
<li> <b>!<u>rbp</u>lay </b> {id} - play a radio station with {id} (eg. !rbplay 96746) </li>
|
||||
<li> <b>!<u>ys</u>earch </b> {keywords} - query youtube. Use <i>!ysearch -n</i> to turn the page. </li>
|
||||
<li> <b>!<u>yp</u>lay </b> {keywords} - add the first search result of {keywords} into the playlist.</li>
|
||||
<li> <b>!<u>sh</u>ortlist </b> (or <b>!sl</b>) {indexes/*} - add {indexes}-th item (or all items if * is given) on the shortlist. </li>
|
||||
<li> <b>!rm </b> {num} - remove the num-th song on the playlist </li>
|
||||
<li> <b>!<u>rep</u>eat </b> [{num}] - repeat current song {num} (1 by default) times.</li>
|
||||
<li> <b>!<u>ran</u>dom </b> - randomize the playlist.</li>
|
||||
</ul>
|
||||
<b>Music Library</b>
|
||||
<ul>
|
||||
<li> <b>!<u>se</u>arch </b> {keywords} - find item with {keywords} in the music library, keywords separated by space.</li>
|
||||
<li> <b>!<u>li</u>stfile </b> [{pattern}] - display list of available files (whose paths match the regex pattern if {pattern} is given) </li>
|
||||
<li> <b>!<u>addt</u>ag </b> [{index}] {tags} - add {tags} to {index}-th(current song if {index} is omitted) item on the playlist, tags separated by ",". </li>
|
||||
<li> <b>!<u>addt</u>ag </b> * {tags} - add {tags} to all items on the playlist. </li>
|
||||
<li> <b>!<u>un</u>tag </b> [{index/*}] {tags}/* - remove {tags}/all tags from {index}-th(current song if {index} is omitted) item on the playlist. </li>
|
||||
<li> <b>!<u>fin</u>dtagged </b> (or <b>!ft</b>) {tags} - find item with {tags} in the music library. </li>
|
||||
<li> <b>!<u>del</u>ete </b> {index} - delete {index}-th item on the shortlist from the music library. </li>
|
||||
</ul>
|
||||
<b>Other</b>
|
||||
<ul>
|
||||
<li> <b>!<u>j</u>oinme {token} </b> - join your own channel with {token}.</li>
|
||||
<li> <b>!<u>password</u> {password} </b> - change your password, used to access the web interface.</li>
|
||||
</ul>
|
||||
|
||||
admin_help = <h3>Admin command</h3>
|
||||
<b>Bot</b>
|
||||
<ul>
|
||||
<li><b>!<u>k</u>ill </b> - kill the bot</li>
|
||||
<li><b>!update </b> - update the bot</li>
|
||||
<li><b>!userban </b> {user} - ban a user</li>
|
||||
<li><b>!userunban </b> {user} - unban a user</li>
|
||||
<li><b>!urlbanlist </b> - list banned url</li>
|
||||
<li><b>!urlban </b> [{url}] - ban {url} (or current item's url by default) and remove this url from the library.</li>
|
||||
<li><b>!urlunban </b> {url} - unban {url}</li>
|
||||
<li><b>!rescan </b> {url} - rebuild local music file cache</li>
|
||||
<li><b>!dropdatabase</b> - clear the entire database, you will lose all settings and music library.</li>
|
||||
</ul>
|
||||
<b>Web Interface</b>
|
||||
<ul>
|
||||
<li><b>!<u>webuserlist</u></b> - list all users that have the permission of accessing the web interface, if auth mode is 'password'.</li>
|
||||
<li><b>!<u>webuseradd</u> {nick name}</b> - grant the user with {nick name} the access to the web interface, if auth mode is 'password'.</li>
|
||||
<li><b>!<u>webuserdel</u> {nick name}</b> - revoke the access to the web interface of {nick name}, if auth mode is 'password'.</li>
|
||||
<li><b>!update </b> - update the bot</li>
|
||||
<li><b>!userban </b> {user} - ban a user</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
@ -177,18 +177,3 @@ port = 64738
|
||||
# see configuration.default.ini. Copy options you want to edit into this file.
|
||||
#play_file = file, f
|
||||
#play_file_match = filematch, fm
|
||||
|
||||
# [strings] is used to compose what the bot says. You can customize them to fit in
|
||||
# the style of your channel, or translate into your own language.
|
||||
# For a full list of strings, please see configuration.default.ini.
|
||||
# Copy options you want to edit into this file.
|
||||
# Note: please keep those {placeholder} of each string in your new string.
|
||||
[strings]
|
||||
# Some examples are:
|
||||
#current_volume = Current volume: {volume}
|
||||
#current_volume = 当前音量为{volume}
|
||||
#current_volume = よく聞いてね!今の音量は{volume}!<br />ちゃんと覚える:大音量で耳が悪くなる!
|
||||
#
|
||||
#bad_command = {command}: command not found
|
||||
#bad_command = {command}: 未知命令,键入'!help'以获取可用命令列表
|
||||
#bad_command = {command}がなに?食べれる?おいしいでしか?
|
||||
|
40
constants.py
40
constants.py
@ -1,24 +1,45 @@
|
||||
import json
|
||||
|
||||
import variables as var
|
||||
|
||||
lang_dict = {}
|
||||
|
||||
def tr(option, *argv, **kwargs):
|
||||
|
||||
def load_lang(lang):
|
||||
global lang_dict
|
||||
with open(f"lang/{lang}", "r") as f:
|
||||
lang_dict = json.load(f)
|
||||
|
||||
|
||||
def tr_cli(option, *argv, **kwargs):
|
||||
try:
|
||||
string = var.config.get("strings", option)
|
||||
string = lang_dict['cli'][option]
|
||||
except KeyError:
|
||||
raise KeyError("Missed strings in configuration file: '{string}'. ".format(string=option)
|
||||
+ "Please restore you configuration file back to default if necessary.")
|
||||
raise KeyError("Missed strings in language file: '{string}'. ".format(string=option))
|
||||
return _tr(string, *argv, **kwargs)
|
||||
|
||||
|
||||
def tr_web(option, *argv, **kwargs):
|
||||
try:
|
||||
string = lang_dict['web'][option]
|
||||
except KeyError:
|
||||
raise KeyError("Missed strings in language file: '{string}'. ".format(string=option))
|
||||
return _tr(string, *argv, **kwargs)
|
||||
|
||||
|
||||
def _tr(string, *argv, **kwargs):
|
||||
if argv or kwargs:
|
||||
try:
|
||||
formatted = string.format(*argv, **kwargs)
|
||||
return formatted
|
||||
except KeyError as e:
|
||||
raise KeyError(
|
||||
"Missed/Unexpected placeholder {{{placeholder}}} in string '{string}'. ".format(placeholder=str(e).strip("'"), string=option)
|
||||
+ "Please restore you configuration file back to default if necessary.")
|
||||
"Missed/Unexpected placeholder {{{placeholder}}} in string "
|
||||
"'{string}'. ".format(placeholder=str(e).strip("'"),
|
||||
string=string))
|
||||
except TypeError:
|
||||
raise KeyError(
|
||||
"Missed placeholder in string '{string}'. ".format(string=option)
|
||||
+ "Please restore you configuration file back to default if necessary.")
|
||||
"Missed placeholder in string '{string}'. ".format(string=string))
|
||||
else:
|
||||
return string
|
||||
|
||||
@ -28,5 +49,4 @@ def commands(command):
|
||||
string = var.config.get("commands", command)
|
||||
return string
|
||||
except KeyError:
|
||||
raise KeyError("Missed command in configuration file: '{string}'. ".format(string=command)
|
||||
+ "Please restore you configuration file back to default if necessary.")
|
||||
raise KeyError("Missed command in configuration file: '{string}'. ".format(string=command))
|
||||
|
28
lang/translate.py
Normal file
28
lang/translate.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import requests
|
||||
|
||||
base_url = "https://translate.azlux.fr/api/v1"
|
||||
client = "be8215d4-2417-49db-9355-c418f26dc3f4"
|
||||
secret = "MIMvdnECLkmTZyCQT4DekONN53EOSsj3"
|
||||
project_id = "4aafb197-3282-47b3-a197-0ca870cf6ab2"
|
||||
|
||||
data = {"grant_type": "client_credentials",
|
||||
"client_id": client,
|
||||
"client_secret": secret}
|
||||
|
||||
r = requests.post(f"{base_url}/auth/token", json=data)
|
||||
token = r.json()["access_token"]
|
||||
|
||||
headers = {"Authorization": "Bearer " + token,
|
||||
"Accept": "application/json, text/plain, */*"}
|
||||
|
||||
r = requests.get(f"{base_url}/projects/{project_id}/translations", headers=headers)
|
||||
translations = r.json()['data']
|
||||
for translation in translations:
|
||||
lang_code = translation['locale']['code']
|
||||
params = {'locale': lang_code,
|
||||
'format': 'jsonnested'}
|
||||
r = requests.get(f"{base_url}/projects/{project_id}/exports", params=params, headers=headers)
|
||||
with open(lang_code, "wb")as f:
|
||||
f.write(r.content)
|
@ -9,7 +9,7 @@ from PIL import Image
|
||||
import util
|
||||
import variables as var
|
||||
from media.item import BaseItem, item_builders, item_loaders, item_id_generators, ValidationFailedError
|
||||
import constants
|
||||
from constants import tr_cli as tr
|
||||
|
||||
'''
|
||||
type : file
|
||||
@ -75,7 +75,7 @@ class FileItem(BaseItem):
|
||||
if not os.path.exists(self.uri()):
|
||||
self.log.info(
|
||||
"file: music file missed for %s" % self.format_debug_string())
|
||||
raise ValidationFailedError(constants.tr('file_missed', file=self.path))
|
||||
raise ValidationFailedError(tr('file_missed', file=self.path))
|
||||
|
||||
if self.duration == 0:
|
||||
self.duration = util.get_media_duration(self.uri())
|
||||
@ -185,14 +185,14 @@ class FileItem(BaseItem):
|
||||
)
|
||||
|
||||
def format_song_string(self, user):
|
||||
return constants.tr("file_item",
|
||||
title=self.title,
|
||||
artist=self.artist if self.artist else '??',
|
||||
user=user
|
||||
)
|
||||
return tr("file_item",
|
||||
title=self.title,
|
||||
artist=self.artist if self.artist else '??',
|
||||
user=user
|
||||
)
|
||||
|
||||
def format_current_playing(self, user):
|
||||
display = constants.tr("now_playing", item=self.format_song_string(user))
|
||||
display = tr("now_playing", item=self.format_song_string(user))
|
||||
if self.thumbnail:
|
||||
thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
|
||||
self.thumbnail + '"/>'
|
||||
@ -208,4 +208,4 @@ class FileItem(BaseItem):
|
||||
return title
|
||||
|
||||
def display_type(self):
|
||||
return constants.tr("file")
|
||||
return tr("file")
|
||||
|
@ -7,7 +7,7 @@ import hashlib
|
||||
|
||||
from media.item import BaseItem
|
||||
from media.item import item_builders, item_loaders, item_id_generators
|
||||
import constants
|
||||
from constants import tr_cli as tr
|
||||
|
||||
log = logging.getLogger("bot")
|
||||
|
||||
@ -147,18 +147,18 @@ class RadioItem(BaseItem):
|
||||
)
|
||||
|
||||
def format_song_string(self, user):
|
||||
return constants.tr("radio_item",
|
||||
url=self.url,
|
||||
title=get_radio_title(self.url), # the title of current song
|
||||
name=self.title, # the title of radio station
|
||||
user=user
|
||||
)
|
||||
return tr("radio_item",
|
||||
url=self.url,
|
||||
title=get_radio_title(self.url), # the title of current song
|
||||
name=self.title, # the title of radio station
|
||||
user=user
|
||||
)
|
||||
|
||||
def format_current_playing(self, user):
|
||||
return constants.tr("now_playing", item=self.format_song_string(user))
|
||||
return tr("now_playing", item=self.format_song_string(user))
|
||||
|
||||
def format_title(self):
|
||||
return self.title if self.title else self.url
|
||||
|
||||
def display_type(self):
|
||||
return constants.tr("radio")
|
||||
return tr("radio")
|
||||
|
14
media/url.py
14
media/url.py
@ -9,7 +9,7 @@ import glob
|
||||
from io import BytesIO
|
||||
import base64
|
||||
|
||||
import constants
|
||||
from constants import tr_cli as tr
|
||||
import media
|
||||
import variables as var
|
||||
from media.item import BaseItem, item_builders, item_loaders, item_id_generators, ValidationFailedError, \
|
||||
@ -99,7 +99,7 @@ class URLItem(BaseItem):
|
||||
# Check the length, useful in case of playlist, it wasn't checked before)
|
||||
log.info(
|
||||
"url: " + self.url + " has a duration of " + str(self.duration / 60) + " min -- too long")
|
||||
raise ValidationFailedError(constants.tr('too_long', song=self.title))
|
||||
raise ValidationFailedError(tr('too_long', song=self.title))
|
||||
else:
|
||||
self.ready = "validated"
|
||||
self.version += 1 # notify wrapper to save me
|
||||
@ -138,7 +138,7 @@ class URLItem(BaseItem):
|
||||
if not succeed:
|
||||
self.ready = 'failed'
|
||||
self.log.error("url: error while fetching info from the URL")
|
||||
raise ValidationFailedError(constants.tr('unable_download', item=self.format_title()))
|
||||
raise ValidationFailedError(tr('unable_download', item=self.format_title()))
|
||||
|
||||
def _download(self):
|
||||
media.system.clear_tmp_folder(var.tmp_folder, var.config.getint('bot', 'tmp_folder_max_size'))
|
||||
@ -193,7 +193,7 @@ class URLItem(BaseItem):
|
||||
os.remove(f)
|
||||
self.ready = "failed"
|
||||
self.downloading = False
|
||||
raise PreparationFailedError(constants.tr('unable_download', item=self.format_title()))
|
||||
raise PreparationFailedError(tr('unable_download', item=self.format_title()))
|
||||
|
||||
def _read_thumbnail_from_file(self, path_thumbnail):
|
||||
if os.path.isfile(path_thumbnail):
|
||||
@ -226,14 +226,14 @@ class URLItem(BaseItem):
|
||||
|
||||
def format_song_string(self, user):
|
||||
if self.ready in ['validated', 'yes']:
|
||||
return constants.tr("url_item",
|
||||
return tr("url_item",
|
||||
title=self.title if self.title else "??",
|
||||
url=self.url,
|
||||
user=user)
|
||||
return self.url
|
||||
|
||||
def format_current_playing(self, user):
|
||||
display = constants.tr("now_playing", item=self.format_song_string(user))
|
||||
display = tr("now_playing", item=self.format_song_string(user))
|
||||
|
||||
if self.thumbnail:
|
||||
thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
|
||||
@ -246,4 +246,4 @@ class URLItem(BaseItem):
|
||||
return self.title if self.title.strip() else self.url
|
||||
|
||||
def display_type(self):
|
||||
return constants.tr("url")
|
||||
return tr("url")
|
||||
|
@ -1,5 +1,5 @@
|
||||
import youtube_dl
|
||||
import constants
|
||||
from constants import tr_cli as tr
|
||||
import variables as var
|
||||
from media.item import item_builders, item_loaders, item_id_generators
|
||||
from media.url import URLItem, url_item_id_generator
|
||||
@ -96,7 +96,7 @@ class PlaylistURLItem(URLItem):
|
||||
)
|
||||
|
||||
def format_song_string(self, user):
|
||||
return constants.tr("url_from_playlist_item",
|
||||
return tr("url_from_playlist_item",
|
||||
title=self.title,
|
||||
url=self.url,
|
||||
playlist_url=self.playlist_url,
|
||||
@ -104,7 +104,7 @@ class PlaylistURLItem(URLItem):
|
||||
user=user)
|
||||
|
||||
def format_current_playing(self, user):
|
||||
display = constants.tr("now_playing", item=self.format_song_string(user))
|
||||
display = tr("now_playing", item=self.format_song_string(user))
|
||||
|
||||
if self.thumbnail:
|
||||
thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
|
||||
@ -114,4 +114,4 @@ class PlaylistURLItem(URLItem):
|
||||
return display
|
||||
|
||||
def display_type(self):
|
||||
return constants.tr("url_from_playlist")
|
||||
return tr("url_from_playlist")
|
||||
|
27
mumbleBot.py
27
mumbleBot.py
@ -23,7 +23,8 @@ from packaging import version
|
||||
|
||||
import util
|
||||
import command
|
||||
from constants import tr, commands
|
||||
import constants
|
||||
from constants import tr_cli as tr
|
||||
from database import SettingsDatabase, MusicDatabase, DatabaseMigration
|
||||
import media.system
|
||||
from media.item import ValidationFailedError, PreparationFailedError
|
||||
@ -713,6 +714,8 @@ def start_web_interface(addr, port):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
supported_languages = util.get_supported_language()
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Bot for playing music on Mumble')
|
||||
|
||||
@ -720,11 +723,11 @@ if __name__ == '__main__':
|
||||
parser.add_argument("--config", dest='config', type=str, default='configuration.ini',
|
||||
help='Load configuration from this file. Default: configuration.ini')
|
||||
parser.add_argument("--db", dest='db', type=str,
|
||||
default=None, help='Settings database file. Default: settings-{username_of_the_bot}.db')
|
||||
default=None, help='Settings database file')
|
||||
parser.add_argument("--music-db", dest='music_db', type=str,
|
||||
default=None, help='Music library database file. Default: music.db')
|
||||
parser.add_argument("--lang", dest='lang', type=str, default='en_US',
|
||||
help='Preferred language.')
|
||||
default=None, help='Music library database file')
|
||||
parser.add_argument("--lang", dest='lang', type=str, default=None,
|
||||
help='Preferred language. Support ' + ", ".join(supported_languages))
|
||||
|
||||
parser.add_argument("-q", "--quiet", dest="quiet",
|
||||
action="store_true", help="Only Error logs")
|
||||
@ -817,6 +820,20 @@ if __name__ == '__main__':
|
||||
var.music_folder = util.solve_filepath(var.config.get('bot', 'music_folder'))
|
||||
var.tmp_folder = util.solve_filepath(var.config.get('bot', 'tmp_folder'))
|
||||
|
||||
# ======================
|
||||
# Translation
|
||||
# ======================
|
||||
|
||||
lang = ""
|
||||
if args.lang:
|
||||
lang = args.lang
|
||||
else:
|
||||
lang = var.config.get('bot', 'language', fallback='en_US')
|
||||
|
||||
if lang not in supported_languages:
|
||||
raise KeyError(f"Unsupported language {lang}")
|
||||
constants.load_lang(lang)
|
||||
|
||||
# ======================
|
||||
# Prepare Cache
|
||||
# ======================
|
||||
|
12
util.py
12
util.py
@ -8,7 +8,6 @@ import io
|
||||
import sys
|
||||
import variables as var
|
||||
import zipfile
|
||||
import requests
|
||||
import re
|
||||
import subprocess as sp
|
||||
import logging
|
||||
@ -416,6 +415,17 @@ def verify_password(password, salted_hash, salt):
|
||||
return False
|
||||
|
||||
|
||||
def get_supported_language():
|
||||
lang_files = os.listdir('lang')
|
||||
lang_list = []
|
||||
for lang_file in lang_files:
|
||||
match = re.search("[a-z]{2}_[A-Z]{2}", lang_file)
|
||||
if match:
|
||||
lang_list.append(lang_file)
|
||||
|
||||
return lang_list
|
||||
|
||||
|
||||
class LoggerIOWrapper(io.TextIOWrapper):
|
||||
def __init__(self, logger: logging.Logger, logging_level, fallback_io_buffer):
|
||||
super().__init__(fallback_io_buffer, write_through=True)
|
||||
|
Loading…
x
Reference in New Issue
Block a user