From 2d2c4a026d0011b12dbbb35864e0e15af94e6317 Mon Sep 17 00:00:00 2001 From: yangjiandong Date: Tue, 28 Aug 2012 14:38:00 +0800 Subject: [PATCH] first... --- .gitignore | 28 ++++ code.py | 153 ++++++++++++++++++ daemon.py | 129 +++++++++++++++ download.py | 130 +++++++++++++++ feed.py | 84 ++++++++++ fetchvc.py | 369 +++++++++++++++++++++++++++++++++++++++++++ login.py | 32 ++++ nginx/nginx.conf | 56 +++++++ nginx/simplecd | 28 ++++ nginx/spawn-fcgi.sh | 2 + pack.py | 40 +++++ readme.txt | 28 ++++ scdd.py | 150 ++++++++++++++++++ searchqueue | 0 static/about.html | 15 ++ static/common.js | 236 +++++++++++++++++++++++++++ static/hot.html | 25 +++ static/main_02.css | 44 ++++++ static/simplecd.png | Bin 0 -> 3231 bytes templates/error.html | 5 + templates/fin.html | 42 +++++ templates/id.html | 114 +++++++++++++ templates/index.html | 121 ++++++++++++++ 23 files changed, 1831 insertions(+) create mode 100644 .gitignore create mode 100644 code.py create mode 100644 daemon.py create mode 100644 download.py create mode 100644 feed.py create mode 100644 fetchvc.py create mode 100644 login.py create mode 100644 nginx/nginx.conf create mode 100644 nginx/simplecd create mode 100644 nginx/spawn-fcgi.sh create mode 100644 pack.py create mode 100644 readme.txt create mode 100644 scdd.py create mode 100644 searchqueue create mode 100644 static/about.html create mode 100644 static/common.js create mode 100644 static/hot.html create mode 100644 static/main_02.css create mode 100644 static/simplecd.png create mode 100644 templates/error.html create mode 100644 templates/fin.html create mode 100644 templates/id.html create mode 100644 templates/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ab4689 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +syntax: glob + +.hg +*.coverage +*.egg-info +*.log +*.pyc +*.db +*.swp +*.swo +*.zip +*.orig +*.cfg +*.tox + +build + +*~ + +fab_settings.py +production_settings.py + +dist +docs/output + +_uploads + +.hgignore diff --git a/code.py b/code.py new file mode 100644 index 0000000..9c81d30 --- /dev/null +++ b/code.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# code.py: based on web.py +# +# author: observer +# email: jingchaohu@gmail.com +# blog: http://obmem.com +# last edit @ 2009.12.23 +import os,sys +import web +from web import form +import sqlite3 +import fetchvc +import time + +web.config.debug = False + +path = os.path.dirname(os.path.realpath(sys.argv[0])) + +db = web.database(dbn='sqlite', db='f:/verycd.sqlite3.db')#db='verycd.sqlite3.db') +#customdb = web.database(dbn='sqlite',db='custom.sqlite3.db') + +conn = sqlite3.connect('custom.sqlite3.db') +conn.text_factory = str + +urls = ( + '/', 'index', + '/add','add', + '/edit','edit', + '/del','del', + '/egg','egg', +) + +render = web.template.render('templates/') + +vform = form.regexp(r".{3,20}$", '资源密码必须是3-20长度的字符串') +vemail = form.regexp(r".*@.*", "必须提供合法的邮件地址") + +add_form = form.Form( + form.Textbox("email",vemail,description="邮件地址"), + form.Textbox("password",vform,description="资源密码"), + form.Textbox("title", description="标题"), + form.Textbox("brief", description="摘要"), + form.Dropdown("category1",args=['电影','剧集','音乐','游戏','动漫','综艺','软件','资料'],value="电影",description="分类"), + form.Textbox("category2",description="子类别"), + form.Textarea("ed2k",value="[格式]\n文件名#地址\n文件名#地址#字幕地址\n",description="资源链接",cols=60,rows=5), + form.Textarea("content",description="资源介绍",cols=60,rows=10), + form.Button("提交", type="submit", description="提交"), +) + +app = web.application(urls, globals()) + +class index: + def GET(self): + i = web.input(id=None,page='1',q=None,download=None,qa=None,cat=None) + hot=open('static/hot.html','r').read() + #显示单个资源 + if i.id: + myvar = dict(id=i.id) + rec = db.select('verycd',vars=myvar,where="verycdid=$id") + for r in rec: + fl = None + if i.download: + links = r['ed2k'].split('`') + links = [ x for x in links if 'ed2k:' in x ] + fl = '
\n'.join(links) + return render.id([r,fl,str(r['verycdid'])]) + return render.error(404) + #显示最新更新的资源 + else: + #深度搜索 + if i.qa: + qa = '+'.join(i.qa.split(' ')) + open(path+'/searchqueue','a').write(qa.encode('utf-8')+'\n') + return render.fin(qa) + #默认情况,不指定分类,没有搜索关键字 + elif (not i.q) and (not i.cat): + vc = db.select('verycd',order='updtime DESC',limit=20,offset=20*(int(i.page)-1)) + num = db.select('verycd',what="count(*) as count")[0].count + arg = '/?page' + #无搜索关键字,指定分类 + elif (not i.q) and (i.cat): + myvar = dict(cat=i.cat) + vc = db.select('verycd',order='updtime DESC',vars=myvar,where='category1=$cat',limit=20,offset=20*(int(i.page)-1)) + num = db.select('verycd',what="count(*) as count",vars=myvar,where='category1=$cat')[0].count + arg = '/?cat='+i.cat+'&page' + #有搜索关键字,指定分类 + elif (i.q) and (i.cat): + qs = i.q.split(' ') + qs = [ 'title like \'%'+x+'%\'' for x in qs ] + where = ' and '.join(qs) + where += ' and category1=\''+i.cat+'\'' + vc = db.select('verycd',order='updtime DESC',limit=20,\ + offset=20*(int(i.page)-1),where=where) + num = db.select('verycd',what="count(*) as count",where=where)[0].count + arg = '/?q='+i.q+'&cat='+i.cat+'&page' + #有搜索关键字,不指定分类 + else: + qs = i.q.split(' ') + qs = [ 'title like \'%'+x+'%\'' for x in qs ] + where = ' and '.join(qs) + vc = db.select('verycd',order='updtime DESC',limit=20,\ + offset=20*(int(i.page)-1),where=where) + num = db.select('verycd',what="count(*) as count",where=where)[0].count + arg = '/?q='+i.q+'&page' + prev = int(i.page)-1 == 0 and '1' or str(int(i.page)-1) + next = int(i.page)+1 <= (num-1)/20+1 and str(int(i.page)+1) or i.page + end = str((num-1)/20+1) + pages = [prev,next,end] + left = min(4,int(i.page)-1) + right = min(4,int(end)-int(i.page)) + if left < 4: + right = min(8-left,int(end)-int(i.page)) + if right < 4: + left = min(8-right,int(i.page)-1) + while left > 0: + pages.append(str(int(i.page)-left)) + left -= 1 + j = 0 + while j <= right: + pages.append(str(int(i.page)+j)) + j += 1 + return render.index([vc,pages,arg,i.q,num,i.cat,hot]) + +class add: + def GET(self): + # do $:f.render() in the template + f = add_form() + return render.add(f) + + def POST(self): + f = add_form() + if not f.validates(): + return render.add(f) + else: + # do whatever is required for registration + now = time.strftime('%Y/%m/%d %H:%M:%S',time.gmtime(time.time()+3600*8)) + c = conn.cursor() + c.execute('insert into custom (title,status,brief,pubtime,updtime,\ + category1,category2,ed2k,content) values(?,?,?,?,?,?,?,?,?)',\ + (f.title.get_value(),'新建',f.brief.get_value(),now,now,\ + f.category1.get_value(),f.category2.get_value(),\ + f.ed2k.get_value(),f.content.get_value())) + c.execute('insert into user (email,password,customid) values (?,?,?)',\ + (f.email.get_value(),f.password.get_value(),c.lastrowid)) + conn.commit() + c.close() + return '...' + +if __name__ == "__main__": + # web.wsgi.runwsgi = lambda func, addr=None: web.wsgi.runfcgi(func, addr) + app.run() diff --git a/daemon.py b/daemon.py new file mode 100644 index 0000000..db3c3a6 --- /dev/null +++ b/daemon.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +import sys, os, time, atexit +from signal import SIGTERM + +class Daemon: + """ + A generic daemon class. + + Usage: subclass the Daemon class and override the run() method + """ + def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): + self.stdin = stdin + self.stdout = stdout + self.stderr = stderr + self.pidfile = pidfile + + def daemonize(self): + """ + do the UNIX double-fork magic, see Stevens' "Advanced + Programming in the UNIX Environment" for details (ISBN 0201563177) + http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 + """ + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError, e: + sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) + sys.exit(1) + + # decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError, e: + sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) + sys.exit(1) + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = file(self.stdin, 'r') + so = file(self.stdout, 'a+') + se = file(self.stderr, 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + + # write pidfile + atexit.register(self.delpid) + pid = str(os.getpid()) + file(self.pidfile,'w+').write("%s\n" % pid) + + def delpid(self): + os.remove(self.pidfile) + + def start(self): + """ + Start the daemon + """ + # Check for a pidfile to see if the daemon already runs + try: + pf = file(self.pidfile,'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if pid: + message = "pidfile %s already exist. Daemon already running?\n" + sys.stderr.write(message % self.pidfile) + sys.exit(1) + + # Start the daemon + self.daemonize() + self.run() + + def stop(self): + """ + Stop the daemon + """ + # Get the pid from the pidfile + try: + pf = file(self.pidfile,'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if not pid: + message = "pidfile %s does not exist. Daemon not running?\n" + sys.stderr.write(message % self.pidfile) + return # not an error in a restart + + # Try killing the daemon process + try: + while 1: + os.kill(pid, SIGTERM) + time.sleep(0.1) + except OSError, err: + err = str(err) + if err.find("No such process") > 0: + if os.path.exists(self.pidfile): + os.remove(self.pidfile) + else: + print str(err) + sys.exit(1) + + def restart(self): + """ + Restart the daemon + """ + self.stop() + self.start() + + def run(self): + """ + You should override this method when you subclass Daemon. It will be called after the process has been + daemonized by start() or restart(). + """ diff --git a/download.py b/download.py new file mode 100644 index 0000000..30af443 --- /dev/null +++ b/download.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# download.py: download with report +# +# author: observer +# email: jingchaohu@gmail.com +# blog: http://obmem.com +# last edit @ 2009.12.23 +import os,sys +import urllib,urllib2,cookielib +import re +from time import time,sleep + +path = os.path.dirname(os.path.realpath(sys.argv[0])) + +islogin = False +isproxy = False + +def useproxy(proxy='http://localhost:3128'): +# proxies = {'http':proxy} +# proxy_support = urllib2.ProxyHandler(proxies) +# opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler) +# urllib2.install_opener(opener) +# global isproxy + isproxy = True + +def login(): + print 'try to login...' +# proxies = {'http':'http://localhost:3128'} +# proxy_support = urllib2.ProxyHandler(proxies) + cookie=cookielib.CookieJar() +# opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie), urllib2.HTTPHandler,proxy_support) + opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie), urllib2.HTTPHandler) + urllib2.install_opener(opener) + + print '...getting login form...' + loginform = urllib2.urlopen('http://secure.verycd.com/signin/*/http://www.verycd.com/').read() + fk = re.compile(r'id="fk" value="(.*)"').findall(loginform)[0] + postdata=urllib.urlencode({'username':'simcdple', + 'password':'simcdple', + 'continueURI':'http://www.verycd.com/', + 'fk':fk, + 'login_submit':'登录', + }) + req = urllib2.Request( + url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/', + data = postdata + ) + req.add_header('User-Agent','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6') + req.add_header('Accept','text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8') + print '...login form submitted' + result = urllib2.urlopen(req).read() + print '...login succeed!' + global islogin + islogin = True + +#functions +def report(blocknum, bs, size, t): + if t == 0: + t = 1 + if size == -1: + print '%10s' % (str(blocknum*bs)) + ' downloaded | Speed =' + '%5.2f' % (bs/t/1024) + 'KB/s' + else: + percent = int(blocknum*bs*100/size) + print '%10s' % (str(blocknum*bs)) + '/' + str(size) + 'downloaded | ' + str(percent) + '% Speed =' + '%5.2f'%(bs/t/1024) + 'KB/s' + +def httpfetch(url, headers={}, reporthook=report, postData=None, report=True, needlogin=False): + ok = False + if (not islogin) and needlogin: + login() + if (not isproxy) and (not islogin): + useproxy() + for _ in range(10): + try: + reqObj = urllib2.Request(url, postData, headers) + fp = urllib2.urlopen(reqObj) + headers = fp.info() + ok = True + break + except: + sleep(1) + continue + + if not ok: + open(path+'/errors','a').write(url+'\n') + return '' + + rawdata = '' + bs = 1024*8 + size = -1 + read = 0 + blocknum = 0 + + if reporthook and report: + if "content-length" in headers: + size = int(headers["Content-Length"]) + reporthook(blocknum, bs, size, 1) + + t0 = time() + while 1: + block = '' + try: + block = fp.read(bs) + except: + open(path+'/errors','a').write(url+'\n') + return '' + if block == "": + print '...',url,'downloaded' + break + rawdata += block + read += len(block) + blocknum += 1 + if reporthook and report: + reporthook(blocknum, bs, size, time()-t0) + t0 = time() + + # raise exception if actual size does not match content-length header + if size >= 0 and read < size: + raise ContentTooShortError("retrieval incomplete: got only %i out " + "of %i bytes" % (read, size), result) + return rawdata + +if __name__ == '__main__': + url = 'http://www.verycd.com/topics/2788317' + + #test it + data = httpfetch(url) + open('down','w').write(data) + diff --git a/feed.py b/feed.py new file mode 100644 index 0000000..4b75440 --- /dev/null +++ b/feed.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# feed.py generate rss feed +# +# author: observer +# email: jingchaohu@gmail.com +# blog: http://obmem.com +# last edit @ 2009.12.22 +import sqlite3 +import time +import os,sys + +def feed(path,conn): + + c=conn.cursor() + + for _ in range(10): + try: + c.execute('select * from verycd order by updtime desc limit 20'); + break + except: + time.sleep(5) + continue + + data = None + + try: + data = c.fetchall() + except: + c.close() + conn.commit() + return + + c.close() + conn.commit() + + pubdate = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()) + + feed = ''' + + + SimpleCD - 最新电驴资源 + +http://www.simplecd.org + +zh-cn\n''' + feed += '%s\n' % pubdate + feed += '%s\n' % pubdate + feed += '''http://blogs.law.harvard.edu/tech/rss +SimpleCD.com +jingchaohu@gmail.com (webmaster) +jingchaohu@gmail.com (webmaster) +4 +''' + + for d in data: + # data:0 1 2 3 4 5 6 7 8 9 + # id ttl status brief pubtime pudtime cat1 cat2 ed2k content + title = d[1] + link = 'http://www.simplecd.org/?id=%s' % d[0] + rss = '摘要信息:'+d[3]+'
\n类别:'+d[6]+'
\n子类别:'+d[7]+'
\n' + rss += d[9] + feed +=''' + + <![CDATA[%s]]> + %s + + %s + observer + +'''% (title,link,rss,pubdate) + + feed +='''
+
''' + return feed + +if __name__ == '__main__': + path = os.path.dirname(os.path.realpath(sys.argv[0])) + conn = sqlite3.connect(path+'/verycd.sqlite3.db') + conn.text_factory = str + print feed(path,conn) diff --git a/fetchvc.py b/fetchvc.py new file mode 100644 index 0000000..a901231 --- /dev/null +++ b/fetchvc.py @@ -0,0 +1,369 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# fetchvc.py fetch resources from verycd +# +# author: observer +# email: jingchaohu@gmail.com +# blog: http://obmem.com +# last edit @ 2009.12.23 +import urllib +import re +import sqlite3 +import time +import os,sys + +from threading import Thread +from Queue import Queue + +from download import httpfetch + +path = os.path.dirname(os.path.realpath(sys.argv[0])) +conn = sqlite3.connect(path+'/verycd.sqlite3.db') +conn.text_factory = str +q = Queue() +MAXC = 8 + +def thread_fetch(): + conn = sqlite3.connect(path+'/verycd.sqlite3.db') + conn.text_factory = str + while True: + topic = q.get() + fetch(topic,conn) + q.task_done() + +def search(keyword,full=True): + '''search verycd, fetch search results''' + + searchlog = path+'/search.log' + open(searchlog,'a').write('\n'+keyword+'\n') + + url = 'http://www.verycd.com/search/folders/'+keyword + print 'fetching search results ...' + res = httpfetch(url) + topics = re.compile(r'/topics/(\d+)',re.DOTALL).findall(res) + topics = set(topics) + links = [] + if full: + links = re.compile(r'/search/folders/(.*?\?start=\d+)',re.DOTALL).findall(res) + print links + print topics + if topics: + for topic in topics: + open(searchlog,'a').write(topic+',') + q.put(topic) + if full and links: + for key in links: + search(key,full=False) + + +def hot(): + ''' read verycd hot res and keep update very day ''' + url = 'http://www.verycd.com/' + print 'fetching homepage ...' + home = httpfetch(url) + hotzone = re.compile(r'热门资源.*?',re.DOTALL).search(home).group() + hot = re.compile(r']*>(《.*?》)[^<]*',re.DOTALL).findall(hotzone) + html = '

每日热门资源

\n' + for topic in hot: + print 'fetching hot topic',topic[0],'...' + q.put(topic[0]) + html += ' %s \n' % topic + open(path+'/static/hot.html','w').write(html) + +def normal(pages): + '''fetch normal res that need login''' + if '-' in pages: + (f,t)=[ int(x) for x in pages.split('-') ] + else: + f = t = int(pages) + for page in range(f,t+1): + url = 'http://www.verycd.com/orz/page%d?stat=normal' % page + idx = httpfetch(url,needlogin=True) + ids = re.compile(r'/topics/(\d+)',re.DOTALL).findall(idx) + print ids[0] + for id in ids: + q.put(id) + +def request(pages): + '''fetch request res that need login''' + if '-' in pages: + (f,t)=[ int(x) for x in pages.split('-') ] + else: + f = t = int(pages) + for page in range(f,t+1): + url = 'http://www.verycd.com/orz/page%d?stat=request' % page + idx = httpfetch(url,needlogin=True) + ids = re.compile(r'/topics/(\d+)',re.DOTALL).findall(idx) + print ids[0] + for id in ids: + q.put(id) + +def feed(): + ''' read verycd feed and keep update very 30 min ''' + url = 'http://www.verycd.com/sto/feed' + print 'fetching feed ...' + feeds = httpfetch(url) + ids = re.compile(r'/topics/(\d+)',re.DOTALL).findall(feeds) + ids = set(ids) + print ids + now = time.mktime(time.gmtime()) + for id in ids: + q.put(id) + #updtime = fetch(id) + #updtime = time.mktime(time.strptime(updtime,'%Y/%m/%d %H:%M:%S'))-8*3600 #gmt+8->gmt + #diff = now - updtime + #print '%10s secs since update' % (diff) + #if diff > 1900: # only need recent 30min updates + # break + +def update(num=10): + urlbase = 'http://www.verycd.com/sto/~all/page' + for i in range(1,num+1): + print 'fetching list',i,'...' + url = urlbase+str(i) + res = httpfetch(url) + res2 = re.compile(r'"topic-list"(.*?)"pnav"',re.DOTALL).findall(res) + if res2: + res2 = res2[0] + else: + continue + topics = re.compile(r'/topics/(\d+)',re.DOTALL).findall(res2) + topics = set(topics) + print topics + for topic in topics: + q.put(topic) + + +def fetchall(ran='1-max',debug=False): + urlbase = 'http://www.verycd.com/archives/' + if ran == '1-max': + m1 = 1 + res = urllib.urlopen(urlbase).read() + m2 = int(re.compile(r'archives/(\d+)').search(res).group(1)) + else: + m = ran.split('-') + m1 = int(m[0]) + m2 = int(m[1]) + print 'fetching list from',m1,'to',m2,'...' + for i in range(m1,m2+1): + url = urlbase + '%05d'%i + '.html' + print 'fetching from',url,'...' + res = httpfetch(url) + ids = re.compile(r'topics/(\d+)/',re.DOTALL).findall(res) + print ids + for id in ids: + q.put(id) + + +def fetch(id,conn=conn,debug=False): + print 'fetching topic',id,'...' + urlbase = 'http://www.verycd.com/topics/' + url = urlbase + str(id) + + res = '' + for _ in range(3): + try: + res = httpfetch(url,report=True) + break + except: + continue + + abstract = re.compile(r'

.*?visit',re.DOTALL).findall(res) + if not abstract: + print res + if res == '' or '很抱歉' in res: + print 'resource does not exist' + return + else: + print 'fetching',id,'again...' + return fetch(id,conn) + abstract = abstract[0] + + title = re.compile(r'

(.*?)

',re.DOTALL).findall(abstract) + if title: + title=title[0] + else: + return + try: + status = re.compile(r'"requestWords">(.*?)<',re.DOTALL).search(abstract).group(1) + brief = re.compile(r'"font-weight:normal">(.*?)',re.DOTALL).search(abstract).group(1) + brief = re.compile(r'<.*?>',re.DOTALL).sub('',brief).strip() + pubtime = re.compile(r'"date-time">(.*?).*?"date-time">(.*?)',re.DOTALL).findall(abstract)[0] + category1 = re.compile(r'分类.*?(.*?)  (.*?)  ',re.DOTALL).findall(abstract)[0] + category = ['',''] + category[0] = re.compile(r'<.*?>',re.DOTALL).sub('',category1[0]).strip() + category[1] = re.compile(r'<.*?>',re.DOTALL).sub('',category1[1]).strip() + +# res2 = re.compile(r'iptcomED2K">',re.DOTALL).findall(res)[0] + + ed2k = re.compile(r'ed2k="([^"]*)" (subtitle_[^=]*="[^"]*"[^>]*)>([^<]*)',re.DOTALL).findall(res) + ed2k.extend( re.compile(r'ed2k="([^"]*)">([^<]*)',re.DOTALL).findall(res) ) + + content = re.compile(r'(.*?)',re.DOTALL).findall(res) + except: + return + + if content: + content = content[0] + content = re.compile(r'
',re.DOTALL).sub('\n',content) + content = re.compile(r'<.*?>',re.DOTALL).sub('',content) + content = re.compile(r'&.*?;',re.DOTALL).sub(' ',content) + content = re.compile(r'\n\s+',re.DOTALL).sub('\n',content) + content = content.strip() + else: + content='' + + if debug: + print title + print status + print brief + print pubtime[0],pubtime[1] + print category[0],category[1] + for x in ed2k: + print x + print content + + ed2kstr = '' + for x in ed2k: + ed2kstr += '`'.join(x)+'`' + tries=0 + while tries<3: + try: + if not dbfind(id,conn): + dbinsert(id,title,status,brief,pubtime,category,ed2kstr,content,conn) + else: + dbupdate(id,title,status,brief,pubtime,category,ed2kstr,content,conn) + break; + except: + tries += 1; + time.sleep(5); + continue; + + return pubtime[1] + +def dbcreate(): + c = conn.cursor() + c.execute('''create table verycd( + verycdid integer primary key, + title text, + status text, + brief text, + pubtime text, + updtime text, + category1 text, + category2 text, + ed2k text, + content text + )''') + conn.commit() + c.close() + +def dbinsert(id,title,status,brief,pubtime,category,ed2k,content,conn): + c = conn.cursor() + tries = 0 + while tries<10: + try: + c.execute('insert into verycd values(?,?,?,?,?,?,?,?,?,?)',\ + (id,title,status,brief,pubtime[0],pubtime[1],category[0],category[1],\ + ed2k,content)) + break + except: + tries += 1 + time.sleep(5) + continue + conn.commit() + c.close() + +def dbupdate(id,title,status,brief,pubtime,category,ed2k,content,conn): + tries = 0 + c = conn.cursor() + while tries<10: + try: + c.execute('update verycd set verycdid=?,title=?,status=?,brief=?,pubtime=?,\ + updtime=?,category1=?,category2=?,ed2k=?,content=? where verycdid=?',\ + (id,title,status,brief,pubtime[0],pubtime[1],category[0],category[1],\ + ed2k,content,id)) + break + except: + tries += 1 + time.sleep(5) + continue + conn.commit() + c.close() + +def dbfind(id,conn): + c = conn.cursor() + c.execute('select 1 from verycd where verycdid=?',(id,)) + c.close() + for x in c: + if 1 in x: + return True + else: + return False + +def dblist(): + c = conn.cursor() + c.execute('select * from verycd') + for x in c: + for y in x: + print y + +def usage(): + print '''Usage: + python fetchvc.py createdb + python fetchvc.py fetchall + python fetchvc.py fetch 1-1611 #fetch archive list + python fetchvc.py fetch 5633~5684 #fetch topics + python fetchvc.py fetch 5633 #fetch a topic + python fetchvc.py fetch q=keyword + python fetchvc.py list #list the database + python fetchvc.py feed #run every 30 min to keep up-to-date + python fetchvc.py hot + python fetchvc.py update #update first 20 pages, run on a daily basis''' + +#initialize thread pool +for i in range(MAXC): + t = Thread(target=thread_fetch) + t.setDaemon(True) + t.start() + +if __name__=='__main__': + + if len(sys.argv) == 1: + usage() + elif len(sys.argv) == 2: + if sys.argv[1] == 'createdb': + dbcreate() + elif sys.argv[1] == 'fetchall': + fetchall() + elif sys.argv[1] == 'update': + update(20) + elif sys.argv[1] == 'update1': + update(1) + elif sys.argv[1] == 'feed': + feed() + elif sys.argv[1] == 'hot': + hot() + elif sys.argv[1] == 'list': + dblist() + elif len(sys.argv) == 3: + if sys.argv[1] != 'fetch': + usage() + elif '~' in sys.argv[2]: + m = sys.argv[2].split('~') + for i in range(int(m[0]),int(m[1])+1): + q.put(i) + elif sys.argv[2].startswith("q="): + search(sys.argv[2][2:]) + elif sys.argv[2].startswith("n="): + normal(sys.argv[2][2:]) + elif sys.argv[2].startswith("r="): + request(sys.argv[2][2:]) + elif '-' in sys.argv[2]: + fetchall(sys.argv[2]) + else: + fetch(int(sys.argv[2]),debug=True) + + # wait all threads done + q.join() diff --git a/login.py b/login.py new file mode 100644 index 0000000..591ab06 --- /dev/null +++ b/login.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# sample +import urllib,urllib2,cookielib +import re + +cookie=cookielib.CookieJar() +opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie), urllib2.HTTPHandler) +urllib2.install_opener(opener) + +loginform = urllib2.urlopen('http://secure.verycd.com/signin/*/http://www.verycd.com/').read() + +#print loginform +fk = re.compile(r'id="fk" value="(.*)"').findall(loginform)[0] +print fk; +postdata=urllib.urlencode({'username':'simcdple', + 'password':'simcdple', + 'continueURI':'http://www.verycd.com/', + 'fk':fk, + 'login_submit':'登录', +}) +req = urllib2.Request( + url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/', + data = postdata +) +req.add_header('User-Agent','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6') +req.add_header('Accept','text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8') +result = urllib2.urlopen(req).read() +#print result +#print result.status +newatt = urllib2.urlopen('http://www.verycd.com/topics/2788317/').read() +print newatt diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..2dbe1ec --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,56 @@ +user www-data; +worker_processes 2; + +error_log /var/log/nginx/error.log; +pid /var/run/nginx.pid; + +events { + worker_connections 2048; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + autoindex on; + autoindex_exact_size off; + autoindex_localtime on; + + log_format main '$remote_addr - $remote_user [$time_local] ' + '"$request" $status $bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '"$gzip_ratio"'; + + log_format download '$remote_addr - $remote_user [$time_local] ' + '"$request" $status $bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '"$http_range" "$sent_http_content_range"'; + + client_header_timeout 3m; + client_body_timeout 3m; + send_timeout 3m; + + client_header_buffer_size 1k; + large_client_header_buffers 4 4k; + + gzip on; + gzip_min_length 1k; + gzip_buffers 4 8k; + gzip_http_version 1.1; + gzip_comp_level 3; + gzip_types text/css text/xml text/plain application/x-javascript application/xml application/pdf application/x-perl application/x-tcl application/msword application/rtf application/vnd.ms-excel application/vnd.ms-powerpoint application/vnd.wap.xhtml+xml image/x-ms-bmp; + gzip_disable "MSIE [1-6] \."; + gzip_vary on; + + output_buffers 1 32k; + postpone_output 1460; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 75 20; + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} diff --git a/nginx/simplecd b/nginx/simplecd new file mode 100644 index 0000000..55448f2 --- /dev/null +++ b/nginx/simplecd @@ -0,0 +1,28 @@ +# You may add here your +# server { +# ... +fastcgi_cache_path /var/www/simplecd/cache + levels=1:2 keys_zone=webpy:50m; +server { + listen 80; + server_name xen.simplecd.org; + access_log /var/log/nginx/xen.simplecd.org.access_log; + error_log /var/log/nginx/xen.simplecd.org.error_log warn; + root /var/www/simplecd/; + index index.html; + location / { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_script_name; + fastcgi_pass 127.0.0.1:9001; + fastcgi_cache webpy; + fastcgi_cache_key $server_addr$request_uri; + fastcgi_cache_valid any 1m; + fastcgi_hide_header Set-Cookie; + } + location /static/ { + if (-f $request_filename) { + rewrite ^/static/(.*)$ /static/$1 break; + } + } +} diff --git a/nginx/spawn-fcgi.sh b/nginx/spawn-fcgi.sh new file mode 100644 index 0000000..b517162 --- /dev/null +++ b/nginx/spawn-fcgi.sh @@ -0,0 +1,2 @@ +spawn-fcgi -u www-data -g www-data -d /var/www/simplecd/ -f /var/www/simplecd/code.py -a 127.0.0.1 -p 9001 -F 2 + diff --git a/pack.py b/pack.py new file mode 100644 index 0000000..43ff567 --- /dev/null +++ b/pack.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# pack.py generate html pack +# author: observer +# email: jingchaohu@gmail.com +# blog: http://obmem.com +# last edit @ 2009.12.23 +import urllib +import re +import sqlite3 +import time +import os,sys +import shutil + +path = os.path.dirname(os.path.realpath(sys.argv[0])) +conn = sqlite3.connect(path+'/verycd.sqlite3.db') +conn.text_factory = str + +def pack(topath="/tmp/simplecd_htmlpack"): + try: + os.mkdir(topath) + except: + pass + shutil.copyfile(path+'/static/main_02.css',topath+'/main_02.css') + shutil.copyfile(path+'/static/common.js',topath+'/common.js') + c = conn.cursor() + c.execute("select verycdid from verycd order by updtime asc") + ids = c.fetchall() + baseurl = 'http://www.simplecd.org/?id=' + for id in ids: + url = baseurl + str(id[0]) + html = urllib.urlopen(url).read() + html.replace('/static/main_02.css','main_02.css') + html.replace('/static/common.js','common.js') + fname = str(id[0])+'.html' + open(topath+'/'+fname,'w').write(html) + c.close() + +if __name__ == '__main__': + pack() diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..32b9c2c --- /dev/null +++ b/readme.txt @@ -0,0 +1,28 @@ +https://code.google.com/p/simplecd/wiki/Deployment + +3. 简易架设攻略 +下载源码 + +cd /var/www +hg clone https://simplecd.googlecode.com/hg simplecd +cd simplecd +hg update dev-sqlite +注:分支建议采用dev-sqlite,这个和目前网站的代码最为相似 + +deployment分支继续不变,因为deployment分支代码简单看起来爽一点。 + +接下来做一些基本的配置 + +#创建数据库 +./fetchvc.py createdb + +#nginx的配置文件(请根据视频进行相应修改) +cp nginx/nginx.conf /etc/nginx/ +cp nginx/simplecd /etc/nginx/sites-available/ +ln -s /etc/nginx/sites-available/simplecd /etc/nginx/sites-enabled/simplecd + +#用spawn-fcgi开fcgi +nginx/spawn-fcgi.sh + +#开启nginx服务 +/etc/init.d/nginx start diff --git a/scdd.py b/scdd.py new file mode 100644 index 0000000..5e55032 --- /dev/null +++ b/scdd.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +#coding: utf-8 +# +# scdd.py daemon process +# +# author: observer +# email: jingchaohu@gmail.com +# blog: http://obmem.com +# last edit @ 2009.12.23 +import os,sys,time +import re +from daemon import Daemon +import sqlite3 +import fetchvc +from download import httpfetch +from Queue import Queue +from threading import Thread +from feed import feed + +class MyDaemon(Daemon): + def __init__(self,path,pid): + self.path = path + self.q = Queue() + Daemon.__init__(self,pid) + + def thread_fetch(self): + conn = sqlite3.connect(self.path+'/verycd.sqlite3.db') + conn.text_factory = str + while True: + topic = self.q.get() + if str(topic)=='feed': + open(self.path+'/static/feed.xml','w').write(feed(self.path,conn)) + self.q.task_done() + continue + try: + fetchvc.fetch(topic,conn) + except: + pass + self.q.task_done() + + def run(self): + for i in range(8): + t = Thread(target=self.thread_fetch) + t.setDaemon(True) + t.start() + + conn = sqlite3.connect(self.path+'/verycd.sqlite3.db') + conn.text_factory = str + while True: + try: + #feed + if time.mktime(time.gmtime())%60<10: + self.q.put('feed') + #check searchqueue every 10 secs + taskqueue = open(self.path+'/searchqueue','r').readlines() + print taskqueue,time.mktime(time.gmtime()),time.mktime(time.gmtime())%900 + open(self.path+'/searchqueue','w').write('') + for task in taskqueue: + url = 'http://www.verycd.com/search/folders/'+task + print 'fetching', url, '...' + res = httpfetch(url) + print '...fetching completed' + topics = re.compile(r'/topics/(\d+)',re.DOTALL).findall(res) + topics = set(topics) + for topic in topics: + self.q.put(topic) + if taskqueue == []: + time.sleep(10) + # read feed every 900 secs + if time.mktime(time.gmtime())%600<10: + url = 'http://www.verycd.com/sto/feed' + print 'fetching feed ...' + feeds = httpfetch(url) + topics = re.compile(r'/topics/(\d+)',re.DOTALL).findall(feeds) + topics = set(topics) + print topics + now = time.mktime(time.gmtime()) + for topic in topics: + self.q.put(topic) + # read hot everyday at gmt 19:00 + # read hot every 4 hours + timeofday = time.mktime(time.gmtime())%(86400/6) +# if timeofday>68400 and timeofday < 68410: + if time.mktime(time.gmtime())%(3600*4)<10: + url = 'http://www.verycd.com/' + print 'fetching homepage ...' + home = httpfetch(url) + hotzone = re.compile(r'热门资源.*?',re.DOTALL).search(home).group() + hot = re.compile(r']*>(《.*?》)[^<]*',re.DOTALL).findall(hotzone) + html = '

