From d61601f1e4b0d15c005509ed4edc70630325a0b9 Mon Sep 17 00:00:00 2001 From: Kurt Bestor Date: Mon, 24 Jul 2023 12:07:59 +0900 Subject: [PATCH] ^q^ --- README.md | 6 +- src/extractor/afreeca_downloader.py | 11 ++- src/extractor/baraag_downloader.py | 3 +- src/extractor/etc_downloader.py | 4 +- src/extractor/fc2_downloader.py | 4 +- src/extractor/iwara_downloader.py | 2 +- src/extractor/jmana_downloader.py | 18 ++-- src/extractor/lhscan_downloader.py | 42 +++----- src/extractor/likee_downloader.py | 117 ---------------------- src/extractor/manatoki_downloader.py | 10 +- src/extractor/mastodon_downloader.py | 32 ++++++ src/extractor/misskey_downloader.py | 123 ++++++++++++++++++++++++ src/extractor/naver_downloader.py | 12 ++- src/extractor/naverpost_downloader.py | 8 +- src/extractor/navertv_downloader.py | 8 +- src/extractor/nico_downloader.py | 8 +- src/extractor/nozomi_downloader.py | 36 +++---- src/extractor/pawoo_downloader.py | 17 +++- src/extractor/pinter_downloader.py | 8 +- src/extractor/pixiv_comic_downloader.py | 5 +- src/extractor/pixiv_downloader.py | 31 ++++-- src/extractor/pornhub_downloader.py | 83 ++++++++-------- src/extractor/sankaku_downloader.py | 3 + src/extractor/soundcloud_downloader.py | 7 +- src/extractor/tiktok_downloader.py | 39 +++----- src/extractor/torrent_downloader.py | 2 +- src/extractor/v2ph_downloader.py | 11 ++- src/extractor/webtoon_downloader.py | 2 + src/extractor/weibo_downloader.py | 13 ++- src/extractor/wikiart_downloader.py | 20 ++-- src/extractor/yandere_downloader.py | 3 +- src/extractor/youporn_downloader.py | 8 +- src/extractor/youtube_downloader.py | 50 ++++++++-- translation/changelog_en.txt | 93 ++++++++++++++++++ translation/changelog_ko.txt | 93 ++++++++++++++++++ translation/tr_ar.hdl | 10 ++ translation/tr_en.hdl | 24 +++-- translation/tr_es.hdl | 10 ++ translation/tr_fr.hdl | 10 ++ translation/tr_ja.hdl | 10 ++ translation/tr_pl.hdl | 10 ++ translation/tr_pt.hdl | 10 ++ translation/tr_si.hdl | 10 ++ translation/tr_tr.hdl | 10 ++ translation/tr_vi.hdl | 10 ++ translation/tr_zh-TW.hdl | 12 ++- translation/tr_zh.hdl | 10 ++ 47 files changed, 749 insertions(+), 319 deletions(-) delete mode 100644 src/extractor/likee_downloader.py create mode 100644 src/extractor/mastodon_downloader.py create mode 100644 src/extractor/misskey_downloader.py diff --git a/README.md b/README.md index 2516add..584db78 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## Links - [Download](https://github.com/KurtBestor/Hitomi-Downloader/releases/latest) - [Issues](https://github.com/KurtBestor/Hitomi-Downloader/issues) -- [Scripts](https://github.com/KurtBestor/Hitomi-Downloader/wiki/Scripts) +- [Scripts & Plugins](https://github.com/KurtBestor/Hitomi-Downloader/wiki/Scripts-&-Plugins) - [Chrome Extension](https://github.com/KurtBestor/Hitomi-Downloader/wiki/Chrome-Extension) ## Demo @@ -60,8 +60,9 @@ | **Iwara** |
| | **Jmana** | | | **カクヨム** | | -| **Likee** | | | **Luscious** | | +| **Mastodon** | | +| **Misskey** | | | **MyReadingManga** | | | **Naver Blog** | | | **Naver Cafe** | | @@ -82,6 +83,7 @@ | **Sankaku Complex** |

