]> git.pld-linux.org Git - packages/pynapi.git/blob - pynapi.py
c99d1e815af89e35eb90e5df5b86e923893d508e
[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         if sub.startswith('NPc') or sub.find('Blad polaczenia z baza danych') != -1:
142             raise Exception('Subtitle NOT FOUND')
143             
144         repeat = 0
145
146     if sub is None or sub == "":
147         raise Exception(error)
148
149     return sub
150
151 def main(argv=sys.argv):
152
153     try:
154         opts, args = getopt.getopt(argv[1:], "d:hl:nuc", ["dest", "help", "lang", "nobackup", "update", "nocover"])
155     except getopt.GetoptError, err:
156         print str(err)
157         usage()
158         return 2
159
160     output = None
161     verbose = False
162     nobackup = False
163     nocover = False
164     update = False
165     lang = 'pl'
166     dest = None
167     for o, a in opts:
168         if o == "-v":
169             verbose = True
170         elif o in ("-h", "--help"):
171             usage()
172             return 0
173         elif o in ("-l", "--lang"):
174             if a in languages:
175                 lang = a
176             else:
177                 print >> sys.stderr, "%s: unsupported language `%s'. Supported languages: %s" % (prog, a, str(languages.keys()))
178                 return 1
179         elif o in ("-n", "--nobackup"):
180             nobackup = True
181         elif o in ("-u", "--update"):
182             update = True
183         elif o in ("-c", "--nocover"):
184             nocover = True
185         elif o in ("-d", "--dest"):
186             dest = a
187         else:
188             print >> sys.stderr, "%s: unhandled option" % prog
189             return 1
190
191     if not args:
192         usage()
193         return 2
194
195     print >> sys.stderr, "%s: Subtitles language `%s'. Finding video files..." % (prog, lang)
196
197     files = []
198     for arg in args:
199         if os.path.isdir(arg):
200             for dirpath, dirnames, filenames in os.walk(arg, topdown=False):
201                 for file in filenames:
202                     if file[-4:-3] == '.' and file.lower()[-3:] in video_files:
203                         files.append(os.path.join(dirpath, file))
204         else:
205             files.append(arg)
206
207     files.sort()
208
209     i_total = len(files)
210     i = 0
211
212     for file in files:
213         i += 1
214
215         vfile = file + '.txt'
216         basefile = file
217         if len(file) > 4:
218             basefile = file[:-4]
219             vfile = basefile + '.txt'
220         if dest:
221             vfile = os.path.join(dest, os.path.split(vfile)[1])
222
223         if not update and os.path.exists(vfile):
224             continue
225
226         if not nobackup and os.path.exists(vfile):
227             vfile_bak = vfile + '-bak'
228             try:
229                 os.rename(vfile, vfile_bak)
230             except (IOError, OSError), e:
231                 print >> sys.stderr, "%s: Skipping due to backup of `%s' as `%s' failure: %s" % (prog, vfile, vfile_bak, e)
232                 continue
233             else:
234                 print >> sys.stderr, "%s: Old subtitle backed up as `%s'" % (prog, vfile_bak)
235
236         print >> sys.stderr, "%s: %d/%d: Processing subtitle for %s" % (prog, i, i_total, file)
237
238         try:
239             digest = calculate_digest(file)
240             sub = get_subtitle(digest, languages[lang])
241         except:
242             print >> sys.stderr, "%s: %d/%d: %s" % (prog, i, i_total, sys.exc_info()[1])
243             continue
244
245         fp = open(vfile, 'wb')
246         fp.write(sub)
247         fp.close()
248     
249         desc = get_desc_links(digest, file)
250         if desc:
251             print >> sys.stderr, "%s: %d/%d: Description: " % (prog, i, i_total)
252             for desc_i in desc:
253                 print >> sys.stderr, "\t\t%s" % desc_i
254    
255         cover_stored = ""
256         if not nocover:
257             cover_data = get_cover(digest)
258             if cover_data:
259                 cover, extension = cover_data
260                 fp = open(basefile + extension, 'wb')
261                 fp.write(cover)
262                 fp.close()
263                 cover_stored = ", %s COVER STORED (%d bytes)" % (extension, len(cover))
264
265         print >> sys.stderr, "%s: %d/%d: SUBTITLE STORED (%d bytes)%s" % (prog, i, i_total, len(sub), cover_stored)
266
267     return 0
268
269 if __name__ == "__main__":
270     ret = None
271     try:
272         ret = main()
273     except (KeyboardInterrupt, SystemExit):
274         print >> sys.stderr, "%s: Interrupted, aborting." % prog
275     sys.exit(ret)
This page took 0.123855 seconds and 2 git commands to generate.