예제 #1
0
def _should_skip(p_name: str, links: Candidates) -> bool:
    key = str(sorted(links))
    skip_dir = Path(get_user_cache_dir('music_manager/disambiguation_skip'))
    skip_path = skip_dir.joinpath(f'{p_name}.json')
    if skip_path.exists():
        with skip_path.open('r') as f:
            try:
                return json.load(f)[key]
            except KeyError:
                return False
    return False
예제 #2
0
def get_clean_paths(max_wait: int, arg_paths):
    from os import getpid
    from selectors import DefaultSelector, EVENT_READ
    from socket import socket
    from time import monotonic
    from filelock import FileLock
    from psutil import Process, NoSuchProcess
    from ds_tools.fs.paths import get_user_cache_dir

    cache_dir = Path(get_user_cache_dir('music_manager'))
    with FileLock(cache_dir.joinpath('init.lock').as_posix()):
        pid = getpid()
        active_path = cache_dir.joinpath('active_pid_port.txt')
        try:
            with active_path.open('r') as f:
                active_pid, port = map(int, f.read().split(','))
        except OSError:
            active = True
        else:
            try:
                active = not Process(active_pid).is_running()
            except NoSuchProcess:
                active = True

        sock = socket()
        if active:
            sock.bind(('localhost', 0))
            sock.listen(100)
            sock.setblocking(False)
            port = sock.getsockname()[1]
            log.info(f'Primary instance with {pid=} {port=}')
            with active_path.open('w') as f:
                f.write(f'{pid},{port}')
        else:
            log.info(f'Follower instance with {pid=} {port=}')

    if active:
        paths = list(arg_paths)
        selector = DefaultSelector()

        def accept(sock, mask):
            conn, addr = sock.accept()
            conn.setblocking(False)
            selector.register(conn, EVENT_READ, read)

        def read(conn, mask):
            if data := conn.recv(2000):
                paths.append(data.decode('utf-8'))
                # log.debug(f'Received path={data!r} from other instance')
            else:
                selector.unregister(conn)
                conn.close()
예제 #3
0
def _always_skip(p_name: str, links: Candidates):
    key = str(sorted(links))
    skip_dir = Path(get_user_cache_dir('music_manager/disambiguation_skip'))
    skip_path = skip_dir.joinpath(f'{p_name}.json')
    if skip_path.exists():
        with skip_path.open('r') as f:
            data = json.load(f)
    else:
        data = {}

    data[key] = True
    with skip_path.open('w') as f:
        json.dump(data, f, sort_keys=True, indent=4)
예제 #4
0
    def get_wiki_cover_choice(self) -> Optional[Path]:
        from ..popups.choose_image import choose_image

        if images := self.get_wiki_cover_images():
            if title := choose_image(images):
                cover_dir = Path(get_user_cache_dir('music_manager/cover_art'))
                name = title.split(
                    ':', 1)[1] if title.lower().startswith('file:') else title
                path = cover_dir.joinpath(name)
                if not path.is_file():
                    img_data = self.wiki_client.get_image(title)
                    with path.open('wb') as f:
                        f.write(img_data)
                return path
예제 #5
0
def init_sym_spell():
    from pathlib import Path
    from symspellpy import SymSpell
    from ds_tools.fs.paths import get_user_cache_dir

    sym_spell = SymSpell(max_dictionary_edit_distance=0, prefix_length=1)
    dict_path_pkl = Path(
        get_user_cache_dir('music_manager')).joinpath('words.pkl.gz')
    if dict_path_pkl.exists():
        log.debug(f'Loading pickled spellcheck dictionary: {dict_path_pkl}')
        sym_spell.load_pickle(dict_path_pkl)
    else:
        import lzma
        import pkg_resources

        dict_path = pkg_resources.resource_filename(
            'symspellpy', 'frequency_dictionary_en_82_765.txt')
        sym_spell.load_dictionary(dict_path, 0, 1)
        word_list_path_xz = Path(
            pkg_resources.resource_filename(
                'music', '../../etc/scowl/words.xz')).resolve()
        log.debug(
            f'Loading default dictionary + word list from {word_list_path_xz}')
        with lzma.open(word_list_path_xz, 'rt', encoding='utf-8') as f:
            word_list = f.read().splitlines()

        loaded = sym_spell._words
        min_count = min(loaded.values())
        add_word = sym_spell.create_dictionary_entry
        for word in word_list:
            try:
                loaded[word]
            except KeyError:
                add_word(word, min_count)

        fmt = 'Saving pickled spellcheck dictionary (this is a one-time action that may take about 15 seconds): {}'
        log.info(fmt.format(dict_path_pkl))
        sym_spell.save_pickle(dict_path_pkl)

    return sym_spell
