This commit is contained in:
KurtBestor 2022-01-02 11:12:31 +09:00
parent 9b2a8221a4
commit ff031782a7
13 changed files with 210 additions and 134 deletions

View File

@ -1,22 +1,19 @@
#coding: utf-8
import downloader
import ree as re
import os
from utils import Downloader, get_max_range, Soup, clean_title, get_print, try_n
from utils import Downloader, get_max_range, clean_title, get_print, try_n, urljoin, check_alive, LazyUrl, get_ext
from translator import tr_
try: # python2
from urllib import quote
from urlparse import urlparse, parse_qs
except: # python3
from urllib.parse import quote
from urllib.parse import urlparse, parse_qs
import sys
from urllib.parse import quote
from urllib.parse import urlparse, parse_qs
from ratelimit import limits, sleep_and_retry
@Downloader.register
class Downloader_danbooru(Downloader):
type='danbooru'
URLS = ['danbooru.donmai.us']
MAX_CORE = 8
_name = None
@classmethod
@ -27,7 +24,7 @@ class Downloader_danbooru(Downloader):
url = url.replace(' ', '+')
while '++' in url:
url = url.replace('++', '+')
url = u'https://danbooru.donmai.us/?tags={}'.format(quote(url))
url = 'https://danbooru.donmai.us/?tags={}'.format(quote(url))
return url.strip('+')
@property
@ -37,15 +34,18 @@ class Downloader_danbooru(Downloader):
qs = parse_qs(parsed_url.query)
if 'donmai.us/favorites' in self.url:
id = qs.get('user_id', [''])[0]
print('len(id) =', len(id), u'"{}"'.format(id))
print('len(id) =', len(id), '"{}"'.format(id))
assert len(id) > 0, '[Fav] User id is not specified'
id = u'fav_{}'.format(id)
id = 'fav_{}'.format(id)
elif 'donmai.us/explore/posts/popular' in self.url: #4160
soup = read_soup(self.url, self.cw)
id = soup.find('h1').text
else:
tags = qs.get('tags', [])
tags.sort()
id = u' '.join(tags)
id = ' '.join(tags)
if not id:
id = u'N/A'
id = 'N/A'
self._name = id
return clean_title(self._name)
@ -56,19 +56,36 @@ class Downloader_danbooru(Downloader):
for img in imgs:
self.urls.append(img.url)
self.filenames[img.url] = img.filename
self.title = self.name
class Image(object):
def __init__(self, id, url):
def __init__(self, id, url, cw):
self._cw = cw
self.id = id
self.url = url
ext = os.path.splitext(url)[1]
self.filename = u'{}{}'.format(id, ext)
self.url = LazyUrl(url, self.get, self)
def get(self, url):
soup = read_soup(url, self._cw)
ori = soup.find('li', id='post-option-view-original')
if ori:
img = ori.find('a')['href']
else:
img = soup.find('li', id='post-info-size').find('a')['href']
img = urljoin(url, img)
ext = get_ext(img)
self.filename = '{}{}'.format(self.id, ext)
return img
@sleep_and_retry
@limits(2, 1)
def wait(cw):
check_alive(cw)
def setPage(url, page):
# Always use HTTPS
url = url.replace('http://', 'https://')
@ -86,6 +103,13 @@ def setPage(url, page):
return url
@try_n(4) #4103
def read_soup(url, cw):
check_alive(cw)
wait(cw)
return downloader.read_soup(url)
def get_imgs(url, title=None, range_=None, cw=None):
if 'donmai.us/artists' in url:
raise NotImplementedError('Not Implemented')
@ -106,18 +130,18 @@ def get_imgs(url, title=None, range_=None, cw=None):
empty_count_global = 0
url_imgs = set()
while i < len(range_):
check_alive(cw)
p = range_[i]
url = setPage(url, p)
print_(url)
html = try_n(4)(downloader.read_html)(url) #4103
soup = Soup(html)
soup = read_soup(url, cw)
articles = soup.findAll('article')
if articles:
empty_count_global = 0
else:
empty_count += 1
if empty_count < 4:
s = u'empty page; retry... {}'.format(p)
s = 'empty page; retry... {}'.format(p)
print_(s)
continue
else:
@ -129,25 +153,21 @@ def get_imgs(url, title=None, range_=None, cw=None):
for article in articles:
id = article.attrs['data-id']
url_img = article.attrs['data-file-url'].strip()
if url_img.startswith('http://') or url_img.startswith('https://'):
pass
else:
url_img = 'https://{}donmai.us'.format('danbooru.' if 'danbooru.' in url else '') + url_img
#url_img = article.attrs['data-file-url'].strip()
url_img = urljoin(url, article.find('a', class_='post-preview-link')['href']) #4160
#print(url_img)
if url_img not in url_imgs:
url_imgs.add(url_img)
img = Image(id, url_img)
img = Image(id, url_img, cw)
imgs.append(img)
if len(imgs) >= max_pid:
break
if cw is not None:
if not cw.alive:
break
cw.setTitle(u'{} {} - {}'.format(tr_(u'읽는 중...'), title, len(imgs)))
cw.setTitle('{} {} - {}'.format(tr_('읽는 중...'), title, len(imgs)))
i += 1
return imgs[:max_pid]

View File

@ -22,7 +22,7 @@ class Page(object):
def __init__(self, title, url):
self.title = clean_title(title)
self.url = url
self.id = int(re.find('/(comic|webtoon)/([0-9]+)', url, err='no id')[1])
self.id = int(re.find(r'/(comic|webtoon)/([0-9]+)', url, err='no id')[1])
@Downloader.register
@ -97,7 +97,7 @@ class Downloader_manatoki(Downloader):
def get_artist(soup):
view = soup.find('div', class_='view-title')
text = view.text.replace('\n', '#')
artist = re.find('작가[ #]*:[ #]*(.+?)#', text, default='N/A').strip()
artist = re.find(r'작가[ #]*:[ #]*(.+?)#', text, default='N/A').strip()
return artist
@ -115,17 +115,19 @@ def get_soup(url, session=None):
def get_pages(url, soup):
list = soup.find('ul', class_='list-body')
pages = []
for item in list.findAll('div', 'wr-subject'):
titles = {}
for item in list.findAll('div', 'wr-subject')[::-1]:
for span in item.a.findAll('span'):
span.decompose()
title = item.a.text.strip()
title = utils.fix_dup(title, titles) #4161
href = item.a['href']
href = urljoin(url, href)
page = Page(title, href)
pages.append(page)
if not pages:
raise Exception('no pages')
return pages[::-1]
return pages
@page_selector.register('manatoki')
@ -179,7 +181,7 @@ def get_imgs_page(page, title, referer, session, cw):
# 2183
session, soup, page.url = get_soup(page.url, session)
title_page = clean_title(soup.find('span', class_='page-desc').text.strip())
title_page = page.title#clean_title(soup.find('span', class_='page-desc').text.strip())
if page.title != title_page:
print_('{} -> {}'.format(page.title, title_page))
page.title = title_page
@ -221,7 +223,7 @@ def get_imgs_page(page, title, referer, session, cw):
def isVisible(tag):
while tag:
if re.search('display: *none', tag.get('style', ''), re.IGNORECASE):
if re.search(r'display: *none', tag.get('style', ''), re.IGNORECASE):
return False
tag = tag.parent
return True

View File

@ -1,7 +1,7 @@
#coding: utf8
import downloader
import ytdl
from utils import Downloader, get_outdir, Soup, LazyUrl, try_n, compatstr, format_filename, get_ext, clean_title, Session, cut_pair, json_loads, get_print, get_resolution
from utils import Downloader, get_outdir, Soup, LazyUrl, try_n, compatstr, format_filename, get_ext, clean_title, Session, get_print, get_resolution, get_max_range
from io import BytesIO
from m3u8_tools import M3u8_stream
import ree as re
@ -70,48 +70,21 @@ class Downloader_twitch(Downloader):
@try_n(2)
def get_videos(url, cw=None):
print_ = get_print(cw)
print_(f'get_videos: {url}')
info = {}
user_id = re.find(r'twitch.tv/([^/?]+)', url, err='no user_id')
print(user_id)
session = Session()
r = session.get(url)
s = cut_pair(re.find(r'headers *: *({.*)', r.text, err='no headers'))
print(s)
headers = json_loads(s)
payload = [
{
'operationName': 'ClipsCards__User',
'variables': {
'login': user_id,
'limit': 20,
'criteria': {'filter': 'ALL_TIME'}},
'extensions': {'persistedQuery': {'version': 1, 'sha256Hash': 'b73ad2bfaecfd30a9e6c28fada15bd97032c83ec77a0440766a56fe0bd632777'}},
options = {
'extract_flat': True,
'playlistend': get_max_range(cw),
}
]
videos = []
cursor = None
cursor_new = None
while True:
if cursor:
payload[0]['variables']['cursor'] = cursor
r = session.post('https://gql.twitch.tv/gql', json=payload, headers=headers)
#print(r)
data = r.json()
for edge in data[0]['data']['user']['clips']['edges']:
url_video = edge['node']['url']
info['name'] = edge['node']['broadcaster']['displayName']
video = Video(url_video, cw)
video.id = int(edge['node']['id'])
videos.append(video)
cursor_new = edge['cursor']
print_('videos: {} / cursor: {}'.format(len(videos), cursor))
if cursor == cursor_new:
print_('same cursor')
break
if cursor_new is None:
break
cursor = cursor_new
ydl = ytdl.YoutubeDL(options, cw=cw)
info = ydl.extract_info(url)
for e in info['entries']:
video = Video(e['url'], cw)
video.id = int(e['id'])
videos.append(video)
if 'name' not in info:
info['name'] = ydl.extract_info(e['url'])['creator']
if not videos:
raise Exception('no videos')
info['videos'] = sorted(videos, key=lambda video: video.id, reverse=True)
@ -161,7 +134,7 @@ class Video(object):
info = extract_info(url, self.cw)
def print_video(video):
print_(video)#
#print_(video)#
print_('{}[{}] [{}] [{}] {}'.format('LIVE ', video['format_id'], video.get('height'), video.get('tbr'), video['url']))
videos = [video for video in info['formats'] if video.get('height')]

View File

@ -1,12 +1,13 @@
from urllib.parse import unquote
from utils import Downloader, urljoin, clean_title, try_n
from utils import Downloader, urljoin, clean_title, try_n, check_alive, LazyUrl, get_ext, get_max_range
from translator import tr_
import ree as re
import os
import downloader
from ratelimit import limits, sleep_and_retry
@try_n(4)
@sleep_and_retry
@limits(4, 1)
def read_soup(url):
return downloader.read_soup(url)
@ -19,36 +20,34 @@ class Downloader_yandere(Downloader):
@classmethod
def fix_url(cls, url):
url = re.sub(r'\?page=[0-9]+&', '?', url)
url = re.sub(r'&page=[0-9]+', '', url)
url = re.sub(r'([?&])page=[0-9]+&?', r'\1', url).rstrip('?&')
pool = re.find('/pool/show/([0-9]+)', url)
if pool is not None:
url = urljoin(url, '/post?tags=pool%3A{}'.format(pool))
return url
def read(self):
cw = self.cw
title = self.get_title(self.url)
ids = set()
url = self.url
n = get_max_range(self.cw)
ids = set()
while True:
check_alive(self.cw)
soup = read_soup(url)
tmp = soup.find_all(attrs={'class':'directlink'}, href=True)
for image_html in tmp:
image_url = image_html['href']
id_ = self.get_id(image_url)
for a in soup.find_all('a', class_='thumb'):
id_ = re.find(r'/show/([0-9]+)', a['href'], err='no id')
if id_ in ids:
self.print_('duplicate: {}'.format(id_))
self.print_(f'dup: {id_}')
continue
ids.add(id_)
self.urls.append(image_url)
self.filenames[image_url] = self.get_filename(image_url)
if not cw.alive:
img = Image(urljoin(url, a['href']), id_)
self.urls.append(img.url)
if len(self.urls) >= n:
del self.urls[n:]
break
cw.setTitle('{} {} - {}'.format(tr_('읽는 중...'), title, len(self.urls)))
self.cw.setTitle('{} {} - {}'.format(tr_('읽는 중...'), title, len(self.urls)))
next_page = soup.find('a', attrs={'rel':'next'}, href=True)
if not next_page:
@ -62,14 +61,6 @@ class Downloader_yandere(Downloader):
id_ = url.split('yande.re%20')[1].split('%20')[0]
return int(id_)
def get_filename(self, url:str) -> str:
url_unquote = unquote(url)
id_tags_extension = url_unquote.split("yande.re")[-1].split(" ")[1:]
filename = "_".join(id_tags_extension)
name, ext = os.path.splitext(filename)
name = str(self.get_id(url))#
return clean_title(name, n=-len(ext)) + ext
def get_title(self, url:str) -> str:
if "tags=" not in url:
raise NotImplementedError('no tags')
@ -77,3 +68,18 @@ class Downloader_yandere(Downloader):
url_tags = url.split("tags=")[-1].split('+')
return clean_title(" ".join(url_tags))
class Image:
def __init__(self, url, id_):
self._id = id_
self.url = LazyUrl(url, self.get, self)
def get(self, url):
soup = read_soup(url)
img = soup.find('a', class_='original-file-unchanged') or soup.find('a', class_='original-file-changed')
img = urljoin(url, img['href'])
ext = get_ext(img)
self.filename = clean_title(self._id, n=-len(ext)) + ext
return img

View File

@ -1,55 +1,91 @@
3.7e 2021-12-27
3.7f 【】
[Bug Resolution / Fix due to site change]
[버그 해결 / 사이트 변경에 의한 수정]
- iwara: fixed un-downloaded channels (#4030)
- Danbooru 업데이트 대응 (#4160)
- Facebook: fixed un-downloaded videos (#4064)
- Hitomi.la 업데이트 대응 (#4214)
- XVideos: fixed un-downloaded videos (#4083)
- 다운로드 중 삭제하면 버벅이는 문제 해결
- Jmana: support for website update (#4070)
- E(x)Hentai private 다운로드 안 되는 문제 해결 (#4223)
- Pixiv Newest works ('Following'): support for website update (#4077)
- Twitch 클립 리스트 다운로드 안 되는 문제 해결 (#4191)
- Bilibili: fixed playlist download (#4117)
- Mastodon: fixed download error (#4125)
- Hitomi.la: support for website update (#4126, #4152)
- syosetu.com, kakuyomu.jp: fixed download error (#4137)
- Other small things
- 기타 자잘한 것들
[Changed/Added Features]
[변경/추가된 기능]
- 4chan: support(#2085, #4116)
- Danbooru popular 다운로드 (#4160)
- YouTube Live Stream: support
- #4161
- Twitch Live Stream: support
- Yande.re 원본 이미지 다운로드 (#4231)
- "View in browser": fixed to work even if HTTP API is turned off (#4060)
- #4159
- Move with with arrow keys (#4060)
- 기타 자잘한 것들
- Deduplication: auto select the most recent (#4085)
- Task list filter: support for logical operator (OR, NOT, parentheses) (#4046)
Example:
--------------------------------------------------------------------------------------------------------------------------------------------
3.7e 【Dec 27, 2021】
[버그 해결 / 사이트 변경에 의한 수정]
- iwara 일부 채널 다운로드 안 되는 문제 해결 (#4030)
- Facebook 일부 영상 다운로드 안 되는 문제 해결 (#4064)
- XVideos 일부 영상 다운로드 안 되는 문제 해결 (#4083)
- Jmana 업데이트 대응 (#4070)
- Pixiv Newest works: Following 업데이트 대응 (#4077)
- Bilibili 플레이리스트 페이지만 다른 영상 동시에 다운로드할 때 생기는 문제 해결 (#4117)
- Mastodon 계열 문제 해결 (#4125)
- Hitomi.la 업데이트 대응 (#4126, #4152)
- #4137
- #4185
- #4196
- 기타 자잘한 것들
[변경/추가된 기능]
- 4chan 지원 (#2085, #4116)
- YouTube Live Stream 지원
- Twitch Live Stream 지원
- "브라우저로 보기" HTTP API 꺼도 보이게 수정 (#4060)
- 방향키로 화 이동 (#4060)
- 중북 이미지 찾기 "자동 선택": 완전히 같은 파일일 경우 최근 이미지 우선 선택 (#4085)
- 작업 목록 필터링 OR, NOT, 괄호 지원 (#4046)
예:
A OR B
NOT type:youtube
(A OR B) C
- danbooru: support to download pages >100 (ex: danbooru.donmai.us/posts?page=101, danbooru.donmai.us/posts?page=102, etc.) #4103
- #4103
- (#4110)
- #4110
- Twitter: optimising download speed (#4130)
- #4130
- Other small things
- 기타 자잘한 것들

View File

@ -1,3 +1,35 @@
3.7f 【】
[버그 해결 / 사이트 변경에 의한 수정]
- Danbooru 업데이트 대응 (#4160)
- Hitomi.la 업데이트 대응 (#4214)
- 다운로드 중 삭제하면 버벅이는 문제 해결
- E(x)Hentai private 다운로드 안 되는 문제 해결 (#4223)
- Twitch 클립 리스트 다운로드 안 되는 문제 해결 (#4191)
- 기타 자잘한 것들
[변경/추가된 기능]
- Danbooru popular 다운로드 (#4160)
- #4161
- Yande.re 원본 이미지 다운로드 (#4231)
- #4159
- 기타 자잘한 것들
--------------------------------------------------------------------------------------------------------------------------------------------
3.7e 【Dec 27, 2021】
[버그 해결 / 사이트 변경에 의한 수정]

View File

@ -207,6 +207,7 @@
"로그인 실패: {}{}\n[옵션 - 설정 - Pixiv 설정 - 로그인] 에서 설정해주세요.": "Failed to login: {}{}\nPlease see [Options - Preferences - Pixiv Setting - Login].",
"로그인 중...": "Logging in...",
"로그인 테스트": "Test Login",
"로컬 파일 감지": "Detect local files",
"로컬 파일로부터 새 작업 만들기": "Create a new task from the local files",
"를 북마크에서 지웠습니다": "is removed from bookmarks",
"릴리즈 노트": "Release note",

View File

@ -207,6 +207,7 @@
"로그인 실패: {}{}\n[옵션 - 설정 - Pixiv 설정 - 로그인] 에서 설정해주세요.": "Error de inicio de sesión: {}{}\n Consulte [Opciones - Preferencias - Configuración de Pixiv - Inicio de sesión].",
"로그인 중...": "Iniciar sesión",
"로그인 테스트": "Probar el inicio de sesión",
"로컬 파일 감지": "Detect local files",
"로컬 파일로부터 새 작업 만들기": "Create a new task from the local files",
"를 북마크에서 지웠습니다": "se elimina de favoritos",
"릴리즈 노트": "Notes de la versió",

View File

@ -207,6 +207,7 @@
"로그인 실패: {}{}\n[옵션 - 설정 - Pixiv 설정 - 로그인] 에서 설정해주세요.": "Échec de la connexion : {}{}\nVeuillez consulter [Options - Paramètres - Paramètres Pixiv - Connexion].",
"로그인 중...": "Se connecter...",
"로그인 테스트": "Tester le Login",
"로컬 파일 감지": "Detect local files",
"로컬 파일로부터 새 작업 만들기": "Créer une nouvelle tâche depuis les fichiers locaux",
"를 북마크에서 지웠습니다": "est supprimé des favoris",
"릴리즈 노트": "Notes de version",

View File

@ -207,6 +207,7 @@
"로그인 실패: {}{}\n[옵션 - 설정 - Pixiv 설정 - 로그인] 에서 설정해주세요.": "ログインに失敗しました: {}{}\n[オプション-環境設定-Pixiv設定-ログイン]をご覧ください。",
"로그인 중...": "ログイン中...",
"로그인 테스트": "テストログイン",
"로컬 파일 감지": "Detect local files",
"로컬 파일로부터 새 작업 만들기": "ローカルファイルから新しいタスクを作成する",
"를 북마크에서 지웠습니다": "をブックマークから消去しました",
"릴리즈 노트": "リリースノート",

View File

@ -207,6 +207,7 @@
"로그인 실패: {}{}\n[옵션 - 설정 - Pixiv 설정 - 로그인] 에서 설정해주세요.": "Falha no login: {}{}\nPor favor veja [Opções - Preferências - Configurações Pixiv - Login].",
"로그인 중...": "Realizando login...",
"로그인 테스트": "Testar login",
"로컬 파일 감지": "Detect local files",
"로컬 파일로부터 새 작업 만들기": "Criar uma nova tarefa a partir de arquivo local",
"를 북마크에서 지웠습니다": "removido dos favoritos",
"릴리즈 노트": "Nota de atualização",

View File

@ -207,6 +207,7 @@
"로그인 실패: {}{}\n[옵션 - 설정 - Pixiv 설정 - 로그인] 에서 설정해주세요.": "Đăng nhập thất bại: {}{}\nVui lòng xem [Lựa chọn - Tùy chỉnh - Pixiv - Đăng nhập].",
"로그인 중...": "Đang đăng nhập...",
"로그인 테스트": "Kiểm tra đăng nhập",
"로컬 파일 감지": "Detect local files",
"로컬 파일로부터 새 작업 만들기": "Tạo nhiệm vụ mới từ tệp cục bộ",
"를 북마크에서 지웠습니다": "Được gỡ bỏ khỏi danh sách yêu thích",
"릴리즈 노트": "Ghi chú khi phát hành",

View File

@ -207,6 +207,7 @@
"로그인 실패: {}{}\n[옵션 - 설정 - Pixiv 설정 - 로그인] 에서 설정해주세요.": "登录失败: {}{}\n请查看 [选项 - 偏好 - Pixiv 设置 - 登录].",
"로그인 중...": "登录...",
"로그인 테스트": "登录测试",
"로컬 파일 감지": "Detect local files",
"로컬 파일로부터 새 작업 만들기": "从本地文件创建新任务",
"를 북마크에서 지웠습니다": "已从书签中删除",
"릴리즈 노트": "版本说明",