├── .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 |
--------------------------------------------------------------------------------