]> git.pld-linux.org Git - packages/pynapi.git/blob - pynapi.py
- rel 5; correct condition
[packages/pynapi.git] / pynapi.py
1 #!/usr/bin/python
2 # -*- coding: UTF-8 -*-
3 #
4 #  Copyright (C) 2009 Arkadiusz Miƛkiewicz <arekm@pld-linux.org>
5 #
6 #  This program is free software: you can redistribute it and/or modify
7 #  it under the terms of the GNU General Public License as published by
8 #  the Free Software Foundation, either version 3 of the License, or
9 #  (at your option) any later version.
10 #
11 #  This program is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #  GNU General Public License for more details.
15 #
16 #  You should have received a copy of the GNU General Public License
17 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19 # napiprojekt.pl API is used with napiproject administration consent
20 # (given by Marek <kontakt@napiprojekt.pl> at Wed, 24 Feb 2010 14:43:00 +0100)
21
22 import re
23 import sys
24 import mimetypes
25 import urllib2
26 import time
27 import os
28 import getopt
29
30 try:
31     from hashlib import md5 as md5
32 except ImportError:
33     from md5 import md5
34
35 prog = os.path.basename(sys.argv[0])
36
37 video_files = [ 'asf', 'avi', 'divx', 'm2ts', 'mkv', 'mp4', 'mpeg', 'mpg', 'ogm', 'rm', 'rmvb', 'wmv' ]
38 languages = { 'pl': 'PL', 'en': 'ENG' }
39
40 def f(z):
41     idx = [ 0xe, 0x3,  0x6, 0x8, 0x2 ]
42     mul = [   2,   2,    5,   4,   3 ]
43     add = [   0, 0xd, 0x10, 0xb, 0x5 ]
44
45     b = []
46     for i in xrange(len(idx)):
47         a = add[i]
48         m = mul[i]
49         i = idx[i]
50
51         t = a + int(z[i], 16)
52         v = int(z[t:t+2], 16)
53         b.append( ("%x" % (v*m))[-1] )
54
55     return ''.join(b)
56
57 def usage():
58     print >> sys.stderr, "Usage: %s [OPTIONS]... [FILE|DIR]..." % prog
59     print >> sys.stderr, "Find video files and download matching subtitles from napiprojekt server."
60     print >> sys.stderr
61     print >> sys.stderr, "Supported options:"
62     print >> sys.stderr, "     -h, --help            display this help and exit"
63     print >> sys.stderr, "     -l, --lang=LANG       subtitles language"
64     print >> sys.stderr, "     -n, --nobackup        make no subtitle backup when in update mode"
65     print >> sys.stderr, "     -c, --nocover         do not download cover images"
66     print >> sys.stderr, "     -u, --update          fetch new and also update existing subtitles"
67     print >> sys.stderr, "     -d, --dest=DIR        destination directory"
68     print >> sys.stderr
69     print >> sys.stderr, "pynapi $Revision$"
70     print >> sys.stderr
71     print >> sys.stderr, "Report bugs to <arekm@pld-linux.org>."
72
73 def get_desc_links(digest, file=None):
74     # improve me
75     re_link = re.compile(r'<a.*?href=[\'"](http://.*?)[ >\'"]', re.IGNORECASE)
76     d = ""
77
78     try:
79         url = "http://www.napiprojekt.pl/index.php3?www=opis.php3&id=%s&film=%s" % (urllib2.quote(digest), urllib2.quote(file))
80         f = urllib2.urlopen(url)
81         d = f.read()
82         f.close()
83     except Exception, e:
84         return False
85     links = re_link.findall(d)
86     ignore = [ r'.*napiprojekt\.pl.*', r'.*nokaut\.pl.*', r'.*rodisite\.com.*' ]
87     for i in range(0, len(ignore)):
88         ignore[i] = re.compile(ignore[i], re.IGNORECASE)
89     ilinks = links[:]
90     for l in ilinks:
91         for i in ignore:
92             if i.match(l):
93                 links.remove(l)
94     return links
95
96 def get_cover(digest):
97     cover = ""
98     try:
99         url = "http://www.napiprojekt.pl/okladka_pobierz.php?id=%s&oceny=-1" % (urllib2.quote(digest))
100         f = urllib2.urlopen(url)
101         cover = f.read()
102         f.close()
103         content_type = f.info()['Content-Type']
104         extension = mimetypes.guess_all_extensions(content_type)[-1]
105     except Exception, e:
106         return False
107     return (cover, extension)
108
109 def calculate_digest(file):
110     d = md5()
111     try:
112         d.update(open(file, "rb").read(10485760))
113     except (IOError, OSError), e:
114         raise Exception('Hashing video file failed: %s' % ( e ))
115     return d.hexdigest()
116
117 def get_subtitle(digest, lang="PL"):
118     url = "http://napiprojekt.pl/unit_napisy/dl.php?l=%s&f=%s&t=%s&v=pynapi&kolejka=false&nick=&pass=&napios=%s" % \
119         (lang, digest, f(digest), os.name)
120     repeat = 3
121     sub = None
122     http_code = 200
123     error = "Fetching subtitle failed:"
124     while repeat > 0:
125         repeat = repeat - 1
126         try:
127             sub = urllib2.urlopen(url)
128             if hasattr(sub, 'getcode'):
129                 http_code = sub.getcode() 
130             sub = sub.read()
131         except (IOError, OSError), e:
132             error = error + " %s" % (e)
133             time.sleep(0.5)
134             continue
135     
136         if http_code != 200:
137             error = error + ",HTTP code: %s" % (str(http_code))
138             time.sleep(0.5)
139             continue
140    
141         err_add = ''
142         if not sub.startswith('NPc'):
143             err_add = " (unknown error)"
144         if len(sub.split('\n')) < 20:
145             raise Exception('Subtitle NOT FOUND%s' % err_add)
146             
147         repeat = 0
148
149     if sub is None or sub == "":
150         raise Exception(error)
151
152     return sub
153
154 def main(argv=sys.argv):
155
156     try:
157         opts, args = getopt.getopt(argv[1:], "d:hl:nuc", ["dest", "help", "lang", "nobackup", "update", "nocover"])
158     except getopt.GetoptError, err:
159         print str(err)
160         usage()
161         return 2
162
163     output = None
164     verbose = False
165     nobackup = False
166     nocover = False
167     update = False
168     lang = 'pl'
169     dest = None
170     for o, a in opts:
171         if o == "-v":
172             verbose = True
173         elif o in ("-h", "--help"):
174             usage()
175             return 0
176         elif o in ("-l", "--lang"):
177             if a in languages:
178                 lang = a
179             else:
180                 print >> sys.stderr, "%s: unsupported language `%s'. Supported languages: %s" % (prog, a, str(languages.keys()))
181                 return 1
182         elif o in ("-n", "--nobackup"):
183             nobackup = True
184         elif o in ("-u", "--update"):
185             update = True
186         elif o in ("-c", "--nocover"):
187             nocover = True
188         elif o in ("-d", "--dest"):
189             dest = a
190         else:
191             print >> sys.stderr, "%s: unhandled option" % prog
192             return 1
193
194     if not args:
195         usage()
196         return 2
197
198     print >> sys.stderr, "%s: Subtitles language `%s'. Finding video files..." % (prog, lang)
199
200     files = []
201     for arg in args:
202         if os.path.isdir(arg):
203             for dirpath, dirnames, filenames in os.walk(arg, topdown=False):
204                 for file in filenames:
205                     if file[-4:-3] == '.' and file.lower()[-3:] in video_files:
206                         files.append(os.path.join(dirpath, file))
207         else:
208             files.append(arg)
209
210     files.sort()
211
212     i_total = len(files)
213     i = 0
214
215     for file in files:
216         i += 1
217
218         vfile = file + '.txt'
219         basefile = file
220         if len(file) > 4:
221             basefile = file[:-4]
222             vfile = basefile + '.txt'
223         if dest:
224             vfile = os.path.join(dest, os.path.split(vfile)[1])
225
226         if not update and os.path.exists(vfile):
227             continue
228
229         if not nobackup and os.path.exists(vfile):
230             vfile_bak = vfile + '-bak'
231             try:
232                 os.rename(vfile, vfile_bak)
233             except (IOError, OSError), e:
234                 print >> sys.stderr, "%s: Skipping due to backup of `%s' as `%s' failure: %s" % (prog, vfile, vfile_bak, e)
235                 continue
236             else:
237                 print >> sys.stderr, "%s: Old subtitle backed up as `%s'" % (prog, vfile_bak)
238
239         print >> sys.stderr, "%s: %d/%d: Processing subtitle for %s" % (prog, i, i_total, file)
240
241         try:
242             digest = calculate_digest(file)
243             sub = get_subtitle(digest, languages[lang])
244         except:
245             print >> sys.stderr, "%s: %d/%d: %s" % (prog, i, i_total, sys.exc_info()[1])
246             continue
247
248         fp = open(vfile, 'wb')
249         fp.write(sub)
250         fp.close()
251     
252         desc = get_desc_links(digest, file)
253         if desc:
254             print >> sys.stderr, "%s: %d/%d: Description: " % (prog, i, i_total)
255             for desc_i in desc:
256                 print >> sys.stderr, "\t\t%s" % desc_i
257    
258         cover_stored = ""
259         if not nocover:
260             cover_data = get_cover(digest)
261             if cover_data:
262                 cover, extension = cover_data
263                 fp = open(basefile + extension, 'wb')
264                 fp.write(cover)
265                 fp.close()
266                 cover_stored = ", %s COVER STORED (%d bytes)" % (extension, len(cover))
267
268         print >> sys.stderr, "%s: %d/%d: SUBTITLE STORED (%d bytes)%s" % (prog, i, i_total, len(sub), cover_stored)
269
270     return 0
271
272 if __name__ == "__main__":
273     ret = None
274     try:
275         ret = main()
276     except (KeyboardInterrupt, SystemExit):
277         print >> sys.stderr, "%s: Interrupted, aborting." % prog
278     sys.exit(ret)
This page took 0.080767 seconds and 3 git commands to generate.