예제 #6
0
파일: client.py 프로젝트: dskrypa/rpi_hvac
 def __init__(
     self, email=None, serial=None, no_store_prompt=False, update_password=False, config_path=None, reauth=False
 ):
     """
     :param str email: The email address to be used for login
     :param str serial: The serial number of the thermostat to be managed by this client
     :param bool no_store_prompt: Do not prompt to store the password securely
     :param bool update_password: Prompt to update the stored password, even if one already exists
     :param str config_path: The config path to use
     :param bool reauth: Force reauth, even if a cached session exists
     """
     super().__init__(NEST_URL, user_agent_fmt=USER_AGENT_CHROME, headers={'Referer': NEST_URL})
     self._reauth = reauth
     self._lock = RLock()
     self._cache_dir = Path(get_user_cache_dir('nest'))
     self._config_path = Path(config_path or DEFAULT_CONFIG_PATH).expanduser()
     self._no_store_pw = no_store_prompt
     self._update_pw = update_password
     self._email = self._get_config('credentials', 'email', 'email address', email, required=True)
     self._session_info = None
     self._session_expiry = None
     self._user_id = None
     self._nest_host_port = ('home.nest.com', None)
     self._serial = self._get_config('device', 'serial', 'thermostat serial number', serial)
예제 #7
0
    def process_lyrics(self,
                       song,
                       title=None,
                       size=12,
                       ignore_len=False,
                       output_dir=None,
                       extra_linebreaks=None,
                       extra_lines=None,
                       replace_lb=False,
                       **kwargs):
        """
        Process lyrics from the given song and write them to an html file

        :param str|None song: Song endpoint for lyrics
        :param str title: Title to use (overrides automatically-extracted title is specified)
        :param int size: Font size to use for output
        :param bool ignore_len: Ignore stanza length mismatches
        :param output_dir:
        :param extra_linebreaks:
        :param english_extra:
        :param korean_extra:
        :param replace_lb:
        :param kwargs: Keyword arguments to pass to :func:`LyricFetcher.get_lyrics`
        """
        if output_dir and (os.path.exists(output_dir)
                           and not os.path.isdir(output_dir)):
            raise ValueError(
                'Invalid output dir - it exists but is not a directory: {}'.
                format(output_dir))

        lyrics = self.get_lyrics(song, title, **kwargs)
        discovered_title = lyrics.pop('title', None)
        stanzas = normalize_lyrics(lyrics,
                                   extra_linebreaks,
                                   extra_lines,
                                   replace_lb=replace_lb,
                                   ignore_len=ignore_len)
        stanzas['Translation'] = stanzas.pop('English')

        max_stanzas = max(
            len(lang_stanzas) for lang_stanzas in stanzas.values())
        for lang, lang_stanzas in stanzas.items():
            add_stanzas = max_stanzas - len(lang_stanzas)
            if add_stanzas:
                for i in range(add_stanzas):
                    lang_stanzas.append([])

        final_title = title or discovered_title or song
        render_vars = {
            'title': final_title,
            'lyrics': stanzas,
            'lang_order': ['Korean', 'Translation'],
            'stanza_count': max_stanzas,
            'url_for': url_for_file
        }
        prettified = self.song_tmpl.render(**render_vars)

        output_dir = output_dir or get_user_cache_dir('lyric_fetcher/lyrics')
        validate_or_make_dir(output_dir)
        output_filename = 'lyrics_{}.html'.format(
            final_title.replace(' ', '_').replace('?', ''))
        output_path = os.path.join(output_dir, output_filename)
        log.info('Saving lyrics to {}'.format(output_path))
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(prettified)
예제 #8
0
        page = self.edition.page
        return MediaWikiClient(page.site)

    def get_album_cover_urls(self) -> Optional[dict[str, str]]:
        page = self.edition.page
        if image_titles := self._edition_client.get_page_image_titles(page.title)[page.title]:
            return self._edition_client.get_image_urls(image_titles)
        return None

    def get_album_cover(self) -> Optional[str]:
        if not self.update_cover:
            return None
        elif not (urls := self.get_album_cover_urls()):
            return None

        cover_dir = Path(get_user_cache_dir('music_manager/cover_art'))
        tmp_dir = TemporaryDirectory()
        _tmp_dir = Path(tmp_dir.name)
        tmp_html = _tmp_dir.joinpath('options.html')
        try:
            song_file = next(iter(self.album_dir))  # type: SongFile
            cover_data, ext = song_file.get_cover_data()
        except Exception as e:
            log.error(f'Unable to extract current album art: {e}')
            tmp_img = None
        else:
            tmp_img = _tmp_dir.joinpath(f'current.{ext}')
            with tmp_img.open('wb') as f:
                f.write(cover_data)

        with tmp_html.open('w', encoding='utf-8', newline='\n') as f: