From 2de2e29e28603875765061c04344357939753a5d Mon Sep 17 00:00:00 2001 From: mo_yy Date: Mon, 30 Mar 2020 22:35:35 +0800 Subject: [PATCH] 3.93 --- AVDC_Main.py | 840 +++++++++++++++++++++--------------- Function/Function.py | 97 +++-- Function/getHtml.py | 45 +- Getter/avsox.py | 96 +++-- Getter/dmm.py | 57 +-- Getter/fc2fans_club.py | 87 ++-- Getter/jav321.py | 152 +++++++ Getter/javbus.py | 246 +++++------ Getter/javdb.py | 325 +++++++------- Getter/mgstage.py | 172 ++++---- {Ui => Img}/AVDC-ico.png | Bin Img/AVDC.ico | Bin 0 -> 1081406 bytes Img/LEAK.png | Bin 0 -> 13236 bytes Img/SUB.png | Bin 0 -> 10532 bytes Img/UNCENSORED.png | Bin 0 -> 11067 bytes Ui/AVDC.py | 414 +++++++++++++----- Ui/AVDC.ui | 901 +++++++++++++++++++++++++++------------ config.ini | 22 +- update_check.json | 4 +- 19 files changed, 2192 insertions(+), 1266 deletions(-) create mode 100644 Getter/jav321.py rename {Ui => Img}/AVDC-ico.png (100%) create mode 100644 Img/AVDC.ico create mode 100644 Img/LEAK.png create mode 100644 Img/SUB.png create mode 100644 Img/UNCENSORED.png diff --git a/AVDC_Main.py b/AVDC_Main.py index e08fb7184..b378a0353 100644 --- a/AVDC_Main.py +++ b/AVDC_Main.py @@ -1,16 +1,15 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- import threading +import json +from PyQt5 import QtWidgets from PyQt5.QtGui import QPixmap from PyQt5.QtGui import QTextCursor, QCursor -from PyQt5.QtWidgets import * +from PyQt5.QtWidgets import QMainWindow, QTreeWidgetItem, QApplication from PyQt5.QtCore import pyqtSignal, Qt -from Ui.AVDC import * import sys import time import os.path -from Function.Function import * -from Function.getHtml import * import requests import shutil import base64 @@ -18,6 +17,10 @@ from aip import AipBodyAnalysis from PIL import Image import os +from configparser import ConfigParser +from Ui.AVDC import Ui_AVDV +from Function.Function import save_config, movie_lists, get_info, getDataFromJSON, escapePath, getNumber +from Function.getHtml import get_html class MyMAinWindow(QMainWindow, Ui_AVDV): @@ -30,9 +33,10 @@ def __init__(self, parent=None): self.Init_Ui() self.set_style() # 初始化需要的变量 - self.version = '3.92' + self.version = '3.93' self.m_drag = False self.m_DragPosition = 0 + self.count_claw = 0 # 批量刮削次数 self.item_succ = self.Ui.treeWidget_number.topLevelItem(0) self.item_fail = self.Ui.treeWidget_number.topLevelItem(1) self.json_array = {} @@ -52,19 +56,18 @@ def Init_Ui(self): ico_path = '' if os.path.exists('AVDC-ico.png'): ico_path = 'AVDC-ico.png' - elif os.path.exists('Ui/AVDC-ico.png'): - ico_path = 'Ui/AVDC-ico.png' + elif os.path.exists('Img/AVDC-ico.png'): + ico_path = 'Img/AVDC-ico.png' pix = QPixmap(ico_path) self.Ui.label_ico.setScaledContents(True) self.Ui.label_ico.setPixmap(pix) # 添加图标 self.Ui.progressBar_avdc.setValue(0) # 进度条清0 self.progressBarValue.connect(self.set_processbar) self.Ui.progressBar_avdc.setTextVisible(False) # 不显示进度条文字 - self.setWindowFlag(QtCore.Qt.FramelessWindowHint) # 隐藏边框 + self.setWindowFlag(Qt.FramelessWindowHint) # 隐藏边框 # self.setWindowOpacity(0.9) # 设置窗口透明度 - self.setAttribute(QtCore.Qt.WA_TranslucentBackground) # 设置窗口背景透明 + self.setAttribute(Qt.WA_TranslucentBackground) # 设置窗口背景透明 self.Ui.treeWidget_number.expandAll() - self.Ui.checkBox_cover.setChecked(True) def set_style(self): # 控件美化 @@ -121,7 +124,7 @@ def set_style(self): border-radius:10px; padding:2px 4px; } - QPushButton#pushButton_start_cap,#pushButton_move_mp4,#pushButton_select_file,#pushButton_select_fanart{ + QPushButton#pushButton_start_cap,#pushButton_move_mp4,#pushButton_select_file,#pushButton_select_thumb{ font-size:20px; background:#F0F8FF; border:2px solid white; @@ -137,8 +140,7 @@ def set_style(self): border-radius:20px; padding:2px 4px; } - QPushButton#pushButton_save_config,#pushButton_show_pic_actor{ - font-size:20px; + QPushButton#pushButton_save_config,#pushButton_show_pic_actor,#pushButton_init_config{ background:#F0F8FF; border:2px solid white; width:300px; @@ -165,81 +167,16 @@ def Init(self): self.Ui.pushButton_about.clicked.connect(self.pushButton_about_clicked) self.Ui.pushButton_start_cap.clicked.connect(self.pushButton_start_cap_clicked) self.Ui.pushButton_save_config.clicked.connect(self.pushButton_save_config_clicked) + self.Ui.pushButton_init_config.clicked.connect(self.pushButton_init_config_clicked) self.Ui.pushButton_move_mp4.clicked.connect(self.move_file) self.Ui.pushButton_add_actor_pic.clicked.connect(self.pushButton_add_actor_pic_clicked) self.Ui.pushButton_show_pic_actor.clicked.connect(self.pushButton_show_pic_actor_clicked) - self.Ui.pushButton_select_fanart.clicked.connect(self.pushButton_select_fanart_clicked) + self.Ui.pushButton_select_thumb.clicked.connect(self.pushButton_select_thumb_clicked) self.Ui.pushButton_log.clicked.connect(self.pushButton_show_log_clicked) self.Ui.checkBox_cover.stateChanged.connect(self.cover_change) self.Ui.horizontalSlider_timeout.valueChanged.connect(self.lcdNumber_timeout_change) self.Ui.horizontalSlider_retry.valueChanged.connect(self.lcdNumber_retry_change) - - # ========================================================================加载config - def Load_Config(self): - config_file = 'config.ini' - config = ConfigParser() - config.read(config_file, encoding='UTF-8') - if int(config['common']['main_mode']) == 1: - self.Ui.radioButton_common.setChecked(True) - elif int(config['common']['main_mode']) == 2: - self.Ui.radioButton_sort.setChecked(True) - if int(config['common']['soft_link']) == 1: - self.Ui.radioButton_soft_on.setChecked(True) - elif int(config['common']['soft_link']) == 0: - self.Ui.radioButton_soft_off.setChecked(True) - if int(config['common']['failed_file_move']) == 1: - self.Ui.radioButton_fail_move_on.setChecked(True) - elif int(config['common']['failed_file_move']) == 0: - self.Ui.radioButton_fail_move_off.setChecked(True) - if int(config['update']['update_check']) == 1: - self.Ui.radioButton_update_on.setChecked(True) - elif int(config['update']['update_check']) == 0: - self.Ui.radioButton_update_off.setChecked(True) - if int(config['log']['save_log']) == 1: - self.Ui.radioButton_log_on.setChecked(True) - elif int(config['log']['save_log']) == 0: - self.Ui.radioButton_log_off.setChecked(True) - if int(config['debug_mode']['switch']) == 1: - self.Ui.radioButton_debug_on.setChecked(True) - elif int(config['debug_mode']['switch']) == 0: - self.Ui.radioButton_debug_off.setChecked(True) - if config['media']['media_warehouse'] == 'emby' or config['media']['media_warehouse'] == 'jellyfin': - self.Ui.radioButton_emby.setChecked(True) - elif config['media']['media_warehouse'] == 'plex': - self.Ui.radioButton_plex.setChecked(True) - elif config['media']['media_warehouse'] == 'kodi': - self.Ui.radioButton_kodi.setChecked(True) - if config['common']['website'] == 'all': - self.Ui.comboBox_website_all.setCurrentIndex(0) - elif config['common']['website'] == 'mgstage': - self.Ui.comboBox_website_all.setCurrentIndex(1) - elif config['common']['website'] == 'fc2club': - self.Ui.comboBox_website_all.setCurrentIndex(2) - elif config['common']['website'] == 'javbus': - self.Ui.comboBox_website_all.setCurrentIndex(3) - elif config['common']['website'] == 'javdb': - self.Ui.comboBox_website_all.setCurrentIndex(4) - elif config['common']['website'] == 'avsox': - self.Ui.comboBox_website_all.setCurrentIndex(5) - elif config['common']['website'] == 'dmm': - self.Ui.comboBox_website_all.setCurrentIndex(6) - self.Ui.lineEdit_success.setText(config['common']['success_output_folder']) - self.Ui.lineEdit_fail.setText(config['common']['failed_output_folder']) - self.Ui.lineEdit_escape_dir.setText(config['escape']['folders']) - self.Ui.lineEdit_escape_char.setText(config['escape']['literals']) - self.Ui.lineEdit_escape_dir_move.setText(config['escape']['folders']) - self.Ui.lineEdit_escape_string.setText(config['escape']['string']) - self.Ui.lineEdit_proxy.setText(config['proxy']['proxy']) - self.Ui.horizontalSlider_timeout.setValue(int(config['proxy']['timeout'])) - self.Ui.horizontalSlider_retry.setValue(int(config['proxy']['retry'])) - self.Ui.lineEdit_dir_name.setText(config['Name_Rule']['folder_name']) - self.Ui.lineEdit_media_name.setText(config['Name_Rule']['naming_media']) - self.Ui.lineEdit_local_name.setText(config['Name_Rule']['naming_file']) - self.Ui.lineEdit_emby_url.setText(config['emby']['emby_url']) - self.Ui.lineEdit_api_key.setText(config['emby']['api_key']) - self.Ui.lineEdit_movie_path.setText(str(config['media']['media_path']).replace('\\', '/')) - self.Ui.lineEdit_movie_type.setText(config['media']['media_type']) - self.Ui.lineEdit_sub_type.setText(config['media']['sub_type']) + self.Ui.horizontalSlider_mark_size.valueChanged.connect(self.lcdNumber_mark_size_change) # ========================================================================显示版本号 def show_version(self): @@ -294,10 +231,14 @@ def lcdNumber_retry_change(self): retry = self.Ui.horizontalSlider_retry.value() self.Ui.lcdNumber_retry.display(retry) + def lcdNumber_mark_size_change(self): + mark_size = self.Ui.horizontalSlider_mark_size.value() + self.Ui.lcdNumber_mark_size.display(mark_size) + def cover_change(self): if not self.Ui.checkBox_cover.isChecked(): self.Ui.label_poster.setText("封面图") - self.Ui.label_fanart.setText("缩略图") + self.Ui.label_thumb.setText("缩略图") def treeWidget_number_clicked(self, qmodeLindex): item = self.Ui.treeWidget_number.currentItem() @@ -312,11 +253,164 @@ def pushButton_start_cap_clicked(self): self.Ui.pushButton_start_cap.setEnabled(False) self.progressBarValue.emit(int(0)) try: + self.count_claw += 1 t = threading.Thread(target=self.AVDC_Main) t.start() # 启动线程,即让线程开始执行 except Exception as error_info: self.add_text_main('[-]Error in pushButton_start_cap_clicked: ' + str(error_info)) + # ========================================================================恢复默认config.ini + def pushButton_init_config_clicked(self): + try: + t = threading.Thread(target=self.init_config_clicked) + t.start() # 启动线程,即让线程开始执行 + except Exception as error_info: + self.add_text_main('[-]Error in pushButton_save_config_clicked: ' + str(error_info)) + + def init_config_clicked(self): + json_config = { + 'show_poster': 1, + 'main_mode': 1, + 'soft_link': 0, + 'switch_debug': 1, + 'failed_file_move': 1, + 'update_check': 1, + 'save_log': 1, + 'website': 'all', + 'failed_output_folder': 'failed', + 'success_output_folder': 'JAV_output', + 'proxy': '127.0.0.1:10809', + 'timeout': 7, + 'retry': 3, + 'folder_name': 'actor/number-title-release', + 'naming_media': 'number-title', + 'naming_file': 'number', + 'literals': '\()', + 'folders': 'failed,JAV_output', + 'string': '1080p,720p,22-sht.me,-HD', + 'emby_url': 'localhost:8096', + 'api_key': 'bb2e96d99cbf471ea83065d40b229fc1', + 'media_path': 'E:/TEMP', + 'media_type': '.mp4|.avi|.rmvb|.wmv|.mov|.mkv|.flv|.ts|.webm|.MP4|.AVI|.RMVB|.WMV|.MOV|.MKV|.FLV|.TS|.WEBM', + 'sub_type': '.smi|.srt|.idx|.sub|.sup|.psb|.ssa|.ass|.txt|.usf|.xss|.ssf|.rt|.lrc|.sbv|.vtt|.ttml', + 'poster_mark': 1, + 'thumb_mark': 1, + 'mark_size': 3, + 'mark_type': 'SUB, LEAK, UNCENSORED', + 'mark_pos': 'top_left', + 'uncensored_poster': 0, + 'uncensored_prefix': 'S2M|BT|LAF|SMD', + } + save_config(json_config) + self.Load_Config() + + # ========================================================================加载config + def Load_Config(self): + config_file = 'config.ini' + config = ConfigParser() + config.read(config_file, encoding='UTF-8') + # ========================================================================common + if int(config['common']['main_mode']) == 1: + self.Ui.radioButton_common.setChecked(True) + elif int(config['common']['main_mode']) == 2: + self.Ui.radioButton_sort.setChecked(True) + if int(config['common']['soft_link']) == 1: + self.Ui.radioButton_soft_on.setChecked(True) + elif int(config['common']['soft_link']) == 0: + self.Ui.radioButton_soft_off.setChecked(True) + if int(config['common']['failed_file_move']) == 1: + self.Ui.radioButton_fail_move_on.setChecked(True) + elif int(config['common']['failed_file_move']) == 0: + self.Ui.radioButton_fail_move_off.setChecked(True) + if int(config['common']['show_poster']) == 1: + self.Ui.checkBox_cover.setChecked(True) + elif int(config['common']['show_poster']) == 0: + self.Ui.checkBox_cover.setChecked(False) + if config['common']['website'] == 'all': + self.Ui.comboBox_website_all.setCurrentIndex(0) + elif config['common']['website'] == 'mgstage': + self.Ui.comboBox_website_all.setCurrentIndex(1) + elif config['common']['website'] == 'fc2club': + self.Ui.comboBox_website_all.setCurrentIndex(2) + elif config['common']['website'] == 'javbus': + self.Ui.comboBox_website_all.setCurrentIndex(3) + elif config['common']['website'] == 'jav321': + self.Ui.comboBox_website_all.setCurrentIndex(4) + elif config['common']['website'] == 'javdb': + self.Ui.comboBox_website_all.setCurrentIndex(5) + elif config['common']['website'] == 'avsox': + self.Ui.comboBox_website_all.setCurrentIndex(6) + elif config['common']['website'] == 'dmm': + self.Ui.comboBox_website_all.setCurrentIndex(7) + self.Ui.lineEdit_success.setText(config['common']['success_output_folder']) + self.Ui.lineEdit_fail.setText(config['common']['failed_output_folder']) + # ========================================================================proxy + self.Ui.lineEdit_proxy.setText(config['proxy']['proxy']) + self.Ui.horizontalSlider_timeout.setValue(int(config['proxy']['timeout'])) + self.Ui.horizontalSlider_retry.setValue(int(config['proxy']['retry'])) + # ========================================================================Name_Rule + self.Ui.lineEdit_dir_name.setText(config['Name_Rule']['folder_name']) + self.Ui.lineEdit_media_name.setText(config['Name_Rule']['naming_media']) + self.Ui.lineEdit_local_name.setText(config['Name_Rule']['naming_file']) + # ========================================================================update + if int(config['update']['update_check']) == 1: + self.Ui.radioButton_update_on.setChecked(True) + elif int(config['update']['update_check']) == 0: + self.Ui.radioButton_update_off.setChecked(True) + # ========================================================================log + if int(config['log']['save_log']) == 1: + self.Ui.radioButton_log_on.setChecked(True) + elif int(config['log']['save_log']) == 0: + self.Ui.radioButton_log_off.setChecked(True) + # ========================================================================media + self.Ui.lineEdit_movie_type.setText(config['media']['media_type']) + self.Ui.lineEdit_sub_type.setText(config['media']['sub_type']) + self.Ui.lineEdit_movie_path.setText(str(config['media']['media_path']).replace('\\', '/')) + # ========================================================================escape + self.Ui.lineEdit_escape_dir.setText(config['escape']['folders']) + self.Ui.lineEdit_escape_char.setText(config['escape']['literals']) + self.Ui.lineEdit_escape_dir_move.setText(config['escape']['folders']) + self.Ui.lineEdit_escape_string.setText(config['escape']['string']) + # ========================================================================debug_mode + if int(config['debug_mode']['switch']) == 1: + self.Ui.radioButton_debug_on.setChecked(True) + elif int(config['debug_mode']['switch']) == 0: + self.Ui.radioButton_debug_off.setChecked(True) + # ========================================================================emby + self.Ui.lineEdit_emby_url.setText(config['emby']['emby_url']) + self.Ui.lineEdit_api_key.setText(config['emby']['api_key']) + # ========================================================================mark + if int(config['mark']['poster_mark']) == 1: + self.Ui.radioButton_poster_mark_on.setChecked(True) + elif int(config['mark']['poster_mark']) == 0: + self.Ui.radioButton_poster_mark_off.setChecked(True) + if int(config['mark']['thumb_mark']) == 1: + self.Ui.radioButton_thumb_mark_on.setChecked(True) + elif int(config['mark']['thumb_mark']) == 0: + self.Ui.radioButton_thumb_mark_off.setChecked(True) + self.Ui.horizontalSlider_mark_size.setValue(int(config['mark']['mark_size'])) + if 'SUB' in config['mark']['mark_type']: + self.Ui.checkBox_sub.setChecked(True) + if 'LEAK' in config['mark']['mark_type']: + self.Ui.checkBox_leak.setChecked(True) + if 'UNCENSORED' in config['mark']['mark_type']: + self.Ui.checkBox_uncensored.setChecked(True) + if 'top_left' == config['mark']['mark_pos']: + self.Ui.radioButton_top_left.setChecked(True) + elif 'bottom_left' == config['mark']['mark_pos']: + self.Ui.radioButton_bottom_left.setChecked(True) + elif 'top_right' == config['mark']['mark_pos']: + self.Ui.radioButton_top_right.setChecked(True) + elif 'bottom_right' == config['mark']['mark_pos']: + self.Ui.radioButton_bottom_right.setChecked(True) + # ========================================================================uncensored + if int(config['uncensored']['uncensored_poster']) == 1: + self.Ui.radioButton_poster_cut.setChecked(True) + elif int(config['uncensored']['uncensored_poster']) == 0: + self.Ui.radioButton_poster_official.setChecked(True) + self.Ui.lineEdit_uncensored_prefix.setText(config['uncensored']['uncensored_prefix']) + + # ========================================================================读取设置页设置,保存在config.ini def pushButton_save_config_clicked(self): try: t = threading.Thread(target=self.save_config_clicked) @@ -324,16 +418,21 @@ def pushButton_save_config_clicked(self): except Exception as error_info: self.add_text_main('[-]Error in pushButton_save_config_clicked: ' + str(error_info)) - # ========================================================================读取设置页设置,保存在config.ini def save_config_clicked(self): main_mode = 1 failed_file_move = 1 soft_link = 0 + show_poster = 0 switch_debug = 0 update_check = 0 save_log = 0 - media_warehouse = '' website = '' + add_mark = 1 + mark_size = 3 + mark_type = '' + mark_pos = '' + uncensored_poster = 0 + # ========================================================================common if self.Ui.radioButton_common.isChecked(): # 普通模式 main_mode = 1 elif self.Ui.radioButton_sort.isChecked(): # 整理模式 @@ -342,10 +441,6 @@ def save_config_clicked(self): soft_link = 1 elif self.Ui.radioButton_soft_off.isChecked(): # 软链接关 soft_link = 0 - if self.Ui.radioButton_fail_move_on.isChecked(): # 失败移动开 - failed_file_move = 1 - elif self.Ui.radioButton_fail_move_off.isChecked(): # 失败移动关 - failed_file_move = 0 if self.Ui.radioButton_debug_on.isChecked(): # 调试模式开 switch_debug = 1 elif self.Ui.radioButton_debug_off.isChecked(): # 调试模式关 @@ -358,12 +453,10 @@ def save_config_clicked(self): save_log = 1 elif self.Ui.radioButton_log_off.isChecked(): # 关闭日志 save_log = 0 - if self.Ui.radioButton_emby.isChecked(): # emby/jellyfin - media_warehouse = 'emby' - elif self.Ui.radioButton_plex.isChecked(): # plex - media_warehouse = 'plex' - elif self.Ui.radioButton_kodi.isChecked(): # kodi - media_warehouse = 'kodi' + if self.Ui.radioButton_fail_move_on.isChecked(): # 失败移动开 + failed_file_move = 1 + elif self.Ui.radioButton_fail_move_off.isChecked(): # 失败移动关 + failed_file_move = 0 if self.Ui.comboBox_website_all.currentText() == 'All websites': # all website = 'all' elif self.Ui.comboBox_website_all.currentText() == 'mgstage': # mgstage @@ -372,20 +465,53 @@ def save_config_clicked(self): website = 'fc2club' elif self.Ui.comboBox_website_all.currentText() == 'javbus': # javbus website = 'javbus' + elif self.Ui.comboBox_website_all.currentText() == 'jav321': # jav321 + website = 'jav321' elif self.Ui.comboBox_website_all.currentText() == 'javdb': # javdb website = 'javdb' elif self.Ui.comboBox_website_all.currentText() == 'avsox': # avsox website = 'avsox' elif self.Ui.comboBox_website_all.currentText() == 'dmm': # dmm website = 'dmm' + if self.Ui.checkBox_cover.isChecked(): # 显示封面 + show_poster = 1 + else: # 关闭封面 + show_poster = 0 + # ========================================================================水印 + if self.Ui.radioButton_poster_mark_on.isChecked(): # 封面添加水印 + poster_mark = 1 + else: # 关闭封面添加水印 + poster_mark = 0 + if self.Ui.radioButton_thumb_mark_on.isChecked(): # 缩略图添加水印 + thumb_mark = 1 + else: # 关闭缩略图添加水印 + thumb_mark = 0 + if self.Ui.checkBox_sub.isChecked(): # 字幕 + mark_type += ',SUB' + if self.Ui.checkBox_leak.isChecked(): # 流出 + mark_type += ',LEAK' + if self.Ui.checkBox_uncensored.isChecked(): # 无码 + mark_type += ',UNCENSORED' + if self.Ui.radioButton_top_left.isChecked(): # 左上 + mark_pos = 'top_left' + elif self.Ui.radioButton_bottom_left.isChecked(): # 左下 + mark_pos = 'bottom_left' + elif self.Ui.radioButton_top_right.isChecked(): # 右上 + mark_pos = 'top_right' + elif self.Ui.radioButton_bottom_right.isChecked(): # 右下 + mark_pos = 'bottom_right' + if self.Ui.radioButton_poster_official.isChecked(): # 官方 + uncensored_poster = 0 + elif self.Ui.radioButton_poster_cut.isChecked(): # 裁剪 + uncensored_poster = 1 json_config = { + 'show_poster': show_poster, 'main_mode': main_mode, 'soft_link': soft_link, 'switch_debug': switch_debug, 'failed_file_move': failed_file_move, 'update_check': update_check, 'save_log': save_log, - 'media_warehouse': media_warehouse, 'website': website, 'failed_output_folder': self.Ui.lineEdit_fail.text(), 'success_output_folder': self.Ui.lineEdit_success.text(), @@ -403,6 +529,13 @@ def save_config_clicked(self): 'media_path': self.Ui.lineEdit_movie_path.text(), 'media_type': self.Ui.lineEdit_movie_type.text(), 'sub_type': self.Ui.lineEdit_sub_type.text(), + 'poster_mark': poster_mark, + 'thumb_mark': thumb_mark, + 'mark_size': self.Ui.horizontalSlider_mark_size.value(), + 'mark_type': mark_type.strip(','), + 'mark_pos': mark_pos, + 'uncensored_poster': uncensored_poster, + 'uncensored_prefix': self.Ui.lineEdit_uncensored_prefix.text(), } save_config(json_config) @@ -446,36 +579,31 @@ def select_file_thread(self, file_name): self.add_text_main("[*]======================================================") # ========================================================================小工具-裁剪封面图 - def pushButton_select_fanart_clicked(self): + def pushButton_select_thumb_clicked(self): path = self.Ui.lineEdit_movie_path.text() filePath, fileType = QtWidgets.QFileDialog.getOpenFileName(self, "选取缩略图", path, "Picture Files(*.jpg);;All Files(*)") if filePath != '': self.Ui.stackedWidget.setCurrentIndex(0) try: - t = threading.Thread(target=self.select_fanart_thread, args=(filePath,)) + t = threading.Thread(target=self.select_thumb_thread, args=(filePath,)) t.start() # 启动线程,即让线程开始执行 except Exception as error_info: - self.add_text_main('[-]Error in pushButton_select_fanart_clicked: ' + str(error_info)) + self.add_text_main('[-]Error in pushButton_select_thumb_clicked: ' + str(error_info)) - def select_fanart_thread(self, file_path): + def select_thumb_thread(self, file_path): file_name = file_path.split('/')[-1] file_path = file_path.replace('/' + file_name, '') - self.image_cut(file_path, file_name) + self.image_cut(file_path, file_name, 2) self.add_text_main("[*]======================================================") - def image_cut(self, path, file_name): + def image_cut(self, path, file_name, mode=1): + png_name = file_name.replace('-thumb.jpg', '-poster.jpg') file_path = os.path.join(path, file_name) - png_name = '' - if self.Ui.radioButton_emby.isChecked(): # emby/jellyfin - png_name = os.path.splitext(file_name)[0] + '.png' - elif self.Ui.radioButton_plex.isChecked(): # plex - png_name = 'poster.jpg' - elif self.Ui.radioButton_kodi.isChecked(): # kodi - png_name = file_name.replace('-fanart.jpg', '-poster.jpg') + png_path = os.path.join(path, png_name) try: - if os.path.exists(os.path.join(path, png_name)): - os.remove(os.path.join(path, png_name)) + if os.path.exists(png_path): + os.remove(png_path) except Exception as error_info: self.add_text_main('[-]Error in image_cut: ' + str(error_info)) return @@ -494,30 +622,43 @@ def image_cut(self, path, file_name): """ 读取图片 """ with open(file_path, 'rb') as fp: image = fp.read() - - """ 调用人体检测与属性识别 """ - result = client.bodyAnalysis(image) - ewidth = int(0.661538 * height) - ex = int(result["person_info"][0]['body_parts']['nose']['x']) - if width - ex < ewidth / 2: - ex = width - ewidth - else: - ex -= int(ewidth / 2) - ey = 0 - ew = ewidth - eh = height + ex, ey, ew, eh = 0, 0, 0, 0 + """ 获取裁剪区域 """ + if height / width <= 1.5: # 长宽比大于1.5,太宽 + """ 调用人体检测与属性识别 """ + result = client.bodyAnalysis(image) + ewidth = int(height / 1.5) + ex = int(result["person_info"][0]['body_parts']['nose']['x']) + if width - ex < ewidth / 2: + ex = width - ewidth + else: + ex -= int(ewidth / 2) + if ex < 0: + ex = 0 + ey = 0 + eh = height + if ewidth > width: + ew = width + else: + ew = ewidth + elif height / width > 1.5: # 长宽比小于1.5,太窄 + ex = 0 + ey = 0 + ew = int(width) + eh = ew * 1.5 fp = open(file_path, 'rb') img = Image.open(fp) img_new_png = img.crop((ex, ey, ew + ex, eh + ey)) fp.close() - img_new_png.save(path + '/' + png_name) + img_new_png.save(png_path) self.add_text_main('[+]Poster Cut ' + png_name + ' from ' + file_name + '!') - pix = QPixmap(file_path) - self.Ui.label_fanart.setScaledContents(True) - self.Ui.label_fanart.setPixmap(pix) # 添加图标 - pix = QPixmap(path + '/' + png_name) - self.Ui.label_poster.setScaledContents(True) - self.Ui.label_poster.setPixmap(pix) # 添加图标 + if mode == 2: + pix = QPixmap(file_path) + self.Ui.label_thumb.setScaledContents(True) + self.Ui.label_thumb.setPixmap(pix) # 添加图标 + pix = QPixmap(png_path) + self.Ui.label_poster.setScaledContents(True) + self.Ui.label_poster.setPixmap(pix) # 添加图标 # ========================================================================小工具-视频移动 def move_file(self): @@ -715,7 +856,7 @@ def upload_profile_picture(self, count, actor, pic_path): # 上传头像 header = {"Content-Type": 'image/png', } else: header = {"Content-Type": 'image/jpeg', } - respones = requests.post(url=url, data=b6_pic, headers=header) + requests.post(url=url, data=b6_pic, headers=header) self.add_text_main( '[+]' + "%4s" % str(count) + '.Success upload profile picture for ' + actor['Name'] + '!') except Exception as error_info: @@ -766,93 +907,73 @@ def DownloadFileWithFilename(self, url, filename, path, Config, filepath, failed proxy = Config['proxy']['proxy'] timeout = int(Config['proxy']['timeout']) retry_count = int(Config['proxy']['retry']) - except: - self.add_text_main('[-]Proxy config error! Please check the config.') + except Exception as error_info: + print('[-]Error in DownloadFileWithFilename! ' + str(error_info)) + self.add_text_main('[-]Error in DownloadFileWithFilename! Proxy config error! Please check the config.') i = 0 while i < retry_count: try: + if not os.path.exists(path): + os.makedirs(path) + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'} if not proxy == '': - if not os.path.exists(path): - os.makedirs(path) - headers = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'} r = requests.get(url, headers=headers, timeout=timeout, proxies={"http": "http://" + str(proxy), "https": "https://" + str(proxy)}) - if r == '': - self.add_text_main('[-]Movie Data not found!') - # os._exit(0) - with open(str(path) + "/" + filename, "wb") as code: - code.write(r.content) - code.close() - return else: - if not os.path.exists(path): - os.makedirs(path) - headers = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'} r = requests.get(url, timeout=timeout, headers=headers) - if r == '': - self.add_text_main('[-]Movie Data not found!') - # os._exit(0) - with open(str(path) + "/" + filename, "wb") as code: - code.write(r.content) - code.close() - return - except : + with open(str(path) + "/" + filename, "wb") as code: + code.write(r.content) + code.close() + return + except Exception as error_info: i += 1 + print('[-]Error in DownloadFileWithFilename! ' + str(error_info)) print('[-]Image Download : Connect retry ' + str(i) + '/' + str(retry_count)) self.add_text_main('[-]Connect Failed! Please check your Proxy or Network!') self.moveFailedFolder(filepath, failed_folder) # ========================================================================下载缩略图 - def fanartDownload(self, option, json_data, path, naming_rule, Config, filepath, failed_folder): - fanart_name = '' - if option == 'emby': - fanart_name = naming_rule + '.jpg' - elif option == 'plex': - fanart_name = 'fanart.jpg' - elif option == 'kodi': - fanart_name = naming_rule + '-fanart.jpg' - if os.path.exists(path + '/' + fanart_name): - self.add_text_main('[+]Fanart Existed! ' + fanart_name) + def thumbDownload(self, json_data, path, naming_rule, Config, filepath, failed_folder): + thumb_name = naming_rule + '-thumb.jpg' + if os.path.exists(path + '/' + thumb_name): + self.add_text_main('[+]Thumb Existed! ' + thumb_name) return i = 1 while i <= int(Config['proxy']['retry']): - self.DownloadFileWithFilename(json_data['cover'], fanart_name, path, Config, filepath, + self.DownloadFileWithFilename(json_data['cover'], thumb_name, path, Config, filepath, failed_folder) - if os.path.getsize(path + '/' + fanart_name) < 10240: + if os.path.getsize(path + '/' + thumb_name) < 10240: print('[!]Image Download Failed! Trying again. ' + str(i) + '/' + Config['proxy']['retry']) i = i + 1 else: break - if os.path.getsize(path + '/' + fanart_name) >= 10240: - self.add_text_main('[+]Fanart Downloaded! ' + fanart_name) + if os.path.getsize(path + '/' + thumb_name) >= 10240: + self.add_text_main('[+]Thumb Downloaded! ' + thumb_name) else: - os.remove(path + '/' + fanart_name) - raise Exception("The Size of Fanart is Error! Deleted " + fanart_name + '!') + os.remove(path + '/' + thumb_name) + raise Exception("The Size of Thumb is Error! Deleted " + thumb_name + '!') # ========================================================================无码片下载封面图 - def smallCoverDownload(self, path, naming_rule, json_data, option, Config, filepath, failed_folder): + def smallCoverDownload(self, path, naming_rule, json_data, Config, filepath, failed_folder): if json_data['imagecut'] == 3: - poster_name = '' - if option == 'emby': - poster_name = naming_rule + '.png' - elif option == 'kodi': - poster_name = naming_rule + '-poster.jpg' - elif option == 'plex': - poster_name = 'poster.jpg' + is_pic_open = 0 + poster_name = naming_rule + '-poster.jpg' if os.path.exists(path + '/' + poster_name): self.add_text_main('[+]Poster Existed! ' + poster_name) return self.DownloadFileWithFilename(json_data['cover_small'], 'cover_small.jpg', path, Config, filepath, failed_folder) try: + if os.path.getsize(path + '/cover_small.jpg') < 10240: + raise Exception("The Size of smallcover is Error! Deleted cover_small.jpg!") fp = open(path + '/cover_small.jpg', 'rb') + is_pic_open = 1 img = Image.open(fp) w = img.width h = img.height - if not (1.45 <= h/w <= 1.55): - self.add_text_main('[-]The size of cover_small.jpg is wrong, Try to cut fanart!') + if not (1.4 <= h/w <= 1.6): + self.add_text_main('[-]The size of cover_small.jpg is unfit, Try to cut thumb!') fp.close() os.remove(path + '/cover_small.jpg') return 'small_cover_error' @@ -862,13 +983,14 @@ def smallCoverDownload(self, path, naming_rule, json_data, option, Config, filep os.remove(path + '/cover_small.jpg') except Exception as error_info: self.add_text_main('[-]Error in smallCoverDownload: ' + str(error_info)) - fp.close() + if is_pic_open: + fp.close() os.remove(path + '/cover_small.jpg') - self.add_text_main('[+]Try to cut fanart!') + self.add_text_main('[+]Try to cut thumb!') return 'small_cover_error' # ========================================================================打印NFO - def PrintFiles(self, option, path, name_file, cn_sub, json_data, filepath, failed_folder): + def PrintFiles(self, path, name_file, cn_sub, leak, json_data, filepath, failed_folder): title, studio, publisher, year, outline, runtime, director, actor_photo, actor, release, tag, number, cover, website, series = get_info( json_data) name_media = json_data['naming_media'].replace('title', title).replace('studio', studio).replace('year', @@ -886,11 +1008,16 @@ def PrintFiles(self, option, path, name_file, cn_sub, json_data, filepath, faile with open(path + "/" + name_file + ".nfo", "wt", encoding='UTF-8') as code: print('', file=code) print("", file=code) - print(" " + name_media + "", file=code) + print(" " + name_media + "", file=code) print(" ", file=code) print(" ", file=code) + try: + if str(json_data['score']) != 'unknown' and str(json_data['score']) != '' and float(json_data['score']) != 0.0: + print(" " + str(json_data['score']) + "", file=code) + except Exception as err: + print("Error in json_data score!" + str(err)) if studio != 'unknown': - print(" " + studio + "+", file=code) + print(" " + studio + "", file=code) if str(year) != 'unknown': print(" " + year + "", file=code) if outline != 'unknown': @@ -900,20 +1027,12 @@ def PrintFiles(self, option, path, name_file, cn_sub, json_data, filepath, faile print(" " + str(runtime).replace(" ", "") + "", file=code) if director != 'unknown': print(" " + director + "", file=code) - if option == 'emby': - print(" " + name_file + ".png", file=code) - print(" " + name_file + ".png", file=code) - print(" " + name_file + '.jpg' + "", file=code) - elif option == 'kodi': - print(" " + name_file + "-poster.jpg", file=code) - print(" " + name_file + '-fanart.jpg' + "", file=code) - elif option == 'plex': - print(" poster.jpg", file=code) - print(" thumb.png", file=code) - print(" fanart.jpg", file=code) + print(" " + name_file + "-poster.jpg", file=code) + print(" " + name_file + "-thumb.jpg", file=code) + print(" " + name_file + '-fanart.jpg' + "", file=code) try: for key, value in actor_photo.items(): - if str(key) != 'unknown': + if str(key) != 'unknown' and str(key) != '': print(" ", file=code) print(" " + key + "", file=code) if not value == '': # or actor_photo == []: @@ -933,67 +1052,60 @@ def PrintFiles(self, option, path, name_file, cn_sub, json_data, filepath, faile print(" " + i + "", file=code) except Exception as error_info: self.add_text_main('[-]Error in tag: ' + str(error_info)) - if re.match('^\d{4,}', number) or re.match('n\d{4}', number) or 'HEYZO' in number.upper(): + if json_data['imagecut'] == 3: print(" 無碼", file=code) + if leak == 1: + print(" 流出", file=code) + if cn_sub == 1: + print(" 中文字幕", file=code) if series != 'unknown': print(" " + '系列:' + series + "", file=code) if studio != 'unknown': print(" " + '製作:' + studio + "", file=code) if publisher != 'unknown': print(" " + '發行:' + publisher + "", file=code) - if cn_sub == 1: - print(" 中文字幕", file=code) try: for i in tag: if i != 'unknown': print(" " + i + "", file=code) except Exception as error_info: self.add_text_main('[-]Error in genre: ' + str(error_info)) - if re.match('^\d{4,}', number) or re.match('n\d{4}', number) or 'HEYZO' in number.upper(): + if json_data['imagecut'] == 3: print(" 無碼", file=code) + if leak == 1: + print(" 流出", file=code) + if cn_sub == 1: + print(" 中文字幕", file=code) if series != 'unknown': print(" " + '系列:' + series + "", file=code) if studio != 'unknown': print(" " + '製作:' + studio + "", file=code) if publisher != 'unknown': print(" " + '發行:' + publisher + "", file=code) - if cn_sub == 1: - print(" 中文字幕", file=code) print(" " + number + "", file=code) if release != 'unknown': - if option == 'emby': - print(" " + release + "", file=code) - elif option == 'kodi' or option == 'plex': - print(" " + release + "", file=code) + print(" " + release + "", file=code) + print(" " + release + "", file=code) print(" " + cover + "", file=code) print(" " + website + "", file=code) print("", file=code) - self.add_text_main("[+]Nfo Writed! " + name_file + ".nfo") + self.add_text_main("[+]Nfo Wrote! " + name_file + ".nfo") except Exception as error_info: self.add_text_main("[-]Write Failed!") self.add_text_main('[-]Error in PrintFiles: ' + str(error_info)) self.moveFailedFolder(filepath, failed_folder) # ========================================================================有码片裁剪封面 - def cutImage(self, option, imagecut, path, naming_rule): + def cutImage(self, imagecut, path, naming_rule): if imagecut != 3: - poster_name = '' - fanart_name = '' - if option == 'emby': - poster_name = naming_rule + '.png' - fanart_name = naming_rule + '.jpg' - elif option == 'kodi': - poster_name = naming_rule + '-poster.jpg' - fanart_name = naming_rule + '-fanart.jpg' - elif option == 'plex': - poster_name = 'poster.jpg' - fanart_name = 'fanart.jpg' + thumb_name = naming_rule + '-thumb.jpg' + poster_name = naming_rule + '-poster.jpg' if os.path.exists(path + '/' + poster_name): self.add_text_main('[+]Poster Existed! ' + poster_name) return if imagecut == 1: try: - img = Image.open(path + '/' + fanart_name) + img = Image.open(path + '/' + thumb_name) w = img.width h = img.height img2 = img.crop((w / 1.9, 0, w, h)) @@ -1002,18 +1114,74 @@ def cutImage(self, option, imagecut, path, naming_rule): except: self.add_text_main('[-]Cover cut failed!') elif imagecut == 0: - self.image_cut(path, fanart_name) - - # ========================================================================jpg复制为Backdrop - def copyRenameJpgToBackdrop(self, option, path, naming_rule): - if not os.path.exists(path + '/Backdrop.jpg'): - if option == 'plex': - shutil.copy(path + '/fanart.jpg', path + '/Backdrop.jpg') - shutil.copy(path + '/poster.jpg', path + '/thumb.png') - if option == 'emby': - shutil.copy(path + '/' + naming_rule + '.jpg', path + '/Backdrop.jpg') - if option == 'kodi': - shutil.copy(path + '/' + naming_rule + '-fanart.jpg', path + '/Backdrop.jpg') + self.image_cut(path, thumb_name) + + # ========================================================================加水印 + def add_mark(self, poster_path, thumb_path, cn_sub, leak, uncensored, config): + mark_type = '' + if cn_sub: + mark_type += ',字幕' + if leak: + mark_type += ',流出' + if uncensored: + mark_type += ',无码' + if self.Ui.radioButton_thumb_mark_on.isChecked() and mark_type != '': + self.add_mark_thread(thumb_path, cn_sub, leak, uncensored) + self.add_text_main('[+]Thumb Add Mark: ' + mark_type.strip(',')) + if self.Ui.radioButton_poster_mark_on.isChecked() and mark_type != '': + self.add_mark_thread(poster_path, cn_sub, leak, uncensored) + self.add_text_main('[+]Poster Add Mark: ' + mark_type.strip(',')) + + def add_mark_thread(self, pic_path, cn_sub, leak, uncensored): + size = 14 - int(self.Ui.horizontalSlider_mark_size.value()) # 获取自定义大小的值 + img_pic = Image.open(pic_path) + count = 0 # 获取自定义位置,取余配合pos达到顺时针添加的效果 + if self.Ui.radioButton_top_left.isChecked(): + count = 0 + elif self.Ui.radioButton_top_right.isChecked(): + count = 1 + elif self.Ui.radioButton_bottom_right.isChecked(): + count = 2 + elif self.Ui.radioButton_bottom_left.isChecked(): + count = 3 + if self.Ui.checkBox_sub.isChecked() and cn_sub == 1: + self.add_to_pic(pic_path, img_pic, size, count, 1) # 添加 + count = (count + 1) % 4 + if self.Ui.checkBox_leak.isChecked() and leak == 1: + self.add_to_pic(pic_path, img_pic, size, count, 2) + count = (count + 1) % 4 + if self.Ui.checkBox_uncensored.isChecked() and uncensored == 1: + self.add_to_pic(pic_path, img_pic, size, count, 3) + img_pic.close() + + + def add_to_pic(self, pic_path, img_pic, size, count, mode): + mark_pic_path = '' + if mode == 1: + mark_pic_path = 'Img/SUB.png' + elif mode == 2: + mark_pic_path = 'Img/LEAK.png' + elif mode == 3: + mark_pic_path = 'Img/UNCENSORED.png' + img_subt = Image.open(mark_pic_path) + scroll_high = int(img_pic.height / size) + scroll_wide = int(scroll_high * img_subt.width / img_subt.height) + img_subt = img_subt.resize((scroll_wide, scroll_high), Image.ANTIALIAS) + r, g, b, a = img_subt.split() # 获取颜色通道,保持png的透明性 + # 封面四个角的位置 + pos = [ + {'x': 0, 'y': 0}, + {'x': img_pic.width - scroll_wide, 'y': 0}, + {'x': img_pic.width - scroll_wide, 'y': img_pic.height - scroll_high}, + {'x': 0, 'y': img_pic.height - scroll_high}, + ] + img_pic.paste(img_subt, (pos[count]['x'], pos[count]['y']), mask=a) + img_pic.save(pic_path, quality=95) + + # ========================================================================thumb复制为fanart + def copyRenameJpgToFanart(self, path, naming_rule): + if not os.path.exists(path + '/' + naming_rule + '-fanart.jpg'): + shutil.copy(path + '/' + naming_rule + '-thumb.jpg', path + '/' + naming_rule + '-fanart.jpg') # ========================================================================移动文件、字幕 def pasteFileToFolder(self, filepath, path, naming_rule, failed_folder): @@ -1034,7 +1202,7 @@ def pasteFileToFolder(self, filepath, path, naming_rule, failed_folder): if os.path.exists(path_old + '/' + filename + sub): # 字幕移动 shutil.move(path_old + '/' + filename + sub, path + '/' + naming_rule + sub) self.add_text_main('[+]Sub moved! ' + naming_rule + sub) - break + return True except FileExistsError: self.add_text_main('[+]Movie Existed! ' + naming_rule + type) if os.path.split(filepath)[0] != path: @@ -1043,6 +1211,7 @@ def pasteFileToFolder(self, filepath, path, naming_rule, failed_folder): self.add_text_main('[-]PermissionError! Please run as Administrator!') except Exception as error_info: self.add_text_main('[-]Error in pasteFileToFolder: ' + str(error_info)) + return False # ========================================================================获取分集序号 def get_part(self, filepath, failed_folder): @@ -1087,12 +1256,12 @@ def creatFolder(self, success_folder, json_data, config): runtime).replace( 'director', director).replace('actor', actor).replace('release', release).replace('number', number).replace( 'series', series).replace('publisher', publisher) # 生成文件夹名 - path = path.replace('//', '/').replace('--', '-').strip('-') + path = path.replace('--', '-').strip('-') if len(path) > 100: # 文件夹名过长 取标题前70个字符 self.add_text_main('[-]Error in Length of Path! Cut title!') path = path.replace(title, title[0:70]) path = success_folder + '/' + path - path = path.replace('//', '/').replace('--', '-').strip('-') + path = path.replace('--', '-').strip('-') if not os.path.exists(path): path = escapePath(path, config) os.makedirs(path) @@ -1100,77 +1269,114 @@ def creatFolder(self, success_folder, json_data, config): # ========================================================================从指定网站获取json_data def get_json_data(self, mode, number, config): - if mode == 5: # javdb模式 + if mode == 6: # javdb模式 self.add_text_main('[!]Please Wait Three Seconds!') time.sleep(3) - json_data = getDataFromJSON(number, config, 5) - else: - json_data = getDataFromJSON(number, config, mode) + json_data = getDataFromJSON(number, config, mode) return json_data # ========================================================================json_data添加到主界面 def add_label_info(self, json_data): + try: + t = threading.Thread(target=self.add_label_info_Thread, args=(json_data,)) + t.start() # 启动线程,即让线程开始执行 + except Exception as error_info: + self.add_text_main('[-]Error in pushButton_start_cap_clicked: ' + str(error_info)) + + def add_label_info_Thread(self, json_data): self.Ui.label_number.setText(json_data['number']) self.Ui.label_release.setText(json_data['release']) self.Ui.label_director.setText(json_data['director']) - self.Ui.label_publish.setText(json_data['publisher']) - self.Ui.label_studio.setText(json_data['studio']) self.Ui.label_label.setText(json_data['series']) + self.Ui.label_studio.setText(json_data['studio']) + self.Ui.label_publish.setText(json_data['publisher']) self.Ui.label_title.setText(json_data['title']) self.Ui.label_actor.setText(json_data['actor']) self.Ui.label_outline.setText(json_data['outline']) self.Ui.label_tag.setText(str(json_data['tag']).strip(" [',']").replace('\'', '')) if self.Ui.checkBox_cover.isChecked(): - fanart_path = json_data['fanart_path'] poster_path = json_data['poster_path'] - if os.path.exists(fanart_path): - pix = QPixmap(fanart_path) - self.Ui.label_fanart.setScaledContents(True) - self.Ui.label_fanart.setPixmap(pix) # 添加缩略图 + thumb_path = json_data['thumb_path'] if os.path.exists(poster_path): pix = QPixmap(poster_path) self.Ui.label_poster.setScaledContents(True) self.Ui.label_poster.setPixmap(pix) # 添加封面图 + if os.path.exists(thumb_path): + pix = QPixmap(thumb_path) + self.Ui.label_thumb.setScaledContents(True) + self.Ui.label_thumb.setPixmap(pix) # 添加缩略图 + + # ========================================================================检查更新 + def UpdateCheck(self): + if self.Ui.radioButton_update_on.isChecked(): + self.add_text_main('[!]Update Checking!') + html2 = get_html('https://raw.githubusercontent.com/moyy996/AVDC/master/update_check.json') + if html2 == 'ProxyError': + return 'ProxyError' + html = json.loads(str(html2)) + if float(self.version) < float(html['version']): + self.add_text_main('[*] * New update ' + html['version'] + ' *') + self.add_text_main('[*] ↓ Download ↓') + self.add_text_main('[*] ' + html['download']) + else: + self.add_text_main('[!]No Newer Version Available!') + self.add_text_main("[*]======================================================") + return 'True' + + # ========================================================================新建失败输出文件夹 + def CreatFailedFolder(self, failed_folder): + if self.Ui.radioButton_fail_move_on.isChecked() and not os.path.exists(failed_folder): + try: + os.makedirs(failed_folder + '/') + self.add_text_main('[+]Created folder named ' + failed_folder + '!') + except Exception as error_info: + self.add_text_main('[-]Error in CreatFailedFolder: ' + str(error_info)) - def Core_Main(self, file_path, number_th, mode, count): + # ========================================================================删除空目录 + def CEF(self, path): + if os.path.exists(path): + for root, dirs, files in os.walk(path): + for dir in dirs: + try: + os.removedirs(root.replace('\\', '/') + '/' + dir) # 删除这个空文件夹 + self.add_text_main('[+]Deleting empty folder ' + root.replace('\\', '/') + '/' + dir) + except: + delete_empty_folder_failed = '' + + def Core_Main(self, filepath, number, mode, count): # =======================================================================初始化所需变量 + leak = 0 + uncensored = 0 + cn_sub = 0 + c_word = '' multi_part = 0 part = '' - c_word = '' - option = '' - cn_sub = 0 - filepath = file_path # 影片的路径 - number = number_th - config_file = 'config.ini' program_mode = 0 + config_file = 'config.ini' Config = ConfigParser() Config.read(config_file, encoding='UTF-8') - if self.Ui.radioButton_emby.isChecked(): # emby/jellyfin - option = 'emby' - elif self.Ui.radioButton_plex.isChecked(): # plex - option = 'plex' - elif self.Ui.radioButton_kodi.isChecked(): # kodi - option = 'kodi' if self.Ui.radioButton_common.isChecked(): program_mode = 1 elif self.Ui.radioButton_sort.isChecked(): program_mode = 2 movie_path = self.Ui.lineEdit_movie_path.text() - success_folder = movie_path + '/' + self.Ui.lineEdit_success.text() # 成功输出目录 + if movie_path == '': + movie_path = os.getcwd().replace('\\', '/') failed_folder = movie_path + '/' + self.Ui.lineEdit_fail.text() # 失败输出目录 + success_folder = movie_path + '/' + self.Ui.lineEdit_success.text() # 成功输出目录 # =======================================================================获取json_data json_data = self.get_json_data(mode, number, Config) + # =======================================================================调试模式 + if self.Ui.radioButton_debug_on.isChecked(): + self.debug_mode(json_data) # =======================================================================是否找到影片信息 if json_data['website'] == 'timeout': self.add_text_main('[-]Connect Failed! Please check your Proxy or Network!') return 'error' - elif mode == 5 and json_data['actor'] == 'N/A': - self.add_text_main('[-]Your IP Has Been Blocked By JAVDB!') - return 'error' elif json_data['title'] == '': self.add_text_main('[-]Movie Data not found!') node = QTreeWidgetItem(self.item_fail) - node.setText(0, str(count) + '.' + os.path.splitext(filepath.split('/')[-1])[0]) + node.setText(0, str(self.count_claw) + '-' + str(count) + '.' + os.path.splitext(filepath.split('/')[-1])[0]) self.item_fail.addChild(node) self.moveFailedFolder(filepath, failed_folder) return 'not found' @@ -1178,103 +1384,69 @@ def Core_Main(self, file_path, number_th, mode, count): raise Exception('Cover Url is None!') elif json_data['imagecut'] == 3 and 'http' not in json_data['cover_small']: raise Exception('Cover_small Url is None!') - - # =======================================================================调试模式 - if self.Ui.radioButton_debug_on.isChecked(): - self.debug_mode(json_data) - # =======================================================================判断-C,-CD后缀 + # =======================================================================判断-C,-CD后缀,无码,流出 if '-CD' in filepath or '-cd' in filepath: multi_part = 1 part = self.get_part(filepath, failed_folder) if '-c.' in filepath or '-C.' in filepath or '中文' in filepath or '字幕' in filepath: cn_sub = 1 c_word = '-C' # 中文字幕影片后缀 + if json_data['imagecut'] == 3: # imagecut=3为无码 + uncensored = 1 + if '流出' in os.path.split(filepath)[1]: + leak = 1 # =======================================================================创建输出文件夹 - path = self.creatFolder(success_folder, json_data, Config) # 创建成功输出文件夹 + path = self.creatFolder(success_folder, json_data, Config) self.add_text_main('[+]Folder : ' + path) self.add_text_main('[+]From : ' + json_data['website']) - # =======================================================================刮削模式 + # =======================================================================文件命名规则 number = json_data['number'] naming_rule = str(self.get_naming_rule(json_data)).replace('--', '-').strip('-') + if leak == 1: + naming_rule += '-流出' if multi_part == 1: naming_rule += part if cn_sub == 1: naming_rule += c_word + # =======================================================================封面路径 + thumb_path = path + '/' + naming_rule + '-thumb.jpg' + poster_path = path + '/' + naming_rule + '-poster.jpg' + # =======================================================================无码封面获取方式 + if json_data['imagecut'] == 3 and self.Ui.radioButton_poster_cut.isChecked(): + json_data['imagecut'] = 0 + # =======================================================================刮削模式 if program_mode == 1: - # imagecut 1 裁剪右半面,0 裁剪缩略图为封面,3 下载小封面 - self.fanartDownload(option, json_data, path, naming_rule, Config, filepath, failed_folder) - if self.smallCoverDownload(path, naming_rule, json_data, option, Config, filepath, + # imagecut 0 判断人脸位置裁剪缩略图为封面,1 裁剪右半面,3 下载小封面 + self.thumbDownload(json_data, path, naming_rule, Config, filepath, failed_folder) + if self.smallCoverDownload(path, naming_rule, json_data, Config, filepath, failed_folder) == 'small_cover_error': # 下载小封面 json_data['imagecut'] = 0 - self.cutImage(option, json_data['imagecut'], path, naming_rule) # 裁剪图 - self.copyRenameJpgToBackdrop(option, path, naming_rule) - self.PrintFiles(option, path, naming_rule, cn_sub, json_data, filepath, failed_folder) # 打印文件 - self.pasteFileToFolder(filepath, path, naming_rule, failed_folder) # 移动文件 - # =======================================================================整理模式 + self.cutImage(json_data['imagecut'], path, naming_rule) # 裁剪图 + self.copyRenameJpgToFanart(path, naming_rule) + if self.pasteFileToFolder(filepath, path, naming_rule, failed_folder): # 移动文件,True 为有外挂字幕 + cn_sub = 1 + self.PrintFiles(path, naming_rule, cn_sub, leak, json_data, filepath, failed_folder) # 打印文件 + self.add_mark(poster_path, thumb_path, cn_sub, leak, uncensored, Config) + # =======================================================================整理模式 elif program_mode == 2: self.pasteFileToFolder(filepath, path, naming_rule, failed_folder) # 移动文件 # =======================================================================json添加封面项 - fanart_path = '' - poster_path = '' - if self.Ui.radioButton_emby.isChecked(): # emby/jellyfin - fanart_path = path + '/' + naming_rule + '.jpg' - poster_path = path + '/' + naming_rule + '.png' - elif self.Ui.radioButton_plex.isChecked(): # plex - fanart_path = path + '/fanart.jpg' - poster_path = path + '/poster.jpg' - elif self.Ui.radioButton_kodi.isChecked(): # kodi - fanart_path = path + '/' + naming_rule + '-fanart.jpg' - poster_path = path + '/' + naming_rule + '-poster.jpg' - json_data['fanart_path'] = fanart_path + json_data['thumb_path'] = thumb_path json_data['poster_path'] = poster_path json_data['number'] = number self.add_label_info(json_data) - self.json_array[str(count)] = json_data + self.json_array[str(self.count_claw) + '-' + str(count)] = json_data return part + c_word - # ========================================================================检查更新 - def UpdateCheck(self): - if self.Ui.radioButton_update_on.isChecked(): - self.add_text_main('[!]Update Checking!') - html2 = get_html('https://raw.githubusercontent.com/moyy996/AVDC/master/update_check.json') - if html2 == 'ProxyError': - return 'ProxyError' - html = json.loads(str(html2)) - if float(self.version) < float(html['version']): - self.add_text_main('[*] * New update ' + html['version'] + ' *') - self.add_text_main('[*] ↓ Download ↓') - self.add_text_main('[*] ' + html['download']) - else: - self.add_text_main('[!]No Newer Version Available!') - self.add_text_main("[*]======================================================") - return 'True' - - # ========================================================================新建失败输出文件夹 - def CreatFailedFolder(self, failed_folder): - if self.Ui.radioButton_fail_move_on.isChecked() and not os.path.exists(failed_folder): - try: - os.makedirs(failed_folder + '/') - self.add_text_main('[+]Created folder named ' + failed_folder + '!') - except Exception as error_info: - self.add_text_main('[-]Error in CreatFailedFolder: ' + str(error_info)) - - # ========================================================================删除空目录 - def CEF(self, path): - if os.path.exists(path): - for root, dirs, files in os.walk(path): - for dir in dirs: - try: - os.removedirs(root.replace('\\', '/') + '/' + dir) # 删除这个空文件夹 - self.add_text_main('[+]Deleting empty folder ' + root.replace('\\', '/') + '/' + dir) - except: - delete_empty_folder_failed = '' - def AVDC_Main(self): # =======================================================================初始化所需变量 + os.chdir(os.getcwd()) config_file = 'config.ini' config = ConfigParser() config.read(config_file, encoding='UTF-8') movie_path = self.Ui.lineEdit_movie_path.text() + if movie_path == '': + movie_path = os.getcwd().replace('\\', '/') failed_folder = movie_path + '/' + self.Ui.lineEdit_fail.text() # 失败输出目录 escape_folder = self.Ui.lineEdit_escape_dir.text() # 多级目录刮削需要排除的目录 mode = self.Ui.comboBox_website_all.currentIndex() + 1 @@ -1301,21 +1473,21 @@ def AVDC_Main(self): self.Ui.label_progress.setText('当前: ' + str(count) + '/' + str(count_all)) percentage = str(count / int(count_all) * 100)[:4] + '%' value = int(count / int(count_all) * 100) - self.add_text_main('[!] - ' + percentage + ' [' + str(count) + '/' + count_all + '] -') + self.add_text_main('[!] - ' + str(self.count_claw) + ' - ' + percentage + ' - [' + str(count) + '/' + count_all + '] -') try: movie_number = getNumber(movie, escape_string) self.add_text_main("[!]Making Data for [" + movie + "], the number is [" + movie_number + "]") result = self.Core_Main(movie, movie_number, mode, count) if result != 'not found' and movie_number != '' and result != 'error': node = QTreeWidgetItem(self.item_succ) - node.setText(0, str(count) + '.' + movie_number + result) + node.setText(0, str(self.count_claw) + '-' + str(count) + '.' + movie_number + result) self.item_succ.addChild(node) elif result == 'error': break self.add_text_main("[*]======================================================") except Exception as error_info: node = QTreeWidgetItem(self.item_fail) - node.setText(0, str(count) + '.' + os.path.splitext(movie.split('/')[-1])[0]) + node.setText(0, str(self.count_claw) + '-' + str(count) + '.' + os.path.splitext(movie.split('/')[-1])[0]) self.item_fail.addChild(node) self.add_text_main('[-]Error in AVDC_Main: ' + str(error_info)) if self.Ui.radioButton_fail_move_on.isChecked() and not os.path.exists(failed_folder + '/' + os.path.split(movie)[1]): diff --git a/Function/Function.py b/Function/Function.py index 987796425..3b9d26aca 100644 --- a/Function/Function.py +++ b/Function/Function.py @@ -1,13 +1,10 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- - import re import os import json from configparser import ConfigParser -import requests -from lxml import etree -from Getter import avsox, javbus, javdb, fc2fans_club, mgstage, dmm +from Getter import avsox, javbus, javdb, fc2fans_club, mgstage, dmm, jav321 # ========================================================================获取config @@ -22,6 +19,35 @@ def get_config(): return config +# ========================================================================是否为无码 +def is_uncensored(number): + if re.match('^\d{4,}', number) or re.match('n\d{4}', number) or 'HEYZO' in number.upper(): + return True + config = get_config() + prefix_list = str(config['uncensored']['uncensored_prefix']).split('|') + for pre in prefix_list: + if pre.upper() in number.upper(): + return True + return False + + +# ========================================================================元数据获取失败检测 +def getDataState(json_data): + if json_data['title'] == '' or json_data['title'] == 'None' or json_data['title'] == 'null': + return 0 + else: + return 1 + + +# ========================================================================去掉异常字符 +def escapePath(path, Config): # Remove escape literals + escapeLiterals = Config['escape']['literals'] + backslash = '\\' + for literal in escapeLiterals: + path = path.replace(backslash + literal, '') + return path + + # ========================================================================获取视频列表 def movie_lists(escape_folder, movie_type, movie_path): if escape_folder != '': @@ -99,31 +125,27 @@ def getNumber(filepath, escape_string): return os.path.splitext(filepath.split('/')[-1])[0] -# ========================================================================去掉异常字符 -def escapePath(path, Config): # Remove escape literals - escapeLiterals = Config['escape']['literals'] - backslash = '\\' - for literal in escapeLiterals: - path = path.replace(backslash + literal, '') - return path - - # ========================================================================根据番号获取数据 def getDataFromJSON(file_number, config, mode): # 从JSON返回元数据 # ================================================网站规则添加开始================================================ + isuncensored = is_uncensored(file_number) json_data = {} if mode == 1: # 从全部网站刮削 - # =======================================================================无码抓取:111111-111,n1111,HEYZO-1111 - if re.match('^\d{4,}', file_number) or re.match('n\d{4}', file_number) or 'HEYZO' in file_number.upper(): + # =======================================================================无码抓取:111111-111,n1111,HEYZO-1111,SMD-115 + if isuncensored: json_data = json.loads(javbus.main_uncensored(file_number)) if getDataState(json_data) == 0: - json_data = json.loads(javdb.main(file_number)) + json_data = json.loads(javdb.main(file_number, True)) + if getDataState(json_data) == 0 and 'HEYZO' in file_number.upper(): + json_data = json.loads(jav321.main(file_number, True)) if getDataState(json_data) == 0: json_data = json.loads(avsox.main(file_number)) # =======================================================================259LUXU-1111 elif re.match('\d+[a-zA-Z]+-\d+', file_number) or 'SIRO' in file_number.upper(): json_data = json.loads(mgstage.main(file_number)) file_number = re.search('[a-zA-Z]+-\d+', file_number).group() + if getDataState(json_data) == 0: + json_data = json.loads(jav321.main(file_number)) if getDataState(json_data) == 0: json_data = json.loads(javdb.main(file_number)) if getDataState(json_data) == 0: @@ -144,6 +166,8 @@ def getDataFromJSON(file_number, config, mode): # 从JSON返回元数据 # =======================================================================MIDE-139 else: json_data = json.loads(javbus.main(file_number)) + if getDataState(json_data) == 0: + json_data = json.loads(jav321.main(file_number)) if getDataState(json_data) == 0: json_data = json.loads(javdb.main(file_number)) if getDataState(json_data) == 0: @@ -159,20 +183,22 @@ def getDataFromJSON(file_number, config, mode): # 从JSON返回元数据 elif mode == 3: # 仅从fc2club json_data = json.loads(fc2fans_club.main(file_number)) elif mode == 4: # 仅从javbus - if re.match('^\d{5,}', file_number) or re.match('n\d{4}', file_number) or 'HEYZO' in file_number.upper(): + if isuncensored: json_data = json.loads(javbus.main_uncensored(file_number)) elif re.search('\D+.\d{2}.\d{2}.\d{2}', file_number): json_data = json.loads(javbus.main_us(file_number)) else: json_data = json.loads(javbus.main(file_number)) - elif mode == 5: # 仅从javdb + elif mode == 5: # 仅从jav321 + json_data = json.loads(jav321.main(file_number, isuncensored)) + elif mode == 6: # 仅从javdb if re.search('\D+.\d{2}.\d{2}.\d{2}', file_number): json_data = json.loads(javdb.main_us(file_number)) else: - json_data = json.loads(javdb.main(file_number)) - elif mode == 6: # 仅从avsox + json_data = json.loads(javdb.main(file_number, isuncensored)) + elif mode == 7: # 仅从avsox json_data = json.loads(avsox.main(file_number)) - elif mode == 7: # 仅从dmm + elif mode == 8: # 仅从dmm json_data = json.loads(dmm.main(file_number)) # ================================================网站规则添加结束================================================ @@ -273,8 +299,9 @@ def save_config(json_config): print("success_output_folder = " + json_config['success_output_folder'], file=code) print("failed_file_move = " + str(json_config['failed_file_move']), file=code) print("soft_link = " + str(json_config['soft_link']), file=code) + print("show_poster = " + str(json_config['show_poster']), file=code) print("website = " + json_config['website'], file=code) - print("# all or mgstage or fc2club or javbus or javdb or avsox or dmm", file=code) + print("# all or mgstage or fc2club or javbus or jav321 or javdb or avsox or dmm", file=code) print("", file=code) print("[proxy]", file=code) print("proxy = " + json_config['proxy'], file=code) @@ -296,8 +323,6 @@ def save_config(json_config): print("media_type = " + json_config['media_type'], file=code) print("sub_type = " + json_config['sub_type'], file=code) print("media_path = " + json_config['media_path'], file=code) - print("media_warehouse = " + json_config['media_warehouse'], file=code) - print("# emby or plex or kodi ,emby = jellyfin", file=code) print("", file=code) print("[escape]", file=code) print("literals = " + json_config['literals'], file=code) @@ -310,12 +335,20 @@ def save_config(json_config): print("[emby]", file=code) print("emby_url = " + json_config['emby_url'], file=code) print("api_key = " + json_config['api_key'], file=code) - code.close() - + print("", file=code) + print("[mark]", file=code) + print("poster_mark = " + str(json_config['poster_mark']), file=code) + print("thumb_mark = " + str(json_config['thumb_mark']), file=code) + print("mark_size = " + str(json_config['mark_size']), file=code) + print("mark_type = " + json_config['mark_type'], file=code) + print("mark_pos = " + json_config['mark_pos'], file=code) + print("# mark_size : range 1-5", file=code) + print("# mark_type : sub, leak, uncensored", file=code) + print("# mark_pos : bottom_right or bottom_left or top_right or top_left", file=code) + print("", file=code) + print("[uncensored]", file=code) + print("uncensored_prefix = " + str(json_config['uncensored_prefix']), file=code) + print("uncensored_poster = " + str(json_config['uncensored_poster']), file=code) + print("# 0 : official, 1 : cut", file=code) -# ========================================================================元数据获取失败检测 -def getDataState(json_data): - if json_data['title'] == '' or json_data['title'] == 'None' or json_data['title'] == 'null': - return 0 - else: - return 1 + code.close() diff --git a/Function/getHtml.py b/Function/getHtml.py index e40a13a8b..1671ad5d9 100644 --- a/Function/getHtml.py +++ b/Function/getHtml.py @@ -3,8 +3,8 @@ from configparser import ConfigParser -# ========================================================================网页请求 -def get_html(url, cookies=None): +# ========================================================================获取config +def get_config(): config_file = '' if os.path.exists('../config.ini'): config_file = '../config.ini' @@ -12,6 +12,12 @@ def get_html(url, cookies=None): config_file = 'config.ini' config = ConfigParser() config.read(config_file, encoding='UTF-8') + return config + + +# ========================================================================网页请求 +def get_html(url, cookies=None): + config = get_config() retry_count = 0 proxy = '' timeout = 0 @@ -19,7 +25,8 @@ def get_html(url, cookies=None): proxy = str(config['proxy']['proxy']) timeout = int(config['proxy']['timeout']) retry_count = int(config['proxy']['retry']) - except: + except Exception as error_info: + print('Error in get_html :' + str(error_info)) print('[-]Proxy config error! Please check the config.') i = 0 while i < retry_count: @@ -39,10 +46,40 @@ def get_html(url, cookies=None): getweb = requests.get(str(url), headers=headers, timeout=timeout, cookies=cookies) getweb.encoding = 'utf-8' return getweb.text - except: + except Exception as error_info: i += 1 + print('Error in get_html :' + str(error_info)) print('[-]Connect retry ' + str(i) + '/' + str(retry_count)) print('[-]Connect Failed! Please check your Proxy or Network!') return 'ProxyError' +def post_html(url: str, query: dict): + config = get_config() + retry_count = 3 + proxy = '' + timeout = 10 + try: + proxy = str(config['proxy']['proxy']) + timeout = int(config['proxy']['timeout']) + retry_count = int(config['proxy']['retry']) + except Exception as error_info: + print('Error in post_html :' + str(error_info)) + print('[-]Proxy config error! Please check the config.') + if proxy: + proxies = {"http": "http://" + proxy, "https": "https://" + proxy} + else: + proxies = {} + for i in range(retry_count): + try: + result = requests.post(url, data=query, proxies=proxies, timeout=timeout) + result.encoding = 'utf-8' + result = result.text + return result + except Exception as error_info: + print('Error in post_html :' + str(error_info)) + print("[-]Connect retry {}/{}".format(i + 1, retry_count)) + print("[-]Connect Failed! Please check your Proxy or Network!") + return 'ProxyError' + + diff --git a/Getter/avsox.py b/Getter/avsox.py index 248b93d4b..a8655d960 100644 --- a/Getter/avsox.py +++ b/Getter/avsox.py @@ -1,6 +1,5 @@ import json import re - from bs4 import BeautifulSoup from lxml import etree from Function.getHtml import get_html @@ -22,7 +21,7 @@ def getTitle(a): try: html = etree.fromstring(a, etree.HTMLParser()) result = str(html.xpath('/html/body/div[2]/h3/text()')).strip(" ['']") # [0] - return result.replace('/', '').replace('_', '-') + return result.replace('/', '') except: return '' @@ -57,7 +56,7 @@ def getSeries(a): def getNum(a): html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//span[contains(text(),"识别码:")]/../span[2]/text()')).strip(" ['']").replace('_', '-') + result1 = str(html.xpath('//span[contains(text(),"识别码:")]/../span[2]/text()')).strip(" ['']") return result1 @@ -81,17 +80,10 @@ def getCover(htmlcode): return result -def getCover_small(htmlcode, number): +def getCover_small(htmlcode, count): html = etree.fromstring(htmlcode, etree.HTMLParser()) - counts = len(html.xpath("//div[@id='waterfall']/div/a/div")) - if counts == 0: - return '' - for count in range(1, counts + 1): # 遍历搜索结果,找到需要的番号 - number_get = html.xpath("//div[@id='waterfall']/div[" + str(count) + "]/a/div[@class='photo-info']/span/date[1]/text()") - if len(number_get) > 0 and number_get[0] == number: - cover_small = html.xpath("//div[@id='waterfall']/div[" + str(count) + "]/a/div[@class='photo-frame']/img/@src")[0] - return cover_small - return '' + cover_small = html.xpath("//div[@id='waterfall']/div[" + str(count) + "]/a/div[@class='photo-frame']/img/@src")[0] + return cover_small def getTag(a): # 获取演员 @@ -103,54 +95,64 @@ def getTag(a): # 获取演员 return d +def getUrl(number): + response = get_html('https://avsox.host/cn/search/' + number) + html = etree.fromstring(response, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + url_list = html.xpath('//*[@id="waterfall"]/div/a/@href') + if len(url_list) > 0: + for i in range(1, len(url_list) + 1): + number_get = str(html.xpath('//*[@id="waterfall"]/div[' + str(i) + ']/a/div[@class="photo-info"]/span/date[1]/text()')).strip(" ['']") + if number.upper() == number_get.upper(): + return i, response, str(html.xpath('//*[@id="waterfall"]/div[' + str(i) + ']/a/@href')).strip(" ['']") + return response, '' + + def main(number): - a = get_html('https://avsox.host/cn/search/' + number) - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//*[@id="waterfall"]/div/a/@href')).strip(" ['']") - if result1 == '' or result1 == 'null' or result1 == 'None': - a = get_html('https://avsox.host/cn/search/' + number.replace('-', '_')) - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//*[@id="waterfall"]/div/a/@href')).strip(" ['']") - if result1 == '' or result1 == 'null' or result1 == 'None': - a = get_html('https://avsox.host/cn/search/' + number.replace('_', '')) - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//*[@id="waterfall"]/div/a/@href')).strip(" ['']") - web = get_html(result1) - soup = BeautifulSoup(web, 'lxml') - info = str(soup.find(attrs={'class': 'row movie'})) try: + count, response, url = getUrl(number) + if str(response) == 'ProxyError': + raise TimeoutError + if url == '': + raise Exception('Movie Data not found in avsox!') + web = get_html(url) + soup = BeautifulSoup(web, 'lxml') + info = str(soup.find(attrs={'class': 'row movie'})) + number = getNum(web) + print(1) dic = { 'actor': getActor(web), - 'title': getTitle(web).strip(getNum(web)).strip().replace(' ', '-'), + 'title': getTitle(web).strip(number).strip().replace(' ', '-'), 'studio': getStudio(info), - 'publisher': '', - 'outline': '', # 'runtime': getRuntime(info), - 'director': '', # 'release': getRelease(info), 'number': getNum(info), - 'cover': getCover(web), - 'cover_small': getCover_small(a, number), - 'imagecut': 3, 'tag': getTag(web), 'series': getSeries(info), - 'year': getYear(getRelease(info)), # str(re.search('\d{4}',getRelease(a)).group()), + 'year': getYear(getRelease(info)), 'actor_photo': getActorPhoto(web), - 'website': result1, + 'cover': getCover(web), + 'cover_small': getCover_small(response, count), + 'imagecut': 3, + 'director': '', + 'publisher': '', + 'outline': '', + 'score': '', + 'website': url, 'source': 'avsox.py', } - except: - if a == 'ProxyError': - dic = { - 'title': '', - 'website': 'timeout', - } - else: - dic = { - 'title': '', - 'website': '', - } + except TimeoutError: + dic = { + 'title': '', + 'website': 'timeout', + } + except Exception as error_info: + print('Error in avsox.main : ' + str(error_info)) + dic = { + 'title': '', + 'website': '', + } js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') return js # print(main('051119-917')) +# print(main('032620_001')) diff --git a/Getter/dmm.py b/Getter/dmm.py index 2bbd3c0da..2011db385 100644 --- a/Getter/dmm.py +++ b/Getter/dmm.py @@ -118,54 +118,57 @@ def getOutline(htmlcode): return result +def getScore(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) + result = str(html.xpath("//p[@class='d-review__average']/strong/text()")[0]).replace('\\n', '').replace('\n', '').replace('点', '') + return result + + def main(number): - htmlcode = get_html('https://www.dmm.co.jp/digital/videoa/-/detail/=/cid=' + number) - url = 'https://www.dmm.co.jp/digital/videoa/-/detail/=/cid=' + number - if '404 Not Found' in htmlcode: - htmlcode = get_html('https://www.dmm.co.jp/mono/dvd/-/detail/=/cid=' + number) - url = 'https://www.dmm.co.jp/mono/dvd/-/detail/=/cid=' + number - if '404 Not Found' in htmlcode: - dic = { - 'title': '', - 'website': '', - } - js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':')) # .encode('UTF-8') - return js try: + htmlcode = get_html('https://www.dmm.co.jp/digital/videoa/-/detail/=/cid=' + number) + url = 'https://www.dmm.co.jp/digital/videoa/-/detail/=/cid=' + number + if '404 Not Found' in htmlcode: + htmlcode = get_html('https://www.dmm.co.jp/mono/dvd/-/detail/=/cid=' + number) + url = 'https://www.dmm.co.jp/mono/dvd/-/detail/=/cid=' + number + if '404 Not Found' in htmlcode: + raise Exception('Movie Data not found in dmm!') + if str(htmlcode) == 'ProxyError': + raise TimeoutError actor = getActor(htmlcode) dic = { 'title': getTitle(htmlcode).strip(getActor(htmlcode)), 'studio': getStudio(htmlcode), 'publisher': getPublisher(htmlcode), 'outline': getOutline(htmlcode), + 'score': getScore(htmlcode), 'runtime': getRuntime(htmlcode), 'director': getDirector(htmlcode), 'actor': actor, 'release': getRelease(htmlcode), 'number': getNum(htmlcode), - 'cover': getCover(htmlcode, number), - 'imagecut': 1, 'tag': getTag(htmlcode), - 'series': getSeries(htmlcode), + 'series': getSeries(htmlcode).replace('-', ''), 'year': getYear(getRelease(htmlcode)), # str(re.search('\d{4}',getRelease(a)).group()), 'actor_photo': getActorPhoto(actor), + 'cover': getCover(htmlcode, number), + 'imagecut': 1, 'website': url, 'source': 'dmm.py', } - except: - if htmlcode == 'ProxyError': - dic = { - 'title': '', - 'website': 'timeout', - } - else: - dic = { - 'title': '', - 'website': '', - } + except TimeoutError: + dic = { + 'title': '', + 'website': 'timeout', + } + except Exception as error_info: + print('Error in dmm.main : ' + str(error_info)) + dic = { + 'title': '', + 'website': '', + } js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':')) # .encode('UTF-8') return js # main('DV-1562') -# input("[+][+]Press enter key exit, you can check the error messge before you exit.\n[+][+]按回车键结束,你可以在结束之前查看和错误信息。") # print(main('mide00139')) diff --git a/Getter/fc2fans_club.py b/Getter/fc2fans_club.py index aff4a1c7c..2f845ddd6 100644 --- a/Getter/fc2fans_club.py +++ b/Getter/fc2fans_club.py @@ -1,15 +1,13 @@ import re -from lxml import etree # need install +from lxml import etree import json from Function.getHtml import get_html -def getTitle(htmlcode): # 获取厂商 - # print(htmlcode) +def getTitle(htmlcode): # 获取标题 html = etree.fromstring(htmlcode, etree.HTMLParser()) result = str(html.xpath('/html/body/div[2]/div/div[1]/h3/text()')).strip(" ['']") result2 = str(re.sub('\D{2}2-\d+', '', result)).replace(' ', '', 1) - # print(result2) return result2 @@ -22,7 +20,7 @@ def getActor(htmlcode): return '' -def getActorPhoto(actor): # //*[@id="star_qdt"]/li/a/img +def getActorPhoto(actor): actor = actor.split('/') d = {} for i in actor: @@ -45,29 +43,23 @@ def getNum(htmlcode): # 获取番号 def getRelease(htmlcode2): # - # a=ADC_function.get_html('http://adult.contents.fc2.com/article_search.php?id='+str(number).lstrip("FC2-").lstrip("fc2-").lstrip("fc2_").lstrip("fc2-")+'&utm_source=aff_php&utm_medium=source_code&utm_campaign=from_aff_php') html = etree.fromstring(htmlcode2, etree.HTMLParser()) result = str(html.xpath('//*[@id="container"]/div[1]/div/article/section[1]/div/div[2]/dl/dd[4]/text()')).strip( " ['']") return result -def getCover(htmlcode, number, htmlcode2): # 获取厂商 # - # a = ADC_function.get_html('http://adult.contents.fc2.com/article_search.php?id=' + str(number).lstrip("FC2-").lstrip("fc2-").lstrip("fc2_").lstrip("fc2-") + '&utm_source=aff_php&utm_medium=source_code&utm_campaign=from_aff_php') - html = etree.fromstring(htmlcode2, etree.HTMLParser()) - result = str(html.xpath('//*[@id="container"]/div[1]/div/article/section[1]/div/div[1]/a/img/@src')).strip(" ['']") - if result == '': - html = etree.fromstring(htmlcode, etree.HTMLParser()) - result2 = str(html.xpath('//*[@id="slider"]/ul[1]/li[1]/img/@src')).strip(" ['']") - return 'https://fc2club.com' + result2 - return 'http:' + result +def getCover(htmlcode): # 获取封面 # + html = etree.fromstring(htmlcode, etree.HTMLParser()) + result2 = str(html.xpath('//*[@id="slider"]/ul[1]/li[1]/img/@src')).strip(" ['']") + return 'https://fc2club.com' + result2 -def getOutline(htmlcode2): # 获取番号 # - html = etree.fromstring(htmlcode2, etree.HTMLParser()) - result = str(html.xpath('/html/body/div[1]/div[2]/div[2]/div[1]/div/article/section[4]/p/text()')).strip( - " ['']").replace("\\n", '', 10000).replace("'", '', 10000).replace(', ,', '').strip(' ').replace('。,', ',') - return result +def getScore(htmlcode): # 获取评分 # + if re.search(r'影片评分:(\d+)分', htmlcode): + score = str(re.findall(r'影片评分:(\d+)分', htmlcode)).strip(" ['']") + score = float(int(score) / 100.0 * 5) + return str(score) def getTag(htmlcode): # 获取番号 @@ -85,44 +77,47 @@ def getYear(release): def main(number): - htmlcode2 = get_html( - 'http://adult.contents.fc2.com/article_search.php?id=' + number + '&utm_source=aff_php&utm_medium=source_code&utm_campaign=from_aff_php') - htmlcode = get_html('https://fc2club.com//html/FC2-' + number + '.html') - actor = getActor(htmlcode) - if len(actor) == 0: - actor = 'FC2系列' try: + htmlcode = get_html('https://fc2club.com//html/FC2-' + number + '.html') + if str(htmlcode) == 'ProxyError': + raise TimeoutError + actor = getActor(htmlcode) + if len(actor) == 0: + actor = 'FC2系列' dic = { - 'title': getTitle(htmlcode).replace(' ', '-'), + 'title': getTitle(htmlcode).strip(' '), 'studio': getStudio(htmlcode), - 'publisher': '', - 'year': '', # str(re.search('\d{4}',getRelease(number)).group()), - 'outline': getOutline(htmlcode2).replace('\n', ''), + 'score': getScore(htmlcode), 'runtime': getYear(getRelease(htmlcode)), - 'director': '', 'actor': actor.replace('/', ','), 'release': getRelease(number), 'number': 'FC2-' + number, - 'cover': getCover(htmlcode, number, htmlcode2), - 'imagecut': 0, - 'series': '', 'tag': getTag(htmlcode), 'actor_photo': getActorPhoto(actor), + 'cover': getCover(htmlcode), + 'imagecut': 0, + 'director': '', + 'series': '', + 'publisher': '', + 'year': '', + 'outline': '', 'website': 'https://fc2club.com//html/FC2-' + number + '.html', 'source': 'fc2fans_club.py', } - except: - if htmlcode2 == 'ProxyError': - dic = { - 'title': '', - 'website': 'timeout', - } - else: - dic = { - 'title': '', - 'website': '', - } - js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') + except TimeoutError: + dic = { + 'title': '', + 'website': 'timeout', + } + except Exception as error_info: + print('Error in fc2fans_club.main : ' + str(error_info)) + dic = { + 'title': '', + 'website': '', + } + js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) return js + # print(main('1251689')) +# print(main('674239')) diff --git a/Getter/jav321.py b/Getter/jav321.py new file mode 100644 index 000000000..763ed4070 --- /dev/null +++ b/Getter/jav321.py @@ -0,0 +1,152 @@ +import re +from lxml import etree +import json +from Function.getHtml import post_html + + +def getActorPhoto(actor): + data = {} + for i in actor: + actor_photo = {i: ''} + data.update(actor_photo) + return data + + +def getTitle(response): + return str(re.findall(r'

(.+) ', response)).strip(" ['']") + + +def getActor(response): + if re.search(r'(\S+)  ', response): + return str(re.findall(r'(\S+)  ', response)).strip(" [',']").replace('\'', '') + elif re.search(r'(\S+)  ', response): + return str(re.findall(r'(\S+)  ', response)).strip(" [',']").replace('\'', + '') + else: + return str(re.findall(r'女优: (.+)  
', response)).strip(" [',']").replace('\'', '') + + +def getStudio(response): + return str(re.findall(r'(\S+)', response)).strip(" ['']") + + +def getRuntime(response): + return str(re.findall(r'播放时长: (\d+) \S+
', response)).strip(" ['']") + + +def getSeries(response): + return str(re.findall(r'系列: (\S+)', response)).strip(" ['']") + + +def getWebsite(detail_page): + return 'https:' + detail_page.xpath('//a[contains(text(),"简体中文")]/@href')[0] + + +def getNum(response): + return str(re.findall(r'番号: (\S+)
', response)).strip(" ['']").upper() + + +def getScore(response): + if re.search(r'评分: ', response): + score = re.findall(r'评分: ', response)[0] + return str(float(score) / 10.0) + else: + return str(re.findall(r'评分: (.+)
', response)).strip(" [',']").replace('\'', '') + + +def getYear(release): + try: + result = str(re.search('\d{4}', release).group()) + return result + except: + return release + + +def getRelease(response): + return str(re.findall(r'发行日期: (\d+-\d+-\d+)
', response)).strip(" ['']").replace('0000-00-00', '') + + +def getCover(detail_page): + cover_url = str(detail_page.xpath("/html/body/div[@class='row'][2]/div[@class='col-md-3']/div[@class='col-xs-12 " + "col-md-12'][1]/p/a/img[@class='img-responsive']/@src")).strip(" ['']") + if cover_url == '': + cover_url = str( + detail_page.xpath("//*[@id='vjs_sample_player']/@poster")).strip(" ['']") + return cover_url + + +def getCoverSmall(detail_page): + return str(detail_page.xpath("//div[@class='panel-body']/div[@class='row'][1]/div[@class='col-md-3']/img[" + "@class='img-responsive']/@src")).strip(" ['']") + + +def getTag(response): # 获取演员 + return re.findall(r'(\S+)', response) + + +def getOutline(detail_page): + return str(detail_page.xpath('/html/body/div[2]/div[1]/div[1]/div[2]/div[3]/div/text()')).strip(" ['']") + + +def main(number, isuncensored=False): + try: + response = post_html("https://www.jav321.com/search", query={"sn": number}) + if str(response) == 'ProxyError': + raise TimeoutError + if '未找到您要找的AV' in response: + raise Exception('Movie Data not found in jav321!') + detail_page = etree.fromstring(response, etree.HTMLParser()) + release = getRelease(response) + actor = getActor(response) + imagecut = 1 + cover_small = '' + if 'HEYZO' in number.upper() or isuncensored: + imagecut = 3 + cover_small = getCoverSmall(detail_page) + if cover_small == '': + imagecut = 0 + dic = { + 'actor': actor, + 'title': getTitle(response), + 'studio': getStudio(response), + 'outline': getOutline(detail_page), + 'runtime': getRuntime(response), + 'release': release, + 'number': getNum(response), + 'score': getScore(response), + 'tag': getTag(response), + 'series': getSeries(response), + 'year': getYear(release), + 'actor_photo': getActorPhoto(actor.split(',')), + 'cover': getCover(detail_page), + 'cover_small': cover_small, + 'imagecut': imagecut, + 'director': '', + 'publisher': '', + 'website': getWebsite(detail_page), + 'source': 'jav321.py', + } + except TimeoutError: + dic = { + 'title': '', + 'website': 'timeout', + } + except Exception as error_info: + print('Error in jav321.main : ' + str(error_info)) + dic = { + 'title': '', + 'website': '', + } + js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') + return js + + +''' +print(main('msfh-010')) +print(main('kavr-065')) +print(main('ssni-645')) +print(main('sivr-038')) +print(main('ara-415')) +print(main('luxu-1257')) +print(main('heyzo-1031')) +''' diff --git a/Getter/javbus.py b/Getter/javbus.py index 12c5a1505..2b1309bd8 100644 --- a/Getter/javbus.py +++ b/Getter/javbus.py @@ -1,12 +1,13 @@ import re -from pyquery import PyQuery as pq # need install -from lxml import etree # need install -from bs4 import BeautifulSoup # need install +from pyquery import PyQuery as pq +from lxml import etree +from bs4 import BeautifulSoup import json from Function.getHtml import get_html +from Function.getHtml import post_html -def getActorPhoto(htmlcode): # //*[@id="star_qdt"]/li/a/img +def getActorPhoto(htmlcode): soup = BeautifulSoup(htmlcode, 'lxml') a = soup.find_all(attrs={'class': 'star-name'}) d = {} @@ -89,16 +90,16 @@ def getDirector(htmlcode): # 获取导演 return result -def getOutline(number): # 获取简介 - try: - dww_htmlcode = get_html('https://www.dmm.co.jp/digital/videoa/-/detail/=/cid=' + number.replace("-", '00')) - if '404 Not Found' in dww_htmlcode: - dww_htmlcode = get_html('https://www.dmm.co.jp/mono/dvd/-/detail/=/cid=' + number.replace("-", '00')) - except: - dww_htmlcode = '' - html = etree.fromstring(dww_htmlcode, etree.HTMLParser()) - result = str(html.xpath("//div[@class='mg-b20 lh4']/text()")).strip(" ['']") - return result.replace('\n', '').replace('\\n', '').replace('\'', '').replace(',', '').replace(' ', '') +def getOutlineScore(number): # 获取简介 + response = post_html("https://www.jav321.com/search", query={"sn": number}) + detail_page = etree.fromstring(response, etree.HTMLParser()) + outline = str(detail_page.xpath('/html/body/div[2]/div[1]/div[1]/div[2]/div[3]/div/text()')).strip(" ['']") + if re.search(r'评分: ', response): + score = re.findall(r'评分: ', response)[0] + score = str(float(score) / 10.0) + else: + score = str(re.findall(r'评分: (.+)
', response)).strip(" [',']").replace('\'', '') + return outline, score def getSeries(htmlcode): @@ -109,21 +110,13 @@ def getSeries(htmlcode): def getCover_small(number): # 从avsox获取封面图 htmlcode = get_html('https://avsox.host/cn/search/' + number) - html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result = str(html.xpath('//*[@id="waterfall"]/div/a/@href')).strip(" ['']") - if result == '' or result == 'null' or result == 'None': - htmlcode = get_html('https://avsox.host/cn/search/' + number.replace('-', '_')) - html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result = str(html.xpath('//*[@id="waterfall"]/div/a/@href')).strip(" ['']") - if result == '' or result == 'null' or result == 'None': - htmlcode = get_html('https://avsox.host/cn/search/' + number.replace('_', '')) html = etree.fromstring(htmlcode, etree.HTMLParser()) counts = len(html.xpath("//div[@id='waterfall']/div/a/div")) if counts == 0: return '' for count in range(1, counts + 1): # 遍历搜索结果,找到需要的番号 number_get = html.xpath("//div[@id='waterfall']/div[" + str(count) + "]/a/div[@class='photo-info']/span/date[1]/text()") - if len(number_get) > 0 and number_get[0] == number: + if len(number_get) > 0 and number_get[0].upper() == number.upper(): cover_small = html.xpath("//div[@id='waterfall']/div[" + str(count) + "]/a/div[@class='photo-frame']/img/@src")[0] return cover_small return '' @@ -142,7 +135,6 @@ def getTag(htmlcode): # 获取标签 def find_number(number): # =======================================================================有码搜索 - counts = 0 if not (re.match('^\d{4,}', number) or re.match('n\d{4}', number) or 'HEYZO' in number.upper()): htmlcode = get_html('https://www.javbus.com/search/' + number + '&type=1') html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() @@ -150,12 +142,9 @@ def find_number(number): if counts != 0: for count in range(1, counts + 1): # 遍历搜索结果,找到需要的番号 number_get = html.xpath("//div[@id='waterfall']/div[@id='waterfall']/div[" + str(count) + "]/a[@class='movie-box']/div[@class='photo-info']/span/date[1]/text()")[0] - # number_get = number_get.replace('_', '-') - if number_get == number.upper() or number_get == number.upper().replace('-', '') or number_get == number.upper().replace('_', ''): - result_url = html.xpath( - "//div[@id='waterfall']/div[@id='waterfall']/div[" + str(count) + "]/a[@class='movie-box']/@href")[0] - return result_url - elif number_get == number.lower() or number_get == number.lower().replace('-', '') or number_get == number.lower().replace('_', ''): + number_get = number_get.upper() + number = number.upper() + if number_get == number or number_get == number.replace('-', '') or number_get == number.replace('_', ''): result_url = html.xpath( "//div[@id='waterfall']/div[@id='waterfall']/div[" + str(count) + "]/a[@class='movie-box']/@href")[0] return result_url @@ -167,12 +156,9 @@ def find_number(number): return 'not found' for count in range(1, counts + 1): # 遍历搜索结果,找到需要的番号 number_get = html.xpath("//div[@id='waterfall']/div[@id='waterfall']/div[" + str(count) + "]/a[@class='movie-box']/div[@class='photo-info']/span/date[1]/text()")[0] - # number_get = number_get.replace('_', '-') - if number_get == number.upper() or number_get == number.upper().replace('-', '') or number_get == number.upper().replace('_', ''): - result_url = html.xpath( - "//div[@id='waterfall']/div[@id='waterfall']/div[" + str(count) + "]/a[@class='movie-box']/@href")[0] - return result_url - elif number_get == number.lower() or number_get == number.lower().replace('-', '') or number_get == number.lower().replace('_', ''): + number_get = number_get.upper() + number = number.upper() + if number_get == number or number_get == number.replace('-', '') or number_get == number.replace('_', ''): result_url = html.xpath( "//div[@id='waterfall']/div[@id='waterfall']/div[" + str(count) + "]/a[@class='movie-box']/@href")[0] return result_url @@ -184,25 +170,22 @@ def find_number(number): def main(number): - result_url = find_number(number) - if result_url == 'not found': - dic = { - 'title': '', - 'actor': '', - 'website': '', - } - js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, - separators=(',', ':'), ) # .encode('UTF-8') - return js - htmlcode = get_html(result_url) try: + result_url = find_number(number) + if result_url == 'not found': + raise Exception('Movie Data not found in javbus.main!') + htmlcode = get_html(result_url) + if str(htmlcode) == 'ProxyError': + raise TimeoutError + outline, score = getOutlineScore(number) number = getNum(htmlcode) dic = { 'title': str(getTitle(htmlcode)).replace(number, '').strip().replace(' ', '-'), 'studio': getStudio(htmlcode), 'publisher': getPublisher(htmlcode), 'year': getYear(getRelease(htmlcode)), - 'outline': getOutline(number), + 'outline': outline, + 'score': score, 'runtime': getRuntime(htmlcode).replace('分鐘', '').strip(), 'director': getDirector(htmlcode), 'actor': getActor(htmlcode), @@ -216,42 +199,41 @@ def main(number): 'website': result_url, 'source': 'javbus.py', } + except TimeoutError: + dic = { + 'title': '', + 'website': 'timeout', + } except Exception as error_info: - print('Error in javbus.main :' + str(error_info)) - if htmlcode == 'ProxyError': - dic = { - 'title': '', - 'website': 'timeout', - } - else: - dic = { - 'title': '', - 'website': '', - } + print('Error in javbus.main : ' + str(error_info)) + dic = { + 'title': '', + 'website': '', + } js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') return js def main_uncensored(number): - result_url = find_number(number) - if result_url == 'not found': - dic = { - 'title': '', - 'actor': '', - 'website': '', - } - js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, - separators=(',', ':'), ) # .encode('UTF-8') - return js - htmlcode = get_html(result_url) try: + result_url = find_number(number) + if result_url == 'not found': + raise Exception('Movie Data not found in javbus.main_uncensored!') + htmlcode = get_html(result_url) + if str(htmlcode) == 'ProxyError': + raise TimeoutError number = getNum(htmlcode) + outline = '' + score = '' + if 'HEYZO' in number.upper(): + outline, score = getOutlineScore(number) dic = { 'title': getTitle(htmlcode).replace(number, '').strip().replace(' ', '-'), 'studio': getStudio(htmlcode), 'publisher': '', 'year': getYear(getRelease(htmlcode)), - 'outline': '', + 'outline': outline, + 'score': score, 'runtime': getRuntime(htmlcode).replace('分鐘', '').strip(), 'director': getDirector(htmlcode), 'actor': getActor(htmlcode), @@ -268,96 +250,90 @@ def main_uncensored(number): } if dic['cover_small'] == '': dic['imagecut'] = 0 - except Exception as error_info: - print('Error in javbus.main_uncensored :' + str(error_info)) - if htmlcode == 'ProxyError': - dic = { - 'title': '', - 'website': 'timeout', - } - else: - dic = { - 'title': '', - 'website': '', - } - js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') - return js - - -def main_us(number): - htmlcode = get_html('https://www.javbus.zone/search/' + number) - html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - counts = len(html.xpath("//div[@class='row']/div[@id='waterfall']/div")) - if counts == 0: + except TimeoutError: dic = { 'title': '', - 'actor': '', - 'website': '', + 'website': 'timeout', } - js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, - separators=(',', ':'), ) # .encode('UTF-8') - return js - result_url = '' - cover_small = '' - for count in range(1, counts + 1): # 遍历搜索结果,找到需要的番号 - number_get = html.xpath("//div[@id='waterfall']/div[" + str( - count) + "]/a[@class='movie-box']/div[@class='photo-info']/span/date[1]/text()")[0] - if number_get.upper() == number.upper() or number_get.replace('-', '').upper() == number.upper(): - result_url = html.xpath( - "//div[@id='waterfall']/div[" + str(count) + "]/a[@class='movie-box']/@href")[0] - cover_small = html.xpath( - "//div[@id='waterfall']/div[" + str( - count) + "]/a[@class='movie-box']/div[@class='photo-frame']/img[@class='img']/@src")[0] - break - if result_url == 'not found': + except Exception as error_info: + print('Error in javbus.main_uncensored : ' + str(error_info)) dic = { 'title': '', - 'actor': '', 'website': '', } - js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, - separators=(',', ':'), ) # .encode('UTF-8') - return js - htmlcode = get_html(result_url) + js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') + return js + + +def main_us(number): try: + htmlcode = get_html('https://www.javbus.zone/search/' + number) + if str(htmlcode) == 'ProxyError': + raise TimeoutError + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + counts = len(html.xpath("//div[@class='row']/div[@id='waterfall']/div")) + if counts == 0: + raise Exception('Movie Data not found in javbus.main_us!') + result_url = '' + cover_small = '' + for count in range(1, counts + 1): # 遍历搜索结果,找到需要的番号 + number_get = html.xpath("//div[@id='waterfall']/div[" + str( + count) + "]/a[@class='movie-box']/div[@class='photo-info']/span/date[1]/text()")[0] + if number_get.upper() == number.upper() or number_get.replace('-', '').upper() == number.upper(): + result_url = html.xpath( + "//div[@id='waterfall']/div[" + str(count) + "]/a[@class='movie-box']/@href")[0] + cover_small = html.xpath( + "//div[@id='waterfall']/div[" + str( + count) + "]/a[@class='movie-box']/div[@class='photo-frame']/img[@class='img']/@src")[0] + break + if result_url == '': + raise Exception('Movie Data not found in javbus.main_us!') + htmlcode = get_html(result_url) + if str(htmlcode) == 'ProxyError': + raise TimeoutError number = getNum(htmlcode) dic = { 'title': getTitle(htmlcode).replace(number, '').strip(), 'studio': getStudio(htmlcode), - 'publisher': '', 'year': getYear(getRelease(htmlcode)), - 'outline': '', 'runtime': getRuntime(htmlcode).replace('分鐘', '').strip(), 'director': getDirector(htmlcode), 'actor': getActor(htmlcode), 'release': getRelease(htmlcode), 'number': getNum(htmlcode), - 'cover': getCover(htmlcode), 'tag': getTag(htmlcode), 'series': getSeries(htmlcode), - 'imagecut': 3, + 'cover': getCover(htmlcode), 'cover_small': cover_small, + 'imagecut': 3, 'actor_photo': getActorPhoto(htmlcode), + 'publisher': '', + 'outline': '', + 'score': '', 'website': result_url, 'source': 'javbus.py', } + except TimeoutError: + dic = { + 'title': '', + 'website': 'timeout', + } except Exception as error_info: - print('Error in javbus.main_us :' + str(error_info)) - if htmlcode == 'ProxyError': - dic = { - 'title': '', - 'website': 'timeout', - } - else: - dic = { - 'title': '', - 'website': '', - } + print('Error in javbus.main_us : ' + str(error_info)) + dic = { + 'title': '', + 'website': '', + } js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') return js -# print(find_number('KA-001')) -# print(main('OFJE-175')) -# print(main_uncensored('010115-001')) -# print(main_uncensored('012715-793')) -# print(main_us('sexart.15.06.10')) + +''' +print(find_number('KA-001')) +print(main_uncensored('010115-001')) +print(main('ssni-644')) +print(main_uncensored('012715-793')) +print(main_us('sexart.15.06.10')) +print(main_uncensored('heyzo-1031')) +''' + diff --git a/Getter/javdb.py b/Getter/javdb.py index d04b26707..e4bf409ad 100644 --- a/Getter/javdb.py +++ b/Getter/javdb.py @@ -1,7 +1,9 @@ import re +from bs4 import BeautifulSoup, SoupStrainer from lxml import etree import json from Function.getHtml import get_html +from Function.getHtml import post_html def getTitle(htmlcode): @@ -15,8 +17,8 @@ def getTitle(htmlcode): def getActor(htmlcode): # //*[@id="center_column"]/div[2]/div[1]/div/table/tbody/tr[1]/td/text() html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = html.xpath('//strong[contains(text(),"演員")]/../following-sibling::span/text()') - result2 = html.xpath('//strong[contains(text(),"演員")]/../following-sibling::span/a/text()') + result1 = html.xpath('//strong[contains(text(),"演員")]/../span/text()') + result2 = html.xpath('//strong[contains(text(),"演員")]/../span/a/text()') return result1 + result2 @@ -31,37 +33,37 @@ def getActorPhoto(actor): # //*[@id="star_qdt"]/li/a/img def getStudio(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//strong[contains(text(),"片商")]/../following-sibling::span/text()')).strip(" ['']") - result2 = str(html.xpath('//strong[contains(text(),"片商")]/../following-sibling::span/a/text()')).strip(" ['']") + result1 = str(html.xpath('//strong[contains(text(),"片商")]/../span/text()')).strip(" ['']") + result2 = str(html.xpath('//strong[contains(text(),"片商")]/../span/a/text()')).strip(" ['']") return str(result1 + result2).strip('+').replace("', '", '').replace('"', '') def getPublisher(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//strong[contains(text(),"發行")]/../following-sibling::span/text()')).strip(" ['']") - result2 = str(html.xpath('//strong[contains(text(),"發行")]/../following-sibling::span/a/text()')).strip(" ['']") + result1 = str(html.xpath('//strong[contains(text(),"發行")]/../span/text()')).strip(" ['']") + result2 = str(html.xpath('//strong[contains(text(),"發行")]/../span/a/text()')).strip(" ['']") return str(result1 + result2).strip('+').replace("', '", '').replace('"', '') def getRuntime(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//strong[contains(text(),"時長")]/../following-sibling::span/text()')).strip(" ['']") - result2 = str(html.xpath('//strong[contains(text(),"時長")]/../following-sibling::span/a/text()')).strip(" ['']") + result1 = str(html.xpath('//strong[contains(text(),"時長")]/../span/text()')).strip(" ['']") + result2 = str(html.xpath('//strong[contains(text(),"時長")]/../span/a/text()')).strip(" ['']") return str(result1 + result2).strip('+').rstrip('mi') def getSeries(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//strong[contains(text(),"系列")]/../following-sibling::span/text()')).strip(" ['']") - result2 = str(html.xpath('//strong[contains(text(),"系列")]/../following-sibling::span/a/text()')).strip(" ['']") + result1 = str(html.xpath('//strong[contains(text(),"系列")]/../span/text()')).strip(" ['']") + result2 = str(html.xpath('//strong[contains(text(),"系列")]/../span/a/text()')).strip(" ['']") return str(result1 + result2).strip('+').replace("', '", '').replace('"', '') def getNumber(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) - result1 = str(html.xpath('//strong[contains(text(),"番號")]/../following-sibling::span/text()')).strip( + result1 = str(html.xpath('//strong[contains(text(),"番號")]/../span/text()')).strip( " ['']").replace('_', '-') - result2 = str(html.xpath('//strong[contains(text(),"番號")]/../following-sibling::span/a/text()')).strip( + result2 = str(html.xpath('//strong[contains(text(),"番號")]/../span/a/text()')).strip( " ['']").replace('_', '-') return str(result2 + result1).strip('+') @@ -76,23 +78,23 @@ def getYear(getRelease): def getRelease(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//strong[contains(text(),"時間")]/../following-sibling::span/text()')).strip(" ['']") - result2 = str(html.xpath('//strong[contains(text(),"時間")]/../following-sibling::span/a/text()')).strip(" ['']") + result1 = str(html.xpath('//strong[contains(text(),"時間")]/../span/text()')).strip(" ['']") + result2 = str(html.xpath('//strong[contains(text(),"時間")]/../span/a/text()')).strip(" ['']") return str(result1 + result2).strip('+') def getTag(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//strong[contains(text(),"类别")]/../following-sibling::span/text()')).strip(" ['']") - result2 = str(html.xpath('//strong[contains(text(),"类别")]/../following-sibling::span/a/text()')).strip(" ['']") + result1 = str(html.xpath('//strong[contains(text(),"類別")]/../span/text()')).strip(" ['']") + result2 = str(html.xpath('//strong[contains(text(),"類別")]/../span/a/text()')).strip(" ['']") return str(result1 + result2).strip('+').replace(",\\xa0", "").replace("'", "").replace(' ', '').replace(',,', '').lstrip( ',') def getCover_small(htmlcode, count): - html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result = html.xpath("//div[@class='item-image fix-scale-cover']/img/@src")[count] + html = etree.fromstring(htmlcode, etree.HTMLParser()) + result = html.xpath("//div[@class='grid-item column']/a[@class='box']/div/img/@src")[count] if not 'https' in result: result = 'https:' + result return result @@ -100,131 +102,140 @@ def getCover_small(htmlcode, count): def getCover(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) - result = str(html.xpath("//div[@class='column column-video-cover']/a/img/@src")).strip(" ['']") + result = str(html.xpath("//img[@class='box video-cover']/@src")).strip(" ['']") + # 有时xpath找不到元素,所以要用bs4 + if not result: + soup = BeautifulSoup(htmlcode, 'lxml', parse_only=SoupStrainer('img', {'class': 'box video-cover'})) + if soup.img is not None: + result = soup.img['src'] return result def getDirector(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//strong[contains(text(),"導演")]/../following-sibling::span/text()')).strip(" ['']") - result2 = str(html.xpath('//strong[contains(text(),"導演")]/../following-sibling::span/a/text()')).strip(" ['']") + result1 = str(html.xpath('//strong[contains(text(),"導演")]/../span/text()')).strip(" ['']") + result2 = str(html.xpath('//strong[contains(text(),"導演")]/../span/a/text()')).strip(" ['']") return str(result1 + result2).strip('+').replace("', '", '').replace('"', '') -def getOutline(number): # 获取简介 - try: - dww_htmlcode = get_html('https://www.dmm.co.jp/digital/videoa/-/detail/=/cid=' + number.replace("-", '00')) - if '404 Not Found' in dww_htmlcode: - dww_htmlcode = get_html('https://www.dmm.co.jp/mono/dvd/-/detail/=/cid=' + number.replace("-", '00')) - except: - dww_htmlcode = '' - html = etree.fromstring(dww_htmlcode, etree.HTMLParser()) - result = str(html.xpath("//div[@class='mg-b20 lh4']/text()")).strip(" ['']") - return result.replace('\n', '').replace('\\n', '').replace('\'', '').replace(',', '').replace(' ', '') - - -def main(number): - htmlcode = '' +def getScore(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + result = str(html.xpath("//span[@class='score-label']/text()")).strip(" ['']") + score = 0 + if re.search(r'\(.+分\)', result): + score = re.findall(r'\((.+)分\)', result)[0] + return format(float(score), '0.1f') + + +def getOutlineScore(number): # 获取简介 + response = post_html("https://www.jav321.com/search", query={"sn": number}) + detail_page = etree.fromstring(response, etree.HTMLParser()) + outline = str(detail_page.xpath('/html/body/div[2]/div[1]/div[1]/div[2]/div[3]/div/text()')).strip(" ['']") + if re.search(r'评分: ', response): + score = re.findall(r'评分: ', response)[0] + score = str(float(score) / 10.0) + else: + score = str(re.findall(r'评分: (.+)
', response)).strip(" [',']").replace('\'', '') + return outline, score + + +def main(number, isuncensored=False): try: + # ========================================================================搜索番号 htmlcode = get_html('https://javdb.com/search?q=' + number + '&f=all').replace(u'\xa0', u' ') + if str(htmlcode) == 'ProxyError': + raise TimeoutError html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() counts = len(html.xpath( '//div[@id=\'videos\']/div[@class=\'grid columns\']/div[@class=\'grid-item column\']')) if counts == 0: - dic = { - 'title': '', - 'actor': '', - 'website': '', - } - js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, - separators=(',', ':'), ) # .encode('UTF-8') - return js + raise Exception('Movie Data not found in javdb.main!') + # ========================================================================遍历搜索结果,找到需要的番号所在URL count = 1 number_get = '' movie_found = 0 - for count in range(1, counts + 1): # 遍历搜索结果,找到需要的番号 + for count in range(1, counts + 1): number_get = html.xpath( '//div[@id=\'videos\']/div[@class=\'grid columns\']/div[@class=\'grid-item column\'][' + str( count) + ']/a[@class=\'box\']/div[@class=\'uid\']/text()')[0] - # number_get = number_get.replace('_', '-') - if number_get == number.upper() or number_get == number.lower(): + if number_get.upper() == number.upper(): movie_found = 1 break + if movie_found == 0: + raise Exception('Movie Data not found in javdb.main!') result_url = 'https://javdb.com' + html.xpath('//*[@id="videos"]/div/div/a/@href')[count - 1] - b = get_html(result_url).replace(u'\xa0', u' ') - actor = getActor(b) + # ========================================================================请求、判断结果 + html_info = get_html(result_url).replace(u'\xa0', u' ') + if str(html_info) == 'ProxyError': + raise TimeoutError + # ========================================================================获取评分、简介 + imagecut = 1 + cover_small = '' + outline = '' + if isuncensored or re.match('^\d{4,}', number) or re.match('n\d{4}', number): # 无码,收集封面、评分 + imagecut = 3 + cover_small = getCover_small(htmlcode, count - 1) + score = getScore(html_info) + elif 'HEYZO' in number.upper(): # HEYZO,收集封面、评分、简介 + imagecut = 3 + cover_small = getCover_small(htmlcode, count - 1) + outline, score = getOutlineScore(number) + else: # 其他,收集评分、简介 + outline, score = getOutlineScore(number) + # ========================================================================收集信息 + actor = getActor(html_info) if len(actor) == 0 and 'FC2-' in number_get: actor.append('FC2-NoActor') - if movie_found == 1: - imagecut = 1 - cover_small = '' - outline = '' - if re.match('^\d{4,}', number) or re.match('n\d{4}', number) or 'HEYZO' in number.upper(): - imagecut = 3 - cover_small = getCover_small(htmlcode, count - 1) - else: - outline = getOutline(number) - dic = { - 'actor': str(actor).strip(" [',']").replace('\'', ''), - 'title': getTitle(b).replace('中文字幕', '').replace("\\n", '').replace('_', '-').replace(number_get, - '').strip().replace( - ' ', '-').replace('--', '-'), - 'studio': getStudio(b), - 'publisher': getPublisher(b), - 'outline': outline, - 'runtime': getRuntime(b).replace(' 分鍾', ''), - 'director': getDirector(b), - 'release': getRelease(b), - 'number': number_get, - 'cover': getCover(b), - 'cover_small': cover_small, - 'imagecut': imagecut, - 'tag': getTag(b), - 'series': getSeries(b), - 'year': getYear(getRelease(b)), # str(re.search('\d{4}',getRelease(htmlcode)).group()), - 'actor_photo': getActorPhoto(actor), - 'website': result_url, - 'source': 'javdb.py', - } - else: # 未找到番号 - dic = { - 'title': '', - 'actor': str(actor).strip(" [',']").replace('\'', ''), - 'website': '', - } - except: # actor 用于判断ip是否被封 - if htmlcode == 'ProxyError': - dic = { - 'title': '', - 'actor': '', - 'website': 'timeout', - } - else: - dic = { - 'title': '', - 'actor': '', - 'website': '', - } + dic = { + 'actor': str(actor).strip(" [',']").replace('\'', ''), + 'title': getTitle(html_info).replace('中文字幕', '').replace('無碼', '').replace("\\n", '').replace('_', + '-').replace( + number_get, '').strip().replace(' ', '-').replace('--', '-'), + 'studio': getStudio(html_info), + 'publisher': getPublisher(html_info), + 'outline': outline, + 'score': score, + 'runtime': getRuntime(html_info).replace(' 分鍾', ''), + 'director': getDirector(html_info), + 'release': getRelease(html_info), + 'number': number_get, + 'cover': getCover(html_info), + 'cover_small': cover_small, + 'imagecut': imagecut, + 'tag': getTag(html_info), + 'series': getSeries(html_info), + 'year': getYear(getRelease(html_info)), # str(re.search('\d{4}',getRelease(htmlcode)).group()), + 'actor_photo': getActorPhoto(actor), + 'website': result_url, + 'source': 'javdb.py', + } + except TimeoutError: + dic = { + 'title': '', + 'website': 'timeout', + } + except Exception as error_info: + print('Error in javdb.main : ' + str(error_info)) + dic = { + 'title': '', + 'website': '', + } js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') return js def main_us(number): - htmlcode = '' try: + # ========================================================================搜索番号 htmlcode = get_html('https://javdb.com/search?q=' + number + '&f=all').replace(u'\xa0', u' ') + if str(htmlcode) == 'ProxyError': + raise TimeoutError html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() counts = len(html.xpath( '//div[@id=\'videos\']/div[@class=\'grid columns\']/div[@class=\'grid-item column\']')) if counts == 0: - dic = { - 'title': '', - 'actor': '', - 'website': '', - } - js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, - separators=(',', ':'), ) # .encode('UTF-8') - return js + raise Exception('Movie Data not found in javdb.main_us!') + # ========================================================================遍历搜索结果,找到需要的番号所在URL number_series = number.split('.')[0] number_date = '20' + number.replace(number_series, '').strip('.') number_date = number_date.replace('.', '-') @@ -240,60 +251,66 @@ def main_us(number): if re.search('\d{4}-\d{1,2}-\d{1,2}', date_get): date_get = re.findall('\d{4}-\d{1,2}-\d{1,2}', date_get)[0] series_get = series_get.replace(' ', '') - if (series_get.upper() == number_series.upper() or series_get.replace('-', '').upper() == number_series.upper()) and number_date == date_get: + if (series_get.upper() == number_series.upper() or series_get.replace('-', + '').upper() == number_series.upper()) and number_date == date_get: movie_found = 1 break + if movie_found == 0: + raise Exception('Movie Data not found in javdb.main_us!') result_url = 'https://javdb.com' + html.xpath('//*[@id="videos"]/div/div/a/@href')[count - 1] + # ========================================================================请求、判断结果 html_info = get_html(result_url).replace(u'\xa0', u' ') + if str(html_info) == 'ProxyError': + raise TimeoutError + # ========================================================================收集信息 actor = getActor(html_info) number = getNumber(html_info) - if movie_found == 1: - dic = { - 'actor': str(actor).strip(" [',']").replace('\'', ''), - 'title': getTitle(html_info).replace('中文字幕', '').replace("\\n", '').replace('_', '-').replace(number, '').strip(), - 'studio': getStudio(html_info), - 'publisher': getPublisher(html_info), - 'outline': getOutline(html_info).replace('\n', ''), - 'runtime': getRuntime(html_info).replace(' 分鍾', ''), - 'director': getDirector(html_info), - 'release': getRelease(html_info), - 'number': number, - 'cover': getCover(html_info), - 'cover_small': getCover_small(htmlcode, count - 1), - 'imagecut': 3, - 'tag': getTag(html_info), - 'series': getSeries(html_info), - 'year': getYear(getRelease(html_info)), # str(re.search('\d{4}',getRelease(htmlcode)).group()), - 'actor_photo': getActorPhoto(actor), - 'website': result_url, - 'source': 'javdb.py', - } - else: # 未找到番号 - dic = { - 'title': '', - 'actor': str(actor).strip(" [',']").replace('\'', ''), - 'website': '', - } - except: # actor 用于判断ip是否被封 - if htmlcode == 'ProxyError': - dic = { - 'title': '', - 'actor': '', - 'website': 'timeout', - } - else: - dic = { - 'title': '', - 'actor': '', - 'website': '', - } + dic = { + 'actor': str(actor).strip(" [',']").replace('\'', ''), + 'title': getTitle(html_info).replace('中文字幕', '').replace("\\n", '').replace('_', '-').replace(number, + '').strip(), + 'studio': getStudio(html_info), + 'publisher': getPublisher(html_info), + 'outline': '', + 'score': getScore(html_info), + 'runtime': getRuntime(html_info).replace(' 分鍾', ''), + 'director': getDirector(html_info), + 'release': getRelease(html_info), + 'number': number, + 'cover': getCover(html_info), + 'cover_small': getCover_small(htmlcode, count - 1), + 'imagecut': 3, + 'tag': getTag(html_info), + 'series': getSeries(html_info), + 'year': getYear(getRelease(html_info)), # str(re.search('\d{4}',getRelease(htmlcode)).group()), + 'actor_photo': getActorPhoto(actor), + 'website': result_url, + 'source': 'javdb.py', + } + except TimeoutError: + dic = { + 'title': '', + 'website': 'timeout', + } + except Exception as error_info: + print('Error in javdb.main_us : ' + str(error_info)) + dic = { + 'title': '', + 'website': '', + } js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') return js -# print(main('LUXU-1217')) -# input("[+][+]Press enter key exit, you can check the error messge before you exit.\n[+][+]按回车键结束,你可以在结束之前查看和错误信息。") -# print(main('abs-141')) -# print(main('HYSD-00083')) -# print(main_us('x-art.19.11.03')) -# print(main('n1403')) +''' +print(main('abs-141')) +print(main('HYSD-00083')) +print(main('IESP-660')) +print(main('n1403')) +print(main('GANA-1910')) +print(main('heyzo-1031')) +print(main_us('x-art.19.11.03')) +print(main('032020-001')) +print(main('S2M-055')) +print(main('LUXU-1217')) +''' diff --git a/Getter/mgstage.py b/Getter/mgstage.py index 43b5b592f..c408ca489 100644 --- a/Getter/mgstage.py +++ b/Getter/mgstage.py @@ -1,28 +1,26 @@ import re from lxml import etree import json -from bs4 import BeautifulSoup from Function.getHtml import get_html -def getTitle(a): +def getTitle(htmlcode): try: - html = etree.fromstring(a, etree.HTMLParser()) + html = etree.fromstring(htmlcode, etree.HTMLParser()) result = str(html.xpath('//*[@id="center_column"]/div[1]/h1/text()')).strip(" ['']") return result.replace('/', ',') except: return '' -def getActor(a): # //*[@id="center_column"]/div[2]/div[1]/div/table/tbody/tr[1]/td/text() - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//th[contains(text(),"出演:")]/../td/a/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - result2 = str(html.xpath('//th[contains(text(),"出演:")]/../td/text()')).strip(" ['']").strip('\\n ').strip('\\n') - return str(result1 + result2).strip('+').replace("', '", '').replace('"', '').replace('/', ',') +def getActor(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + result1 = str(html.xpath('//th[contains(text(),"出演")]/../td/a/text()')).strip(" ['']") + result2 = str(html.xpath('//th[contains(text(),"出演")]/../td/text()')).strip(" ['']") + return str(result1 + result2).replace('/', ',').replace('\'', '').replace(' ', '').replace('\\n', '') -def getActorPhoto(actor): # //*[@id="star_qdt"]/li/a/img +def getActorPhoto(actor): d = {} for i in actor: if ',' not in i or ')' in i: @@ -31,49 +29,39 @@ def getActorPhoto(actor): # //*[@id="star_qdt"]/li/a/img return d -def getStudio(a): - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//th[contains(text(),"メーカー:")]/../td/a/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - result2 = str(html.xpath('//th[contains(text(),"メーカー:")]/../td/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - return str(result1 + result2).strip('+').replace("', '", '').replace('"', '') +def getStudio(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + result1 = str(html.xpath('//th[contains(text(),"メーカー:")]/../td/a/text()')).strip(" ['']") + result2 = str(html.xpath('//th[contains(text(),"メーカー:")]/../td/text()')).strip(" ['']") + return str(result1 + result2).replace('\'', '').replace(' ', '').replace('\\n', '') -def getPublisher(a): - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//th[contains(text(),"レーベル:")]/../td/a/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - result2 = str(html.xpath('//th[contains(text(),"レーベル:")]/../td/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - return str(result1 + result2).strip('+').replace("', '", '').replace('"', '') +def getPublisher(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + result1 = str(html.xpath('//th[contains(text(),"レーベル:")]/../td/a/text()')).strip(" ['']") + result2 = str(html.xpath('//th[contains(text(),"レーベル:")]/../td/text()')).strip(" ['']") + return str(result1 + result2).replace('\'', '').replace(' ', '').replace('\\n', '') -def getRuntime(a): - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//th[contains(text(),"収録時間:")]/../td/a/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - result2 = str(html.xpath('//th[contains(text(),"収録時間:")]/../td/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - return str(result1 + result2).strip('+').rstrip('mi') +def getRuntime(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + result1 = str(html.xpath('//th[contains(text(),"収録時間:")]/../td/a/text()')).strip(" ['']") + result2 = str(html.xpath('//th[contains(text(),"収録時間:")]/../td/text()')).strip(" ['']") + return str(result1 + result2).rstrip('min').replace('\'', '').replace(' ', '').replace('\\n', '') -def getSeries(a): - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//th[contains(text(),"シリーズ:")]/../td/a/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - result2 = str(html.xpath('//th[contains(text(),"シリーズ:")]/../td/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - return str(result1 + result2).strip('+').replace("', '", '').replace('"', '') +def getSeries(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + result1 = str(html.xpath('//th[contains(text(),"シリーズ:")]/../td/a/text()')).strip(" ['']") + result2 = str(html.xpath('//th[contains(text(),"シリーズ:")]/../td/text()')).strip(" ['']") + return str(result1 + result2).replace('\'', '').replace(' ', '').replace('\\n', '') -def getNum(a): - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//th[contains(text(),"品番:")]/../td/a/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - result2 = str(html.xpath('//th[contains(text(),"品番:")]/../td/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - return str(result1 + result2).strip('+') +def getNum(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + result1 = str(html.xpath('//th[contains(text(),"品番:")]/../td/a/text()')).strip(" ['']") + result2 = str(html.xpath('//th[contains(text(),"品番:")]/../td/text()')).strip(" ['']") + return str(result1 + result2).replace('\'', '').replace(' ', '').replace('\\n', '') def getYear(getRelease): @@ -84,28 +72,23 @@ def getYear(getRelease): return getRelease -def getRelease(a): - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//th[contains(text(),"配信開始日:")]/../td/a/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - result2 = str(html.xpath('//th[contains(text(),"配信開始日:")]/../td/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - return str(result1 + result2).strip('+') +def getRelease(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + result1 = str(html.xpath('//th[contains(text(),"配信開始日:")]/../td/a/text()')).strip(" ['']") + result2 = str(html.xpath('//th[contains(text(),"配信開始日:")]/../td/text()')).strip(" ['']") + return str(result1 + result2).replace('\'', '').replace(' ', '').replace('\\n', '') -def getTag(a): - html = etree.fromstring(a, etree.HTMLParser()) # //table/tr[1]/td[1]/text() - result1 = str(html.xpath('//th[contains(text(),"ジャンル:")]/../td/a/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - result2 = str(html.xpath('//th[contains(text(),"ジャンル:")]/../td/text()')).strip(" ['']").strip('\\n ').strip( - '\\n') - return str(result1 + result2).strip('+').replace("', '\\n", ",").replace("', '", "").replace('"', '') +def getTag(htmlcode): + html = etree.fromstring(htmlcode, etree.HTMLParser()) # //table/tr[1]/td[1]/text() + result1 = str(html.xpath('//th[contains(text(),"ジャンル:")]/../td/a/text()')).strip(" ['']") + result2 = str(html.xpath('//th[contains(text(),"ジャンル:")]/../td/text()')).strip(" ['']") + return str(result1 + result2).replace('\'', '').replace(' ', '').replace('\\n', '') def getCover(htmlcode): html = etree.fromstring(htmlcode, etree.HTMLParser()) result = str(html.xpath('//*[@id="center_column"]/div[1]/div[1]/div/div/h2/img/@src')).strip(" ['']") - # /html/body/div[2]/article[2]/div[1]/div[1]/div/div/h2/img/@src return result @@ -115,49 +98,54 @@ def getOutline(htmlcode): return result +def getScore(htmlcode): + return str(re.findall(r'5点満点中 (\S+)点', htmlcode)).strip(" ['']") + + def main(number): - number = number.upper() - htmlcode = str( - get_html('https://www.mgstage.com/product/product_detail/' + str(number) + '/', cookies={'adc': '1'})) - soup = BeautifulSoup(htmlcode, 'lxml') - a = str(soup.find(attrs={'class': 'detail_data'})).replace('\n ', - '').replace(' ', - '').replace('\n ', - '').replace( - '\n ', '') try: - actor = getActor(a).replace(' ', '') + number = number.upper() + htmlcode = str( + get_html('https://www.mgstage.com/product/product_detail/' + str(number) + '/', cookies={'adc': '1'})) + htmlcode = htmlcode.replace('ahref', 'a href') # 针对a标签、属性中间未分开 + if str(htmlcode) == 'ProxyError': + raise TimeoutError + actor = getActor(htmlcode).replace(' ', '') dic = { 'title': getTitle(htmlcode).replace("\\n", '').replace(' ', ''), - 'studio': getStudio(a), - 'publisher': getPublisher(a), + 'studio': getStudio(htmlcode), + 'publisher': getPublisher(htmlcode), 'outline': getOutline(htmlcode).replace('\n', ''), - 'runtime': getRuntime(a), - 'director': '', + 'score': getScore(htmlcode), + 'runtime': getRuntime(htmlcode), 'actor': actor, - 'release': getRelease(a), - 'number': getNum(a), + 'release': getRelease(htmlcode), + 'number': getNum(htmlcode), 'cover': getCover(htmlcode), 'imagecut': 0, - 'tag': getTag(a).strip(','), - 'series': getSeries(a).strip(','), - 'year': getYear(getRelease(a)), # str(re.search('\d{4}',getRelease(a)).group()), + 'tag': getTag(htmlcode).strip(','), + 'series': getSeries(htmlcode).strip(','), + 'year': getYear(getRelease(htmlcode)), 'actor_photo': getActorPhoto(actor.split(',')), + 'director': '', 'website': 'https://www.mgstage.com/product/product_detail/' + str(number) + '/', 'source': 'mgstage.py', } - except: - if htmlcode == 'ProxyError': - dic = { - 'title': '', - 'website': 'timeout', - } - else: - dic = { - 'title': '', - 'website': '', - } + except TimeoutError: + dic = { + 'title': '', + 'website': 'timeout', + } + except Exception as error_info: + print('Error in mgstage.main : ' + str(error_info)) + dic = { + 'title': '', + 'website': '', + } js = json.dumps(dic, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'), ) # .encode('UTF-8') return js - -# print(main('300MIUM-382')) +''' +print(main('200GANA-2240')) +print(main('SIRO-4042')) +print(main('300MIUM-382')) +''' diff --git a/Ui/AVDC-ico.png b/Img/AVDC-ico.png similarity index 100% rename from Ui/AVDC-ico.png rename to Img/AVDC-ico.png diff --git a/Img/AVDC.ico b/Img/AVDC.ico new file mode 100644 index 0000000000000000000000000000000000000000..6decf924c53e5eb46698207e89e1073ed0bd2391 GIT binary patch literal 1081406 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

I3jwk9j?( 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%0DOc&OR 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 Xi0r!9Fv_nVY4o&>ZWR4-FYLbnHQe}5 literal 0 HcmV?d00001 diff --git a/Img/UNCENSORED.png b/Img/UNCENSORED.png new file mode 100644 index 0000000000000000000000000000000000000000..094e4245e07d7e753579b6863bfea5e23966dce9 GIT binary patch literal 11067 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 QVyU#%^==gYeJ}X`0DMD87ytkO literal 0 HcmV?d00001 diff --git a/Ui/AVDC.py b/Ui/AVDC.py index 53377eb18..a59027f76 100644 --- a/Ui/AVDC.py +++ b/Ui/AVDC.py @@ -64,12 +64,12 @@ def setupUi(self, AVDV): self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setHorizontalSpacing(7) self.gridLayout.setObjectName("gridLayout") - self.label_fanart = QtWidgets.QLabel(self.gridLayoutWidget) - self.label_fanart.setEnabled(True) - self.label_fanart.setFrameShape(QtWidgets.QFrame.Box) - self.label_fanart.setAlignment(QtCore.Qt.AlignCenter) - self.label_fanart.setObjectName("label_fanart") - self.gridLayout.addWidget(self.label_fanart, 0, 0, 1, 1) + self.label_thumb = QtWidgets.QLabel(self.gridLayoutWidget) + self.label_thumb.setEnabled(True) + self.label_thumb.setFrameShape(QtWidgets.QFrame.Box) + self.label_thumb.setAlignment(QtCore.Qt.AlignCenter) + self.label_thumb.setObjectName("label_thumb") + self.gridLayout.addWidget(self.label_thumb, 0, 0, 1, 1) self.line = QtWidgets.QFrame(self.page_avdc) self.line.setGeometry(QtCore.QRect(0, 50, 791, 20)) self.line.setFrameShape(QtWidgets.QFrame.HLine) @@ -208,6 +208,7 @@ def setupUi(self, AVDV): self.comboBox_website.addItem("") self.comboBox_website.addItem("") self.comboBox_website.addItem("") + self.comboBox_website.addItem("") self.label_2 = QtWidgets.QLabel(self.groupBox_7) self.label_2.setGeometry(QtCore.QRect(230, 30, 72, 21)) self.label_2.setObjectName("label_2") @@ -245,9 +246,9 @@ def setupUi(self, AVDV): self.groupBox_13 = QtWidgets.QGroupBox(self.page_tool) self.groupBox_13.setGeometry(QtCore.QRect(10, 470, 751, 111)) self.groupBox_13.setObjectName("groupBox_13") - self.pushButton_select_fanart = QtWidgets.QPushButton(self.groupBox_13) - self.pushButton_select_fanart.setGeometry(QtCore.QRect(10, 20, 201, 71)) - self.pushButton_select_fanart.setObjectName("pushButton_select_fanart") + self.pushButton_select_thumb = QtWidgets.QPushButton(self.groupBox_13) + self.pushButton_select_thumb.setGeometry(QtCore.QRect(10, 20, 201, 71)) + self.pushButton_select_thumb.setObjectName("pushButton_select_thumb") self.label_6 = QtWidgets.QLabel(self.groupBox_13) self.label_6.setGeometry(QtCore.QRect(230, 20, 511, 71)) self.label_6.setObjectName("label_6") @@ -263,26 +264,8 @@ def setupUi(self, AVDV): self.tab = QtWidgets.QWidget() self.tab.setObjectName("tab") self.groupBox_10 = QtWidgets.QGroupBox(self.tab) - self.groupBox_10.setGeometry(QtCore.QRect(10, 10, 761, 421)) + self.groupBox_10.setGeometry(QtCore.QRect(10, 10, 761, 351)) self.groupBox_10.setObjectName("groupBox_10") - self.formLayoutWidget_3 = QtWidgets.QWidget(self.groupBox_10) - self.formLayoutWidget_3.setGeometry(QtCore.QRect(0, 350, 751, 61)) - self.formLayoutWidget_3.setObjectName("formLayoutWidget_3") - self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget_3) - self.formLayout.setContentsMargins(0, 0, 0, 0) - self.formLayout.setObjectName("formLayout") - self.label_38 = QtWidgets.QLabel(self.formLayoutWidget_3) - self.label_38.setObjectName("label_38") - self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_38) - self.lineEdit_escape_char = QtWidgets.QLineEdit(self.formLayoutWidget_3) - self.lineEdit_escape_char.setObjectName("lineEdit_escape_char") - self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lineEdit_escape_char) - self.label_39 = QtWidgets.QLabel(self.formLayoutWidget_3) - self.label_39.setObjectName("label_39") - self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_39) - self.lineEdit_escape_string = QtWidgets.QLineEdit(self.formLayoutWidget_3) - self.lineEdit_escape_string.setObjectName("lineEdit_escape_string") - self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEdit_escape_string) self.verticalLayoutWidget_2 = QtWidgets.QWidget(self.groupBox_10) self.verticalLayoutWidget_2.setGeometry(QtCore.QRect(10, 20, 741, 321)) self.verticalLayoutWidget_2.setObjectName("verticalLayoutWidget_2") @@ -291,74 +274,99 @@ def setupUi(self, AVDV): self.verticalLayout_3.setObjectName("verticalLayout_3") self.groupBox = QtWidgets.QGroupBox(self.verticalLayoutWidget_2) self.groupBox.setObjectName("groupBox") - self.radioButton_common = QtWidgets.QRadioButton(self.groupBox) - self.radioButton_common.setGeometry(QtCore.QRect(200, 10, 181, 19)) + self.horizontalLayoutWidget_7 = QtWidgets.QWidget(self.groupBox) + self.horizontalLayoutWidget_7.setGeometry(QtCore.QRect(140, 10, 591, 31)) + self.horizontalLayoutWidget_7.setObjectName("horizontalLayoutWidget_7") + self.horizontalLayout_9 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_7) + self.horizontalLayout_9.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_9.setObjectName("horizontalLayout_9") + self.radioButton_common = QtWidgets.QRadioButton(self.horizontalLayoutWidget_7) self.radioButton_common.setObjectName("radioButton_common") - self.radioButton_sort = QtWidgets.QRadioButton(self.groupBox) - self.radioButton_sort.setGeometry(QtCore.QRect(510, 10, 181, 19)) + self.horizontalLayout_9.addWidget(self.radioButton_common) + self.radioButton_sort = QtWidgets.QRadioButton(self.horizontalLayoutWidget_7) self.radioButton_sort.setObjectName("radioButton_sort") + self.horizontalLayout_9.addWidget(self.radioButton_sort) self.verticalLayout_3.addWidget(self.groupBox) self.groupBox_2 = QtWidgets.QGroupBox(self.verticalLayoutWidget_2) self.groupBox_2.setObjectName("groupBox_2") - self.radioButton_soft_on = QtWidgets.QRadioButton(self.groupBox_2) - self.radioButton_soft_on.setGeometry(QtCore.QRect(200, 10, 181, 19)) + self.horizontalLayoutWidget_8 = QtWidgets.QWidget(self.groupBox_2) + self.horizontalLayoutWidget_8.setGeometry(QtCore.QRect(140, 10, 591, 31)) + self.horizontalLayoutWidget_8.setObjectName("horizontalLayoutWidget_8") + self.horizontalLayout_10 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_8) + self.horizontalLayout_10.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_10.setObjectName("horizontalLayout_10") + self.radioButton_soft_on = QtWidgets.QRadioButton(self.horizontalLayoutWidget_8) self.radioButton_soft_on.setObjectName("radioButton_soft_on") - self.radioButton_soft_off = QtWidgets.QRadioButton(self.groupBox_2) - self.radioButton_soft_off.setGeometry(QtCore.QRect(510, 10, 181, 19)) + self.horizontalLayout_10.addWidget(self.radioButton_soft_on) + self.radioButton_soft_off = QtWidgets.QRadioButton(self.horizontalLayoutWidget_8) self.radioButton_soft_off.setObjectName("radioButton_soft_off") + self.horizontalLayout_10.addWidget(self.radioButton_soft_off) self.verticalLayout_3.addWidget(self.groupBox_2) self.groupBox_3 = QtWidgets.QGroupBox(self.verticalLayoutWidget_2) self.groupBox_3.setObjectName("groupBox_3") - self.radioButton_debug_on = QtWidgets.QRadioButton(self.groupBox_3) - self.radioButton_debug_on.setGeometry(QtCore.QRect(200, 10, 181, 19)) + self.horizontalLayoutWidget_9 = QtWidgets.QWidget(self.groupBox_3) + self.horizontalLayoutWidget_9.setGeometry(QtCore.QRect(140, 10, 591, 31)) + self.horizontalLayoutWidget_9.setObjectName("horizontalLayoutWidget_9") + self.horizontalLayout_11 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_9) + self.horizontalLayout_11.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_11.setObjectName("horizontalLayout_11") + self.radioButton_debug_on = QtWidgets.QRadioButton(self.horizontalLayoutWidget_9) self.radioButton_debug_on.setObjectName("radioButton_debug_on") - self.radioButton_debug_off = QtWidgets.QRadioButton(self.groupBox_3) - self.radioButton_debug_off.setGeometry(QtCore.QRect(510, 10, 181, 19)) + self.horizontalLayout_11.addWidget(self.radioButton_debug_on) + self.radioButton_debug_off = QtWidgets.QRadioButton(self.horizontalLayoutWidget_9) self.radioButton_debug_off.setObjectName("radioButton_debug_off") + self.horizontalLayout_11.addWidget(self.radioButton_debug_off) self.verticalLayout_3.addWidget(self.groupBox_3) self.groupBox_4 = QtWidgets.QGroupBox(self.verticalLayoutWidget_2) self.groupBox_4.setObjectName("groupBox_4") - self.radioButton_update_on = QtWidgets.QRadioButton(self.groupBox_4) - self.radioButton_update_on.setGeometry(QtCore.QRect(200, 10, 181, 19)) + self.horizontalLayoutWidget_10 = QtWidgets.QWidget(self.groupBox_4) + self.horizontalLayoutWidget_10.setGeometry(QtCore.QRect(140, 10, 591, 31)) + self.horizontalLayoutWidget_10.setObjectName("horizontalLayoutWidget_10") + self.horizontalLayout_12 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_10) + self.horizontalLayout_12.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_12.setObjectName("horizontalLayout_12") + self.radioButton_update_on = QtWidgets.QRadioButton(self.horizontalLayoutWidget_10) self.radioButton_update_on.setObjectName("radioButton_update_on") - self.radioButton_update_off = QtWidgets.QRadioButton(self.groupBox_4) - self.radioButton_update_off.setGeometry(QtCore.QRect(510, 10, 181, 19)) + self.horizontalLayout_12.addWidget(self.radioButton_update_on) + self.radioButton_update_off = QtWidgets.QRadioButton(self.horizontalLayoutWidget_10) self.radioButton_update_off.setObjectName("radioButton_update_off") + self.horizontalLayout_12.addWidget(self.radioButton_update_off) self.verticalLayout_3.addWidget(self.groupBox_4) self.groupBox_17 = QtWidgets.QGroupBox(self.verticalLayoutWidget_2) self.groupBox_17.setObjectName("groupBox_17") - self.radioButton_log_on = QtWidgets.QRadioButton(self.groupBox_17) - self.radioButton_log_on.setGeometry(QtCore.QRect(200, 10, 181, 19)) + self.horizontalLayoutWidget_11 = QtWidgets.QWidget(self.groupBox_17) + self.horizontalLayoutWidget_11.setGeometry(QtCore.QRect(140, 10, 591, 31)) + self.horizontalLayoutWidget_11.setObjectName("horizontalLayoutWidget_11") + self.horizontalLayout_13 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_11) + self.horizontalLayout_13.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_13.setObjectName("horizontalLayout_13") + self.radioButton_log_on = QtWidgets.QRadioButton(self.horizontalLayoutWidget_11) self.radioButton_log_on.setObjectName("radioButton_log_on") - self.radioButton_log_off = QtWidgets.QRadioButton(self.groupBox_17) - self.radioButton_log_off.setGeometry(QtCore.QRect(510, 10, 81, 19)) + self.horizontalLayout_13.addWidget(self.radioButton_log_on) + self.radioButton_log_off = QtWidgets.QRadioButton(self.horizontalLayoutWidget_11) self.radioButton_log_off.setObjectName("radioButton_log_off") + self.horizontalLayout_13.addWidget(self.radioButton_log_off) self.verticalLayout_3.addWidget(self.groupBox_17) self.groupBox_15 = QtWidgets.QGroupBox(self.verticalLayoutWidget_2) self.groupBox_15.setObjectName("groupBox_15") - self.radioButton_fail_move_on = QtWidgets.QRadioButton(self.groupBox_15) - self.radioButton_fail_move_on.setGeometry(QtCore.QRect(200, 10, 181, 19)) + self.horizontalLayoutWidget_12 = QtWidgets.QWidget(self.groupBox_15) + self.horizontalLayoutWidget_12.setGeometry(QtCore.QRect(140, 10, 591, 31)) + self.horizontalLayoutWidget_12.setObjectName("horizontalLayoutWidget_12") + self.horizontalLayout_14 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_12) + self.horizontalLayout_14.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_14.setObjectName("horizontalLayout_14") + self.radioButton_fail_move_on = QtWidgets.QRadioButton(self.horizontalLayoutWidget_12) self.radioButton_fail_move_on.setObjectName("radioButton_fail_move_on") - self.radioButton_fail_move_off = QtWidgets.QRadioButton(self.groupBox_15) - self.radioButton_fail_move_off.setGeometry(QtCore.QRect(510, 10, 81, 19)) + self.horizontalLayout_14.addWidget(self.radioButton_fail_move_on) + self.radioButton_fail_move_off = QtWidgets.QRadioButton(self.horizontalLayoutWidget_12) self.radioButton_fail_move_off.setObjectName("radioButton_fail_move_off") + self.horizontalLayout_14.addWidget(self.radioButton_fail_move_off) self.verticalLayout_3.addWidget(self.groupBox_15) - self.groupBox_5 = QtWidgets.QGroupBox(self.verticalLayoutWidget_2) - self.groupBox_5.setObjectName("groupBox_5") - self.radioButton_emby = QtWidgets.QRadioButton(self.groupBox_5) - self.radioButton_emby.setGeometry(QtCore.QRect(200, 10, 181, 19)) - self.radioButton_emby.setObjectName("radioButton_emby") - self.radioButton_plex = QtWidgets.QRadioButton(self.groupBox_5) - self.radioButton_plex.setGeometry(QtCore.QRect(450, 10, 81, 19)) - self.radioButton_plex.setObjectName("radioButton_plex") - self.radioButton_kodi = QtWidgets.QRadioButton(self.groupBox_5) - self.radioButton_kodi.setGeometry(QtCore.QRect(630, 10, 81, 19)) - self.radioButton_kodi.setObjectName("radioButton_kodi") - self.verticalLayout_3.addWidget(self.groupBox_5) - self.groupBox_11 = QtWidgets.QGroupBox(self.verticalLayoutWidget_2) + self.groupBox_11 = QtWidgets.QGroupBox(self.tab) + self.groupBox_11.setGeometry(QtCore.QRect(10, 370, 761, 61)) self.groupBox_11.setObjectName("groupBox_11") self.comboBox_website_all = QtWidgets.QComboBox(self.groupBox_11) - self.comboBox_website_all.setGeometry(QtCore.QRect(200, 10, 481, 21)) + self.comboBox_website_all.setGeometry(QtCore.QRect(150, 20, 591, 21)) self.comboBox_website_all.setObjectName("comboBox_website_all") self.comboBox_website_all.addItem("") self.comboBox_website_all.addItem("") @@ -367,7 +375,7 @@ def setupUi(self, AVDV): self.comboBox_website_all.addItem("") self.comboBox_website_all.addItem("") self.comboBox_website_all.addItem("") - self.verticalLayout_3.addWidget(self.groupBox_11) + self.comboBox_website_all.addItem("") self.tabWidget.addTab(self.tab, "") self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName("tab_2") @@ -413,12 +421,18 @@ def setupUi(self, AVDV): self.lineEdit_movie_path = QtWidgets.QLineEdit(self.formLayoutWidget_5) self.lineEdit_movie_path.setObjectName("lineEdit_movie_path") self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lineEdit_movie_path) - self.label_48 = QtWidgets.QLabel(self.formLayoutWidget_5) - self.label_48.setObjectName("label_48") - self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_48) - self.lineEdit_escape_dir = QtWidgets.QLineEdit(self.formLayoutWidget_5) - self.lineEdit_escape_dir.setObjectName("lineEdit_escape_dir") - self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.lineEdit_escape_dir) + self.label_40 = QtWidgets.QLabel(self.formLayoutWidget_5) + self.label_40.setObjectName("label_40") + self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_40) + self.lineEdit_movie_type = QtWidgets.QLineEdit(self.formLayoutWidget_5) + self.lineEdit_movie_type.setObjectName("lineEdit_movie_type") + self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lineEdit_movie_type) + self.label_42 = QtWidgets.QLabel(self.formLayoutWidget_5) + self.label_42.setObjectName("label_42") + self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_42) + self.lineEdit_sub_type = QtWidgets.QLineEdit(self.formLayoutWidget_5) + self.lineEdit_sub_type.setObjectName("lineEdit_sub_type") + self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.lineEdit_sub_type) self.label_46 = QtWidgets.QLabel(self.formLayoutWidget_5) self.label_46.setObjectName("label_46") self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_46) @@ -432,22 +446,112 @@ def setupUi(self, AVDV): self.lineEdit_success = QtWidgets.QLineEdit(self.formLayoutWidget_5) self.lineEdit_success.setObjectName("lineEdit_success") self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.lineEdit_success) - self.label_40 = QtWidgets.QLabel(self.formLayoutWidget_5) - self.label_40.setObjectName("label_40") - self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_40) - self.lineEdit_movie_type = QtWidgets.QLineEdit(self.formLayoutWidget_5) - self.lineEdit_movie_type.setObjectName("lineEdit_movie_type") - self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEdit_movie_type) - self.label_42 = QtWidgets.QLabel(self.formLayoutWidget_5) - self.label_42.setObjectName("label_42") - self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_42) - self.lineEdit_sub_type = QtWidgets.QLineEdit(self.formLayoutWidget_5) - self.lineEdit_sub_type.setObjectName("lineEdit_sub_type") - self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lineEdit_sub_type) + self.label_48 = QtWidgets.QLabel(self.formLayoutWidget_5) + self.label_48.setObjectName("label_48") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_48) + self.lineEdit_escape_dir = QtWidgets.QLineEdit(self.formLayoutWidget_5) + self.lineEdit_escape_dir.setObjectName("lineEdit_escape_dir") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEdit_escape_dir) self.label_7 = QtWidgets.QLabel(self.groupBox_16) self.label_7.setGeometry(QtCore.QRect(10, 210, 731, 61)) self.label_7.setObjectName("label_7") self.tabWidget.addTab(self.tab_2, "") + self.tab_4 = QtWidgets.QWidget() + self.tab_4.setObjectName("tab_4") + self.groupBox_14 = QtWidgets.QGroupBox(self.tab_4) + self.groupBox_14.setGeometry(QtCore.QRect(10, 150, 761, 71)) + self.groupBox_14.setObjectName("groupBox_14") + self.horizontalLayoutWidget_3 = QtWidgets.QWidget(self.groupBox_14) + self.horizontalLayoutWidget_3.setGeometry(QtCore.QRect(150, 30, 601, 31)) + self.horizontalLayoutWidget_3.setObjectName("horizontalLayoutWidget_3") + self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_3) + self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.checkBox_sub = QtWidgets.QCheckBox(self.horizontalLayoutWidget_3) + self.checkBox_sub.setObjectName("checkBox_sub") + self.horizontalLayout_5.addWidget(self.checkBox_sub) + self.checkBox_leak = QtWidgets.QCheckBox(self.horizontalLayoutWidget_3) + self.checkBox_leak.setObjectName("checkBox_leak") + self.horizontalLayout_5.addWidget(self.checkBox_leak) + self.checkBox_uncensored = QtWidgets.QCheckBox(self.horizontalLayoutWidget_3) + self.checkBox_uncensored.setObjectName("checkBox_uncensored") + self.horizontalLayout_5.addWidget(self.checkBox_uncensored) + self.groupBox_19 = QtWidgets.QGroupBox(self.tab_4) + self.groupBox_19.setGeometry(QtCore.QRect(10, 240, 761, 71)) + self.groupBox_19.setObjectName("groupBox_19") + self.horizontalLayoutWidget_2 = QtWidgets.QWidget(self.groupBox_19) + self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(150, 30, 601, 31)) + self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2") + self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_2) + self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.radioButton_top_left = QtWidgets.QRadioButton(self.horizontalLayoutWidget_2) + self.radioButton_top_left.setObjectName("radioButton_top_left") + self.horizontalLayout_4.addWidget(self.radioButton_top_left) + self.radioButton_bottom_left = QtWidgets.QRadioButton(self.horizontalLayoutWidget_2) + self.radioButton_bottom_left.setObjectName("radioButton_bottom_left") + self.horizontalLayout_4.addWidget(self.radioButton_bottom_left) + self.radioButton_top_right = QtWidgets.QRadioButton(self.horizontalLayoutWidget_2) + self.radioButton_top_right.setObjectName("radioButton_top_right") + self.horizontalLayout_4.addWidget(self.radioButton_top_right) + self.radioButton_bottom_right = QtWidgets.QRadioButton(self.horizontalLayoutWidget_2) + self.radioButton_bottom_right.setObjectName("radioButton_bottom_right") + self.horizontalLayout_4.addWidget(self.radioButton_bottom_right) + self.groupBox_21 = QtWidgets.QGroupBox(self.tab_4) + self.groupBox_21.setGeometry(QtCore.QRect(10, 330, 761, 81)) + self.groupBox_21.setObjectName("groupBox_21") + self.horizontalLayoutWidget_4 = QtWidgets.QWidget(self.groupBox_21) + self.horizontalLayoutWidget_4.setGeometry(QtCore.QRect(40, 30, 711, 41)) + self.horizontalLayoutWidget_4.setObjectName("horizontalLayoutWidget_4") + self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_4) + self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.horizontalSlider_mark_size = QtWidgets.QSlider(self.horizontalLayoutWidget_4) + self.horizontalSlider_mark_size.setMinimum(1) + self.horizontalSlider_mark_size.setMaximum(5) + self.horizontalSlider_mark_size.setPageStep(1) + self.horizontalSlider_mark_size.setProperty("value", 3) + self.horizontalSlider_mark_size.setOrientation(QtCore.Qt.Horizontal) + self.horizontalSlider_mark_size.setObjectName("horizontalSlider_mark_size") + self.horizontalLayout_6.addWidget(self.horizontalSlider_mark_size) + self.lcdNumber_mark_size = QtWidgets.QLCDNumber(self.horizontalLayoutWidget_4) + self.lcdNumber_mark_size.setProperty("intValue", 3) + self.lcdNumber_mark_size.setObjectName("lcdNumber_mark_size") + self.horizontalLayout_6.addWidget(self.lcdNumber_mark_size) + self.groupBox_20 = QtWidgets.QGroupBox(self.tab_4) + self.groupBox_20.setGeometry(QtCore.QRect(10, 10, 761, 51)) + self.groupBox_20.setObjectName("groupBox_20") + self.horizontalLayoutWidget_5 = QtWidgets.QWidget(self.groupBox_20) + self.horizontalLayoutWidget_5.setGeometry(QtCore.QRect(150, 20, 601, 31)) + self.horizontalLayoutWidget_5.setObjectName("horizontalLayoutWidget_5") + self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_5) + self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_7.setObjectName("horizontalLayout_7") + self.radioButton_poster_mark_on = QtWidgets.QRadioButton(self.horizontalLayoutWidget_5) + self.radioButton_poster_mark_on.setObjectName("radioButton_poster_mark_on") + self.horizontalLayout_7.addWidget(self.radioButton_poster_mark_on) + self.radioButton_poster_mark_off = QtWidgets.QRadioButton(self.horizontalLayoutWidget_5) + self.radioButton_poster_mark_off.setObjectName("radioButton_poster_mark_off") + self.horizontalLayout_7.addWidget(self.radioButton_poster_mark_off) + self.label_9 = QtWidgets.QLabel(self.tab_4) + self.label_9.setGeometry(QtCore.QRect(20, 430, 701, 61)) + self.label_9.setObjectName("label_9") + self.groupBox_22 = QtWidgets.QGroupBox(self.tab_4) + self.groupBox_22.setGeometry(QtCore.QRect(10, 80, 761, 51)) + self.groupBox_22.setObjectName("groupBox_22") + self.horizontalLayoutWidget_6 = QtWidgets.QWidget(self.groupBox_22) + self.horizontalLayoutWidget_6.setGeometry(QtCore.QRect(150, 20, 601, 31)) + self.horizontalLayoutWidget_6.setObjectName("horizontalLayoutWidget_6") + self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_6) + self.horizontalLayout_8.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_8.setObjectName("horizontalLayout_8") + self.radioButton_thumb_mark_on = QtWidgets.QRadioButton(self.horizontalLayoutWidget_6) + self.radioButton_thumb_mark_on.setObjectName("radioButton_thumb_mark_on") + self.horizontalLayout_8.addWidget(self.radioButton_thumb_mark_on) + self.radioButton_thumb_mark_off = QtWidgets.QRadioButton(self.horizontalLayoutWidget_6) + self.radioButton_thumb_mark_off.setObjectName("radioButton_thumb_mark_off") + self.horizontalLayout_8.addWidget(self.radioButton_thumb_mark_off) + self.tabWidget.addTab(self.tab_4, "") self.tab_3 = QtWidgets.QWidget() self.tab_3.setObjectName("tab_3") self.groupBox_9 = QtWidgets.QGroupBox(self.tab_3) @@ -501,7 +605,67 @@ def setupUi(self, AVDV): self.lcdNumber_retry.setObjectName("lcdNumber_retry") self.horizontalLayout_retry.addWidget(self.lcdNumber_retry) self.formLayout_4.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout_retry) + self.groupBox_39 = QtWidgets.QGroupBox(self.tab_3) + self.groupBox_39.setGeometry(QtCore.QRect(10, 250, 761, 121)) + self.groupBox_39.setObjectName("groupBox_39") + self.label_14 = QtWidgets.QLabel(self.groupBox_39) + self.label_14.setGeometry(QtCore.QRect(70, 60, 681, 61)) + self.label_14.setObjectName("label_14") + self.horizontalLayoutWidget_24 = QtWidgets.QWidget(self.groupBox_39) + self.horizontalLayoutWidget_24.setGeometry(QtCore.QRect(200, 20, 551, 31)) + self.horizontalLayoutWidget_24.setObjectName("horizontalLayoutWidget_24") + self.horizontalLayout_27 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_24) + self.horizontalLayout_27.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_27.setObjectName("horizontalLayout_27") + self.radioButton_poster_official = QtWidgets.QRadioButton(self.horizontalLayoutWidget_24) + self.radioButton_poster_official.setObjectName("radioButton_poster_official") + self.horizontalLayout_27.addWidget(self.radioButton_poster_official) + self.radioButton_poster_cut = QtWidgets.QRadioButton(self.horizontalLayoutWidget_24) + self.radioButton_poster_cut.setObjectName("radioButton_poster_cut") + self.horizontalLayout_27.addWidget(self.radioButton_poster_cut) + self.groupBox_40 = QtWidgets.QGroupBox(self.tab_3) + self.groupBox_40.setGeometry(QtCore.QRect(10, 380, 761, 111)) + self.groupBox_40.setObjectName("groupBox_40") + self.formLayoutWidget = QtWidgets.QWidget(self.groupBox_40) + self.formLayoutWidget.setGeometry(QtCore.QRect(0, 30, 751, 31)) + self.formLayoutWidget.setObjectName("formLayoutWidget") + self.formLayout_9 = QtWidgets.QFormLayout(self.formLayoutWidget) + self.formLayout_9.setContentsMargins(0, 0, 0, 0) + self.formLayout_9.setObjectName("formLayout_9") + self.label_16 = QtWidgets.QLabel(self.formLayoutWidget) + self.label_16.setObjectName("label_16") + self.formLayout_9.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_16) + self.lineEdit_uncensored_prefix = QtWidgets.QLineEdit(self.formLayoutWidget) + self.lineEdit_uncensored_prefix.setObjectName("lineEdit_uncensored_prefix") + self.formLayout_9.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lineEdit_uncensored_prefix) + self.label_17 = QtWidgets.QLabel(self.groupBox_40) + self.label_17.setGeometry(QtCore.QRect(70, 70, 671, 31)) + self.label_17.setObjectName("label_17") + self.groupBox_18 = QtWidgets.QGroupBox(self.tab_3) + self.groupBox_18.setGeometry(QtCore.QRect(10, 140, 761, 101)) + self.groupBox_18.setObjectName("groupBox_18") + self.formLayoutWidget_3 = QtWidgets.QWidget(self.groupBox_18) + self.formLayoutWidget_3.setGeometry(QtCore.QRect(0, 30, 751, 61)) + self.formLayoutWidget_3.setObjectName("formLayoutWidget_3") + self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget_3) + self.formLayout.setContentsMargins(0, 0, 0, 0) + self.formLayout.setObjectName("formLayout") + self.label_38 = QtWidgets.QLabel(self.formLayoutWidget_3) + self.label_38.setObjectName("label_38") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_38) + self.lineEdit_escape_char = QtWidgets.QLineEdit(self.formLayoutWidget_3) + self.lineEdit_escape_char.setObjectName("lineEdit_escape_char") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lineEdit_escape_char) + self.label_39 = QtWidgets.QLabel(self.formLayoutWidget_3) + self.label_39.setObjectName("label_39") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_39) + self.lineEdit_escape_string = QtWidgets.QLineEdit(self.formLayoutWidget_3) + self.lineEdit_escape_string.setObjectName("lineEdit_escape_string") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEdit_escape_string) self.tabWidget.addTab(self.tab_3, "") + self.pushButton_init_config = QtWidgets.QPushButton(self.page_setting) + self.pushButton_init_config.setGeometry(QtCore.QRect(0, 680, 71, 28)) + self.pushButton_init_config.setObjectName("pushButton_init_config") self.stackedWidget.addWidget(self.page_setting) self.page_about = QtWidgets.QWidget() self.page_about.setObjectName("page_about") @@ -570,7 +734,7 @@ def setupUi(self, AVDV): def retranslateUi(self, AVDV): _translate = QtCore.QCoreApplication.translate - AVDV.setWindowTitle(_translate("AVDV", "AVDC-3.92")) + AVDV.setWindowTitle(_translate("AVDV", "AVDC-3.93")) self.pushButton_start_cap.setText(_translate("AVDV", "开始")) self.textBrowser_warning.setHtml(_translate("AVDV", "\n" "