每日热门资源

\n' + for topic in hot: + print 'fetching hot topic',topic[0],'...' + self.q.put(topic[0]) + html += ' %s \n' % topic + open(self.path+'/static/hot.html','w').write(html) + # update 20 whole pages at gmt 19:10 + if timeofday>69000 and timeofday < 69010: + urlbase = 'http://www.verycd.com/sto/~all/page' + for i in range(1,20): + print 'fetching list',i,'...' + url = urlbase+str(i) + res = httpfetch(url) + res2 = re.compile(r'"topic-list"(.*?)"pnav"',re.DOTALL).findall(res) + if res2: + res2 = res2[0] + else: + continue + topics = re.compile(r'/topics/(\d+)',re.DOTALL).findall(res2) + topics = set(topics) + print topics + for topic in topics: + self.q.put(topic) + # update 1 pages@normal and 1 pages@request every 3600 secs + if time.mktime(time.gmtime())%3600<10: + url = 'http://www.verycd.com/orz/page1?stat=normal' + idx = httpfetch(url,needlogin=True) + ids = re.compile(r'/topics/(\d+)',re.DOTALL).findall(idx) + print ids[0] + for id in ids: + self.q.put(id) + url = 'http://www.verycd.com/orz/page1?stat=request' + idx = httpfetch(url,needlogin=True) + ids = re.compile(r'/topics/(\d+)',re.DOTALL).findall(idx) + print ids[0] + for id in ids: + self.q.put(id) + except: + time.sleep(10) + continue + + +if __name__ == "__main__": + path = os.path.dirname(os.path.realpath(sys.argv[0])) + daemon = MyDaemon(path=path,pid='/tmp/simplevc.pid') + if len(sys.argv) == 2: + if 'start' == sys.argv[1]: + daemon.start() + elif 'stop' == sys.argv[1]: + daemon.stop() + elif 'restart' == sys.argv[1]: + daemon.restart() + elif 'run' == sys.argv[1]: + daemon.run() + else: + print "Unknown command" + sys.exit(2) + sys.exit(0) + else: + print "usage: %s start|stop|restart" % sys.argv[0] + sys.exit(2) diff --git a/searchqueue b/searchqueue new file mode 100644 index 0000000..e69de29 diff --git a/static/about.html b/static/about.html new file mode 100644 index 0000000..aa4d051 --- /dev/null +++ b/static/about.html @@ -0,0 +1,15 @@ + + + + 关于SimpleCD + + +

