Files
2025-12-14 10:04:51 +01:00

117 lines
4.1 KiB
Python

import glob
import json
import os
import re
import subprocess
from collections import OrderedDict
from configparser import ConfigParser
from itertools import chain
_settings = None
BASE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
DB_PATH = os.path.join(BASE_PATH, 'scripts/birds.db')
MODEL_PATH = os.path.join(BASE_PATH, 'model')
FONT_DIR = os.path.join(BASE_PATH, 'homepage/static')
ANALYZING_NOW = os.path.expanduser('~/BirdSongs/StreamData/analyzing_now.txt')
def get_font():
conf = get_settings()
if conf['DATABASE_LANG'] == 'ar':
ret = {'font.family': 'Noto Sans Arabic', 'path': os.path.join(FONT_DIR, 'NotoSansArabic-Regular.ttf')}
elif conf['DATABASE_LANG'] in ['ja', 'zh_CN', 'zh_TW']:
ret = {'font.family': 'Noto Sans JP', 'path': os.path.join(FONT_DIR, 'NotoSansJP-Regular.ttf')}
elif conf['DATABASE_LANG'] == 'ko':
ret = {'font.family': 'Noto Sans KR', 'path': os.path.join(FONT_DIR, 'NotoSansKR-Regular.ttf')}
elif conf['DATABASE_LANG'] == 'th':
ret = {'font.family': 'Noto Sans Thai', 'path': os.path.join(FONT_DIR, 'NotoSansThai-Regular.ttf')}
else:
ret = {'font.family': 'Roboto Flex', 'path': os.path.join(FONT_DIR, 'RobotoFlex-Regular.ttf')}
return ret
class PHPConfigParser(ConfigParser):
def get(self, section, option, *, raw=False, vars=None, fallback=None):
value = super().get(section, option, raw=raw, vars=vars, fallback=fallback)
if raw:
return value
else:
return value.strip('"')
def _load_settings(settings_path='/etc/birdnet/birdnet.conf', force_reload=False):
global _settings
if _settings is None or force_reload:
with open(settings_path) as f:
parser = PHPConfigParser(interpolation=None)
# preserve case
parser.optionxform = lambda option: option
lines = chain(("[top]",), f)
parser.read_file(lines)
_settings = parser['top']
return _settings
def get_settings(settings_path='/etc/birdnet/birdnet.conf', force_reload=False):
settings = _load_settings(settings_path, force_reload)
return settings
def get_open_files_in_dir(dir_name):
result = subprocess.run(['lsof', '-w', '-Fn', '+D', f'{dir_name}'], check=False, capture_output=True)
ret = result.stdout.decode('utf-8')
err = result.stderr.decode('utf-8')
if err:
raise RuntimeError(f'{ret}:\n {err}')
names = [line.lstrip('n') for line in ret.splitlines() if line.startswith('n')]
return names
def get_wav_files():
conf = get_settings()
files = (glob.glob(os.path.join(conf['RECS_DIR'], '*/*/*.wav')) +
glob.glob(os.path.join(conf['RECS_DIR'], 'StreamData/*.wav')))
files.sort()
files = [os.path.join(conf['RECS_DIR'], file) for file in files]
rec_dir = os.path.join(conf['RECS_DIR'], 'StreamData')
open_recs = get_open_files_in_dir(rec_dir)
files = [file for file in files if file not in open_recs]
return files
def get_language(language=None):
if language is None:
language = get_settings()['DATABASE_LANG']
file_name = os.path.join(MODEL_PATH, f'l18n/labels_{language}.json')
with open(file_name) as f:
ret = json.loads(f.read())
return ret
def save_language(labels, language):
file_name = os.path.join(MODEL_PATH, f'l18n/labels_{language}.json')
with open(file_name, 'w') as f:
f.write(json.dumps(OrderedDict(sorted(labels.items())), indent=2, ensure_ascii=False))
def get_model_labels(model=None):
if model is None:
model = get_settings()['MODEL']
file_name = os.path.join(MODEL_PATH, f'{model}_Labels.txt')
with open(file_name) as f:
labels = [line.strip() for line in f.readlines()]
if labels and labels[0].count('_') == 1:
labels = [re.sub(r'_.+$', '', label) for label in labels]
return labels
def set_label_file():
lang = get_language()
labels = [f'{label}_{lang[label]}\n' for label in get_model_labels()]
file_name = os.path.join(MODEL_PATH, 'labels.txt')
if os.path.islink(file_name):
os.remove(file_name)
with open(file_name, 'w') as f:
f.writelines(labels)