| | **Soundcloud** | | | **小説家になろう** | | +| **TikTok** |
| | **TOKYO Motion** | | | **Tumblr** | | | **Twitch** | | diff --git a/src/extractor/afreeca_downloader.py b/src/extractor/afreeca_downloader.py index 752b518..e98577c 100644 --- a/src/extractor/afreeca_downloader.py +++ b/src/extractor/afreeca_downloader.py @@ -22,6 +22,11 @@ def __init__(self, stream, referer, id, title, url_thumb): downloader.download(url_thumb, buffer=self.thumb) +class LoginRequired(errors.LoginRequired): + def __init__(self, *args): + super().__init__(*args, method='browser', url='https://login.afreecatv.com/afreeca/login.php') + + class Downloader_afreeca(Downloader): type = 'afreeca' @@ -61,11 +66,11 @@ def get_video(url, session, cw): html = downloader.read_html(url, session=session) if "document.location.href='https://login." in html: - raise errors.LoginRequired() + raise LoginRequired() if len(html) < 2000: alert = re.find(r'''alert\(['"](.+?)['"]\)''', html) if alert: - raise errors.LoginRequired(alert) + raise LoginRequired(alert) soup = Soup(html) url_thumb = soup.find('meta', {'property': 'og:image'}).attrs['content'] @@ -85,7 +90,7 @@ def get_video(url, session, cw): title = data['full_title'] if data.get('adult_status') == 'notLogin': - raise errors.LoginRequired(title) + raise LoginRequired(title) urls_m3u8 = [] for file in data['files']: diff --git a/src/extractor/baraag_downloader.py b/src/extractor/baraag_downloader.py index ee67e97..c8e1e4a 100644 --- a/src/extractor/baraag_downloader.py +++ b/src/extractor/baraag_downloader.py @@ -28,7 +28,6 @@ def read(self): id_ = get_id(self.url) info = get_info('baraag.net', id_, f'baraag_{id_}', self.session, self.cw) - for img in info['imgs']: - self.urls.append(img.url) + self.urls += info['files'] self.title = clean_title('{} (baraag_{})'.format(info['title'], id_)) diff --git a/src/extractor/etc_downloader.py b/src/extractor/etc_downloader.py index a90c373..07f819e 100644 --- a/src/extractor/etc_downloader.py +++ b/src/extractor/etc_downloader.py @@ -120,7 +120,7 @@ def _get_video(url, session, cw, ie_key=None, allow_m3u8=True): fs = [] for i, f in enumerate(formats): f['_index'] = i - f['_resolution'] = int_or_none(re.find('([0-9]+)p', f['format'], re.IGNORECASE)) or f.get('height') or f.get('width') or int_or_none(f.get('quality')) or int(f.get('vcodec', 'none') != 'none') #5995 + f['_resolution'] = int_or_none(re.find(r'([0-9]+)p', f['format'], re.I)) or f.get('height') or f.get('width') or int_or_none(f.get('quality')) or int(f.get('vcodec', 'none') != 'none') #5995 f['_vbr'] = f.get('vbr') or 0 f['_audio'] = f.get('abr') or f.get('asr') or int(f.get('acodec', 'none') != 'none') print_(format_(f)) @@ -144,7 +144,7 @@ def filter_f(fs): print_('invalid url: {}'.format(f['url'])) return list(fs)[0]# - f_video = filter_f(reversed(sorted(fs, key=lambda f:(f['_resolution'], f['_vbr'], f['_index'])))) + f_video = filter_f(sorted(fs, key=lambda f:(f['_resolution'], int(bool(f['_audio'])), f['_vbr'], f['_index']), reverse=True)) #6072, #6118 print_('video0: {}'.format(format_(f_video))) if f_video['_audio']: diff --git a/src/extractor/fc2_downloader.py b/src/extractor/fc2_downloader.py index 7aaf9db..0831d31 100644 --- a/src/extractor/fc2_downloader.py +++ b/src/extractor/fc2_downloader.py @@ -14,8 +14,8 @@ class Downloader_fc2(Downloader): @classmethod def fix_url(cls, url): - if not re.match('https?://.+', url, re.IGNORECASE): - url = 'https://video.fc2.com/content/{}'.format(url) + if not re.match(r'https?://.+', url, re.I): + url = f'https://video.fc2.com/content/{url}' return url @classmethod diff --git a/src/extractor/iwara_downloader.py b/src/extractor/iwara_downloader.py index f200876..6337fac 100644 --- a/src/extractor/iwara_downloader.py +++ b/src/extractor/iwara_downloader.py @@ -126,7 +126,7 @@ def f(html, browser=None): if time() - t0 > 10 or '/profile/' in url.lower(): for a in soup.findAll('a'): if urljoin(url, a.get('href', '')) == urljoin(url, '/login'): - raise errors.LoginRequired(method='browser', url='https://www.iwara.tv/login') #5794 + raise errors.LoginRequired(method='browser', url='https://www.iwara.tv/login', cookie=False) #5794 buttons = soup.findAll(class_='button--primary') if buttons: for i, button in enumerate(buttons): diff --git a/src/extractor/jmana_downloader.py b/src/extractor/jmana_downloader.py index 0f5683f..f2111fd 100644 --- a/src/extractor/jmana_downloader.py +++ b/src/extractor/jmana_downloader.py @@ -9,7 +9,7 @@ import bs4 import clf2 PATTERN = r'jmana[0-9]*.*/(comic_list_title|book)\?book' -PATTERN_ALL = r'jmana[0-9]*.*/(comic_list_title|book|bookdetail)\?book' +PATTERN_ALL = r'jmana[0-9]*.*/((comic_list_title|book|bookdetail)\?book|book_by_title\?title)' #6157 PATTERN_ID = '[?&]bookdetailid=([0-9]+)' @@ -56,7 +56,7 @@ def init(self): self.url = self.fix_url(url) self._soup = None - for i, page in enumerate(get_pages(self.url, self.session, self.soup)): + for i, page in enumerate(get_pages(self.url, self.soup, self.session)): if page.id == int(op['value']): break else: @@ -147,10 +147,7 @@ def get_imgs_page(page, referer, session, cw=None): return imgs -def get_pages(url, session=None, soup=None): - if soup is None: - res = clf2.solve(url, session=session) #4070 - soup = Soup(res['html']) +def get_pages(url, soup, session): pages = [] for inner in soup.findAll('div', class_='inner'): a = inner.find('a') @@ -172,12 +169,13 @@ def get_pages(url, session=None, soup=None): @page_selector.register('jmana') -@try_n(4) -def f(url): +def f(url, win): if re.search(PATTERN_ID, url): raise Exception(tr_('목록 주소를 입력해주세요')) session = Session() - pages = get_pages(url, session=session) + res = clf2.solve(url, session=session, win=win) #4070 + soup = Soup(res['html']) + pages = get_pages(url, soup, session) return pages @@ -186,7 +184,7 @@ def get_imgs(url, title, session, soup=None, cw=None): if soup is None: html = downloader.read_html(url, session=session) soup = Soup(html) - pages = get_pages(url, soup=soup) + pages = get_pages(url, soup, session) print_('pages: {}'.format(len(pages))) pages = page_selector.filter(pages, cw) imgs = [] diff --git a/src/extractor/lhscan_downloader.py b/src/extractor/lhscan_downloader.py index 4dc16f5..325ae34 100644 --- a/src/extractor/lhscan_downloader.py +++ b/src/extractor/lhscan_downloader.py @@ -36,10 +36,10 @@ def __init__(self, title, url): self.url = url -def get_soup_session(url, cw=None): +def get_soup_session(url, cw=None, win=None): print_ = get_print(cw) session = Session() - res = clf2.solve(url, session=session, cw=cw) + res = clf2.solve(url, session=session, cw=cw, win=win) print_('{} -> {}'.format(url, res['url'])) if res['url'].rstrip('/') == 'https://welovemanga.one': raise errors.LoginRequired() @@ -55,10 +55,9 @@ class Downloader_lhscan(Downloader): ] MAX_CORE = 16 display_name = 'LHScan' - _soup = None def init(self): - self._soup, self.session = get_soup_session(self.url, self.cw) + self.soup, self.session = get_soup_session(self.url, self.cw) if not self.soup.find('ul', class_='manga-info'): raise errors.Invalid('{}: {}'.format(tr_('목록 주소를 입력해주세요'), self.url)) @@ -68,21 +67,6 @@ def fix_url(cls, url): url = url.replace('welovemanga.net', 'welovemanga.one') #4298 return url - @property - def soup(self): - if self._soup is None: - for try_ in range(8): - try: - html = downloader.read_html(self.url, session=self.session) - break - except Exception as e: - e_ = e - print(e) - else: - raise e_ - self._soup = Soup(html) - return self._soup - @property def name(self): title = self.soup.find('ul', class_='manga-info').find('h3').text @@ -115,10 +99,10 @@ def get_imgs_page(page, referer, session, cw=None): pass soup = Soup(html) - view = soup.find('div', class_='chapter-content') - - if not view: - raise Exception('no chapter-content') + cid = re.find(r'''load_image\(([0-9]+)''', html) + if cid: #6186 + url_api = urljoin(page.url, f'/app/manga/controllers/cont.listImg.php?cid={cid}') + soup = downloader.read_soup(url_api, page.url, session=session) imgs = [] for img in soup.findAll('img', class_='chapter-img'): @@ -140,9 +124,12 @@ def get_imgs_page(page, referer, session, cw=None): continue if '/uploads/lazy_loading.gif' in src: continue + if '/xstaff.jpg.pagespeed.ic.gPQ2SGcYaN.webp' in src: + continue src = src.replace('\n', '').replace('\r', '') #5238 - if 'proxy.php?link=' not in src: #5351 - src = 'https://welovekai.com/proxy.php?link=' + src #5238 + #6105 +## if 'proxy.php?link=' not in src: #5351 +## src = 'https://welovekai.com/proxy.php?link=' + src #5238 if not imgs: print_(src0) print_(src) @@ -174,9 +161,8 @@ def get_pages(url, session, soup=None, cw=None): @page_selector.register('lhscan') -@try_n(4) -def f(url): - soup, session = get_soup_session(url) +def f(url, win): + soup, session = get_soup_session(url, win=win) pages = get_pages(url, session, soup=soup) return pages diff --git a/src/extractor/likee_downloader.py b/src/extractor/likee_downloader.py deleted file mode 100644 index bd8ade6..0000000 --- a/src/extractor/likee_downloader.py +++ /dev/null @@ -1,117 +0,0 @@ -import downloader -from utils import Session, Downloader, get_ext, LazyUrl, get_print, check_alive -import ree as re -import json -from io import BytesIO -from translator import tr_ - - - -class Downloader_likee(Downloader): - type = 'likee' - URLS = ['likee.video'] - single = True - display_name = 'Likee' - - def init(self): - self.session = Session() - - def read(self): - info = get_info(self.url, self.session, self.cw) - self.print_('type: {}'.format(info['type'])) - self.artist = info['artist'] - - if info['type'] != 'single': - video = self.process_playlist(info['title'], info['videos']) - else: - video = info['videos'][0] - video.url() - self.urls.append(video.url) - self.title = info['title'] - - thumb = BytesIO() - downloader.download(video.url_thumb, referer=self.url, buffer=thumb) - self.setIcon(thumb) - - -def get_info(url, session, cw=None): - print_ = get_print(cw) - - info = {} - info['videos'] = [] - - if '/video/' in url: - info['type'] = 'single' - video = Video(url, session) - video.url() - info['videos'].append(video) - info['title'] = video.id_ - info['artist'] = video.artist - return info - - info['type'] = 'channel' - html = downloader.read_html(url, session=session) - data_raw = html.split('window.data = ')[1].split('};')[0]+'}' - data = json.loads(data_raw) - info['uid'] = data['userinfo']['uid'] - info['username'] = data['userinfo']['yyuid'] - info['artist'] = data['userinfo']['nick_name'] - info['title'] = '{} (likee_{})'.format(info['artist'], info['username']) - - lastPostId = '' - urls = set() - while True: - check_alive(cw) - url_api = 'https://likee.video/official_website/VideoApi/getUserVideo' - r = session.post(url_api, data={'uid': info['uid'], 'count': '30', 'lastPostId': lastPostId}) - data = json.loads(r.text) - - videos = data['data']['videoList'] - if not videos: - break - - for data in videos: - url_post = 'https://likee.video/@{}/video/{}'.format(data['likeeId'], data['postId']) - if url_post in urls: - print_('duplicate: {}'.format(url_post)) - continue - urls.add(url_post) - video = Video(url_post, session, data) - video.url() - info['videos'].append(video) - lastPostId = data['postId'] - - msg = '{} {} - {}'.format(tr_('읽는 중...'), info['title'], len(info['videos'])) - if cw: - cw.setTitle(msg) - else: - print(msg) - - return info - - -class Video: - def __init__(self, url, session, data=None): - self.id_ = re.find('/video/([0-9]+)', url, err='no id') - self._session = session - self._data = data - self.url = LazyUrl(url, self.get, self) - - def get(self, url): - if self._data: - video = self._data - else: - url_api = 'https://likee.video/official_website/VideoApi/getVideoInfo' - r = self._session.post(url_api, data={'postIds': str(self.id_)}) - - data = json.loads(r.text) - video = data['data']['videoList'][0] - - url_video = video['videoUrl'] - self.url_thumb = video['coverUrl'] - self.artist = video['nickname'] - ext = get_ext(url_video) - self.title = self.id_ - self.filename = '{}{}'.format(self.id_, ext) - - return url_video diff --git a/src/extractor/manatoki_downloader.py b/src/extractor/manatoki_downloader.py index 7420830..47c3e1b 100644 --- a/src/extractor/manatoki_downloader.py +++ b/src/extractor/manatoki_downloader.py @@ -123,7 +123,7 @@ def get_artist(soup): @sleep_and_retry @limits(1, 10) -def get_soup(url, session=None, cw=None): +def get_soup(url, session=None, cw=None, win=None): if session is None: session = Session() virgin = True @@ -138,7 +138,7 @@ def f(html, browser=None): return False browser.hide() return True - res = clf2.solve(url, session=session, f=f, cw=cw) + res = clf2.solve(url, session=session, f=f, cw=cw, win=win) soup = Soup(res['html'], apply_css=True) return session, soup, res['url'] @@ -190,8 +190,8 @@ def get_pages(url, soup, sub=False): @page_selector.register('manatoki') -def f(url): - session, soup, url = get_soup(url) +def f(url, win): + session, soup, url = get_soup(url, win=win) list = soup.find('ul', class_='list-body') if list is None: raise Exception(tr_('목록 주소를 입력해주세요')) @@ -281,7 +281,7 @@ def get_imgs_page(page, title, referer, session, cw): def isVisible(tag): while tag: - if re.search(r'display:\s*none', tag.get('style', ''), re.IGNORECASE): + if re.search(r'display:\s*none', tag.get('style', ''), re.I): return False tag = tag.parent return True diff --git a/src/extractor/mastodon_downloader.py b/src/extractor/mastodon_downloader.py new file mode 100644 index 0000000..1d276fc --- /dev/null +++ b/src/extractor/mastodon_downloader.py @@ -0,0 +1,32 @@ +#coding:utf8 +from utils import Downloader, clean_title, Session +from mastodon import get_info +import ree as re + + + +def get_id(url): + return re.find('mastodon.social/([^/]+)', url.lower()) + + + +class Downloader_mastodon(Downloader): + type = 'mastodon' + URLS = ['mastodon.social'] + ACCEPT_COOKIES = [r'(.*\.)?mastodon\.social'] + + def init(self): + self.session = Session() + + @classmethod + def fix_url(cls, url): + id_ = get_id(url) or url + return f'https://mastodon.social/{id_}' + + def read(self): + id_ = get_id(self.url) + info = get_info('mastodon.social', id_, f'mastodon_{id_}', self.session, self.cw) + + self.urls += info['files'] + + self.title = clean_title('{} (mastodon_{})'.format(info['title'], id_)) diff --git a/src/extractor/misskey_downloader.py b/src/extractor/misskey_downloader.py new file mode 100644 index 0000000..f73cf3c --- /dev/null +++ b/src/extractor/misskey_downloader.py @@ -0,0 +1,123 @@ +from utils import Downloader, Session, clean_title, get_ext, errors, check_alive, tr_, try_n, File +import downloader +import ree as re +from ratelimit import limits, sleep_and_retry +from datetime import datetime +import utils +DOMAIN = 'misskey.io' +SUBFOLDER = True +if not utils.SD.get('misskey', {}).get('format'): + utils.SD.setdefault('misskey', {}) + utils.SD['misskey']['format'] = '[date] id_ppage' + + +def get_file(nid, url, referer, session, p, time): + ext = get_ext(url) or downloader.get_ext(url, session, referer) + date = datetime.fromtimestamp(float(time)) + date = date.strftime('%y-%m-%d') # local time + filename = utils.SD['misskey']['format'].replace('date', date).replace('id', str(nid)).replace('page', str(p)) + ext + info = {'name': filename, 'url': url, 'referer': referer} + return File(info) + + +def get_time(note): + ds = note['createdAt'] + time = datetime.strptime(ds.split('.')[0], '%Y-%m-%dT%H:%M:%S') + time = (time-datetime(1970,1,1)).total_seconds() + return time + + +class Downloader_misskey(Downloader): + type = 'misskey' + URLS = [f'{DOMAIN}/notes/', f'{DOMAIN}/@'] + display_name = 'Misskey' + ACCEPT_COOKIES = [rf'(.*\.)?{DOMAIN}'] + MAX_CORE = 8 + + @classmethod + def fix_url(cls, url): + if DOMAIN.lower() in url.lower() and '://' not in url: + url = 'https://' + url + if url.startswith('@'): + url = f'https://{DOMAIN}/{url}' + return url + + def init(self): + self.session = Session() + + @try_n(4, sleep=5) + @sleep_and_retry + @limits(1, 2) + def call(self, path, payload): + token = self.session.cookies.get('token', domain=DOMAIN) + url_api = f'https://{DOMAIN}/api/{path}' + if token: + payload['i'] = token + r = self.session.post(url_api, json=payload) + d = r.json() + if isinstance(d, dict): + err = d.get('error') + if err: + raise errors.Invalid(err['message']) + return d + + def read(self): + nid = re.find(rf'{DOMAIN}/notes/([^/]+)', self.url) + if nid: + self.single = True + data = {'noteId':nid, + } + note = self.call('notes/show', data) + username = note['user']['username'] + self.artist = note['user']['name'] or username + host = note['user']['host'] + if host: + username += f'@{host}' + self.title = f'{clean_title(self.artist)} (misskey_@{username})' + time = get_time(note) + for file in note['files']: + file = get_file(note['id'], file['url'], self.url, self.session, len(self.urls), time) + if SUBFOLDER: + file['name'] = self.title + '/' + file['name'] + self.urls.append(file) + else: + username = re.find(rf'{DOMAIN}/@([a-zA-Z0-9_@\.]+)', self.url, err='no username') + if '@' in username: + username, host = username.split('@') + else: + host = None + data = {"username":username, + "host":host, + } + d = self.call('users/show', data) + username = d['username'] + self.artist = d['name'] or username + host = d['host'] or None + if host: + username += f'@{host}' + uid = d['id'] + self.title = title = f'{clean_title(self.artist)} (misskey_@{username})' + untilId = None + nids = set() + while check_alive(self.cw): + data = {"userId":uid, + "limit":30, + } + if untilId: + data["untilId"] = untilId + d = self.call('users/notes', data) + if not d: + break + for note in d: + nid = note['id'] + if nid in nids: + continue + nids.add(nid) + time = get_time(note) + url_note = f'https://{DOMAIN}/notes/{nid}' + for p, file in enumerate(note['files']): + file = get_file(note['id'], file['url'], url_note, self.session, p, time) + self.urls.append(file) + untilId = nid + self.cw.setTitle(f'{tr_("읽는 중...")} {title} - {len(self.urls)}') + self.title = title diff --git a/src/extractor/naver_downloader.py b/src/extractor/naver_downloader.py index 485fb13..8b43e32 100644 --- a/src/extractor/naver_downloader.py +++ b/src/extractor/naver_downloader.py @@ -1,7 +1,7 @@ #coding:utf-8 import downloader import ree as re -from utils import urljoin, Downloader, Soup, LazyUrl, clean_title, get_ext +from utils import urljoin, Downloader, Soup, LazyUrl, clean_title, get_ext, get_print import json from timee import sleep import collections @@ -51,7 +51,7 @@ def name(self): def read(self): self.title = '읽는 중... {}'.format(self.name) - imgs = get_imgs(self.url) + imgs = get_imgs(self.url, self.cw) filenames = {} for img in imgs: @@ -78,7 +78,7 @@ def read_page(url, depth=0): print('read_page', url, depth) if depth > 10: raise Exception('Too deep') - html = downloader.read_html(url, header=HDR) + html = downloader.read_html(url, headers=HDR) if len(html) < 5000: id = re.find('logNo=([0-9]+)', html, err='no id') @@ -97,7 +97,8 @@ def read_page(url, depth=0): -def get_imgs(url): +def get_imgs(url, cw): + print_ = get_print(cw) url = url.replace('blog.naver', 'm.blog.naver') referer = url url_frame, soup = read_page(url) @@ -145,10 +146,11 @@ def get_imgs(url): pairs = [] - for video in soup.findAll('span', class_='_naverVideo'): + for video in soup.findAll(class_='_naverVideo'): vid = video.attrs['vid'] key = video.attrs['key'] pairs.append((vid, key)) + print_(f'pairs: {pairs}') for script in soup.findAll('script', class_='__se_module_data'): data_raw = script['data-module'] diff --git a/src/extractor/naverpost_downloader.py b/src/extractor/naverpost_downloader.py index 231f3b2..9247c41 100644 --- a/src/extractor/naverpost_downloader.py +++ b/src/extractor/naverpost_downloader.py @@ -74,16 +74,16 @@ def read(self): # https://github.com/KurtBestor/Hitomi-Downloader/blob/master/src/extractor/manatoki_downloader.py#L106 참고 @page_selector.register("naverpost") -def f(url): - client = Client(urlparse(url), get_soup(url)) +def f(url, win): + client = Client(urlparse(url), get_soup(url, win=win)) return [ page for page_list in client.posts for page in page_list ] # 2차원 리스트 -> 1차원 리스트 # https://github.com/KurtBestor/Hitomi-Downloader/blob/master/src/extractor/manatoki_downloader.py#L84 참고 -def get_soup(url: str) -> BeautifulSoup: - res = clf2.solve(url) +def get_soup(url: str, win=None) -> BeautifulSoup: + res = clf2.solve(url, win=win) return Soup(res["html"]) diff --git a/src/extractor/navertv_downloader.py b/src/extractor/navertv_downloader.py index 2bec703..73ed484 100644 --- a/src/extractor/navertv_downloader.py +++ b/src/extractor/navertv_downloader.py @@ -15,9 +15,11 @@ class Downloader_navertv(Downloader): URLS = ['tv.naver.com'] display_name = 'Naver TV' - def init(self): - if not re.match('https?://.+', self.url, re.IGNORECASE): - self.url = 'https://tv.naver.com/v/{}'.format(self.url) + @classmethod + def fix_url(cls, url): + if not re.match(r'https?://.+', url, re.I): + url = f'https://tv.naver.com/v/{url}' + return url def read(self): video = Video(self.url, cw=self.cw) diff --git a/src/extractor/nico_downloader.py b/src/extractor/nico_downloader.py index 70797a4..dfeb988 100644 --- a/src/extractor/nico_downloader.py +++ b/src/extractor/nico_downloader.py @@ -6,7 +6,6 @@ import utils import ffmpeg import os -import errors import ytdl import threading import errors @@ -17,6 +16,11 @@ def get_id(url): return re.find('/watch/([a-zA-Z0-9]+)', url) +class LoginRequired(errors.LoginRequired): + def __init__(self, *args): + super().__init__(*args, method='browser', url='https://account.nicovideo.jp/login') + + class Video: def __init__(self, session, info, format, cw, hb=None, d=None): self.session = session @@ -156,7 +160,7 @@ def get_video(session, url, format, cw=None, d=None): msg = box.find('p', class_='channel-invitation-box-body-channel-desc-msg1') if msg: msg = msg.text.strip() - raise errors.LoginRequired(msg or None) + raise LoginRequired(msg or None) else: raise e_ fs = info['formats'] diff --git a/src/extractor/nozomi_downloader.py b/src/extractor/nozomi_downloader.py index 7126181..88e48fe 100644 --- a/src/extractor/nozomi_downloader.py +++ b/src/extractor/nozomi_downloader.py @@ -1,20 +1,25 @@ import downloader from urllib.parse import quote from io import BytesIO -from utils import Downloader, query_url, LazyUrl, get_ext, urljoin, clean_title, check_alive, lock, get_print, get_max_range +from utils import Downloader, query_url, get_ext, urljoin, clean_title, check_alive, lock, get_print, get_max_range, File import errors from translator import tr_ -from multiprocessing.pool import ThreadPool -from math import ceil from ratelimit import limits, sleep_and_retry -class Image: - def __init__(self, id, url, referer, p): - self.url = LazyUrl(referer, lambda _: url, self) - ext = get_ext(url) - self.filename = '{}{}{}'.format(id, f'_p{p}' if p else '', ext) +class File_nozomi(File): + type = 'nozomi' + + def get(self): + infos = [] + for p, img in enumerate(read_post(self['id'], self['referer'], self.cw)): + url = img['url'] + ext = get_ext(url) + filename = '{}{}{}'.format(img['id'], f'_p{p}' if p else '', ext) + info = {'url': url, 'name': filename, 'referer': img['referer']} + infos.append(info) + return infos @sleep_and_retry @@ -31,7 +36,7 @@ def read_post(id, referer, cw): print_(f'{id}: {e}') return [] #5989 imgs = [] - for p, url in enumerate(j['imageurls']): + for url in j['imageurls']: did = url['dataid'] if j.get('is_video'): #5754 cdn = 'v' @@ -40,12 +45,11 @@ def read_post(id, referer, cw): cdn = 'g' if j.get('type') == 'gif' else 'w' ext = 'gif' if url.get('type') == 'gif' else 'webp' url = 'https://{}.nozomi.la/{}/{}/{}.{}'.format(cdn, did[-1], did[-3:-1], did, ext) #5340 - img = Image(id, url, f'https://nozomi.la/post/{id}.html', p) + img = {'id': id, 'url': url, 'referer': f'https://nozomi.la/post/{id}.html'} imgs.append(img) return imgs - class Downloader_nozomi(Downloader): type = 'nozomi' URLS = ['nozomi.la'] @@ -76,13 +80,9 @@ def read(self): ids = get_ids_multi(q, self._popular, self.cw) self.print_(f'ids: {len(ids)}') max_pid = get_max_range(self.cw) - p = ThreadPool(6) - step = 10 - for i in range(int(ceil(len(ids)/step))): - for imgs in p.map(lambda id: read_post(id, self.url, self.cw), ids[i*step:(i+1)*step]): - self.urls += [img.url for img in imgs] - s = '{} {} - {} / {}'.format(tr_('읽는 중...'), self.name, i*step, len(ids)) - self.cw.setTitle(s) + for id in ids: + file = File_nozomi({'id': id, 'url': f'https://nozomi.la/post/{id}.html', 'referer': self.url}) + self.urls.append(file) if len(self.urls) >= max_pid: break self.title = self.name diff --git a/src/extractor/pawoo_downloader.py b/src/extractor/pawoo_downloader.py index 2dedb96..6cb5d3a 100644 --- a/src/extractor/pawoo_downloader.py +++ b/src/extractor/pawoo_downloader.py @@ -1,5 +1,6 @@ #coding:utf8 -from utils import Downloader, clean_title, Session +from utils import Downloader, clean_title, Session, Soup, urljoin +import clf2 from mastodon import get_info import ree as re @@ -17,17 +18,25 @@ class Downloader_pawoo(Downloader): def init(self): self.session = Session() + if get_id(self.url) == 'web': #6123 + soup = Soup(clf2.solve(self.url)['html']) + name = soup.find('div', class_='account__header__tabs__name') + id_ = name.find('small').text.strip() + self.url = urljoin(self.url, f'/{id_}') @classmethod def fix_url(cls, url): + if url.endswith('/media'): + url = url[:-len('/media')] id_ = get_id(url) or url + if id_ == 'web': + return url return f'https://pawoo.net/{id_}' def read(self): id_ = get_id(self.url) info = get_info('pawoo.net', id_, f'pawoo_{id_}', self.session, self.cw) - for img in info['imgs']: - self.urls.append(img.url) + self.urls += info['files'] - self.title = clean_title('{} (pawoo{})'.format(info['title'], id_)) + self.title = clean_title('{} (pawoo_{})'.format(info['title'], id_)) diff --git a/src/extractor/pinter_downloader.py b/src/extractor/pinter_downloader.py index 046b2dc..847ccbe 100644 --- a/src/extractor/pinter_downloader.py +++ b/src/extractor/pinter_downloader.py @@ -16,10 +16,12 @@ class Downloader_pinter(Downloader): URLS = ['pinterest.'] type_pinter = 'board' display_name = 'Pinterest' + ACCEPT_COOKIES = [r'(.*\.)?(pinterest)\.'] @try_n(4) def init(self): - self.api = PinterestAPI() + self.session = Session('chrome') + self.api = PinterestAPI(self.session) self._pin_id = re.find(r'https?://.*pinterest\.[^/]+/pin/([0-9]+)', self.url) if self._pin_id is not None: self.type_pinter = 'pin' @@ -104,8 +106,8 @@ class PinterestAPI: 'Origin': BASE_URL, } - def __init__(self): - self.session = Session('chrome') + def __init__(self, session): + self.session = session self.session.headers.update(self.HEADERS) def pin(self, pin_id): diff --git a/src/extractor/pixiv_comic_downloader.py b/src/extractor/pixiv_comic_downloader.py index c0de28b..af877d1 100644 --- a/src/extractor/pixiv_comic_downloader.py +++ b/src/extractor/pixiv_comic_downloader.py @@ -122,10 +122,10 @@ def get_pages(soup, url, cw=None): @page_selector.register('pixiv_comic') @try_n(4) -def f(url): +def f(url, win): if '/viewer/' in url: raise Exception(tr_('목록 주소를 입력해주세요')) - html = clf2.solve(url, show='fake')['html'] + html = clf2.solve(url, show='fake', win=win)['html'] soup = Soup(html) pages = get_pages(soup, url) return pages @@ -172,6 +172,7 @@ def get_imgs_page(page, session): for p in pages: img = p['url'] img = img.replace('webp%3Ajpeg', 'jpeg') + img = img.replace('q=50', 'q=100') img = Image(img, page, len(imgs)) imgs.append(img) diff --git a/src/extractor/pixiv_downloader.py b/src/extractor/pixiv_downloader.py index 9c3d215..b9dcd3c 100644 --- a/src/extractor/pixiv_downloader.py +++ b/src/extractor/pixiv_downloader.py @@ -25,6 +25,10 @@ constants.available_extra.append(header) +class LoginRequired(errors.LoginRequired): + def __init__(self, *args): + super().__init__(*args, method='browser', url='https://accounts.pixiv.net/login') + class Downloader_pixiv(Downloader): @@ -53,7 +57,10 @@ def f(html, browser=None): return False browser.hide() return True - res = clf2.solve('https://accounts.pixiv.net/login', session=self.session, cw=self.cw, f=f, delay=3) + try: + res = clf2.solve('https://accounts.pixiv.net/login', session=self.session, cw=self.cw, f=f, delay=3) + except clf2.Timeout: + raise LoginRequired() self.print_('yeee') res = clf2.solve(self.url, session=self.session, cw=self.cw) soup = Soup(res['html']) @@ -64,6 +71,13 @@ def f(html, browser=None): @classmethod def fix_url(cls, url): + rt = utils.query_url(url).get('return_to') + if rt: + url = urljoin(url, rt[0]) + + if '/search_user.php?' in url: + url = 'https://pixiv.me/{}'.format(utils.query_url(url).get('nick')[0]) + if url.startswith('illust_'): url = 'https://www.pixiv.net/en/artworks/{}'.format(url[len('illust_'):]) elif url.startswith('bmk_'): @@ -81,11 +95,14 @@ def fix_url(cls, url): url = re.sub(r'(users/[0-9]+)/artworks$', r'\1', url) url = re.sub(r'[?&]p=[0-9]+$', '', url) + + if '://' not in url: #6082 + url = 'https://' + url return url.strip('/') @classmethod def key_id(cls, url): - return url.replace('://www.', '://').replace('/en/', '/') + return url.replace('://www.', '://').replace('/en/', '/').replace('http://', 'https://').lower() def read(self): ## loop = asyncio.new_event_loop() @@ -104,7 +121,7 @@ def read(self): pass -class PixivAPIError(errors.LoginRequired): pass +class PixivAPIError(LoginRequired): pass class HTTPError(Exception): pass @@ -312,9 +329,9 @@ def get_info(url, session, cw=None, depth=0, tags_add=None): data = api.illust(id_) login = 'noLoginData' not in data if not login:# - raise errors.LoginRequired() + raise LoginRequired() if data['xRestrict'] and not login: - raise errors.LoginRequired('R-18') + raise LoginRequired('R-18') info['artist'] = data['userName'] info['artist_id'] = data['userId'] info['raw_title'] = data['illustTitle'] @@ -484,7 +501,7 @@ def my_id(session, cw): print_ = get_print(cw) sid = session.cookies.get('PHPSESSID', domain='.pixiv.net', path='/') if not sid: - raise errors.LoginRequired() + raise LoginRequired() if cw is not None: _ = getattr(cw, 'sid?', None) if _ is None: @@ -492,7 +509,7 @@ def my_id(session, cw): print_(f'sid: {sid}') userid = re.find(r'^([0-9]+)', sid) if userid is None: - raise errors.LoginRequired() + raise LoginRequired() return userid diff --git a/src/extractor/pornhub_downloader.py b/src/extractor/pornhub_downloader.py index 5bce46a..14d8cd3 100644 --- a/src/extractor/pornhub_downloader.py +++ b/src/extractor/pornhub_downloader.py @@ -78,8 +78,8 @@ def get(self, url): if self._url: return self._url - id_ = re.find(r'viewkey=(\w+)', url, re.IGNORECASE) or \ - re.find(r'/embed/(\w+)', url, re.IGNORECASE) + id_ = re.find(r'viewkey=(\w+)', url, re.I) or \ + re.find(r'/embed/(\w+)', url, re.I) print_('id: {}'.format(id_)) if 'viewkey=' not in url.lower() and '/gif/' not in url.lower(): if id_ is None: @@ -203,7 +203,7 @@ class Downloader_pornhub(Downloader): single = True strip_header = False URLS = ['pornhub.com', 'pornhubpremium.com', 'pornhubthbh7ap3u.onion'] - ACCEPT_COOKIES = [r'.*(pornhub|phncdn).*'] + ACCEPT_COOKIES = [r'.*(pornhub|phncdn|pornhubpremium).*'] #6181 @classmethod def fix_url(cls, url): @@ -238,9 +238,14 @@ def read(self): session = self.session = Session() # 1791 self.purge_cookies() + session.cookies.update({ + 'age_verified': '1', + 'accessAgeDisclaimerPH': '1', + 'accessPH': '1', + }) #6124 if 'pornhubpremium.com' in self.url.lower() and\ not is_login(session, cw): - raise errors.LoginRequired() + raise errors.LoginRequired(method='browser', url='https://www.pornhubpremium.com/premium/login') videos = [] tab = ''.join(self.url.replace('pornhubpremium.com', 'pornhub.com', 1).split('?')[0].split('#')[0].split('pornhub.com/')[-1].split('/')[2:3]) @@ -256,8 +261,7 @@ def read(self): elif '/photo/' in self.url: self.print_('Photo') info = read_photo(self.url, session=session) - for photo in info['photos']: - self.urls.append(photo.url) + self.urls.append(info['photo'].url) self.title = info['title'] elif tab not in ['', 'videos']: @@ -303,16 +307,34 @@ def fix_soup(soup, url, session=None, cw=None): +class Photo_lazy: + ''' + Photo_lazy + ''' + + def __init__(self, url, session): + self._session = session + self.url = LazyUrl(url, self.get, self) + + def get(self, url): + info = read_photo(url, self._session) + photo = info['photo'] + url = photo.url() + self.filename = photo.filename + return url + + + class Photo: ''' Photo ''' - def __init__(self, id_, url, referer): - self.id_ = id_ - self.url = LazyUrl(referer, lambda x: url, self) + def __init__(self, url, referer, id_, session): + self._session = session ext = get_ext(url) self.filename = f'{id_}{ext}' + self.url = LazyUrl(referer, lambda _: url, self) @try_n(8) @@ -320,32 +342,18 @@ def read_album(url, session=None): ''' read_album ''' + photos = [] soup = downloader.read_soup(url, session=session) id_album = re.find('/album/([0-9]+)', url, err='no album id') - url_json = 'https://www.pornhub.com/album/show_album_json?album={}'.format(id_album) - data = downloader.read_json(url_json, url, session=session) - block = soup.find('div', class_='photoAlbumListBlock') - href = block.a.attrs['href'] - id_ = re.find('/photo/([0-9]+)', href, err='no photo id') - ids = [id_] - while True: - item = data[id_] - id_ = item['next'] - if id_ in ids: - break - ids.append(id_) - - photos = [] - for id_ in ids: - item = data[id_] - img = item['img_large'] - referer = 'https://www.pornhub.com/photo/{}'.format(id_) - photo = Photo(id_, img, referer) + for block in soup.findAll('div', class_='photoAlbumListBlock'): + href = block.a.attrs['href'] + href = urljoin(url, href) + photo = Photo_lazy(href, session) photos.append(photo) info = {} - title = clean_title(soup.find('h1', class_='photoAlbumTitleV2').text) - info['title'] = format_filename(title, 'album_{}'.format(id_album)) + title = soup.find('h1', class_='photoAlbumTitleV2').text + info['title'] = format_filename(title, f'album_{id_album}') info['photos'] = photos return info @@ -357,16 +365,13 @@ def read_photo(url, session=None): ''' id_ = re.find('/photo/([0-9]+)', url, err='no photo id') soup = downloader.read_soup(url, session=session) - div = soup.find('div', id='thumbSlider') - href = urljoin(url, div.find('a').attrs['href']) - info = read_album(href) - photos = [] - for photo in info['photos']: - if str(photo.id_) == id_: - photos.append(photo) + section = soup.find('div', id='photoImageSection') + photo = section.find('img')['src'] - info['photos'] = photos - info['title'] = '{} - {}'.format(info['title'], photos[0].filename) + info = {} + info['photo'] = Photo(photo, url, id_, session) + title = soup.find('h1').text + info['title'] = format_filename(title, f'photo_{id_}') return info diff --git a/src/extractor/sankaku_downloader.py b/src/extractor/sankaku_downloader.py index b4bfd76..e37ea6b 100644 --- a/src/extractor/sankaku_downloader.py +++ b/src/extractor/sankaku_downloader.py @@ -286,6 +286,9 @@ def get_imgs(url, title=None, cw=None, d=None, types=['img', 'gif', 'video'], se banner = soup.find('div', class_='has-mail') if banner: #5861 banner.decompose() + banner = soup.find('div', class_='popular-previews') + if banner: #6171 + banner.decompose() err = soup.find('div', class_='post-premium-browsing_error') if err and not imgs: raise errors.LoginRequired(err.text.strip()) diff --git a/src/extractor/soundcloud_downloader.py b/src/extractor/soundcloud_downloader.py index fe4b8cb..fbbaa58 100644 --- a/src/extractor/soundcloud_downloader.py +++ b/src/extractor/soundcloud_downloader.py @@ -42,7 +42,12 @@ def get(self, url): formats = info['formats'] print(formats) - formats = sorted(formats, key=lambda x: int(x.get('abr', 0)), reverse=True) + def key(f): + abr = f.get('abr') + if abr is None: + abr = 320 + return int(abr) + formats = sorted(formats, key=key, reverse=True) url_audio = None for format in formats: diff --git a/src/extractor/tiktok_downloader.py b/src/extractor/tiktok_downloader.py index b9e989b..c0890bb 100644 --- a/src/extractor/tiktok_downloader.py +++ b/src/extractor/tiktok_downloader.py @@ -12,8 +12,11 @@ SHOW = True -def is_captcha(soup): - return soup.find('div', class_="verify-wrap") is not None +def is_captcha(soup, cw=None): + r = soup.find('div', class_="verify-wrap") is not None + if r: + get_print(cw)('captcha') + return r @@ -29,7 +32,7 @@ def init(self): res = clf2.solve(self.url, self.session, cw) self.url = self.fix_url(res['url']) #4324 soup = Soup(res['html']) - if is_captcha(soup): + if is_captcha(soup, cw): def f(html): return not is_captcha(Soup(html)) clf2.solve(self.url, self.session, cw, show=True, f=f) @@ -118,22 +121,17 @@ def read_channel(url, session, cw=None, title=None): def f(html, browser=None): soup = Soup(html) - if is_captcha(soup): - print('captcha') + if is_captcha(soup, cw): browser.show() sd['shown'] = True elif sd['shown'] and not SHOW: browser.hide() sd['shown'] = False if 'tiktok.com' in url.lower(): # TikTok - try: - st = soup.find('h2', class_='share-title') - if st is None: - st = soup.find('h2', class_=lambda c: c and 'ShareTitle' in c) + try: #6114 + st = soup.find(['h1', 'h2'], class_='share-title') or soup.find(['h1', 'h2'], class_=lambda c: c and 'ShareTitle' in c) info['uid'] = st.text.strip() - st = soup.find('h1', class_='share-sub-title') - if st is None: - st = soup.find('h1', class_=lambda c: c and 'ShareSubTitle' in c) + st = soup.find(['h1', 'h2'], class_='share-sub-title') or soup.find(['h1', 'h2'], class_=lambda c: c and 'ShareSubTitle' in c) info['nickname'] = st.text.strip() except Exception as e: print_(print_error(e)) @@ -150,18 +148,13 @@ def f(html, browser=None): else: # Douyin items = soup.findAll('a') for item in items: - if item.name == 'a': - a = item - else: - a = item.find('a') - if a is None: - continue - href = a.get('href') - if not href: - continue - m = re.search(PATTERN_VID, href) - if m is None: + def foo(a): + return re.search(PATTERN_VID, a.get('href') or '') + as_ = [item] + item.findAll('a') #6119 + as_ = [a for a in as_ if foo(a)] + if not as_: continue + m = foo(as_[0]) id_video = int(m.group('id')) ids_now.add(id_video) if id_video in ids: diff --git a/src/extractor/torrent_downloader.py b/src/extractor/torrent_downloader.py index fb2975d..383349a 100644 --- a/src/extractor/torrent_downloader.py +++ b/src/extractor/torrent_downloader.py @@ -12,7 +12,7 @@ from cacher import Cache import myjson as json torrent = None -TIMEOUT = 600 +TIMEOUT = 1800 CACHE_INFO = True diff --git a/src/extractor/v2ph_downloader.py b/src/extractor/v2ph_downloader.py index d5dda26..3065776 100644 --- a/src/extractor/v2ph_downloader.py +++ b/src/extractor/v2ph_downloader.py @@ -1,6 +1,6 @@ #coding:utf8 import downloader -from utils import get_ext, LazyUrl, Downloader, try_n, clean_title, get_print +from utils import get_ext, LazyUrl, Downloader, try_n, clean_title, get_print, print_error import ree as re from translator import tr_ from timee import sleep @@ -82,7 +82,14 @@ def get_imgs(url, session, title, cw=None): for p in range(1, 1001): url = setPage(url, p) print_(url) - soup = read_soup(url, session) + try: + soup = read_soup(url, session) + except Exception as e: + if p > 1: + print_(print_error(e)) + break + else: + raise e view = soup.find('div', class_='photos-list') if view is None: diff --git a/src/extractor/webtoon_downloader.py b/src/extractor/webtoon_downloader.py index 6e057d0..d980982 100644 --- a/src/extractor/webtoon_downloader.py +++ b/src/extractor/webtoon_downloader.py @@ -4,6 +4,7 @@ import page_selector from translator import tr_ import ree as re +import clf2 @@ -17,6 +18,7 @@ class Downloader_webtoon(Downloader): def init(self): self.session = Session() + clf2.solve(self.url, session=self.session) self.url = get_main(self.url, self.session) self.soup = downloader.read_soup(self.url, session=self.session) diff --git a/src/extractor/weibo_downloader.py b/src/extractor/weibo_downloader.py index 466c8d5..112d4da 100644 --- a/src/extractor/weibo_downloader.py +++ b/src/extractor/weibo_downloader.py @@ -21,6 +21,11 @@ def suitable(url): return True +class LoginRequired(errors.LoginRequired): + def __init__(self, *args): + super().__init__(*args, method='browser', url='https://weibo.com/login.php') + + class Downloader_weibo(Downloader): type = 'weibo' @@ -64,7 +69,7 @@ def read(self): def checkLogin(session): c = session.cookies._cookies.get('.weibo.com', {}).get('/',{}).get('SUBP') if not c or c.is_expired(): - raise errors.LoginRequired() + raise LoginRequired() class Album: @@ -95,7 +100,7 @@ def get_id(url, cw=None): html = res['html'] soup = Soup(html) if soup.find('div', class_='gn_login') or soup.find('a', class_=lambda c: c and c.startswith('LoginBtn')): - raise errors.LoginRequired() + raise LoginRequired() oid = _get_page_id(html) if not oid: raise Exception('no page_id') @@ -106,7 +111,7 @@ def get_id(url, cw=None): raise Exception('no name') break except errors.LoginRequired as e: - raise + raise e except Exception as e: e_ = e print(e) @@ -151,7 +156,7 @@ def get_albums(page): referer = 'https://photo.weibo.com/{}/albums?rd=1'.format(uid) html = downloader.read_html(url, referer, session=session) if '新浪通行证' in html: - raise errors.LoginRequired() + raise LoginRequired() j = json.loads(html) data = j['data'] albums = [] diff --git a/src/extractor/wikiart_downloader.py b/src/extractor/wikiart_downloader.py index fcb8493..4639b92 100644 --- a/src/extractor/wikiart_downloader.py +++ b/src/extractor/wikiart_downloader.py @@ -1,7 +1,7 @@ #coding:utf8 import downloader import json -from utils import LazyUrl, Downloader, Soup, get_print, clean_title, check_alive +from utils import LazyUrl, Downloader, get_print, clean_title, check_alive import os from timee import sleep from translator import tr_ @@ -22,18 +22,15 @@ class Downloader_wikiart(Downloader): type = 'wikiart' URLS = ['wikiart.org'] display_name = 'WikiArt' + ACCEPT_COOKIES = [r'(.*\.)?wikiart\.org'] - def init(self): - self.url = 'https://www.wikiart.org/en/{}'.format(self.id_) - html = downloader.read_html(self.url) - self.soup = Soup(html) - - @property - def id_(self): - return get_id(self.url) + @classmethod + def fix_url(cls, url): + url = 'https://www.wikiart.org/en/{}'.format(get_id(url)) + return url def read(self): - artist = get_artist(self.id_, self.soup) + artist = get_artist(get_id(self.url)) self.artist = artist for img in get_imgs(self.url, artist, cw=self.cw): @@ -97,7 +94,6 @@ def get_imgs(url, artist, cw=None): def get_artist(userid, soup=None): if soup is None: url = 'https://www.wikiart.org/en/{}'.format(userid) - html = downloader.read_html(url) - soup = Soup(html) + soup = downloader.read_soup(url) return soup.find('h3').text.strip() diff --git a/src/extractor/yandere_downloader.py b/src/extractor/yandere_downloader.py index 492d5f9..742d59c 100644 --- a/src/extractor/yandere_downloader.py +++ b/src/extractor/yandere_downloader.py @@ -3,6 +3,7 @@ import ree as re import downloader from ratelimit import limits, sleep_and_retry +from urllib.parse import unquote @try_n(4) @@ -67,7 +68,7 @@ def get_title(self, url:str) -> str: url_tags = url.split("tags=")[-1].split('+') - return clean_title(" ".join(url_tags)) + return clean_title(unquote(" ".join(url_tags))) class Image: diff --git a/src/extractor/youporn_downloader.py b/src/extractor/youporn_downloader.py index 5f892f5..78b1a34 100644 --- a/src/extractor/youporn_downloader.py +++ b/src/extractor/youporn_downloader.py @@ -5,6 +5,7 @@ from constants import try_n from utils import Downloader, LazyUrl, get_ext, format_filename, clean_title import ytdl +from m3u8_tools import M3u8_stream @@ -39,11 +40,16 @@ def __init__(self, url, cw=None): f = info['formats'][-1] url_video = f['url'] + + ext = get_ext(url_video) + if ext.lower() == '.m3u8': #6142 + ext = '.mp4' + url_video = M3u8_stream(url_video, referer=url) + self.url = LazyUrl(url, lambda _: url_video, self) self.url_thumb = info['thumbnails'][0]['url'] self.thumb = BytesIO() downloader.download(self.url_thumb, buffer=self.thumb) self.title = info['title'] - ext = get_ext(url_video) self.filename = format_filename(self.title, info['id'], ext) diff --git a/src/extractor/youtube_downloader.py b/src/extractor/youtube_downloader.py index 5ca97cd..d5d4b1d 100644 --- a/src/extractor/youtube_downloader.py +++ b/src/extractor/youtube_downloader.py @@ -35,6 +35,8 @@ class Video: _url = None vcodec = None filename0 = None + chapters = None + utime = None def __init__(self, url, session, type='video', only_mp4=False, audio_included=False, max_res=None, max_abr=None, cw=None): self.type = type @@ -77,12 +79,16 @@ def get(self, url, force=False): else: raise e_ + if utils.ui_setting.chapterMarkerCheck.isChecked(): + self.chapters = yt.info.get('chapters') + streams = yt.streams.all() print_streams(streams, cw) #3528 time = datetime.strptime(yt.info['upload_date'], '%Y%m%d') - self.utime = (time-datetime(1970,1,1)).total_seconds() + if utils.ui_setting.youtubeMtimeCheck.isChecked(): #6092 + self.utime = (time-datetime(1970,1,1)).total_seconds() print_('utime: {}'.format(self.utime)) if type == 'video': @@ -112,6 +118,21 @@ def get(self, url, force=False): res = int(stream.resolution.replace('p','')) if max_res is None or res <= max_res: streams.append(stream) + def key(stream): + vc = stream.video_codec + if not vc: + return 1000 + vc = vc.lower().split('.')[0].lower() + if vc == 'av01': + vc = 'av1' + if vc == 'vp09': + vc = 'vp9' + try: + i = constants.CODECS_PRI.index(vc) + except ValueError: + return 999 + return i + streams = sorted(streams, key=key) #6079 print_('') elif type == 'audio': streams[:] = [stream for stream in streams if stream.abr] @@ -135,7 +156,7 @@ def get(self, url, force=False): if type == 'video': ress = [int_(stream.resolution.replace('p', '')) for stream in streams] m = max(ress) - prefer_format = 'mp4' + prefer_format = None#'mp4' elif type == 'audio': ress = [stream.abr for stream in streams] m = min(ress) @@ -150,7 +171,8 @@ def get(self, url, force=False): foo = False if stream_final is None or (stream_final.fps <= stream.fps and (foo or (stream_final.subtype.lower()!=prefer_format and stream.subtype.lower()==prefer_format) or stream_final.fps < stream.fps)): #print(foo) - print_('# stream_final {} {} {} {} {} {}fps'.format(stream, stream.format, stream.resolution, stream.subtype, stream.audio_codec, stream.fps)) + print_('# stream_final') + print_streams([stream], cw) stream_final = stream ok = downloader.ok_url(stream_final.url, referer=url, session=self.session) if isinstance(stream_final.url, str) else True @@ -315,6 +337,17 @@ def pp(self, filename, i=0): s = print_error(e) print_(s) + if self.chapters and self.type == 'video': #6085 + try: + chapters = [] + for chapter in self.chapters: + chapter = ffmpeg.Chapter(chapter['title'], chapter['start_time'], chapter['end_time']) + chapters.append(chapter) + ffmpeg.add_chapters(filename_new, chapters, cw=cw) + except Exception as e: + s = print_error(e) + print_(s) + utils.pp_subtitle(self, filename_new, cw) return filename_new @@ -361,20 +394,23 @@ def init(self): @classmethod def fix_url(cls, url): #2033 - if not re.match('https?://.+', url, re.IGNORECASE): + if not re.match('https?://.+', url, re.I): url = 'https://www.youtube.com/watch?v={}'.format(url) qs = query_url(url) if 'v' in qs: url = url.split('?')[0] + '?v={}'.format(qs['v'][0]) for header in ['channel', 'user', 'c']: #5365, #5374 - tab = re.find(rf'/{header}/[^/]+/?(.+)?', url, re.IGNORECASE) + tab = re.find(rf'/{header}/[^/]+/?(.+)?', url, re.I) if tab == 'playlists': - url = re.sub(rf'(/{header}/[^/]+/?)(.+)?', r'\1', url, flags=re.IGNORECASE) + url = re.sub(rf'(/{header}/[^/]+/?)(.+)?', r'\1', url, flags=re.I) tab = '' if tab in ['', 'featured'] and '/{}/'.format(header) in url.lower(): - username = re.find(r'/{}/([^/\?]+)'.format(header), url, re.IGNORECASE) + username = re.find(r'/{}/([^/\?]+)'.format(header), url, re.I) url = urljoin(url, '/{}/{}/videos'.format(header, username)) + m = re.find(rf'youtube.com/(@[^/]+)/?(.+)?', url, re.I) + if m and m[1] in ['', 'featured']: #6129 + url = urljoin(url, f'/{m[0]}/videos') return url.strip('/') @classmethod diff --git a/translation/changelog_en.txt b/translation/changelog_en.txt index 3d7d810..cf91add 100644 --- a/translation/changelog_en.txt +++ b/translation/changelog_en.txt @@ -1,3 +1,96 @@ +3.8e 【】 + +[버그 해결 / 사이트 변경에 의한 수정] + +- yt-dlp 문제 해결 (#6086, #6087, #6089) + +- #6093 + +- Tiktok 업데이트 대응 (#6114) + +- WeLoveManga 업데이트 대응 (#6105, #6186) + +- Tiktok 제목 없는 영상 다운로드 안 되는 문제 해결 (#6119) + +- PornHub 업데이트 대응 (#6124) + +- YouTube "youtube.com/@(id)" 형식 URL 잘못 인식하는 문제 해결 (#6129) + +- yt-dlp 업데이트 대응 (#6136) + +- 한국어 로케일에서 설정 파일 없이 시작했을 때 일부 글자 깨지는 문제 해결 + +- YouPorn 업데이트 대응 (#6142) + +- #6115 + +- Jmana 업데이트 대응 (#6157) + +- "선택 화 다운로드" 할 때 내장 웹브라우저 문제 해결 + +- SoundCloud 업데이트 대응 + +- Naver Blog 업데이트 대응 + +- SankakuComplex Popular 부분 다운로드되는 문제 해결 (#6171) + +- #6190 + +- 기타 자잘한 것들 + + +[변경/추가된 기능] + +- Mastodon 지원 (#6123) + +- Misskey 지원 (#6051, #6161) + +- Likee 지원 종료 + +- YouTube 비디오 코덱 우선순위 설정 (#6079) + 옵션 - 설정 - YouTube 설정 - 비디오 코덱 우선순위... + +- YouTube 가능한 경우 챕터 마커 추가 설정 (#6085) + +- pixivコミック 화질 개선 + +- TVer 등 일부 yt-dlp 지원 사이트 다운로드 속도 개선 (#6072, #6118) + +- Twitter "twitter.com/i/user/(User ID)" 형식 URL 지원 (#5841, #6120) + 여기에서 확인 가능: 작업 우 클릭 - 작업 정보... - extras - uids + +- Pawoo "pawoo.net/web/accounts/(id)" 형식 URL 지원 (#6123) + +- 자동 재시작 (#6152) + 코멘트에 "restart:30:00" 입력하면 작업 완료 후 30분 뒤에 다시 시작 + +- "중복 이미지 찾기" 파일 검색 속도 최적화 + +- "중복 이미지 찾기" "폴더 열기" 단축키 추가 + +- 검색기 검색 전 파일 검색 속도 최적화 + +- "저장 폴더에 있는 모든 갤러리 넘버 복사" 속도 최적화 + +- 테마 변경 속도 최적화 + +- 다중 직접 다운로드 (#6158) + +- 트레이 아이콘에서 다운로드 시작 / 완료 표시 (#6102) + +- 작업 완료 알림 (#6102) + 옵션 - 설정 - 고급 설정 - 작업이 완료되면 알림 보이기 + 옵션 - 설정 - 고급 설정 - 모든 작업이 완료되면 알림 보이기 + +- "클립보드에서 자동 추가" 로 추가시 알림음 (#6102) + +- 내장 웹브라우저로 바로 로그인할 수 있게 버튼 표시 + +- 기타 자잘한 것들 + + + +-------------------------------------------------------------------------------------------------------------------------------------------- 3.8d 【Jun 23, 2023】 [버그 해결 / 사이트 변경에 의한 수정] diff --git a/translation/changelog_ko.txt b/translation/changelog_ko.txt index b87acfe..c9a9061 100644 --- a/translation/changelog_ko.txt +++ b/translation/changelog_ko.txt @@ -1,3 +1,96 @@ +3.8e 【】 + +[버그 해결 / 사이트 변경에 의한 수정] + +- yt-dlp 문제 해결 (#6086, #6087, #6089) + +- #6093 + +- Tiktok 업데이트 대응 (#6114) + +- WeLoveManga 업데이트 대응 (#6105, #6186) + +- Tiktok 제목 없는 영상 다운로드 안 되는 문제 해결 (#6119) + +- PornHub 업데이트 대응 (#6124) + +- YouTube "youtube.com/@(id)" 형식 URL 잘못 인식하는 문제 해결 (#6129) + +- yt-dlp 업데이트 대응 (#6136) + +- 한국어 로케일에서 설정 파일 없이 시작했을 때 일부 글자 깨지는 문제 해결 + +- YouPorn 업데이트 대응 (#6142) + +- #6115 + +- Jmana 업데이트 대응 (#6157) + +- "선택 화 다운로드" 할 때 내장 웹브라우저 문제 해결 + +- SoundCloud 업데이트 대응 + +- Naver Blog 업데이트 대응 + +- SankakuComplex Popular 부분 다운로드되는 문제 해결 (#6171) + +- #6190 + +- 기타 자잘한 것들 + + +[변경/추가된 기능] + +- Mastodon 지원 (#6123) + +- Misskey 지원 (#6051, #6161) + +- Likee 지원 종료 + +- YouTube 비디오 코덱 우선순위 설정 (#6079) + 옵션 - 설정 - YouTube 설정 - 비디오 코덱 우선순위... + +- YouTube 가능한 경우 챕터 마커 추가 설정 (#6085) + +- pixivコミック 화질 개선 + +- TVer 등 일부 yt-dlp 지원 사이트 다운로드 속도 개선 (#6072, #6118) + +- Twitter "twitter.com/i/user/(User ID)" 형식 URL 지원 (#5841, #6120) + 여기에서 확인 가능: 작업 우 클릭 - 작업 정보... - extras - uids + +- Pawoo "pawoo.net/web/accounts/(id)" 형식 URL 지원 (#6123) + +- 자동 재시작 (#6152) + 코멘트에 "restart:30:00" 입력하면 작업 완료 후 30분 뒤에 다시 시작 + +- "중복 이미지 찾기" 파일 검색 속도 최적화 + +- "중복 이미지 찾기" "폴더 열기" 단축키 추가 + +- 검색기 검색 전 파일 검색 속도 최적화 + +- "저장 폴더에 있는 모든 갤러리 넘버 복사" 속도 최적화 + +- 테마 변경 속도 최적화 + +- 다중 직접 다운로드 (#6158) + +- 트레이 아이콘에서 다운로드 시작 / 완료 표시 (#6102) + +- 작업 완료 알림 (#6102) + 옵션 - 설정 - 고급 설정 - 작업이 완료되면 알림 보이기 + 옵션 - 설정 - 고급 설정 - 모든 작업이 완료되면 알림 보이기 + +- "클립보드에서 자동 추가" 로 추가시 알림음 (#6102) + +- 내장 웹브라우저로 바로 로그인할 수 있게 버튼 표시 + +- 기타 자잘한 것들 + + + +-------------------------------------------------------------------------------------------------------------------------------------------- 3.8d 【Jun 23, 2023】 [버그 해결 / 사이트 변경에 의한 수정] diff --git a/translation/tr_ar.hdl b/translation/tr_ar.hdl index 3460d41..c764d45 100644 --- a/translation/tr_ar.hdl +++ b/translation/tr_ar.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『 {} 』 إشارة مرجعية", "『 {} 』를 저장 폴더에서 불러왔습니다": "『 {} 』 تم تحميله من مجلد التنزيل", "가능하면 일본어 제목 사용": "استخدم العنوان الياباني إذا كان متاحًا", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "يستورد", "가져오기 실패": "فشل الاستيراد", "간단 검색": "بحث بسيط", @@ -255,6 +256,8 @@ "모두 선택": "اختر الكل", "모든 갤러리 넘버를 복사했습니다.": "نسخ جميع معرفات المعرض.", "모든 언어": "كل اللغات", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "قائمة", "목록 주소를 입력해주세요": "الرجاء كتابة عنوان URL للقائمة", "목록 지우기": "لائحة خالية", @@ -291,6 +294,7 @@ "뷰어... (&V)": "&Viewer...", "브라우저로 보기": "إظهار في المتصفح", "브라우저로 보기 (&B)": "إظهار في المستعرض (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "تضمين صور متشابهة (بطيئة)", "비율 유지": "ابعاد متزنة", "비율 유지 - 꽉 차게": "نسبة العرض إلى الارتفاع - ملء", @@ -380,6 +384,7 @@ "예(&Y)": "&نعم", "예상치 못한 오류로 다운로드에 실패했습니다.": "فشل التنزيل بسبب خطأ غير متوقع.", "예시": "مثال", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "نطاق غير صالح", "올바르지 않은 주소입니다": "URL غير صالح", "올바르지 않은 형식의 검색 필터입니다": "خطأ في بناء الجملة غير صالح مع عامل التصفية", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "تم استيراد المهام", "작업들을 내보냈습니다": "تصدير المهام", "작업이 아직 완료되지 않았습니다": "المهمة لم تنته بعد", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "قائمة معرض الاستيراد", "작품 목록 내보내기": "قائمة معرض التصدير", "잠금": "قفل", @@ -577,6 +584,7 @@ "트래커 추가": "أضف أدوات تعقب", "트레이로 전환되었습니다": "تصغير إلى علبة النظام", "트레이로 최소화": "يخفض الى قاع النظام", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "إظهار الإخطارات في الدرج", "파일": "ملف", "파일 목록": "قائمة الملفات", @@ -593,6 +601,7 @@ "파일명 형식": "تنسيق اسم الملف", "파일을 고르세요:": "اختر الملفات:", "파일을 선택하세요": "حدد ملف", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "لا ملفات", "패스워드": "كلمة المرور", "퍼지로 찾기": "البحث عن طريق ضبابي", @@ -614,6 +623,7 @@ "폴더 열기": "افتح المجلد", "폴더 이동": "انقل المجلد", "폴더 추가": "أضف المجلد", + "폴더가 없습니다": "No folder", "폴더들": "الدلائل", "폴더를 선택하세요": "حدد مجلدًا", "폴더를 추가해주세요": "الرجاء إضافة بعض المجلدات", diff --git a/translation/tr_en.hdl b/translation/tr_en.hdl index 697a258..12c6385 100644 --- a/translation/tr_en.hdl +++ b/translation/tr_en.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『 {} 』is bookmarked", "『 {} 』를 저장 폴더에서 불러왔습니다": "『 {} 』is loaded from the download folder", "가능하면 일본어 제목 사용": "Use Japanese title if available", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "Import", "가져오기 실패": "Failed to import", "간단 검색": "Simple search", @@ -193,9 +194,9 @@ "다운로드 완료 후 자동 제거": "Remove automatically after complete download", "다운로드 일시 정지 / 재개": "Download Pause / Resume", "다운로드 중": "Downloading", - "다운로드가 완료되면 알림": "Show notification when downloading is finished", - "다운로드가 완료될 때까지 절전모드 방지": "Prevent system sleep until downloads are finished", - "다운로드하기 전에 파일 고르기": "Select files before download", + "다운로드가 완료되면 알림": "Show notifications when downloading is complete", + "다운로드가 완료될 때까지 절전모드 방지": "Prevent system sleep until downloads are complete", + "다운로드하기 전에 파일 고르기": "Select files before downloading", "다운로드하지 않음": "Don't download", "다운로드한 작품만": "Only downloaded galleries", "다음 검색시 더 빠르게 검색": "Improve performance the next time", @@ -206,7 +207,7 @@ "단축키 불러오기 성공": "Shortcuts are successfully imported", "단축키 수정": "Edit shortcuts", "단축키 초기화 성공": "Shortcuts are successfully reseted", - "닫기 버튼으로 트레이로 최소화": "Close button minimizes to system tray", + "닫기 버튼으로 트레이로 최소화": "Minimize to tray with the close button", "대기 중": "Waiting", "대기 중...": "Waiting...", "데이터 분류 중...": "Classifying data...", @@ -255,6 +256,8 @@ "모두 선택": "Select all", "모든 갤러리 넘버를 복사했습니다.": "Copied all gallery IDs.", "모든 언어": "All languages", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "List", "목록 주소를 입력해주세요": "Please type a list URL", "목록 지우기": "Clear list", @@ -291,6 +294,7 @@ "뷰어... (&V)": "&Viewer...", "브라우저로 보기": "Show in browser", "브라우저로 보기 (&B)": "Show in browser (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "Include similar images (Slow)", "비율 유지": "Aspect ratio", "비율 유지 - 꽉 차게": "Aspect ratio - fill", @@ -380,13 +384,14 @@ "예(&Y)": "&Yes", "예상치 못한 오류로 다운로드에 실패했습니다.": "Failed to download by unexpected error.", "예시": "Example", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "Invalid range", "올바르지 않은 주소입니다": "Invalid URL", "올바르지 않은 형식의 검색 필터입니다": "Invalid syntax error with filter", "올바르지 않은 형식의 스크립트입니다": "Invalid format script", "옵션": "Options", "옵션 (Options)": "Options", - "완료": "Finished", + "완료": "Complete", "완료된 작업 모두 제거": "Remove all complete tasks", "완료됨으로 표시": "Mark as complete", "완전 삭제": "Delete permanently", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "Tasks imported", "작업들을 내보냈습니다": "Tasks exported", "작업이 아직 완료되지 않았습니다": "Task is not finished yet", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "Import gallery list", "작품 목록 내보내기": "Export gallery list", "잠금": "Lock", @@ -531,7 +538,7 @@ "최대 다운로드 속도": "Maximum download speed", "최대 동시 작업": "Maximum concurrent tasks", "최대 페이지 제한": "Maximum page limit", - "최소화 버튼으로 트레이로 최소화": "Minimize button minimizes to system tray", + "최소화 버튼으로 트레이로 최소화": "Minimize to tray with the minimize button", "추가한 날짜": "Date added", "취소": "Cancel", "캐릭터": "Characters", @@ -577,7 +584,8 @@ "트래커 추가": "Add trackers", "트레이로 전환되었습니다": "Minimized to system tray", "트레이로 최소화": "Minimize to system tray", - "트레이에서 알림 보이기": "Show notifications in tray", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", + "트레이에서 알림 보이기": "Show notifications in system tray", "파일": "File", "파일 목록": "File list", "파일 삭제": "Delete files", @@ -593,6 +601,7 @@ "파일명 형식": "Filename format", "파일을 고르세요:": "Select files:", "파일을 선택하세요": "Select a file", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "No files", "패스워드": "Password", "퍼지로 찾기": "Search by Fuzzy", @@ -614,6 +623,7 @@ "폴더 열기": "Open Folder", "폴더 이동": "Move folder", "폴더 추가": "Add folder", + "폴더가 없습니다": "No folder", "폴더들": "Directories", "폴더를 선택하세요": "Select a folder", "폴더를 추가해주세요": "Please add some folders", diff --git a/translation/tr_es.hdl b/translation/tr_es.hdl index 681bf42..7437d2c 100644 --- a/translation/tr_es.hdl +++ b/translation/tr_es.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『{}』 se agrega a favoritos", "『 {} 』를 저장 폴더에서 불러왔습니다": "『{}』 se carga desde la carpeta de descargas", "가능하면 일본어 제목 사용": "Use Japanese title if available", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "Importación", "가져오기 실패": "Error al importar", "간단 검색": "Búsqueda simple", @@ -255,6 +256,8 @@ "모두 선택": "Seleccionar todo", "모든 갤러리 넘버를 복사했습니다.": "ID de galerías copiadas.", "모든 언어": "Todos los idiomas", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "Lista", "목록 주소를 입력해주세요": "Por favor, introduzca una lista de URL", "목록 지우기": "Borrar la lista", @@ -291,6 +294,7 @@ "뷰어... (&V)": "&Viewer...", "브라우저로 보기": "Show in browser", "브라우저로 보기 (&B)": "Ver en el navegador (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "Incluir imágenes similares (lento)", "비율 유지": "Mantener relación de aspecto", "비율 유지 - 꽉 차게": "Aspect ratio - fill", @@ -380,6 +384,7 @@ "예(&Y)": "&Sí", "예상치 못한 오류로 다운로드에 실패했습니다.": "Error al descargar con un error inesperado.", "예시": "Ejemplo", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "Rango inválido", "올바르지 않은 주소입니다": "URL no válida", "올바르지 않은 형식의 검색 필터입니다": "Error de sintaxis no válido con filtro", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "Tareas importadas", "작업들을 내보냈습니다": "Tareas exportadas", "작업이 아직 완료되지 않았습니다": "La tarea no ha sido finalizada", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "Import gallery list", "작품 목록 내보내기": "Export gallery list", "잠금": "Bloquear", @@ -577,6 +584,7 @@ "트래커 추가": "Add trackers", "트레이로 전환되었습니다": "Minimizar en la barra de tareas", "트레이로 최소화": "Reducir en la barra de tareas", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "Visualizar las notificaciones", "파일": "Archivo", "파일 목록": "File list", @@ -593,6 +601,7 @@ "파일명 형식": "Formato del archivo", "파일을 고르세요:": "Select files:", "파일을 선택하세요": "Select a file", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "No files", "패스워드": "Contraseña", "퍼지로 찾기": "Buscar por fuzzy", @@ -614,6 +623,7 @@ "폴더 열기": "Obrir la carpeta", "폴더 이동": "Move folder", "폴더 추가": "Agrega la carpeta", + "폴더가 없습니다": "No folder", "폴더들": "Directories", "폴더를 선택하세요": "Selecciona una carpeta", "폴더를 추가해주세요": "Por favor, agregar carpetas", diff --git a/translation/tr_fr.hdl b/translation/tr_fr.hdl index 3f513e0..05a6e06 100644 --- a/translation/tr_fr.hdl +++ b/translation/tr_fr.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『{}』 est ajouté aux favoris", "『 {} 』를 저장 폴더에서 불러왔습니다": "『{}』 est chargé à partir du dossier de téléchargements", "가능하면 일본어 제목 사용": "Utiliser le titre en japonais si disponible", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "Importation", "가져오기 실패": "Échec de l'importation", "간단 검색": "Recherche simple", @@ -255,6 +256,8 @@ "모두 선택": "Tout sélectionner", "모든 갤러리 넘버를 복사했습니다.": "ID des galleries copiés.", "모든 언어": "Toutes les langues", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "Liste", "목록 주소를 입력해주세요": "Veuillez taper une liste d'URLs", "목록 지우기": "Effacer la liste", @@ -291,6 +294,7 @@ "뷰어... (&V)": "&Visualisateur...", "브라우저로 보기": "Show in browser", "브라우저로 보기 (&B)": "Afficher dans le navigateur (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "Inclure les images similaires (lent)", "비율 유지": "Conserver les proportions", "비율 유지 - 꽉 차게": "Aspect ratio - fill", @@ -380,6 +384,7 @@ "예(&Y)": "&Oui", "예상치 못한 오류로 다운로드에 실패했습니다.": "Échec du téléchargement par une erreur inattendue.", "예시": "Exemple", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "Plage invalide", "올바르지 않은 주소입니다": "URL invalide", "올바르지 않은 형식의 검색 필터입니다": "Erreur de syntaxe non valide avec le filtre", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "Tâches importées", "작업들을 내보냈습니다": "Tâches exportées", "작업이 아직 완료되지 않았습니다": "La tâche n'est pas encore terminée", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "Import gallery list", "작품 목록 내보내기": "Export gallery list", "잠금": "Verrouiller", @@ -577,6 +584,7 @@ "트래커 추가": "Add trackers", "트레이로 전환되었습니다": "Minimiser dans la barre des tâches", "트레이로 최소화": "Réduire dans la barre des tâches", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "Afficher les notifications", "파일": "Fichier", "파일 목록": "File list", @@ -593,6 +601,7 @@ "파일명 형식": "Format de fichier", "파일을 고르세요:": "Select files:", "파일을 선택하세요": "Sélectionner un fichier", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "No files", "패스워드": "Mot de passe", "퍼지로 찾기": "Recherche par fuzzy", @@ -614,6 +623,7 @@ "폴더 열기": "Ouvrir le dossier", "폴더 이동": "Déplacer le dossier", "폴더 추가": "Ajouter le dossier", + "폴더가 없습니다": "No folder", "폴더들": "Directories", "폴더를 선택하세요": "Sélectionnez un dossier", "폴더를 추가해주세요": "Merci d'ajouter des dossiers", diff --git a/translation/tr_ja.hdl b/translation/tr_ja.hdl index 40ab919..38583aa 100644 --- a/translation/tr_ja.hdl +++ b/translation/tr_ja.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『 {} 』をブックマークしました", "『 {} 』를 저장 폴더에서 불러왔습니다": "『 {} 』がダウンロードフォルダから読み込まれました", "가능하면 일본어 제목 사용": "利用可能なら日本語のタイトルを使用", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "インポート", "가져오기 실패": "インポートに失敗しました", "간단 검색": "簡易検索", @@ -255,6 +256,8 @@ "모두 선택": "すべて選択", "모든 갤러리 넘버를 복사했습니다.": "すべてのギャラリーIDをコピーしました。", "모든 언어": "すべての言語", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "一覧", "목록 주소를 입력해주세요": "リストのURLを入力してください。", "목록 지우기": "一覧の消去", @@ -291,6 +294,7 @@ "뷰어... (&V)": "ビューア... (&V)", "브라우저로 보기": "ブラウザで表示", "브라우저로 보기 (&B)": "ブラウザで表示 (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "類似画像を含める (遅い)", "비율 유지": "アスペクト比", "비율 유지 - 꽉 차게": "アスペクト比 - 塗りつぶし", @@ -380,6 +384,7 @@ "예(&Y)": "はい(&Y)", "예상치 못한 오류로 다운로드에 실패했습니다.": "予期しないエラーによりダウンロードに失敗しました。", "예시": "例", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "無効な範囲", "올바르지 않은 주소입니다": "無効なURL", "올바르지 않은 형식의 검색 필터입니다": "フィルターでの無効な構文エラー", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "タスクをインポートしました", "작업들을 내보냈습니다": "タスクをエクスポートしました", "작업이 아직 완료되지 않았습니다": "タスクはまだ終了していません", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "ギャラリーのリストをインポート", "작품 목록 내보내기": "ギャラリーのリストをエクスポート", "잠금": "ロック", @@ -577,6 +584,7 @@ "트래커 추가": "トラッカーを追加する", "트레이로 전환되었습니다": "システムトレイに最小化", "트레이로 최소화": "システムトレイに最小化", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "トレイに通知を表示", "파일": "ファイル", "파일 목록": "ファイル一覧", @@ -593,6 +601,7 @@ "파일명 형식": "ファイル名の形式", "파일을 고르세요:": "ファイルの選択:", "파일을 선택하세요": "ファイルの選択", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "ファイルがありません", "패스워드": "パスワード", "퍼지로 찾기": "あいまい検索", @@ -614,6 +623,7 @@ "폴더 열기": "フォルダを開く", "폴더 이동": "フォルダを移動", "폴더 추가": "フォルダを追加", + "폴더가 없습니다": "No folder", "폴더들": "ディレクトリ", "폴더를 선택하세요": "フォルダの選択", "폴더를 추가해주세요": "フォルダを追加してください", diff --git a/translation/tr_pl.hdl b/translation/tr_pl.hdl index 0194f78..7d34978 100644 --- a/translation/tr_pl.hdl +++ b/translation/tr_pl.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『 {} 』jest dodany do zakładek", "『 {} 』를 저장 폴더에서 불러왔습니다": "『 {} 』jest załadowany z folderu pobierania", "가능하면 일본어 제목 사용": "Użyj japońskiego tytułu. jeśli jest dostępne", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "Zaimportuj", "가져오기 실패": "Nie udało się zaimportować", "간단 검색": "Proste wyszukiwanie", @@ -255,6 +256,8 @@ "모두 선택": "Zaznacz wszystko", "모든 갤러리 넘버를 복사했습니다.": "Skopiowano wszystkie ID galerii.", "모든 언어": "Wszystkie języki", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "Lista", "목록 주소를 입력해주세요": "Proszę podaj adres listy", "목록 지우기": "Wyczyść listę", @@ -291,6 +294,7 @@ "뷰어... (&V)": "&Przeglądarka...", "브라우저로 보기": "Wyświetl w przeglądarce", "브라우저로 보기 (&B)": "Wyświetl w przeglądarce (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "Uwzględnij podobne obrazy (Wolne)", "비율 유지": "Proporcja obrazu", "비율 유지 - 꽉 차게": "Aspect ratio - fill", @@ -380,6 +384,7 @@ "예(&Y)": "&Tak", "예상치 못한 오류로 다운로드에 실패했습니다.": "Nie udało się pobrać z powodu nieoczekiwanego błędu.", "예시": "Przykład", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "Nieprawidłowy zakres", "올바르지 않은 주소입니다": "Nieprawidłowy link", "올바르지 않은 형식의 검색 필터입니다": "Nieprawidłowo sformatowany filtr wyszukiwania", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "Zadania zaimportowane", "작업들을 내보냈습니다": "Zadania wyeksportowane", "작업이 아직 완료되지 않았습니다": "Zadanie nie zostało jeszcze zakończone", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "Importuj listę galerii", "작품 목록 내보내기": "Eksportuj listę galerii", "잠금": "Zablokuj", @@ -577,6 +584,7 @@ "트래커 추가": "Add trackers", "트레이로 전환되었습니다": "Zminimalizowany do zasobnika systemowego", "트레이로 최소화": "Minimalizuj do zasobnika systemowego", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "Wyświetl powiadomienia w zasobniku", "파일": "Plik", "파일 목록": "File list", @@ -593,6 +601,7 @@ "파일명 형식": "Format nazwy pliku", "파일을 고르세요:": "Select files:", "파일을 선택하세요": "Wybierz plik", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "Brak plików", "패스워드": "Hasło", "퍼지로 찾기": "Szukaj używając Fuzzy", @@ -614,6 +623,7 @@ "폴더 열기": "Otwórz folder", "폴더 이동": "Przenieś folder", "폴더 추가": "Dodaj folder", + "폴더가 없습니다": "No folder", "폴더들": "Katalogi", "폴더를 선택하세요": "Wybierz folder", "폴더를 추가해주세요": "Proszę dodać kilka folderów", diff --git a/translation/tr_pt.hdl b/translation/tr_pt.hdl index 87adaa6..930e587 100644 --- a/translation/tr_pt.hdl +++ b/translation/tr_pt.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『 {} 』foi favoritado", "『 {} 』를 저장 폴더에서 불러왔습니다": "『 {} 』foi carregado da pasta de downloads", "가능하면 일본어 제목 사용": "Usar título em Japonês se disponível", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "Importar", "가져오기 실패": "Falha na importação", "간단 검색": "Pesquisa simples", @@ -255,6 +256,8 @@ "모두 선택": "Selecionar todos", "모든 갤러리 넘버를 복사했습니다.": "Todas as IDs copiadas", "모든 언어": "Todos os idiomas", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "Lista", "목록 주소를 입력해주세요": "Por favor faça uma lista de URLs", "목록 지우기": "Limpar lista", @@ -291,6 +294,7 @@ "뷰어... (&V)": "&Visualizador...", "브라우저로 보기": "Show in browser", "브라우저로 보기 (&B)": "Mostrar no navegador (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "Incluir imagens similares (Lento)", "비율 유지": "Proporção de tela", "비율 유지 - 꽉 차게": "Aspect ratio - fill", @@ -380,6 +384,7 @@ "예(&Y)": "&Sim", "예상치 못한 오류로 다운로드에 실패했습니다.": "O download falhou por um erro inesperado.", "예시": "Exemplo", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "Intervalo inválido", "올바르지 않은 주소입니다": "URL Inválida", "올바르지 않은 형식의 검색 필터입니다": "Filtro de pesquisa formatado de forma inválida", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "Tarefas importadas", "작업들을 내보냈습니다": "Tarefas exportadas", "작업이 아직 완료되지 않았습니다": "A tarefa ainda não foi finalizada", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "Importar lista de galerias", "작품 목록 내보내기": "Exportar lista de galerias", "잠금": "Bloquear", @@ -577,6 +584,7 @@ "트래커 추가": "Add trackers", "트레이로 전환되었습니다": "Minimizado para a bandeja do sistema", "트레이로 최소화": "Minimizar para a bandeja do sistema", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "Mostrar notificações na bandeja", "파일": "Arquivo", "파일 목록": "File list", @@ -593,6 +601,7 @@ "파일명 형식": "Formatação de nome de arquivo", "파일을 고르세요:": "Select files:", "파일을 선택하세요": "Selecione um arquivo", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "Nenhum arquivo", "패스워드": "Senha", "퍼지로 찾기": "Busca imprecisa", @@ -614,6 +623,7 @@ "폴더 열기": "Abrir pasta", "폴더 이동": "Mover pasta", "폴더 추가": "Adicionar pasta", + "폴더가 없습니다": "No folder", "폴더들": "Diretórios", "폴더를 선택하세요": "Selecione uma pasta", "폴더를 추가해주세요": "Por favor adicione uma pasta", diff --git a/translation/tr_si.hdl b/translation/tr_si.hdl index 81e069a..feada8b 100644 --- a/translation/tr_si.hdl +++ b/translation/tr_si.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『 {} 』පිටු සලකුණු කර ඇත", "『 {} 』를 저장 폴더에서 불러왔습니다": "『 {} 』බාගැනීම් ෆෝල්ඩරයෙන් අවපතනය කරනු ලැබේ", "가능하면 일본어 제목 사용": "තිබේ නම් ජපන් මාතෘකාව භාවිතා කරන්න", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "ආයාත", "가져오기 실패": "ආයාත කිරීමට අසමත් විය", "간단 검색": "සරල සෙවීම", @@ -255,6 +256,8 @@ "모두 선택": "සියල්ල තෝරන්න", "모든 갤러리 넘버를 복사했습니다.": "සියලුම ගැලරි හැඳුනුම්පත් පිටපත් කරන ලදී.", "모든 언어": "සියලුම භාෂා", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "ලැයිස්තුව", "목록 주소를 입력해주세요": "කරුණාකර ලැයිස්තු URL එකක් ටයිප් කරන්න", "목록 지우기": "ලැයිස්තුව හිස් කරන්න", @@ -291,6 +294,7 @@ "뷰어... (&V)": "&නරඹන්නා...", "브라우저로 보기": "බ්‍රවුසරයේ පෙන්වන්න", "브라우저로 보기 (&B)": "බ්‍රවුසරයේ පෙන්වන්න (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "සමාන රූප ඇතුළත් කරන්න (මන්දගාමී)", "비율 유지": "දර්ශන අනුපාතය", "비율 유지 - 꽉 차게": "දර්ශන අනුපාතය - පිරවීම", @@ -380,6 +384,7 @@ "예(&Y)": "&ඔව්", "예상치 못한 오류로 다운로드에 실패했습니다.": "අනපේක්ෂිත දෝෂයකින් බාගත කිරීම අසාර්ථක විය.", "예시": "උදාහරණය", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "වලංගු නොවන පරාසය", "올바르지 않은 주소입니다": "වලංගු නැතිURL", "올바르지 않은 형식의 검색 필터입니다": "පෙරහන සමඟ වලංගු නොවන වාක්‍ය ඛණ්ඩ දෝෂයකි", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "කාර්යයන් ආයාත කරන ලදී", "작업들을 내보냈습니다": "කාර්යයන් නිර්යාත කරන ලදී", "작업이 아직 완료되지 않았습니다": "කාර්යය තවමත් අවසන් නැත", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "ගැලරි ලැයිස්තුව ආයාත කරන්න", "작품 목록 내보내기": "ගැලරි ලැයිස්තුව නිර්යාත කරන්න", "잠금": "අගුළු දමන්න", @@ -577,6 +584,7 @@ "트래커 추가": "ට්රැකර් එකතු කරන්න", "트레이로 전환되었습니다": "පද්ධති තැටියට අවම කර ඇත", "트레이로 최소화": "පද්ධති තැටියට අවම කර ඇත", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "තැටියේ දැනුම්දීම් පෙන්වන්න", "파일": "ගොනුව", "파일 목록": "ගොනු ලැයිස්තුව", @@ -593,6 +601,7 @@ "파일명 형식": "ගොනු නාම ආකෘතිය", "파일을 고르세요:": "ගොනු තෝරන්න:", "파일을 선택하세요": "ගොනුවක් තෝරන්න", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "ගොනු නැත", "패스워드": "මුරපදය", "퍼지로 찾기": "Fuzzy විසින් සොයන්න", @@ -614,6 +623,7 @@ "폴더 열기": "ෆෝල්ඩරය විවෘත කරන්න", "폴더 이동": "ෆෝල්ඩරය ගෙන යන්න", "폴더 추가": "ගොනුවක් එක් කරන්න", + "폴더가 없습니다": "No folder", "폴더들": "නාමාවලි", "폴더를 선택하세요": "ෆෝල්ඩරයක් තෝරන්න", "폴더를 추가해주세요": "කරුණාකර ෆෝල්ඩර කිහිපයක් එක් කරන්න", diff --git a/translation/tr_tr.hdl b/translation/tr_tr.hdl index ed2c197..5dc4cd7 100644 --- a/translation/tr_tr.hdl +++ b/translation/tr_tr.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『 {} 』is bookMartked", "『 {} 』를 저장 폴더에서 불러왔습니다": "『 {} 』is loaded from the download folder", "가능하면 일본어 제목 사용": "Use Japanese title if available", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "Import", "가져오기 실패": "Failed to import", "간단 검색": "Simple search", @@ -255,6 +256,8 @@ "모두 선택": "Select all", "모든 갤러리 넘버를 복사했습니다.": "Copied all gallery IDs.", "모든 언어": "All languages", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "List", "목록 주소를 입력해주세요": "Please type a list URL", "목록 지우기": "Clear list", @@ -291,6 +294,7 @@ "뷰어... (&V)": "&Viewer...", "브라우저로 보기": "Show in browser", "브라우저로 보기 (&B)": "Show in browser (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "Include similar images (Slow)", "비율 유지": "Aspect ratio", "비율 유지 - 꽉 차게": "Aspect ratio - fill", @@ -380,6 +384,7 @@ "예(&Y)": "&Yes", "예상치 못한 오류로 다운로드에 실패했습니다.": "Failed to download by unexpected error.", "예시": "Example", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "Invalid range", "올바르지 않은 주소입니다": "Invalid URL", "올바르지 않은 형식의 검색 필터입니다": "Invalid syntax error with filter", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "Tasks imported", "작업들을 내보냈습니다": "Tasks exported", "작업이 아직 완료되지 않았습니다": "Task is not finished yet", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "Import gallery list", "작품 목록 내보내기": "Export gallery list", "잠금": "Lock", @@ -577,6 +584,7 @@ "트래커 추가": "Add trackers", "트레이로 전환되었습니다": "Minimized to system tray", "트레이로 최소화": "Minimize to system tray", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "Show notifications in tray", "파일": "File", "파일 목록": "File list", @@ -593,6 +601,7 @@ "파일명 형식": "Filename format", "파일을 고르세요:": "Select files:", "파일을 선택하세요": "Select a file", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "No files", "패스워드": "Password", "퍼지로 찾기": "Search by Fuzzy", @@ -614,6 +623,7 @@ "폴더 열기": "Open Folder", "폴더 이동": "Move folder", "폴더 추가": "Add folder", + "폴더가 없습니다": "No folder", "폴더들": "Directories", "폴더를 선택하세요": "Select a folder", "폴더를 추가해주세요": "Please add some folders", diff --git a/translation/tr_vi.hdl b/translation/tr_vi.hdl index 3e06cc0..99cf29f 100644 --- a/translation/tr_vi.hdl +++ b/translation/tr_vi.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『 {} 』 là mục trong danh sách yêu thích", "『 {} 』를 저장 폴더에서 불러왔습니다": "『 {} 』được tải lên từ tệp tải xuống", "가능하면 일본어 제목 사용": "Dùng nhãn tiếng Nhật nếu có thể", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "Nhập vào", "가져오기 실패": "Nhập vào thất bại", "간단 검색": "Tìm đơn giản", @@ -255,6 +256,8 @@ "모두 선택": "Chọn all", "모든 갤러리 넘버를 복사했습니다.": "Sao chép tất cả ID Thư viện.", "모든 언어": "Tất cả ngôn ngữ", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "Danh sách", "목록 주소를 입력해주세요": "Xin hãy nhập vào danh sách đường dẫn", "목록 지우기": "Xóa danh sách", @@ -291,6 +294,7 @@ "뷰어... (&V)": "&Trình xem...", "브라우저로 보기": "Show in browser", "브라우저로 보기 (&B)": "Xem trong trình duyệt (&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "Bao gồm các bức ảnh tương tự (Chậm)", "비율 유지": "Tỉ lệ", "비율 유지 - 꽉 차게": "Aspect ratio - fill", @@ -380,6 +384,7 @@ "예(&Y)": "&Đúng", "예상치 못한 오류로 다운로드에 실패했습니다.": "Tải xuống thất bại vì gặp lỗi ngoài dự đoán.", "예시": "Mẫu", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "Phạm vi không hợp lệ", "올바르지 않은 주소입니다": "Đường dẫn không hợp lệ", "올바르지 않은 형식의 검색 필터입니다": "Lỗi cú pháp với bộ lọc", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "Nhiệm vụ đã nhập", "작업들을 내보냈습니다": "Nhiệm vụ đã xuất", "작업이 아직 완료되지 않았습니다": "Nhiệm vụ vẫn chưa được hoàn thành", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "Nhập vào danh sách thư viện", "작품 목록 내보내기": "Xuất ra danh sách thư viện", "잠금": "Khóa", @@ -577,6 +584,7 @@ "트래커 추가": "Add trackers", "트레이로 전환되었습니다": "Đã ẩn xuống khay hệ thống", "트레이로 최소화": "Ẩn xuống khay hệ thống", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "Xem thông báo trong khay", "파일": "Tệp", "파일 목록": "File list", @@ -593,6 +601,7 @@ "파일명 형식": "Định dạng tên tệp", "파일을 고르세요:": "Select files:", "파일을 선택하세요": "Chọn tệp", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "Tệp không tồn tại", "패스워드": "Mật khẩu", "퍼지로 찾기": "Tìm kiếm mờ", @@ -614,6 +623,7 @@ "폴더 열기": "Mở tệp", "폴더 이동": "Di chuyển tệp", "폴더 추가": "Thêm tệp", + "폴더가 없습니다": "No folder", "폴더들": "Thư mục", "폴더를 선택하세요": "Chọn một thư mục", "폴더를 추가해주세요": "Xin hãy thêm vài thư mục", diff --git a/translation/tr_zh-TW.hdl b/translation/tr_zh-TW.hdl index 62ef31d..7197c31 100644 --- a/translation/tr_zh-TW.hdl +++ b/translation/tr_zh-TW.hdl @@ -124,6 +124,7 @@ "『 {} 』를 북마크했습니다": "已將『 {} 』加入收藏夾", "『 {} 』를 저장 폴더에서 불러왔습니다": "已從下載資料夾載入『 {} 』", "가능하면 일본어 제목 사용": "如有可能,使用日文標題", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "匯入", "가져오기 실패": "匯入失敗", "간단 검색": "簡單搜尋", @@ -264,6 +265,8 @@ "모두 선택": "全選", "모든 갤러리 넘버를 복사했습니다.": "已複製所有相簿 ID。", "모든 언어": "所有語言", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "清單", "목록 주소를 입력해주세요": "請輸入清單網址", "목록 지우기": "清空清單", @@ -300,6 +303,7 @@ "뷰어... (&V)": "檢視器(&V)……", "브라우저로 보기": "在瀏覽器中檢視", "브라우저로 보기 (&B)": "在瀏覽器中檢視(&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "包含相似的圖片(較慢)", "비율 유지": "保持比例", "비율 유지 - 꽉 차게": "保持比例-填滿", @@ -389,6 +393,7 @@ "예(&Y)": "是(&Y)", "예상치 못한 오류로 다운로드에 실패했습니다.": "意外的錯誤導致下載失敗。", "예시": "範例", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "範圍無效", "올바르지 않은 주소입니다": "無效的URL", "올바르지 않은 형식의 검색 필터입니다": "搜尋過濾器格式無效", @@ -471,6 +476,8 @@ "작업들을 가져왔습니다": "已匯入任務", "작업들을 내보냈습니다": "已匯出任務", "작업이 아직 완료되지 않았습니다": "任務還未完成", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "匯入作品列表", "작품 목록 내보내기": "匯出作品列表", "잠금": "鎖定", @@ -586,6 +593,7 @@ "트래커 추가": "新增 Tracker", "트레이로 전환되었습니다": "最小化到系統列", "트레이로 최소화": "最小化到系統列", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "在系統列中顯示通知", "파일": "檔案", "파일 목록": "檔案清單", @@ -602,6 +610,7 @@ "파일명 형식": "檔名格式", "파일을 고르세요:": "選擇檔案:", "파일을 선택하세요": "選擇檔案", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "沒有檔案", "패스워드": "密碼", "퍼지로 찾기": "模糊搜尋", @@ -623,6 +632,7 @@ "폴더 열기": "開啟資料夾", "폴더 이동": "移動資料夾", "폴더 추가": "新增資料夾", + "폴더가 없습니다": "No folder", "폴더들": "資料夾列表", "폴더를 선택하세요": "選擇一個資料夾", "폴더를 추가해주세요": "請添加一些資料夾", @@ -655,4 +665,4 @@ "후원": "贊助", "휴지통으로 이동": "移動到資源回收桶" } -} +} \ No newline at end of file diff --git a/translation/tr_zh.hdl b/translation/tr_zh.hdl index 2f73c93..3fb1652 100644 --- a/translation/tr_zh.hdl +++ b/translation/tr_zh.hdl @@ -115,6 +115,7 @@ "『 {} 』를 북마크했습니다": "『 {} 』书签有", "『 {} 』를 저장 폴더에서 불러왔습니다": "『 {} 』从下载文件夹加载", "가능하면 일본어 제목 사용": "使用日语标题(如果可用)", + "가능한 경우 챕터 마커 추가": "Add chapter markers if available", "가져오기": "导入", "가져오기 실패": "导入失败", "간단 검색": "简单搜索", @@ -255,6 +256,8 @@ "모두 선택": "全选", "모든 갤러리 넘버를 복사했습니다.": "复制所有图库 ID。", "모든 언어": "所有语言", + "모든 작업이 완료되면 알림 보이기": "Show notifications when all tasks are complete", + "모든 작업이 완료되었습니다": "All tasks are complete", "목록": "列表", "목록 주소를 입력해주세요": "请输入列表地址", "목록 지우기": "删除列表", @@ -291,6 +294,7 @@ "뷰어... (&V)": "查看器(&V)...", "브라우저로 보기": "在浏览器中显示", "브라우저로 보기 (&B)": "在浏览器中查看(&B)", + "비디오 코덱 우선순위": "Video codec priority", "비슷한 이미지 포함 (느림)": "包括相似的图像(慢)", "비율 유지": "宽高比", "비율 유지 - 꽉 차게": "Aspect ratio - fill", @@ -380,6 +384,7 @@ "예(&Y)": "是(&Y)", "예상치 못한 오류로 다운로드에 실패했습니다.": "下载失败,出现意外错误。", "예시": "示例", + "오디오 코덱 우선순위": "Audio codec priority", "올바르지 않은 범위입니다": "无效的范围", "올바르지 않은 주소입니다": "无效的网址", "올바르지 않은 형식의 검색 필터입니다": "搜索过滤器格式不正确", @@ -462,6 +467,8 @@ "작업들을 가져왔습니다": "已导入任务", "작업들을 내보냈습니다": "已导出任务", "작업이 아직 완료되지 않았습니다": "任务尚未完成", + "작업이 완료되면 알림 보이기": "Show notifications when tasks are complete", + "작업이 완료되었습니다": "The task is complete", "작품 목록 가져오기": "导入图库列表", "작품 목록 내보내기": "导出图库列表", "잠금": "锁定", @@ -577,6 +584,7 @@ "트래커 추가": "Add trackers", "트레이로 전환되었습니다": "最小化到系统托盘", "트레이로 최소화": "最小化到系统托盘", + "트레이로 최소화 알림 보이기": "Show minimize notifications in the tray", "트레이에서 알림 보이기": "在托盘中显示通知", "파일": "文件", "파일 목록": "文件列表", @@ -593,6 +601,7 @@ "파일명 형식": "文件名格式", "파일을 고르세요:": "Select files:", "파일을 선택하세요": "选择一个文件", + "파일의 수정한 날짜를 업로드 날짜로 변경": "Change the file's modified date to the upload date", "파일이 없습니다": "无文件", "패스워드": "密码", "퍼지로 찾기": "模糊搜索", @@ -614,6 +623,7 @@ "폴더 열기": "打开文件夹", "폴더 이동": "移动文件夹", "폴더 추가": "添加文件夹", + "폴더가 없습니다": "No folder", "폴더들": "目录", "폴더를 선택하세요": "选择一个文件夹", "폴더를 추가해주세요": "请输入一个文件夹",