关于SimpleCD

+

由于最近某国内耗剧烈,殃及了池鱼,大量BT站点被关,消息人士认为这一切是因为我们知道的太多了,最后连VeryCD都无法访问了,稍后虽然证实是虚惊一场,但是本人兴起了为VeryCD备份的念头,以防其再遭不测。这就是本站诞生的由来。

+

VeryCD倒掉之前的那段时间里,有先见之明的人士为其做了部分镜像来缅怀VeryCD,但是杯水车薪,75M的镜像只保留了大约100个链接,而且搜索功能什么的都是无法保存的

+

VeryCD恢复之后,我试着用wget和httrack工具为其备份,但是效果一般,而且也有无法搜索的问题。如此,下一步的改进计划出炉:用爬虫脚本爬VeryCD的资料,然后保存到数据库,根据数据库建站,于是就是本站目前的状况。

+

本站目前还处于开发和调试阶段,VeryCD的访问相当缓慢,所以爬虫脚本仍在努力地工作中,等到一切稳定下来以后,本站将会开源。

+

关于本人

+

土人一个,经营Blog一只(一直懒得调整Wordpress主题和RSSFeed,导致现在不伦不类的。),欢迎来踩。

+ + diff --git a/static/common.js b/static/common.js new file mode 100644 index 0000000..af4a565 --- /dev/null +++ b/static/common.js @@ -0,0 +1,236 @@ +function init(str){ + checkAll(str,true); +} +function checkAll(str,checked) { + var a = document.getElementsByName(str); + var n = a.length; + + for (var i = 0; i < n; i++) { + a[i].checked = checked; + } + em_size(str); +} +function em_size(str) { + var a = document.getElementsByName(str); +// var b = document.getElementsByName(str+"size"); + var n = a.length; + try { + var input_checkall = document.getElementById("checkall_"+str); + var size = 0; + input_checkall.checked = true ; + for (var i=0; i < n; i++) { + if (a[i].checked) { + var piecesArray = a[i].value.split( "|" ); +// b[i].innerHTML = gen_size(piecesArray[3]*1,3,1); + size += piecesArray[3]*1; + } else { + input_checkall.checked = false; + } + } + test = document.getElementById("size_"+str); + test.innerHTML = gen_size(size, 3, 1); + } catch (e) { + + } +} +function gen_size(val, li, sepa ) { + if (parseInt(val)<1) return 0; + sep = Math.pow(10, sepa); //小数点后的位数 + li = Math.pow(10, li); //开始截断的长度 + retval = val; + unit = 'Bytes'; + if (val >= li*1000000000) { + val = Math.round( val / (1099511627776/sep) ) / sep; + unit = 'TB'; + } else if (val >= li*1000000) { + val = Math.round( val / (1073741824/sep) ) / sep; + unit = 'GB'; + } else if (val >= li*1000) { + val = Math.round( val / (1048576/sep) ) / sep; + unit = 'MB'; + } else if (val >= li) { + val = Math.round( val / (1024/sep) ) / sep; + unit = 'KB'; + } + return val + unit; +} +function copy(str) { + var a = document.getElementsByName(str); + var n = a.length; + var ed2kcopy = ""; + for (var i = 0; i < n; i++) { + if(a[i].checked) { + ed2kcopy += a[i].value; + ed2kcopy += "\n"; + } + } + copyToClipboard(ed2kcopy); +} +function countlink(str){ + var r = 0; + a = document.getElementsByName(str); + n = a.length; + for ( var i = 0; i < n; i++ ){ + if ( a[i].checked) { + r += 1; + } + } + return r; +} +function copy2popup(str){ + var a = document.getElementsByName(str); + var n = a.length; + var ed2kcopy = ""; + for (var i = 0;i < n; i++) { + if (a[i].checked) { + ed2kcopy += a[i].value; + ed2kcopy += "
\n"; + } + } + return ed2kcopy; +} +function copyToClipboard(txt) { + if(window.clipboardData) { + window.clipboardData.clearData(); + window.clipboardData.setData("Text", txt); + } else if(navigator.userAgent.indexOf("Opera") != -1) { + window.location = txt; + } else if (window.netscape) { + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch (e) { + alert("被浏览器拒绝!\n请在浏览器地址栏输入'about:config'并回车\n然后将'signed.applets.codebase_principal_support'设置为'true'"); + } + var clip = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance(Components.interfaces.nsIClipboard); + if (!clip) + return; + var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable); + if (!trans) + return; + trans.addDataFlavor('text/unicode'); + var str = new Object(); + var len = new Object(); + var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString); + var copytext = txt; + str.data = copytext; + trans.setTransferData("text/unicode",str,copytext.length*2); + var clipid = Components.interfaces.nsIClipboard; + if (!clip) + return false; + clip.setData(trans,null,clipid.kGlobalClipboard); + } +} +function download(str, i, first) { + var a = document.getElementsByName(str); + var n = a.length; + + //尝试使用activex方式批量新增下载 + try { + var ed2k_links = ''; + var ax = new ActiveXObject("IE2EM.IE2EMUrlTaker"); + var emule_version = ax.GetEmuleVersion(); + if ('e' != emule_version.substr(0,1)) { + throw {errorCode:'eMule not Installed.'}; + } + for (var i = i; i < n; i++) { + if(a[i].checked) { + if (ed2k_links=='') { + ed2k_links = a[i].value; + } else { + ed2k_links += "\n"+a[i].value; + } + } + } + ax.SendUrl(ed2k_links, 'dd', document.location); + delete ax; + return; + } catch (e) {} + + if (!window.continueDown) { + //使用最旧的方法来批量新增下载 + for (var i = i; i < n; i++) { + if(a[i].checked) { + window.location=a[i].value; + if (first) + timeout = 6000; + else + timeout = 500; + i++; + window.setTimeout("download('"+str+"', "+i+", 0)", timeout); + break; + } + } + } else { + //使用稍微新一点的方法来批量新增下载 + for (var i = i; i < n; i++) { + if(a[i].checked) { + if(first){ + var k = i; + var current_link = a[k].nextSibling; + var multi_text = ''; + var tmp_counter = 0; + var comma = ''; + while(true){ + if(a[k].checked && current_link){//如果是有效节点并且被选中 + if(current_link.href){ + if(current_link.href.indexOf('ed2k') !== 0){ + current_link = current_link.nextSibling; + continue; + } + if(tmp_counter > 7){//收集超过若干个有效链接后,退出 + multi_text += '
…………'; + break; + } + var right_link = current_link; + tmp_counter++; + if (navigator.userAgent.toLowerCase().indexOf("msie")==-1) { + multi_text += comma+current_link.text; + }else{ + multi_text += comma+current_link.innerText; + } + comma = '
'; + } + + current_link = current_link.nextSibling; + }else{//未被选中,或往下没有相邻节点了,那么切换到下个父节点 + if(++k >= n){//如果父节点也到底了,那么退出 + break; + } + current_link = a[k].nextSibling; + } + } + downPopup(right_link,multi_text); + } + + continueDown(a[i].value); + //window.location=a[i].value; + if (first) + timeout = 6000; + else + timeout = 500; + i++; + window.setTimeout("download('"+str+"', "+i+", 0)", timeout); + break; + } + } + } +} +function showPopup(txt,t,l,w,h){ + var popUp = document.getElementById("popupcontent"); + + popUp.style.top = t + "px"; + popUp.style.left = l + "px"; + popUp.style.width = w + "px"; + popUp.style.height = h + "px"; + + popUp.innerHTML = txt;// + +//"
"; + +// var sbar = document.getElementById("statusbar"); +// sbar.style.marginTop = (parseInt(h)-40) + "px"; + popUp.style.visibility = "visible"; +} +function hidePopup(){ + var popUp = document.getElementById("popupcontent"); + popUp.style.visibility = "hidden"; +} diff --git a/static/hot.html b/static/hot.html new file mode 100644 index 0000000..3b531f1 --- /dev/null +++ b/static/hot.html @@ -0,0 +1,25 @@ +

每日热门资源

《未来战警》  + 《YYeTs人人影视2009年12月RMVB电影合辑》  + 《海豚湾》  + 《无主之地:内德博士的僵尸岛》  + 《拆弹部队》  + 《2012》  + 《2009年北美上映电影预告片合辑(按上映时间及时更新)-更新至2009年第51周(2009.12.18)》  + 《复仇》  + 《萨莉娜》  + 《别对我撒谎 第二季》  + 《虎!虎!虎!》  + 《灌篮高手十日后画册》  + 《野兽家园》  + 《下一站./幸福》  + 《余烬清风》  + 《生活大爆炸 第三季》  + 《疲惫不堪的生活》  + 《蜗居》  + 《深空失忆》  + 《三教九流大观》  + 《山楂树之恋》  + 《极度恐慌2:重生》  + 《同门》  + 《计算理论书籍合集》  diff --git a/static/main_02.css b/static/main_02.css new file mode 100644 index 0000000..4020e79 --- /dev/null +++ b/static/main_02.css @@ -0,0 +1,44 @@ +td {font-size:10pt; line-height:180%;} +.xt{font-size:10pt;line-height:180%; border-bottom:1px #bbbbbb dashed;font-family:"", "arial", "ms sans serif";} +.bt{font-size:10pt;line-height:180%; border-bottom:1px #bbbbbb solid;font-family:"", "arial", "ms sans serif";} +.inp{font-size:11.5pt; height: 28px;} +a:link {color: blue; text-decoration: none } +a:active {color: blue; text-decoration: underline} +a:visited {color: #c04dc0; text-decoration: none} +a:hover {color: blue; text-decoration: underline;position:relative;left:1px;top:1px} +a.cat:link {color: red; text-decoration: none } +a.cat:active {color: red; text-decoration: none} +a.cat:visited {color: red; text-decoration: none} +a.cat:hover {color: blue; text-decoration: underline;position:relative;left:1px;top:1px} +a.tt:link {color: black; text-decoration: none} +a.tt:active {color: blue; text-decoration: underline} +a.tt:visited {color: black; text-decoration: none;} +a.tt:hover {color: blue; text-decoration: underline;position:relative;left:1px;top:1px} +a.bl:link {color: blue; text-decoration: none} +a.bl:active {color: red; text-decoration: none} +a.bl:visited {color: blue; text-decoration: none} +a.bl:hover {color: red; text-decoration: underline;position:relative;left:1px;top:1px} +a.tl:link {color: #123b8d; text-decoration: none} +a.tl:active {color: blue; text-decoration: none} +a.tl:visited {color: #123b8d; text-decoration: none} +a.tl:hover {color: blue; text-decoration: underline;position:relative;left:1px;top:1px} +body {margin-top:0px;margin-right:0px;margin-bottom:0px;} +h1 {font-size:22px;line-height:180%;margin:0px;padding: 0px;color: #cc0000;} +p {font-size:10.5pt;line-height:180%;} +input{font-size:11.5pt;height:25px;} +div,form,img,ul,li,img{margin:0; padding:0; border:0;} +table{background-color:#ffffff;} .ed2kzone{background-color: #9FaFbF;border: 1px solid #CCC;} +.ed2ktitle{background:#AAA;color:#FFFFFF;font-weight:bold;} +.ed2ktitle a{color:#888;} +.ed2kheader{background:#c0d0e0;color:#000000} +.ed2kitem{background-color: #FFFFFF;} +.ed2kitemChecked{background-color: #FFFFCC;} +#popupcontent{ +position: relative; +visibility: hidden; +border:1px solid #CCC; +background-color:#F9F9F9; +border:1px solid #333; +padding:5px; +overflow:scroll; +} diff --git a/static/simplecd.png b/static/simplecd.png new file mode 100644 index 0000000000000000000000000000000000000000..841d6500445c7548123a6fc2a5af61f1ff5b732e GIT binary patch literal 3231 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 R?9c!J002ovPDHLkV1hPq +$err 出错啦 + diff --git a/templates/fin.html b/templates/fin.html new file mode 100644 index 0000000..02061cf --- /dev/null +++ b/templates/fin.html @@ -0,0 +1,42 @@ +$def with (req) + + + SimpleCD|精简版的VeryCD + + + + + + + + + + + + +
+ 怕了国内那些大爷了,所以为VeryCD做了个简单备份
+ +
+ + + + +
+

搜索"$req"已经提交队列,请等待服务器处理,如果空闲的话,5分钟左右就能处理好,请5分钟以后再次搜索同一关键字,说不定就有了。本页面将在十五秒钟之后自动跳转回主页,或者点此直接返回主页

+
+ + + diff --git a/templates/id.html b/templates/id.html new file mode 100644 index 0000000..8539331 --- /dev/null +++ b/templates/id.html @@ -0,0 +1,114 @@ +$def with (r) + +$code: + rec = r[0] + fl = r[1] + id = r[2] + name = 'topic'+id + + def emsize(link): + if len(link.split('|'))<4: + return 'Unknown'; + n = int(link.split('|')[3]) + if n < 1024: + return '%d Bytes' % n + elif n < 1024*1024: + n2 = n/1.0/1024 + return '%3.1f KB' % n2 + elif n < 1024*1024*1024: + n2 = n/1.0/1024/1024 + return '%3.1f MB' % n2 + elif n < 1024*1024*1024*1024: + n2 = n/1.0/1024/1024/1024 + return '%3.1f GB' % n2 + def format(content): + return content.replace('\n','
') + def emlink(ed2k): + links = ed2k.split('`') + rtn = ''' + + + + ''' + + i = 0 + while i+1 < len(links): + if links[i].startswith('ed2k') and 'ed2k://' in links[i+1]: + rtn += ''' + + + \n''' % (links[i],name,links[i],links[i],links[i+2],name,emsize(links[i])) + i += 3 + else: + rtn += ''' + + + ''' % (links[i],name,links[i],links[i],links[i+1],name,emsize(links[i])) + i += 2 + rtn += ''' + +
'''+'下面是用户共享的文件列表,推荐使用'.decode('utf-8')+'''eMule '''+'进行下载,您可以点击这些文件名进行下载'.decode('utf-8')+'''
%s%s
%s%s
''' % name + return rtn + + + + SimpleCD:让分享变得简单 $rec.title + + + + + + + +$if fl: +

复制下列链接,在emule中选择新建任务即可

+ $:fl +$else: + +
+ + +
+ +   + +
+ + + + + + + + + +
VeryCD Topic ID: $:rec.verycdid
$:rec.title | from VeryCD
状态:$:rec.status
摘要:$:rec.brief
发布时间:$:rec.pubtime
更新时间:$:rec.updtime
类别:$:rec.category1,$:rec.category2
+ $:emlink(rec.ed2k) +
This is a popup window!
+
+ + +
$:format(rec.content)
+
+ +
+ + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..3c86204 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,121 @@ +$def with (vcp) +$code + vc=vcp[0] + pages=vcp[1] + arg=vcp[2] + if vcp[3] == None: + q='' + else: + q=vcp[3] + num=vcp[4] + if vcp[5]: + cat=vcp[5] + else: + cat='' + hot = vcp[6] + + + + SimpleCD|精简版的VeryCD + + + + + + + + + +
+ 本站源码 |  + 全站html打包下载 |  + 论坛 |  + 订阅更新 |  + 报告错误 |  + 关于 +
+ + + +
+ 怕了国内那些大爷了,所以为VeryCD做了个简单备份 
+ +
+ $if q == '': + + +
+ $:hot +
+ + +
+ 分类: + $if cat=='': + 全部 + $if cat=='': + $for catname in ['电影','剧集','音乐','游戏','动漫','综艺','软件','资料']: + $if cat==catname.decode('utf-8'): + $catname + $if cat==catname.decode('utf-8'): +
+ + + + + + + + $for r in vc: + + + + + + +
   最近更新的资源摘要更新时间VeryCD原链
$:r.title$:r.brief$:r.updtimeTopic$r.verycdid
+ + + + +
+ + 首页 + 上一页 + $for p in pages[3:]: + $p + 下一页 + 末页 + +
+ $if q != '' and num<=5: + + + + + +
+ 对搜索结果不满意?VeryCD上有更多结果?试试 + + +
+ + +