├── .github └── FUNDING.yml ├── Bl ├── App.py ├── Play.py ├── Search.py ├── Update.py └── __init__.py ├── Da ├── AppBase.py ├── Aria2.py ├── BdApi.py ├── Config.py ├── ResGdyy.py ├── ResVhao.py ├── ResZmz.py ├── Updater.py └── __init__.py ├── LICENSE ├── Lib ├── Tools.py ├── Update.py └── __init__.py ├── README.md ├── Resources ├── biticon.ico ├── chromedriver ├── chromedriver.exe ├── icon.icns ├── icon.ico └── logo.png ├── View ├── AppInfoView.py ├── ConfigView.py ├── MainView.py ├── MenuBarView.py ├── PlayerView.py ├── ResultView.py ├── UpdateInfoView.py └── __init__.py ├── packmac.spec └── packwin.spec /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: evilcult 4 | custom: 'https://evilcult.dev/donation/' 5 | -------------------------------------------------------------------------------- /Bl/App.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import sys 4 | import time 5 | import tkinter 6 | 7 | sys.path.append("..") 8 | from View import MainView 9 | from Bl import Update 10 | 11 | class App : 12 | 13 | def __init__ (self) : 14 | self.Update = Update.Update() 15 | 16 | def run (self) : 17 | mainWindow = MainView.GUI() 18 | self.Update.chkUpdate() 19 | mainWindow.run() 20 | 21 | App = App() 22 | App.run() -------------------------------------------------------------------------------- /Bl/Play.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import threading 4 | import webbrowser 5 | import tkinter.messagebox 6 | import time 7 | 8 | from Da import BdApi 9 | from Da import Config 10 | from View import PlayerView 11 | 12 | class Play : 13 | 14 | def __init__ (self, master) : 15 | self.master = master 16 | self.bdAuth = {} 17 | self.Cfg = Config.Config() 18 | 19 | cfgInfo = self.Cfg.get() 20 | 21 | self.BD = BdApi.BdApi() 22 | 23 | if cfgInfo['bdc'] == '' : 24 | self.BDLogin = False 25 | else : 26 | self.BDLogin = True 27 | 28 | self.Player = PlayerView.GUI(self.master) 29 | 30 | def watchLink (self, target) : 31 | self.Player.watchLinkStat = {'err': 0, 'msg': ''} 32 | if self.BDLogin : 33 | self.downloadUrl = target[1] 34 | 35 | self.Player.showWatchLink() 36 | linkType = self.downloadUrl[0:6] 37 | if linkType != 'magnet' : 38 | threading.Thread(target = self.__bdPlay).start() 39 | else : 40 | self.Player.watchLinkStat['err'] = 2 41 | else : 42 | tkinter.messagebox.showinfo('Error', '本功能需要云支持,请于菜单栏「Edit -> Baidu Login」登录百度云。') 43 | 44 | def dlLink (self, target) : 45 | self.Player.downLinkStat = {'err': 0, 'msg': ''} 46 | if self.BDLogin : 47 | self.downloadUrl = target[1] 48 | self.dlFileName = target[0] 49 | 50 | self.Player.showCloudLink() 51 | linkType = self.downloadUrl[0:6] 52 | if linkType != 'magnet' : 53 | threading.Thread(target = self.__bdDownload).start() 54 | else : 55 | self.Player.downLinkStat['err'] = 2 56 | else : 57 | tkinter.messagebox.showinfo('Error', '本功能需要云支持,请于菜单栏「Edit -> Baidu Login」登录百度云。') 58 | 59 | def showLink (self, target) : 60 | self.downloadUrl = target[1] 61 | self.Player.showDlLink(self.downloadUrl) 62 | 63 | def __bdlogin (self) : 64 | self.Player.showLoginWindow(self.BD.saveLogin) 65 | 66 | def __bdPlay (self) : 67 | result = self.BD.addTask(self.downloadUrl, self.bdAuth) 68 | if result['err'] == 0 : 69 | taskID = result['taskID'] 70 | playUrl = self.BD.getPlayUrl(taskID) 71 | if playUrl != '' : 72 | self.Player.watchLinkStat['msg'] = playUrl 73 | else : 74 | self.Player.watchLinkStat['err'] = 1 75 | else : 76 | self.bdAuth = { 77 | 'vcode': result['vcode'], 78 | 'input': '' 79 | } 80 | self.Player.watchLinkStat['err'] = 3 81 | self.Player.watchLinkStat['msg'] = result['img'] 82 | self.Player.authDownload = lambda authKey = '' : self.__authPlay(authKey) 83 | 84 | def __bdDownload (self) : 85 | result = self.BD.addTask(self.downloadUrl, self.bdAuth) 86 | if result['err'] == 0 : 87 | taskID = result['taskID'] 88 | dlUrl = self.BD.getDlUrl(taskID) 89 | if dlUrl != '' : 90 | self.Player.downLinkStat['msg'] = dlUrl 91 | else : 92 | self.Player.downLinkStat['err'] = 1 93 | else : 94 | self.bdAuth = { 95 | 'vcode': result['vcode'], 96 | 'input': '' 97 | } 98 | self.Player.downLinkStat['err'] = 3 99 | self.Player.downLinkStat['msg'] = result['img'] 100 | self.Player.authDownload = lambda authKey = '' : self.__authDownload(authKey) 101 | 102 | def __authCode (self, imgUrl, authType) : 103 | authKey = '' 104 | 105 | if authType == 'play': 106 | self.Player.authDownload = lambda authKey = authKey : self.__authPlay(authKey) 107 | else : 108 | self.Player.authDownload = lambda authKey = authKey : self.__authDownload(authKey) 109 | 110 | self.Player.showAuthCode(imgUrl) 111 | 112 | def __authPlay (self, authKey) : 113 | self.Player.watchLinkStat = {'err': 0, 'msg': ''} 114 | self.bdAuth['input'] = authKey 115 | self.Player.showWatchLink() 116 | threading.Thread(target = self.__bdPlay).start() 117 | 118 | def __authDownload (self, authKey) : 119 | self.Player.downLinkStat = {'err': 0, 'msg': ''} 120 | self.bdAuth['input'] = authKey 121 | self.Player.showCloudLink() 122 | threading.Thread(target = self.__bdDownload).start() -------------------------------------------------------------------------------- /Bl/Search.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import threading 4 | import webbrowser 5 | from Da import ResZmz 6 | from Da import ResVhao 7 | from View import ResultView 8 | import urllib.request, urllib.parse, urllib.error 9 | 10 | class Search : 11 | 12 | def __init__ (self, master) : 13 | self.master = master 14 | self.ResWindow = ResultView.GUI(self.master) 15 | 16 | def showResult (self, key) : 17 | searchKey = key.get() 18 | 19 | self.ResWindow.showList(searchKey) 20 | self.ResWindow.listRst = '' 21 | data = '' 22 | 23 | self.ResWindow.getDetail = lambda data = data : self.__searchMovDetails(data) 24 | 25 | threading.Thread(target = lambda key = searchKey : self.__searchMov(key)).start() 26 | 27 | self.ResWindow.updateList() 28 | 29 | def __searchMov (self, key) : 30 | # 开启两重匹配找寻 31 | self.mainSearcher = ResZmz.Searcher() 32 | self.subSearcher = ResVhao.Searcher() 33 | mainResult = self.mainSearcher.find(key) 34 | subResult = self.subSearcher.find(key) 35 | 36 | mainResult.append({'title':'\n--------以下为低质量资源:--------\n','url':''}) 37 | mainResult.extend(subResult) 38 | 39 | self.ResWindow.listRst = mainResult 40 | 41 | def __searchMovDetails (self, data): 42 | self.ResWindow.resRst = '' 43 | self.ResWindow.showRes() 44 | 45 | # 开启多线程 46 | threading.Thread(target = lambda data = data : self.__getDetails(data)).start() 47 | 48 | self.ResWindow.updateRes() 49 | 50 | def __getDetails (self, data) : 51 | if data['url'] != '' : 52 | if data['source'] == 'zmz' : 53 | result = self.mainSearcher.getLink(data['url']) 54 | else : 55 | result = self.subSearcher.getLink(data['url']) 56 | 57 | self.ResWindow.resRst = result -------------------------------------------------------------------------------- /Bl/Update.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import threading 4 | import time 5 | 6 | from Da import AppBase 7 | from Da import Config 8 | from Da import Updater 9 | from View import UpdateInfoView 10 | 11 | class Update : 12 | 13 | def __init__ (self) : 14 | self.app = AppBase.info 15 | self.Updater = Updater.Updater() 16 | self.Cfg = Config.Config() 17 | self.UdView = UpdateInfoView.GUI() 18 | 19 | def chkUpdate (self, force = False) : 20 | cfgInfo = self.Cfg.get() 21 | now = int(time.time()) 22 | 23 | if force == False : 24 | if cfgInfo['udrate'] == 1: 25 | updateTime = int(cfgInfo['udtime']) + 86400 26 | elif cfgInfo['udrate'] == 2: 27 | updateTime = int(cfgInfo['udtime']) + 86400 * 7 28 | elif cfgInfo['udrate'] == 3: 29 | updateTime = int(cfgInfo['udtime']) + 86400 * 30 30 | else : 31 | updateTime = int(cfgInfo['udtime']) + 86400 * 7 32 | else : 33 | updateTime = 0 34 | 35 | if updateTime < now : 36 | self.UdView.show() 37 | threading.Thread(target = self.__check).start() 38 | self.UdView.updateInfo() 39 | 40 | def __check (self) : 41 | now = int(time.time()) 42 | 43 | info = self.Updater.check(self.app['build']) 44 | self.Cfg.save({'udtime': now}) 45 | self.UdView.udInfo = info 46 | -------------------------------------------------------------------------------- /Bl/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilCult/moviecatcher/6e6b1476e43fbaa7f13a16535e11133d8cc4f980/Bl/__init__.py -------------------------------------------------------------------------------- /Da/AppBase.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | info = { 5 | 'title' : 'Movie Catcher', 6 | 'ver' : 'Beta 0.9.7', 7 | 'build' : '29c6c' 8 | } 9 | -------------------------------------------------------------------------------- /Da/Aria2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import os 5 | import webbrowser 6 | 7 | from Lib import Tools 8 | from . import Config 9 | 10 | class Aria2 : 11 | 12 | def __init__ (self) : 13 | self.Tools = Tools.Tools() 14 | self.Cfg = Config.Config() 15 | 16 | cfgInfo = self.Cfg.get() 17 | 18 | self.ariaHost = cfgInfo['ariarpc'] 19 | self.ariaGuiPath = cfgInfo['ariapath'] 20 | 21 | def chkAria (self) : 22 | try : 23 | os.system('open -a "' + str(self.ariaGuiPath) + '"') 24 | except Exception as e: 25 | self.ariaGuiPath = '' 26 | 27 | param = { 28 | "jsonrpc": "2.0", 29 | "method": "aria2.getGlobalStat", 30 | "id": 1, 31 | "params": [], 32 | } 33 | ariaRpc = json.JSONEncoder().encode([param]) 34 | 35 | try: 36 | ariaStat = self.Tools.getPage(self.ariaHost, [], ariaRpc) 37 | return ariaStat['code'] == 200 38 | except Exception as e: 39 | return False 40 | 41 | def download (self, fileUrl, fileName) : 42 | rpc = self.__getRpc(fileUrl, fileName) 43 | dlStat = self.Tools.getPage(self.ariaHost, [], rpc) 44 | 45 | if self.ariaGuiPat != '': 46 | os.system('open -a "' + str(self.ariaGuiPath) + '"') 47 | else : 48 | webbrowser.open_new('http://aria2c.com/') 49 | 50 | def __getRpc (self, fileUrl, fileName) : 51 | link = [fileUrl] 52 | conf = { 53 | "out": fileName, 54 | "split": "20", 55 | "max-connection-per-server": "20", 56 | "seed-ratio": "0" 57 | } 58 | 59 | dlTemplate = { 60 | "jsonrpc": "2.0", 61 | "method": "aria2.addUri", 62 | "id": 1, 63 | "params": [link, conf], 64 | } 65 | 66 | ariaRpc = json.JSONEncoder().encode([dlTemplate]) 67 | 68 | return ariaRpc 69 | -------------------------------------------------------------------------------- /Da/BdApi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import re 5 | import urllib.request, urllib.parse, urllib.error 6 | import base64 7 | import time 8 | 9 | from Lib import Tools 10 | from . import Config 11 | 12 | class BdApi : 13 | 14 | def __init__ (self) : 15 | self.Tools = Tools.Tools() 16 | self.Cfg = Config.Config() 17 | 18 | cfgInfo = self.Cfg.get() 19 | self.bdInfo = { 20 | 'saveDir': cfgInfo['path'], 21 | 'cookie': 'Cookie:' + cfgInfo['bdc'] 22 | } 23 | 24 | if cfgInfo['bdc'] != '' : 25 | self.__getBdInfo() 26 | 27 | def saveLogin (self, cookieStr = '') : 28 | data = {'bdc': cookieStr} 29 | self.Cfg.save(data) 30 | 31 | def getBtInfo (self, url, auth = {}) : 32 | bdApi = 'https://pan.baidu.com/rest/2.0/services/cloud_dl?channel=chunlei&web=1&app_id=250528&bdstoken={}&clienttype=0'.format(self.bdInfo['token']) 33 | 34 | postData = { 35 | 'method' : 'query_magnetinfo', 36 | 'app_id' : '250528', 37 | 'source_url' : url, 38 | 'save_path' : '/' + self.bdInfo['saveDir'] + '/', 39 | 'type' : '4' 40 | } 41 | 42 | if auth != {} : 43 | postData['input'] = auth['input'] 44 | postData['vcode'] = auth['vcode'] 45 | 46 | html = self.Tools.getPage(bdApi, self.requestHeader, postData) 47 | if html['code'] == 200 : 48 | body = html['body'] 49 | info = json.JSONDecoder().decode(body) 50 | 51 | idx = 1 52 | for x in info: 53 | fileName = x['file_name'].split('/') 54 | fileName.pop(0) 55 | fileName = '/'.join(fileName) 56 | # some code... 57 | idx += 1 58 | 59 | result = { 60 | 'err': 0, 61 | 'btInfo': info['magnet_info'] 62 | } 63 | else : 64 | body = html['body'] 65 | info = json.JSONDecoder().decode(body) 66 | 67 | result = { 68 | 'err': 1, 69 | 'vcode': info['vcode'], 70 | 'img': info['img'] 71 | } 72 | 73 | return result 74 | 75 | def addTask (self, url, auth = {}, btIdx = 0) : 76 | bdApi = 'https://pan.baidu.com/rest/2.0/services/cloud_dl?channel=chunlei&web=1&app_id=250528&bdstoken={}&clienttype=0'.format(self.bdInfo['token']) 77 | postData = { 78 | 'method' : 'add_task', 79 | 'app_id' : '250528', 80 | 'source_url' : url, 81 | 'save_path' : '/' + self.bdInfo['saveDir'] + '/', 82 | 'type' : '3' 83 | } 84 | 85 | if auth != {} : 86 | postData['input'] = auth['input'] 87 | postData['vcode'] = auth['vcode'] 88 | 89 | html = self.Tools.getPage(bdApi, self.requestHeader, postData) 90 | if html['code'] == 200 : 91 | body = html['body'] 92 | info = json.JSONDecoder().decode(body) 93 | result = { 94 | 'err': 0, 95 | 'taskID': info['task_id'] 96 | } 97 | else : 98 | body = html['body'] 99 | info = json.JSONDecoder().decode(body) 100 | 101 | result = { 102 | 'err': 1, 103 | 'vcode': info['vcode'], 104 | 'img': info['img'] 105 | } 106 | 107 | return result 108 | 109 | def getPlayUrl (self, taskID) : 110 | taskID = str(taskID) 111 | bdApi = 'https://yun.baidu.com/rest/2.0/services/cloud_dl?need_task_info=1&status=255&start=0&limit=10&method=list_task&app_id=250528&channel=chunlei&web=1&app_id=250528&bdstoken={}&clienttype=0'.format(self.bdInfo['token']) 112 | html = self.Tools.getPage(bdApi, self.requestHeader) 113 | if html['code'] == '200' : 114 | body = html['body'] 115 | else : 116 | body = html['body'] 117 | 118 | info = json.JSONDecoder().decode(body) 119 | taskInfo = info['task_info'] 120 | 121 | try: 122 | for x in taskInfo : 123 | if taskID == x['task_id'] : 124 | savePath = urllib.parse.quote(x['save_path'].encode("UTF8")) 125 | playUrl = 'https://yun.baidu.com/play/video#video/path=' + savePath 126 | break 127 | except Exception as e: 128 | playUrl = '' 129 | 130 | return (playUrl) 131 | 132 | def getDlUrl (self, taskID, retry = 0) : 133 | taskID = str(taskID) 134 | fID = self.__tIdTofId(taskID) 135 | fID = '["' + str(fID) + '"]' 136 | bdApi = 'https://yun.baidu.com/api/download?type=dlink&fidlist={}×tamp={}&sign={}&channel=chunlei&clienttype=0&web=1&app_id=250528'.format( 137 | urllib.parse.quote(fID), 138 | self.bdInfo['time'], 139 | urllib.parse.quote(self.bdInfo['sign']) 140 | ) 141 | 142 | html = self.Tools.getPage(bdApi, self.requestHeader) 143 | if html['code'] == '200' : 144 | body = html['body'] 145 | else : 146 | body = html['body'] 147 | 148 | info = json.JSONDecoder().decode(body) 149 | 150 | if info['errno'] == 0 : 151 | try: 152 | dlLink = info['dlink'][0]['dlink'] 153 | except Exception as e: 154 | dlLink = '' 155 | 156 | return dlLink 157 | else : 158 | if retry < 3 : 159 | retry += 1 160 | time.sleep(3) 161 | self.getDlUrl(taskID, retry) 162 | else : 163 | return '' 164 | 165 | def __getBdInfo (self) : 166 | bdApi = 'https://yun.baidu.com/disk/home?errno=0&errmsg=Auth%20Login%20Sucess&&bduss=&ssnerror=0' 167 | self.requestHeader = [ 168 | self.bdInfo['cookie'], 169 | 'Host:pan.baidu.com', 170 | 'Origin:https://pan.baidu.com', 171 | 'Referer:https://pan.baidu.com/disk/home', 172 | 'User-Agent:netdisk;5.3.4.5;PC;PC-Windows;5.1.2600;WindowsBaiduYunGuanJia' 173 | ] 174 | html = self.Tools.getPage(bdApi, self.requestHeader) 175 | 176 | yunData = re.findall(r"var context\=([\s\S]*?)yunData", html['body']) 177 | 178 | if len(yunData) > 0 : 179 | yunData = yunData[0] 180 | else : 181 | yunData = '' 182 | 183 | self.bdInfo['username'] = re.findall(r'"username":"(.*?)"', yunData)[0] 184 | self.bdInfo['token'] = re.findall(r'"bdstoken":"(.*?)"', yunData)[0] 185 | self.bdInfo['time'] = re.findall(r'"timestamp":(.*?),', yunData)[0] 186 | 187 | bdSign1 = re.findall(r'"sign1":"(.*?)"', yunData)[0] 188 | bdSign3 = re.findall(r'"sign3":"(.*?)"', yunData)[0] 189 | self.bdInfo['sign'] = self.__getSign(bdSign3, bdSign1) 190 | 191 | def __getSign (self, j, r): 192 | a = [] 193 | p = [] 194 | o = '' 195 | v = len(j) 196 | 197 | for q in range(256): 198 | a.append(ord(j[q % v])) 199 | p.append(q) 200 | 201 | u = 0 202 | for q in range(256): 203 | u = (u + p[q] + a[q]) % 256 204 | t = p[q] 205 | p[q] = p[u] 206 | p[u] = t 207 | 208 | i = 0 209 | u = 0 210 | for q in range(len(r)): 211 | i = (i + 1) % 256 212 | u = (u + p[i]) % 256 213 | t = p[i] 214 | p[i] = p[u] 215 | p[u] = t 216 | k = p[((p[i] + p[u]) % 256)] 217 | o += chr(ord(r[q]) ^ k) 218 | 219 | return base64.b64encode(o.encode()) #升级到python3需要加上.encode() 220 | 221 | def __tIdTofId (self, taskID) : 222 | taskID = str(taskID) 223 | bdApi = 'https://yun.baidu.com/rest/2.0/services/cloud_dl?need_task_info=1&status=255&start=0&limit=10&method=list_task&app_id=250528&channel=chunlei&web=1&app_id=250528&bdstoken={}&clienttype=0'.format(self.bdInfo['token']) 224 | html = self.Tools.getPage(bdApi, self.requestHeader) 225 | if html['code'] == '200' : 226 | body = html['body'] 227 | else : 228 | body = html['body'] 229 | 230 | info = json.JSONDecoder().decode(body) 231 | taskInfo = info['task_info'] 232 | 233 | savePath = '' 234 | for x in taskInfo : 235 | if taskID == x['task_id'] : 236 | savePath = x['save_path'] 237 | break 238 | 239 | bdApi = 'https://yun.baidu.com/api/list?order=time&desc=1&showempty=0&web=1&page=1&num=100&dir=%2F{}&channel=chunlei&web=1&app_id=250528&bdstoken={}&clienttype=0'.format(self.bdInfo['saveDir'], self.bdInfo['token']) 240 | html = self.Tools.getPage(bdApi, self.requestHeader) 241 | if html['code'] == '200' : 242 | body = html['body'] 243 | else : 244 | body = html['body'] 245 | 246 | info = json.JSONDecoder().decode(body) 247 | fileInfo = info['list'] 248 | 249 | fId = 0 250 | for x in fileInfo : 251 | if savePath == x['path'] : 252 | fId = x['fs_id'] 253 | break 254 | return fId -------------------------------------------------------------------------------- /Da/Config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import os 4 | import sqlite3 5 | import platform 6 | import time 7 | 8 | from View import ConfigView 9 | from Da import AppBase 10 | 11 | class Config : 12 | 13 | def __init__(self): 14 | self.appTitle = AppBase.info['title'] 15 | self.__getConfigPath() 16 | 17 | self.table = 'config' 18 | if self.__connect() == False: 19 | self.connStat = False 20 | else : 21 | self.connStat = True 22 | self.__chkTable() 23 | 24 | def __del__ (self) : 25 | if self.connStat == True : 26 | try: 27 | self.__disConn() 28 | except Exception as e: 29 | pass 30 | 31 | def show (self) : 32 | CfgView = ConfigView.GUI() 33 | data = self.get() 34 | CfgView.save = lambda data = data : self.save(data) 35 | CfgView.show(data) 36 | 37 | def get (self) : 38 | result = {'stat' : 1, 'msg' : ''} 39 | 40 | if self.connStat != False : 41 | sql = "SELECT * FROM " + self.table + " ORDER BY id DESC LIMIT 1" 42 | self.cur.execute(sql) 43 | values = self.cur.fetchone() 44 | 45 | if values : 46 | result['stat'] = 0 47 | result['bdc'] = values[1] 48 | result['path'] = values[2] 49 | result['ariarpc'] = values[3] 50 | result['ariapath'] = values[4] 51 | result['udrate'] = values[5] 52 | result['udtime'] = values[6] 53 | 54 | return result 55 | 56 | def save (self, data) : 57 | result = {'stat' : 1, 'msg' : ''} 58 | 59 | param = '' 60 | for k, v in list(data.items()) : 61 | param += ", " + k + " = '" + str(v) + "'" 62 | param = param[1:] 63 | 64 | if self.connStat != False : 65 | sql = "UPDATE " + self.table + " SET " + param 66 | self.cur.execute(sql) 67 | self.conn.commit() 68 | result['msg'] = '更新成功!' 69 | 70 | return result 71 | 72 | def lastUd (self, timeStr) : 73 | if self.connStat != False : 74 | sql = "UPDATE " + self.table + " SET udtime = " + str(timeStr) 75 | self.cur.execute(sql) 76 | self.conn.commit() 77 | 78 | def __connect (self) : 79 | try: 80 | if not os.path.exists(self.configPath) : 81 | os.makedirs(self.configPath) 82 | self.configPath = os.path.join(self.configPath, 'Config') 83 | 84 | self.conn = sqlite3.connect(self.configPath, check_same_thread = False) 85 | self.cur = self.conn.cursor() 86 | return True 87 | except: 88 | return False 89 | 90 | def __chkTable (self) : 91 | if self.connStat == False : return False 92 | 93 | sql = "SELECT tbl_name FROM sqlite_master WHERE type='table'" 94 | tableStat = False 95 | 96 | self.cur.execute(sql) 97 | values = self.cur.fetchall() 98 | 99 | for x in values: 100 | if self.table in x : 101 | tableStat = True 102 | 103 | if tableStat == False : 104 | self.__create() 105 | 106 | def __create (self) : 107 | if self.connStat == False : return False 108 | 109 | sql = 'create table ' + self.table + ' (id integer PRIMARY KEY autoincrement, bdc text, path varchar(500), ariarpc varchar(500), ariapath varchar(500), udrate int(1), udtime varchar(100))' 110 | self.cur.execute(sql); 111 | 112 | bdc = '' 113 | path = 'MovieCatcherFiles' 114 | ariarpc = '' 115 | ariapath = '' 116 | udrate = '2' 117 | udtime = str(int(time.time())) 118 | 119 | sql = "insert into " + self.table + " (bdc, path, ariarpc, ariapath, udrate, udtime) values ('" + bdc + "', '" + path + "', '" + ariarpc + "', '" + ariapath + "', " + udrate + ", '" + udtime + "')" 120 | 121 | self.cur.execute(sql) 122 | self.conn.commit() 123 | 124 | def __disConn (self) : 125 | if self.connStat == False : return False 126 | 127 | self.cur.close() 128 | self.conn.close() 129 | 130 | def __getConfigPath (self) : 131 | osType = platform.system() 132 | homeDir = os.path.expanduser('~') 133 | 134 | if osType == 'Darwin' : 135 | self.configPath = os.path.join(homeDir, 'Library', 'Application Support', self.appTitle) 136 | elif osType == 'Windows' : 137 | sysDrive = os.getenv("SystemDrive") 138 | self.configPath = os.path.join(homeDir, 'Documents', self.appTitle) -------------------------------------------------------------------------------- /Da/ResGdyy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import re 4 | 5 | from Lib import Tools 6 | 7 | class Searcher : 8 | 9 | def __init__ (self) : 10 | self.Tools = Tools.Tools() 11 | self.page = 1 12 | self.zCookie = '' 13 | 14 | def find (self, keyword) : 15 | self.result = [] 16 | keyword = keyword.encode("UTF8") 17 | self.getList(keyword) 18 | return self.result 19 | 20 | def getList (self, keyword) : 21 | url = 'http://www.3gdyy.com/search.htm' 22 | header = [ 23 | 'Host:www.3gdyy.com', 24 | 'Origin:http://www.3gdyy.com', 25 | 'Pragma:no-cache', 26 | 'Referer:http://www.3gdyy.com/search.htm', 27 | 'Upgrade-Insecure-Requests:1', 28 | 'User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36' 29 | ] 30 | post = {'keyword': str(keyword)} 31 | html = self.Tools.getPage(url, header, post) 32 | 33 | print(html) 34 | 35 | # data = re.findall(r"(.*?)", html['body']) 36 | 37 | # try: 38 | # for x in data : 39 | # self.result.append({ 40 | # 'title': x[1], 41 | # 'url': 'http://www.3gdyy.com/' + x[0], 42 | # 'source': 'gdyy' 43 | # }) 44 | # except Exception as e: 45 | # pass 46 | 47 | return self.result 48 | 49 | 50 | def getLink (self, url) : 51 | result = [] 52 | 53 | header = [ 54 | 'Host:www.3gdyy.com', 55 | 'Origin:http://www.3gdyy.com', 56 | 'Pragma:no-cache', 57 | 'Referer:http://www.3gdyy.com/search.htm', 58 | 'Upgrade-Insecure-Requests:1', 59 | 'User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36' 60 | ] 61 | html = self.Tools.getPage(url, header) 62 | 63 | data = re.findall(r"[\s\S]*?[\s\S]*?(.*?)[\s\S]*?[\s\S]*?(.*?)[\s\S]*?", html['body']) 64 | 65 | try: 66 | for x in data : 67 | temp = ( 68 | '[' + x[2] + ']' + x[1], 69 | x[0] 70 | ) 71 | 72 | result.append(temp) 73 | 74 | except Exception as e: 75 | pass 76 | 77 | return result -------------------------------------------------------------------------------- /Da/ResVhao.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import re 4 | 5 | from Lib import Tools 6 | 7 | class Searcher : 8 | 9 | def __init__ (self) : 10 | self.Tools = Tools.Tools() 11 | self.page = 1 12 | self.zCookie = '' 13 | 14 | def find (self, keyword) : 15 | self.result = [] 16 | keyword = keyword.encode("gbk") 17 | self.getList(keyword) 18 | return self.result 19 | 20 | def getList (self, keyword) : 21 | url = 'http://www.6vhao.tv/e/search/index.php' 22 | header = [ 23 | 'Host:www.6vhao.tv', 24 | 'Origin:http://www.6vhao.tv', 25 | 'Pragma:no-cache', 26 | 'Connection:keep-alive', 27 | 'Referer:http://www.6vhao.tv', 28 | 'Content-Type:application/x-www-form-urlencoded', 29 | 'Upgrade-Insecure-Requests:1', 30 | 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36' 31 | ] 32 | 33 | post = { 34 | 'keyboard': keyword, 35 | 'show': 'title,smalltext', 36 | 'tempid': 1, 37 | 'tbname': 'Article' 38 | } 39 | html = self.Tools.getPage(url, header, post) 40 | 41 | data = re.findall(r"listimg[\s\S]*?href=\"(.*?)\"[\s\S]*?alt=\"(.*?)\"[\s\S]*?listInfo", html['body']) 42 | 43 | try: 44 | for x in data : 45 | self.result.append({ 46 | 'title': x[1], 47 | 'url': x[0], 48 | 'source': 'vhao' 49 | }) 50 | except Exception as e: 51 | pass 52 | 53 | return self.result 54 | 55 | def getLink (self, url) : 56 | result = [] 57 | 58 | header = [ 59 | 'Host:www.6vhao.tv', 60 | 'Origin:http://www.6vhao.tv', 61 | 'Pragma:no-cache', 62 | 'Connection:keep-alive', 63 | 'Referer:http://www.6vhao.tv', 64 | 'Content-Type:application/x-www-form-urlencoded', 65 | 'Upgrade-Insecure-Requests:1', 66 | 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36' 67 | ] 68 | html = self.Tools.getPage(url, header) 69 | 70 | data = re.findall(r"#ffffbb[\s\S]*?href=\"(.*?)\"[\s\S]*?>(.*?)<\/a>", html['body']) 71 | 72 | try: 73 | for x in data : 74 | if x[0][0:4] != 'http': 75 | if x[0][0:4] == 'ed2k' : 76 | resultType = 'ed2k' 77 | else : 78 | resultType = 'magnet' 79 | 80 | temp = ( 81 | '[' + resultType + ']' + x[1], 82 | x[0] 83 | ) 84 | 85 | result.append(temp) 86 | 87 | except Exception as e: 88 | pass 89 | 90 | return result -------------------------------------------------------------------------------- /Da/ResZmz.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import re 4 | 5 | from Lib import Tools 6 | 7 | class Searcher : 8 | 9 | def __init__ (self) : 10 | self.Tools = Tools.Tools() 11 | self.page = 1 12 | self.zCookie = '' 13 | self.zmzUserInfo = { 14 | 'username': 'moviecatcher', 15 | 'password': '666666' 16 | } 17 | 18 | def find (self, keyword) : 19 | self.result = [] 20 | #keyword = keyword.encode("UTF8") 21 | self.getList(keyword) 22 | return self.result 23 | 24 | def login (self) : 25 | url = 'http://www.zmz2019.com/User/Login/ajaxLogin' 26 | requestHeader = [ 27 | 'Origin:http://www.zmz2019.com', 28 | 'Host:www.zmz2019.com', 29 | 'Referer:http://www.zmz2019.com/user/login', 30 | 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', 31 | 'X-Requested-With:XMLHttpRequest' 32 | ] 33 | postData = { 34 | 'account': self.zmzUserInfo['username'], 35 | 'password': self.zmzUserInfo['password'], 36 | 'remember': '1', 37 | 'url_back': 'http://www.zmz2019.com/' 38 | } 39 | html = self.Tools.getPage(url, requestHeader, postData) 40 | #zmz2019网站改版后,cookie应重新获取正确的,否则登录失败 41 | string = '' 42 | for s,v in html['header'].items(): 43 | if s=='Set-Cookie': 44 | if re.findall('Max-Age=0',v): 45 | pass 46 | else: 47 | string += v 48 | else: 49 | pass 50 | s = re.findall('(GINFO=uid[\s\S]*?);',string) 51 | v = re.findall('(GKEY=[\s\S]*?);',string) 52 | string = s[0] + ';' + v[0] + ';' 53 | 54 | self.zCookie = 'Cookie: ' + self.Tools.fmtCookie(string) 55 | 56 | def getList (self, keyword) : 57 | url = 'http://www.zmz2019.com/search/index/?page=' + str(self.page) + '&keyword=' + str(keyword) + '&type=' 58 | html = self.Tools.getPage(url) 59 | 60 | data = re.findall(r"search-result([\s\S]*?)pages-padding", html['body']) 61 | page = re.findall(r"\.\.\.(\d*?)", html['body']) 62 | 63 | if page != [] and page != [''] : 64 | page = int(page[-1]) #每次都会出现在-1的位置 65 | else : 66 | page = 1 67 | 68 | try: 69 | resultlist = re.findall(r"search-item([\s\S]*?)f4 time", data[0]) 70 | 71 | for x in resultlist : 72 | resultType = re.findall(r"([\s\S]*?)", x)[0] 73 | 74 | if resultType == '电影': 75 | self.result.append({ 76 | 'title': r'[电影]'+re.findall(r"list_title\">([\s\S]*?)", x)[0], 77 | 'url': 'http://www.zmz2019.com' + re.findall(r"([\s\S]*?)", x)[0], 83 | 'url': 'http://www.zmz2019.com' + re.findall(r"", html['body']) 106 | 107 | try: 108 | for x in data : 109 | resultType = re.findall(r"class=\"it\">([\s\S]*?)", x)[0] 110 | resultData = re.findall(r"class=\"fr\"([\s\S]*?)", x) 111 | resultInfo = re.findall(r"class=\"fl\"([\s\S]*?)", x) 112 | 113 | if resultType != '离线+在线' and resultType != 'RMVB' and resultData !=[] : 114 | for idx, item in enumerate(resultData) : 115 | resultlist = re.findall(r"", item) 116 | movInfo = re.findall(r"', self.__cleanSearchKey) # 事件监听绑定 57 | 58 | Searcher = Search.Search(self.master) # 实例化search类 59 | self.sBtn = tkinter.Button( 60 | self.mainTop, 61 | text = '搜索电影', 62 | width = 10, 63 | fg = '#222', 64 | highlightbackground = '#444', 65 | command = lambda key = self.searchKey : tkinter.messagebox.showinfo('Error', '请输入想要查询的电视剧/电影名再进行查询') if self.searchKey.get() == '电影名/电视剧名' or self.searchKey.get() == '' else Searcher.showResult(key) 66 | ) 67 | self.sBtn.grid(row = 1, column = 1) 68 | 69 | self.mainTop.grid_columnconfigure(0, weight=1) 70 | self.mainTop.grid_columnconfigure(2, weight=1) 71 | 72 | def __cleanSearchKey(self, e) : 73 | key = self.searchKey.get() # 获取文件框的值 74 | 75 | if key == '电影名/电视剧名' : 76 | self.searchKey.delete('0', 'end') # 删除所有值 77 | 78 | def run (self) : 79 | self.master.mainloop() # tk的基本格式,启动 80 | 81 | # 入口在BI的App.py里 -------------------------------------------------------------------------------- /View/MenuBarView.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import tkinter 5 | import webbrowser 6 | 7 | from . import AppInfoView 8 | from Da import Config 9 | from Da import BdApi 10 | from . import PlayerView 11 | from Bl import Update 12 | 13 | 14 | class GUI : 15 | 16 | def __init__ (self, master) : 17 | self.master = master 18 | 19 | def show (self) : 20 | menubar = tkinter.Menu(self.master) 21 | 22 | fileMenu = tkinter.Menu(menubar, tearoff = 0) 23 | appInfo = AppInfoView.GUI() 24 | fileMenu.add_command(label = "About Movie Catcher", command = appInfo.show) 25 | # url = 'https://github.com/EvilCult' 26 | # fileMenu.add_command(label = "Website", command = lambda url = url : webbrowser.open_new(url)) 27 | url = 'https://github.com/EvilCult/moviecatcher/wiki' 28 | fileMenu.add_command(label = "Guide", command = lambda url = url : webbrowser.open_new(url)) 29 | Ud = Update.Update() 30 | fileMenu.add_command(label = "Check Update", command = lambda force = True : Ud.chkUpdate(force)) 31 | fileMenu.add_separator() 32 | url = 'https://evilcult.github.io/moviecatcher/donate.html' 33 | fileMenu.add_command(label = "Donate", command = lambda url = url : webbrowser.open_new(url)) 34 | fileMenu.add_separator() 35 | fileMenu.add_command(label = "Quit", command = self.master.quit) 36 | menubar.add_cascade(label = "File", menu = fileMenu) 37 | 38 | editMenu = tkinter.Menu(menubar, tearoff = 0) 39 | Cfg = Config.Config() 40 | editMenu.add_command(label = "Config", command = Cfg.show) 41 | editMenu.add_separator() 42 | editMenu.add_command(label = "Baidu Login", command = lambda cb = BdApi.BdApi().saveLogin : PlayerView.GUI(self.master).showLoginWindow(cb)) 43 | menubar.add_cascade(label = "Edit", menu = editMenu) 44 | 45 | winMenu = tkinter.Menu(menubar, tearoff = 0) 46 | url = 'https://pan.baidu.com' 47 | winMenu.add_command(label = "BaiduYun", command = lambda url = url : webbrowser.open_new(url)) 48 | menubar.add_cascade(label = "Window", menu = winMenu) 49 | 50 | helpMenu = tkinter.Menu(menubar, tearoff = 0) 51 | url = 'https://github.com/EvilCult/moviecatcher' 52 | helpMenu.add_command(label = "GitHub", command = lambda target = url : webbrowser.open_new(target)) 53 | url = 'https://github.com/EvilCult/moviecatcher/releases' 54 | helpMenu.add_command(label = "Release Notes", command = lambda target = url : webbrowser.open_new(target)) 55 | url = 'https://github.com/EvilCult/moviecatcher/issues' 56 | helpMenu.add_command(label = "Send Feedback", command = lambda target = url : webbrowser.open_new(target)) 57 | menubar.add_cascade(label = "Help", menu = helpMenu) 58 | 59 | self.master.config(menu = menubar) -------------------------------------------------------------------------------- /View/PlayerView.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import tkinter 4 | import urllib.request, urllib.error, urllib.parse 5 | import ssl 6 | import io 7 | import PIL.Image 8 | import PIL.ImageTk 9 | import tkinter.messagebox 10 | import time 11 | import webbrowser 12 | from selenium import webdriver 13 | 14 | from Lib import Tools 15 | 16 | class GUI : 17 | 18 | def __init__ (self, master) : 19 | self.master = master 20 | self.authDownload = '' 21 | self.watchLinkStat = {'err': 0, 'msg': ''} 22 | self.downLinkStat = {'err': 0, 'msg': ''} 23 | self.Tools = Tools.Tools() 24 | 25 | def showDlLink (self, link) : 26 | window = tkinter.Toplevel() 27 | window.title('下载链接') 28 | window.resizable(width = 'false', height = 'false') 29 | if self.Tools.isWin() : 30 | window.iconbitmap(self.Tools.getRes('biticon.ico')) 31 | 32 | topZone = tkinter.Frame(window, bd = 0, bg="#444") 33 | topZone.pack(expand = True, fill = 'both') 34 | 35 | textZone = tkinter.Text(topZone, height = 8, width = 50, bd = 10, bg="#444", fg = '#ddd', highlightthickness = 0, selectbackground = '#116cd6') 36 | textZone.grid(row = 0, column = 0, sticky = '') 37 | textZone.insert('insert', link) 38 | 39 | dlBtn = tkinter.Button(topZone, text = '下载', width = 10, fg = '#222', highlightbackground = '#444', command = lambda url = link : webbrowser.open_new(url)) 40 | dlBtn.grid(row = 1, column = 0, pady = 5) 41 | 42 | def showWatchLink (self) : 43 | if self.watchLinkStat['err'] == 0 : 44 | if self.watchLinkStat['msg'] == '' : 45 | self.timer = self.master.after(50, self.showWatchLink) 46 | else : 47 | webbrowser.open_new(self.watchLinkStat['msg']) 48 | elif self.watchLinkStat['err'] == 1 : 49 | tkinter.messagebox.showinfo('Error', '云端未能完成该任务,请等待云端下载完成or换个资源试试!') 50 | elif self.watchLinkStat['err'] == 2 : 51 | tkinter.messagebox.showinfo('Notice', '磁力链接目前不支持在线观看,待后续版本更新。\r\n暂时请手动下载或上传链接至百度云!') 52 | elif self.watchLinkStat['err'] == 3 : 53 | self.showAuthCode(self.watchLinkStat['msg']) 54 | 55 | def showCloudLink (self) : 56 | if self.downLinkStat['err'] == 0 : 57 | if self.downLinkStat['msg'] == '' : 58 | self.timer = self.master.after(50, self.showCloudLink) 59 | else : 60 | window = tkinter.Toplevel() 61 | window.title('离线下载链接') 62 | window.resizable(width = 'false', height = 'false') 63 | if self.Tools.isWin() : 64 | window.iconbitmap(self.Tools.getRes('biticon.ico')) 65 | 66 | topZone = tkinter.Frame(window, bd = 0, bg="#444") 67 | topZone.pack(expand = True, fill = 'both') 68 | 69 | textZone = tkinter.Text(topZone, height = 8, width = 50, bd = 10, bg="#444", fg = '#ddd', highlightthickness = 0, selectbackground = '#116cd6') 70 | textZone.grid(row = 0, column = 0, sticky = '') 71 | textZone.insert('insert', self.downLinkStat['msg']) 72 | 73 | dlBtn = tkinter.Button(topZone, text = '下载', width = 10, fg = '#222', highlightbackground = '#444', command = lambda url = self.downLinkStat['msg'] : webbrowser.open_new(url)) 74 | dlBtn.grid(row = 1, column = 0, pady = 5) 75 | 76 | elif self.downLinkStat['err'] == 1 : 77 | tkinter.messagebox.showinfo('Error', '云端未能完成该任务,请等待云端下载完成or换个资源试试!') 78 | elif self.downLinkStat['err'] == 2 : 79 | tkinter.messagebox.showinfo('Notice', '磁力链接目前不支持离线下载,待后续版本更新。\r\n暂时请手动下载或上传链接至百度云!') 80 | elif self.downLinkStat['err'] == 3 : 81 | self.showAuthCode(self.downLinkStat['msg']) 82 | 83 | def showAuthCode (self, imgUrl) : 84 | self.authWindow = tkinter.Toplevel() 85 | self.authWindow.title('验证码') 86 | self.authWindow.resizable(width = 'false', height = 'false') 87 | if self.Tools.isWin() : 88 | self.authWindow.iconbitmap(self.Tools.getRes('biticon.ico')) 89 | self.authWindow.config(background='#444') 90 | 91 | winTop = tkinter.Frame(self.authWindow, bd = 10, bg = '#444') 92 | winTop.grid(row = 0, column = 0, sticky = '') 93 | 94 | ctx = ssl.create_default_context() 95 | ctx.check_hostname = False 96 | ctx.verify_mode = ssl.CERT_NONE 97 | image = urllib.request.urlopen(imgUrl, context = ctx).read() 98 | imgData = io.BytesIO(image) 99 | pilImage = PIL.Image.open(imgData) 100 | tkImg = PIL.ImageTk.PhotoImage(pilImage) 101 | 102 | label = tkinter.Label(winTop, image = tkImg, bd = 0, bg = '#111', relief = 'solid') 103 | label.img = tkImg 104 | label.grid(row = 0, column = 0, sticky = '', pady = 5) 105 | 106 | self.authKeyInput = tkinter.Entry(winTop, width = 20, bd = 0, bg = "#222", fg = "#ddd", highlightthickness = 1, highlightcolor="#111", highlightbackground = '#111', justify='center') 107 | self.authKeyInput.grid(row = 1, column = 0, pady = 5) 108 | self.authKeyInput.insert('end', '') 109 | 110 | btn = tkinter.Button(winTop, text = '确认', width = 10, fg = '#222', highlightbackground = '#444', command = self.__getAuthInput) 111 | btn.grid(row = 2, column = 0, pady = 5) 112 | 113 | def showLoginWindow (self, callback = '') : 114 | loginUrl = 'https://pan.baidu.com/' 115 | if self.Tools.isWin() : 116 | chromeDriver = self.Tools.getRes('chromedriver.exe') 117 | else : 118 | chromeDriver = self.Tools.getRes('chromedriver') 119 | 120 | # try: 121 | self.browser = webdriver.Chrome(executable_path = chromeDriver) 122 | self.browser.get(loginUrl) 123 | 124 | self.browser.maximize_window() 125 | 126 | self.slave = tkinter.Toplevel() 127 | self.slave.title('Login') 128 | self.slave.resizable(width = 'false', height = 'false') 129 | if self.Tools.isWin() : 130 | self.slave.iconbitmap(self.Tools.getRes('biticon.ico')) 131 | 132 | mainFrame = tkinter.Frame(self.slave, bd = 0, bg="#444") 133 | mainFrame.pack(expand = True, fill = 'both', ipadx = '10') 134 | 135 | msgLabel = tkinter.Label(mainFrame, text="请于页面中登陆百度云账号\r\n登陆成功后点击下方「获取cookies」按钮", fg = '#ddd', bg="#444", anchor = 'center') 136 | msgLabel.grid(row = 0, column = 1, pady = 5) 137 | 138 | loginBtn = tkinter.Button(mainFrame, text = '获取cookies', width = 20, fg = '#222', highlightbackground = '#444', command = lambda cb = callback : self.__getLoginInput(cb)) 139 | loginBtn.grid(row = 4, column = 1, pady = 5) 140 | 141 | mainFrame.grid_columnconfigure(0, weight=1) 142 | mainFrame.grid_columnconfigure(2, weight=1) 143 | # except Exception as e: 144 | # tkMessageBox.showinfo('Notice', '为保障密码安全:登陆功能将完全在Chrome浏览器中进行。\r\n所以需要Chrome支持。\r\n请先安装Google Chrome浏览器。') 145 | 146 | def __getLoginInput (self, callback = '') : 147 | time.sleep(5) 148 | 149 | if self.browser.title == '百度网盘-全部文件' : 150 | cookies = self.browser.get_cookies() 151 | cookieStr = '' 152 | for x in cookies : 153 | cookieStr += x['name'] + '=' + x['value'] + '; ' 154 | 155 | result = {'stat': 1, 'msg': '获取成功'} 156 | else : 157 | result = {'stat': 2, 'msg': '获取失败'} 158 | 159 | self.browser.quit() 160 | 161 | if result['stat'] == 1 : 162 | self.slave.destroy() 163 | tkinter.messagebox.showinfo('Success', '登陆成功') 164 | callback(cookieStr) 165 | else : 166 | tkinter.messagebox.showinfo('Error', result['msg']) 167 | 168 | def __getAuthInput (self) : 169 | authKey = self.authKeyInput.get() 170 | self.authDownload(authKey) 171 | self.authWindow.destroy() 172 | 173 | -------------------------------------------------------------------------------- /View/ResultView.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import tkinter 4 | import tkinter.messagebox 5 | 6 | from Bl import Play 7 | from Lib import Tools 8 | 9 | class GUI : 10 | 11 | def __init__ (self, master) : 12 | self.master = master 13 | self.Tools = Tools.Tools() 14 | self.listRst = '' 15 | self.resRst = '' 16 | self.getDetail = '' 17 | 18 | def showList (self, searchKey) : 19 | rstWindow = tkinter.Toplevel() 20 | rstWindow.title('资源列表') 21 | rstWindow.resizable(width = 'false', height = 'false') 22 | if self.Tools.isWin() : 23 | rstWindow.iconbitmap(self.Tools.getRes('biticon.ico')) 24 | 25 | titleFrame = tkinter.Frame(rstWindow, bd = 0, bg="#444") 26 | titleFrame.pack(expand = True, fill = 'both') 27 | 28 | titleLabel = tkinter.Label(titleFrame, text = '关键词 :「 ' + searchKey + ' 」的搜索结果', fg = '#ddd', bg="#444", font = ("Helvetica", "12")) 29 | titleLabel.grid(row = 1, column = 1, pady = 10) 30 | 31 | titleFrame.grid_columnconfigure(0, weight=1) 32 | titleFrame.grid_columnconfigure(2, weight=1) 33 | 34 | self.frame = tkinter.Frame(rstWindow, bd = 0, bg="#222") 35 | self.frame.pack(expand = True, fill = 'both') 36 | 37 | self.window = tkinter.Listbox(self.frame, height = 14, width = 40, bd = 0, bg="#222", fg = '#ddd', selectbackground = '#116cd6', highlightthickness = 0) 38 | self.window.grid(row = 0, column = 0, padx = 10, pady = 10) 39 | self.window.bind('', self.__getMovDetails) 40 | 41 | try : 42 | self.window.delete(0, 100) 43 | except : 44 | pass 45 | 46 | def updateList (self) : 47 | if self.listRst != '' : 48 | idx = 0 49 | for x in self.listRst : 50 | self.window.insert(idx, x['title']) 51 | idx += 1 52 | else : 53 | self.timer = self.frame.after(50, self.updateList) 54 | 55 | def showRes (self) : 56 | self.resWindow = tkinter.Toplevel() 57 | self.resWindow.title(self.target['title']) 58 | self.resWindow.resizable(width = 'false', height = 'false') 59 | if self.Tools.isWin() : 60 | self.resWindow.iconbitmap(self.Tools.getRes('biticon.ico')) 61 | self.resWindow.config(background='#444') 62 | 63 | self.resFrame = tkinter.Frame(self.resWindow, bd = 0, bg="#444") 64 | self.resFrame.grid(row = 0, column = 0, sticky = '') 65 | 66 | btnZone = tkinter.Frame(self.resWindow, bd = 10, bg="#444") 67 | btnZone.grid(row = 1, column = 0, sticky = '') 68 | 69 | self.resList = tkinter.Listbox(self.resFrame, height = 8, width = 50, bd = 0, bg="#222", fg = '#ddd',selectbackground = '#116cd6', highlightthickness = 0) 70 | self.resList.grid(row = 0, sticky = '') 71 | 72 | viewBtn = tkinter.Button(btnZone, text = '查看连接', width = 10, fg = '#222', highlightbackground = '#444', command = self.__taskShow) 73 | viewBtn.grid(row = 0, column = 0, padx = 5) 74 | 75 | watchBtn = tkinter.Button(btnZone, text = '在线观看', width = 10, fg = '#222', highlightbackground = '#444', command = self.__taskWatch) 76 | watchBtn.grid(row = 0, column = 1, padx = 5) 77 | 78 | dlBtn = tkinter.Button(btnZone, text = '离线下载', width = 10, fg = '#222', highlightbackground = '#444', command = self.__taskDownload) 79 | dlBtn.grid(row = 0, column = 2, padx = 5) 80 | 81 | def updateRes (self) : 82 | if self.resRst != '' : 83 | if len(self.resRst) > 0: 84 | idx = 0 85 | for x in self.resRst : 86 | self.resList.insert(idx, x[0]) 87 | idx += 1 88 | else : 89 | self.resList.insert(0, '该资源已被和谐,暂时无法播放。') 90 | else : 91 | self.timer = self.resFrame.after(50, self.updateRes) 92 | 93 | def __getMovDetails (self, event) : 94 | idx = int(self.window.curselection()[0]) 95 | 96 | self.target = self.listRst[idx] 97 | 98 | self.getDetail(self.target) 99 | 100 | def __getChoose (self) : 101 | if self.resList.curselection() == () : 102 | tkinter.messagebox.showinfo('Notice', '请选择一个文件进行操作!') 103 | else : 104 | idx = int(self.resList.curselection()[0]) 105 | 106 | target = self.resRst[idx] 107 | 108 | def __taskWatch (self) : 109 | if self.resList.curselection() == () : 110 | tkinter.messagebox.showinfo('提示', '请选择一个文件进行操作!') 111 | else : 112 | idx = int(self.resList.curselection()[0]) 113 | 114 | target = self.resRst[idx] 115 | 116 | Player = Play.Play(self.master) 117 | Player.watchLink(target) 118 | 119 | def __taskShow (self) : 120 | if self.resList.curselection() == () : 121 | tkinter.messagebox.showinfo('提示', '请选择一个文件进行操作!') 122 | else : 123 | idx = int(self.resList.curselection()[0]) 124 | 125 | target = self.resRst[idx] 126 | 127 | Player = Play.Play(self.master) 128 | Player.showLink(target) 129 | 130 | def __taskDownload (self) : 131 | if self.resList.curselection() == () : 132 | tkinter.messagebox.showinfo('提示', '请选择一个文件进行操作!') 133 | else : 134 | idx = int(self.resList.curselection()[0]) 135 | 136 | target = self.resRst[idx] 137 | 138 | Player = Play.Play(self.master) 139 | Player.dlLink(target) 140 | -------------------------------------------------------------------------------- /View/UpdateInfoView.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import tkinter 4 | import webbrowser 5 | 6 | from Lib import Tools 7 | from Da import AppBase 8 | 9 | class GUI : 10 | 11 | def __init__ (self) : 12 | self.winTitle = 'Update' 13 | self.Tools = Tools.Tools() 14 | self.app = AppBase.info 15 | self.udInfo = [] 16 | 17 | def show (self) : 18 | self.slave = tkinter.Toplevel() 19 | self.slave.title(self.winTitle) 20 | self.slave.resizable(width = 'false', height = 'false') 21 | if self.Tools.isWin() : 22 | self.slave.iconbitmap(self.Tools.getRes('biticon.ico')) 23 | 24 | self.frame = tkinter.Frame(self.slave, bd = 0, bg="#444") 25 | self.frame.pack(expand = True, fill = 'both', ipadx = '5', ipady = '5') 26 | 27 | titleLabel = tkinter.Label(self.frame, text = self.app['title'], fg = '#ddd', bg="#444", font = ("Helvetica", "16", 'bold'), anchor = 'center') 28 | titleLabel.grid(row = 0, column = 1, pady = 5) 29 | 30 | version = str(self.app['ver']) + ' Build (' + str(self.app['build']) + ')' 31 | verlabel = tkinter.Label(self.frame, text = 'Version : ' + version, fg = '#ddd', bg="#444", font = ("Helvetica", "10"), anchor = 'center') 32 | verlabel.grid(row = 1, column = 1) 33 | 34 | self.information = tkinter.Text(self.frame, height = 8, width = 35, bd = 0, fg = '#ddd', bg="#222", highlightthickness = 1, highlightcolor="#111", highlightbackground = '#111', selectbackground = '#116cd6', font = ("Helvetica", "12")) 35 | self.information.grid(row = 2, column = 1, pady = 10) 36 | self.information.insert('end', '更新检测中。。。') 37 | 38 | self.frame.grid_columnconfigure(0, weight=1) 39 | self.frame.grid_columnconfigure(2, weight=1) 40 | 41 | def updateInfo (self) : 42 | if self.udInfo != [] : 43 | if self.udInfo['version'] != '' : 44 | version = str(self.udInfo['version']) 45 | else : 46 | version = str(self.app['ver']) + ' Build (' + str(self.app['build']) + ')' 47 | verlabel = tkinter.Label(self.frame, text = 'Version : ' + version, fg = '#ddd', bg="#444", font = ("Helvetica", "10"), anchor = 'center') 48 | verlabel.grid(row = 1, column = 1) 49 | 50 | self.information = tkinter.Text(self.frame, height = 8, width = 35, bd = 0, fg = '#ddd', bg="#222", highlightthickness = 1, highlightcolor="#111", highlightbackground = '#111', selectbackground = '#116cd6', font = ("Helvetica", "12")) 51 | self.information.grid(row = 2, column = 1, pady = 10) 52 | self.information.delete('0.0', 'end') 53 | self.information.insert('end', self.udInfo['msg']) 54 | 55 | btn = tkinter.Button(self.frame, text = 'Download', width = 10, fg = '#222', highlightbackground = '#444', command = lambda target = self.udInfo['dUrl'] : webbrowser.open_new(target)) 56 | btn.grid(row = 3, column = 1) 57 | else : 58 | self.timer = self.frame.after(50, self.updateInfo) 59 | 60 | def close (self) : 61 | self.slave.destroy() 62 | 63 | -------------------------------------------------------------------------------- /View/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilCult/moviecatcher/6e6b1476e43fbaa7f13a16535e11133d8cc4f980/View/__init__.py -------------------------------------------------------------------------------- /packmac.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | block_cipher = None 4 | 5 | 6 | a = Analysis(['Bl/App.py'], 7 | pathex=['/Users/Ray/Python/MovieSearch'], 8 | binaries=None, 9 | datas=[('Resources/logo.png', 'RES'), ('Resources/chromedriver', 'RES')], 10 | hiddenimports=[], 11 | hookspath=[], 12 | runtime_hooks=[], 13 | excludes=[], 14 | win_no_prefer_redirects=False, 15 | win_private_assemblies=False, 16 | cipher=block_cipher) 17 | pyz = PYZ(a.pure, a.zipped_data, 18 | cipher=block_cipher) 19 | exe = EXE(pyz, 20 | a.scripts, 21 | a.binaries, 22 | a.zipfiles, 23 | a.datas, 24 | name='Movie Catcher', 25 | debug=False, 26 | strip=False, 27 | upx=True, 28 | console=True ) 29 | app = BUNDLE(exe, 30 | name='Movie Catcher.app', 31 | icon='Resources/icon.icns', 32 | bundle_identifier=None, 33 | info_plist={ 34 | 'NSHighResolutionCapable': 'True' 35 | }, 36 | ) -------------------------------------------------------------------------------- /packwin.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | block_cipher = None 4 | 5 | 6 | a = Analysis(['bl\\app.py'], 7 | pathex=['C:\\Users\\lwpo2\\AppData\\Local\\Programs\\Python\\Python37\\Lib\\site-packages','C:\\Users\\lwpo2\\Downloads\\moviecatcher-master'], 8 | binaries=None, 9 | datas=[('Resources\\logo.png', 'RES'), ('Resources\\biticon.ico', 'RES'), ('Resources\\chromedriver.exe', 'RES')], 10 | hiddenimports=[], 11 | hookspath=[], 12 | runtime_hooks=[], 13 | excludes=[], 14 | win_no_prefer_redirects=False, 15 | win_private_assemblies=False, 16 | cipher=block_cipher) 17 | pyz = PYZ(a.pure, a.zipped_data, 18 | cipher=block_cipher) 19 | exe = EXE(pyz, 20 | a.scripts, 21 | a.binaries, 22 | a.zipfiles, 23 | a.datas, 24 | name='Movie Catcher', 25 | debug=False, 26 | strip=False, 27 | upx=True, 28 | console=False , icon='Resources\\icon.ico') 29 | --------------------------------------------------------------------------------