Browse Source

lazy update

John ShaggyTwoDope Jenkins 4 years ago
parent
commit
c43f56a834
8 changed files with 2147 additions and 0 deletions
  1. 8
    0
      bar_vol.sh
  2. 1506
    0
      buffquote
  3. 369
    0
      epub
  4. 14
    0
      html2txt.sh
  5. 12
    0
      make-thumb.sh
  6. 84
    0
      pubreader
  7. 13
    0
      rename.sh
  8. 141
    0
      tuxalarm.sh

+ 8
- 0
bar_vol.sh View File

@@ -0,0 +1,8 @@
1
+#!/bin/bash
2
+
3
+VOL=`mpc volume | sed '1 s/volume://'`
4
+PERC=`echo $VOL`
5
+VOLBAR=`echo -e "$PERC" | dzen2-gdbar -bg '#454545' -fg '#cd546c' -h 1 -w 50 | sed "s/\ .*\%//g"`
6
+
7
+echo "$VOLBAR"
8
+

+ 1506
- 0
buffquote
File diff suppressed because it is too large
View File


+ 369
- 0
epub View File

@@ -0,0 +1,369 @@
1
+#!/usr/bin/env python2
2
+'''
3
+python/curses epub reader. Requires BeautifulSoup
4
+
5
+Keyboard commands:
6
+    Esc/q          - quit
7
+    Tab/Left/Right - toggle between TOC and chapter views
8
+    TOC view:
9
+        Up         - up a line
10
+        Down       - down a line
11
+        PgUp       - up a page
12
+        PgDown     - down a page
13
+    Chapter view:
14
+        Up         - up a page
15
+        Down       - down a page
16
+        PgUp       - up a line
17
+        PgDown     - down a line
18
+        i          - open images on page in web browser
19
+'''
20
+
21
+import curses.wrapper, curses.ascii
22
+import formatter, htmllib, locale, os, StringIO, re, readline, tempfile, zipfile
23
+import base64, webbrowser
24
+
25
+from BeautifulSoup import BeautifulSoup
26
+
27
+try:
28
+    from fabulous import image
29
+    import PIL
30
+except ImportError:
31
+    images = False
32
+else:
33
+    images = True
34
+
35
+locale.setlocale(locale.LC_ALL, 'en_US.utf-8')
36
+
37
+basedir = ''
38
+
39
+def run(screen, program, *args):
40
+    curses.nocbreak()
41
+    screen.keypad(0)
42
+    curses.echo()
43
+    pid = os.fork()
44
+    if not pid:
45
+        os.execvp(program, (program,) +  args)
46
+    os.wait()[0]
47
+    curses.noecho()
48
+    screen.keypad(1)
49
+    curses.cbreak()
50
+
51
+def open_image(screen, name, s):
52
+    ''' show images with PIL and fabulous '''
53
+    if not images:
54
+        screen.addstr(0, 0, "missing PIL or fabulous", curses.A_REVERSE)
55
+        return
56
+
57
+    ext = os.path.splitext(name)[1]
58
+
59
+    screen.erase()
60
+    screen.refresh()
61
+    curses.setsyx(0, 0)
62
+    image_file = tempfile.NamedTemporaryFile(suffix=ext, delete=False)
63
+    image_file.write(s)
64
+    image_file.close()
65
+    try:
66
+        print image.Image(image_file.name)
67
+    except:
68
+        print image_file.name
69
+    finally:
70
+        os.unlink(image_file.name)
71
+
72
+def textify(html_snippet, img_size=(80, 45), maxcol=72):
73
+    ''' text dump of html '''
74
+    class Parser(htmllib.HTMLParser):
75
+        def anchor_end(self):
76
+            self.anchor = None
77
+        def handle_image(self, source, alt, ismap, alight, width, height):
78
+            global basedir
79
+            self.handle_data(
80
+                '[img="{0}{1}" "{2}"]'.format(basedir, source, alt)
81
+            )
82
+
83
+    class Formatter(formatter.AbstractFormatter):
84
+        pass
85
+
86
+    class Writer(formatter.DumbWriter):
87
+        def __init__(self, fl, maxcol=72):
88
+            formatter.DumbWriter.__init__(self, fl)
89
+            self.maxcol = maxcol
90
+        def send_label_data(self, data):
91
+            self.send_flowing_data(data)
92
+            self.send_flowing_data(' ')
93
+
94
+    o = StringIO.StringIO()
95
+    p = Parser(Formatter(Writer(o, maxcol)))
96
+    p.feed(html_snippet)
97
+    p.close()
98
+
99
+    return o.getvalue()
100
+
101
+def table_of_contents(fl):
102
+    global basedir
103
+
104
+    # find opf file
105
+    soup = BeautifulSoup(fl.read('META-INF/container.xml'))
106
+    opf = dict(soup.find('rootfile').attrs)['full-path']
107
+
108
+    basedir = os.path.dirname(opf)
109
+    if basedir:
110
+        basedir = '{0}/'.format(basedir)
111
+
112
+    soup =  BeautifulSoup(fl.read(opf))
113
+
114
+    # title
115
+    yield (soup.find('dc:title').text, None)
116
+
117
+    # all files, not in order
118
+    x, ncx = {}, None
119
+    for item in soup.find('manifest').findAll('item'):
120
+        d = dict(item.attrs)
121
+        x[d['id']] = '{0}{1}'.format(basedir, d['href'])
122
+        if d['media-type'] == 'application/x-dtbncx+xml':
123
+            ncx = '{0}{1}'.format(basedir, d['href'])
124
+
125
+    # reading order, not all files
126
+    y = []
127
+    for item in soup.find('spine').findAll('itemref'):
128
+        y.append(x[dict(item.attrs)['idref']])
129
+
130
+    z = {}
131
+    if ncx:
132
+        # get titles from the toc
133
+        soup =  BeautifulSoup(fl.read(ncx))
134
+
135
+        for navpoint in soup('navpoint'):
136
+            k = navpoint.content.get('src', None)
137
+            # strip off any anchor text
138
+            k = k.split('#')[0]
139
+            if k:
140
+                z[k] = navpoint.navlabel.text
141
+
142
+    # output
143
+    for section in y:
144
+        if section in z:
145
+            yield (z[section].encode('utf-8'), section.encode('utf-8'))
146
+        else:
147
+            yield (u'', section.encode('utf-8').strip())
148
+
149
+def list_chaps(screen, chaps, start, length):
150
+    for i, (title, src) in enumerate(chaps[start:start+length]):
151
+        try:
152
+            if start == 0:
153
+                screen.addstr(i, 0, '      {0}'.format(title), curses.A_BOLD)
154
+            else:
155
+                screen.addstr(i, 0, '{0:-5} {1}'.format(start, title))
156
+        except:
157
+            pass
158
+        start += 1
159
+    screen.refresh()
160
+    return i
161
+
162
+def check_epub(fl):
163
+    if os.path.isfile(fl) and os.path.splitext(fl)[1].lower() == '.epub':
164
+        return True
165
+
166
+def dump_epub(fl, maxcol=float("+inf")):
167
+    if not check_epub(fl):
168
+        return
169
+    fl = zipfile.ZipFile(fl, 'r')
170
+    chaps = [i for i in table_of_contents(fl)]
171
+    for title, src in chaps:
172
+        print title
173
+        print '-' * len(title)
174
+        if src:
175
+            soup = BeautifulSoup(fl.read(src))
176
+            print textify(
177
+                unicode(soup.find('body')).encode('utf-8'),
178
+                maxcol=maxcol,
179
+            )
180
+        print '\n'
181
+
182
+def curses_epub(screen, fl):
183
+    if not check_epub(fl):
184
+        return
185
+
186
+    #curses.mousemask(curses.BUTTON1_CLICKED)
187
+
188
+    fl = zipfile.ZipFile(fl, 'r')
189
+    chaps = [i for i in table_of_contents(fl)]
190
+    chaps_pos = [0 for i in chaps]
191
+    start = 0
192
+    cursor_row = 0
193
+
194
+    # toc
195
+    while True:
196
+        curses.curs_set(1)
197
+        maxy, maxx = screen.getmaxyx()
198
+
199
+        if cursor_row >= maxy:
200
+            cursor_row = maxy - 1
201
+
202
+        len_chaps = list_chaps(screen, chaps, start, maxy)
203
+        screen.move(cursor_row, 0)
204
+        ch = screen.getch()
205
+
206
+        # quit
207
+        if ch == curses.ascii.ESC:
208
+            return
209
+        try:
210
+           if chr(ch) == 'q':
211
+               return
212
+        except:
213
+            pass
214
+
215
+        # up/down line
216
+        if ch in [curses.KEY_DOWN]:
217
+            if start < len(chaps) - maxy:
218
+                start += 1
219
+                screen.clear()
220
+            elif cursor_row < maxy - 1 and cursor_row < len_chaps:
221
+                cursor_row += 1
222
+        elif ch in [curses.KEY_UP]:
223
+            if start > 0:
224
+                start -= 1
225
+                screen.clear()
226
+            elif cursor_row > 0:
227
+                cursor_row -= 1
228
+
229
+        # up/down page
230
+        elif ch in [curses.KEY_NPAGE]:
231
+            if start + maxy - 1 < len(chaps):
232
+                start += maxy - 1
233
+                if len_chaps < maxy:
234
+                    start = len(chaps) - maxy
235
+                screen.clear()
236
+        elif ch in [curses.KEY_PPAGE]:
237
+            if start > 0:
238
+                start -= maxy - 1
239
+                if start < 0:
240
+                    start = 0
241
+                screen.clear()
242
+
243
+        # to chapter
244
+        elif ch in [curses.ascii.HT, curses.KEY_RIGHT, curses.KEY_LEFT]:
245
+            if chaps[start + cursor_row][1]:
246
+                html = fl.read(chaps[start + cursor_row][1])
247
+                soup = BeautifulSoup(html)
248
+                chap = textify(
249
+                    unicode(soup.find('body')).encode('utf-8'),
250
+                    img_size=screen.getmaxyx(),
251
+                    maxcol=screen.getmaxyx()[1]
252
+                ).split('\n')
253
+            else:
254
+                chap = ''
255
+            screen.clear()
256
+            curses.curs_set(0)
257
+
258
+            # chapter
259
+            while True:
260
+                maxy, maxx = screen.getmaxyx()
261
+                images = []
262
+                for i, line in enumerate(chap[
263
+                    chaps_pos[start + cursor_row]:
264
+                    chaps_pos[start + cursor_row] + maxy
265
+                ]):
266
+                    try:
267
+                        screen.addstr(i, 0, line)
268
+                        mch = re.search('\[img="([^"]+)" "([^"]*)"\]', line)
269
+                        if mch:
270
+                            images.append(mch.group(1))
271
+                    except:
272
+                        pass
273
+                screen.refresh()
274
+                ch = screen.getch()
275
+
276
+                # quit
277
+                if ch == curses.ascii.ESC:
278
+                    return
279
+                try:
280
+                   if chr(ch) == 'q':
281
+                       return
282
+                except:
283
+                    pass
284
+
285
+                # to TOC
286
+                if ch in [curses.ascii.HT, curses.KEY_RIGHT, curses.KEY_LEFT]:
287
+                    screen.clear()
288
+                    break
289
+
290
+                # up/down page
291
+                elif ch in [curses.KEY_DOWN]:
292
+                    if chaps_pos[start + cursor_row] + maxy - 1 < len(chap):
293
+                        chaps_pos[start + cursor_row] += maxy - 1
294
+                        screen.clear()
295
+                elif ch in [curses.KEY_UP]:
296
+                    if chaps_pos[start + cursor_row] > 0:
297
+                        chaps_pos[start + cursor_row] -= maxy - 1
298
+                        if chaps_pos[start + cursor_row] < 0:
299
+                            chaps_pos[start + cursor_row] = 0
300
+                        screen.clear()
301
+
302
+                # up/down line
303
+                elif ch in [curses.KEY_NPAGE]:
304
+                    if chaps_pos[start + cursor_row] + maxy - 1 < len(chap):
305
+                        chaps_pos[start + cursor_row] += 1
306
+                        screen.clear()
307
+                elif ch in [curses.KEY_PPAGE]:
308
+                    if chaps_pos[start + cursor_row] > 0:
309
+                        chaps_pos[start + cursor_row] -= 1
310
+                        screen.clear()
311
+
312
+                #elif ch in [curses.KEY_MOUSE]:
313
+                #    id, x, y, z, bstate = curses.getmouse()
314
+                #    line = screen.instr(y, 0)
315
+                #    mch = re.search('\[img="([^"]+)" "([^"]*)"\]', line)
316
+                #    if mch:
317
+                #            img_fl = mch.group(1)
318
+
319
+                else:
320
+                    try:
321
+                        if chr(ch) == 'i':
322
+                            for img in images:
323
+                                err = open_image(screen, img, fl.read(img))
324
+                                if err:
325
+                                    screen.addstr(0, 0, err, curses.A_REVERSE)
326
+
327
+                        # edit html
328
+                        elif chr(ch) == 'e':
329
+
330
+                            tmpfl = tempfile.NamedTemporaryFile(delete=False)
331
+                            tmpfl.write(html)
332
+                            tmpfl.close()
333
+                            run(screen, 'vim', tmpfl.name)
334
+                            with open(tmpfl.name) as changed:
335
+                                new_html = changed.read()
336
+                                os.unlink(tmpfl.name)
337
+                                if new_html != html:
338
+                                    pass
339
+                                    # write to zipfile?
340
+
341
+                            # go back to TOC
342
+                            screen.clear()
343
+                            break
344
+
345
+                    except (ValueError, IndexError):
346
+                        pass
347
+
348
+if __name__ == '__main__':
349
+    import argparse
350
+
351
+    parser = argparse.ArgumentParser(
352
+        formatter_class=argparse.RawDescriptionHelpFormatter,
353
+        description=__doc__,
354
+    )
355
+    parser.add_argument('-d', '--dump', action='store_true',
356
+                        help='dump EPUB to text')
357
+    parser.add_argument('-c', '--cols', action='store', type=int, default=float("+inf"),
358
+                        help='Number of columns to wrap; default is no wrapping.')
359
+    parser.add_argument('EPUB', help='view EPUB')
360
+    args = parser.parse_args()
361
+
362
+    if args.EPUB:
363
+        if args.dump:
364
+            dump_epub(args.EPUB, args.cols)
365
+        else:
366
+            try:
367
+                curses.wrapper(curses_epub, args.EPUB)
368
+            except KeyboardInterrupt:
369
+                pass

+ 14
- 0
html2txt.sh View File

@@ -0,0 +1,14 @@
1
+#!/bin/sh
2
+# h2t, convert all htm and html files of a directory to text 
3
+
4
+for file in `ls *.htm`
5
+do
6
+new=`basename $file htm`
7
+lynx -dump $file > ${new}txt 
8
+done
9
+#####
10
+for file in `ls *.html`
11
+do
12
+new=`basename $file html`
13
+lynx -dump $file > ${new}txt 
14
+done

+ 12
- 0
make-thumb.sh View File

@@ -0,0 +1,12 @@
1
+#!/bin/sh
2
+# Thumbnails for something, invocation from workingdir
3
+make_thumbnail() {
4
+    pic=$1
5
+    thumb=$(dirname "$1")/thumb-$(basename "$1")
6
+    convert "$pic" -thumbnail x150 "$thumb"
7
+}
8
+
9
+for pic in ./*.png
10
+do
11
+    make_thumbnail "$pic"
12
+done

+ 84
- 0
pubreader View File

@@ -0,0 +1,84 @@
1
+#!/usr/bin/env bash
2
+
3
+read_epub()
4
+{
5
+einfo -q -p $1 | elinks -force-html -dump
6
+}
7
+
8
+read_html()
9
+{
10
+elinks -dump $1
11
+}
12
+
13
+read_txt()
14
+{
15
+cat $1
16
+}
17
+
18
+view_txt()
19
+{
20
+book="$(dialog --backtitle "Choose a text file" --fselect $HOME 0 0 --stdout)"
21
+dialog --backtitle "$book" --textbox $book 0 0
22
+}
23
+
24
+view_html()
25
+{
26
+book="$(dialog --backtitle "Choose an HTML file" --fselect $HOME 0 0 --stdout)"
27
+read_html $book > $HOME/.etemp.txt
28
+dialog --backtitle "$1" --textbox $HOME/.etemp.txt 0 0
29
+rm $HOME/.etemp.txt
30
+}
31
+
32
+show_metadata()
33
+{
34
+einfo $1
35
+}
36
+
37
+view_epub()
38
+{
39
+book="$(dialog --backtitle "Choose a book" --fselect $HOME/Books/ 0 0 --stdout)"
40
+read_epub $book > $HOME/.etemp.txt
41
+dialog --backtitle "$book" --textbox $HOME/.etemp.txt 0 0
42
+rm $HOME/.etemp.txt
43
+}
44
+
45
+do_help()
46
+{
47
+cat << EOF
48
+Usage:
49
+
50
+$0 -r {epub,html,txt} file | less
51
+
52
+Dump a file according to specified format to standard output for pagers like less.
53
+
54
+$0 -m file
55
+
56
+Show an ePub book's metadata.
57
+
58
+$0 -v {epub,html,txt}
59
+
60
+Select and read a file via curses dialogs.
61
+
62
+$0 -h
63
+
64
+Display this help page.
65
+EOF
66
+}
67
+
68
+if [ -e ~/.pubreader.rc ];then
69
+	source ~/.pubreader.rc
70
+else
71
+	cat > ~/.pubreader.rc << EOF
72
+#add new functions below
73
+EOF
74
+	source ~/.pubreader.rc
75
+fi
76
+
77
+while getopts "r:m:v:h" option;do
78
+	case "$option" in
79
+		r) read_${OPTARG} $3;;
80
+		m) show_metadata ${OPTARG};;
81
+		v) view_${OPTARG};;
82
+		h) do_help;;
83
+	esac
84
+done

+ 13
- 0
rename.sh View File

@@ -0,0 +1,13 @@
1
+#!/bin/bash
2
+     # renames.sh
3
+     # basic file renamer
4
+
5
+for file in *.png
6
+do
7
+ mv "$file" "p${file%.png}.png"
8
+done
9
+for file in *.jpg
10
+do
11
+mv "$file" "p${file%.jpg}.jpg"
12
+
13
+done

+ 141
- 0
tuxalarm.sh View File

@@ -0,0 +1,141 @@
1
+#!/bin/dash
2
+
3
+NAME="tuxalarm.sh"
4
+AUTHOR="Craciun Dan"
5
+HTTP="http://www.tuxarena.com/intro/tuxalarm.php"
6
+MAIL="floydian.embryo@yahoo.com"
7
+VERSION="0.2.0"
8
+DATE="Feb 15, 2014"
9
+LICENSE="GPLv2"
10
+
11
+# TODO: make a cli music player using gstreamer and use that instead of avplay
12
+
13
+alarm1="Replace this with the absolute path to an audio file (e.g. $HOME/Music/alarm.mp3)."
14
+alarm2="Replace this with the absolute path to an audio file (e.g. $HOME/Music/alarm.mp3)."
15
+alarm3="Replace this with the absolute path to a directory containing audio files."
16
+interval="5"
17
+
18
+bin_ogg123=0
19
+bin_avplay=0
20
+
21
+if [ -x /usr/bin/ogg123 ]; then
22
+	#bin_ogg123=1
23
+	bin_ogg123=0 # set this to 1 to use ogg123 instead of avplay
24
+	# or replace all ogg123 occurences with mpg123; ogg123 plays only ogg and flac files
25
+fi
26
+if [ -x /usr/bin/avplay ]; then
27
+	bin_avplay=1
28
+fi
29
+
30
+if [ $bin_ogg123 -eq 0 ] && [ $bin_avplay -eq 0 ]; then
31
+	echo "WARNING: No suitable player found. The alarm will NOT work! (Tip: install vorbis-tools or avplay)"
32
+	echo "Exiting..."
33
+	exit 0
34
+fi
35
+
36
+echo -n "Enter alarm time as HHMM format (e.g. 0620 for 6:20 AM): "
37
+read alarm
38
+
39
+echo "Available alarms:"
40
+echo "1. $alarm1"
41
+echo "2. $alarm2"
42
+echo "3. All files inside $alarm3"
43
+
44
+valid=0
45
+while [ $valid -eq 0 ]; do
46
+	echo -n "Choose alarm file (default 1): "
47
+	read input
48
+	if [ "$input" = "1" ] || [ "$input" = "" ]; then
49
+		valid=1
50
+		default=1
51
+	elif [ "$input" = "2" ]; then
52
+		valid=1
53
+		default=2
54
+	elif [ "$input" = "3" ]; then
55
+		found=0
56
+		for i in $alarm3/*.ogg; do
57
+			if [ -f $i ]; then
58
+				found=1
59
+			fi
60
+		done
61
+		for i in $alarm3/*.mp3; do
62
+			if [ -f $i ]; then
63
+				found=1
64
+			fi
65
+		done
66
+		if [ $found -eq 1 ]; then
67
+			valid=1
68
+			default=3
69
+		else
70
+			echo "No .ogg or .mp3 files found inside $alarm3! Change the directory or the alarm will NOT work!"
71
+			echo "Exiting..."
72
+			exit 0
73
+		fi
74
+	fi
75
+done
76
+
77
+printalarm () {
78
+	if [ $bin_ogg123 -eq 1 ]; then
79
+		if [ $default -eq 1 ]; then
80
+			echo ogg123 $alarm1
81
+		elif [ $default -eq 2 ]; then
82
+			echo ogg123 $alarm2
83
+		else
84
+			echo ogg123 $alarm3/*
85
+		fi
86
+	elif [ $bin_avplay -eq 1 ]; then
87
+		if [ $default -eq 1 ]; then
88
+			echo avplay -nodisp -autoexit $alarm1
89
+		elif [ $default -eq 2 ]; then
90
+			echo avplay -nodisp -autoexit $alarm2
91
+		else
92
+			echo avplay -nodisp -autoexit $alarm3'/*'
93
+		fi
94
+	fi
95
+}
96
+
97
+echo ""
98
+echo "Alarm time: $alarm"
99
+echo "Repeat interval: $interval"
100
+echo -n "Command: "
101
+printalarm
102
+echo ""
103
+
104
+playalarm () {
105
+	if [ $bin_ogg123 -eq 1 ]; then
106
+		if [ $default -eq 1 ]; then
107
+			ogg123 $alarm1
108
+		elif [ $default -eq 2 ]; then
109
+			ogg123 $alarm2
110
+		else
111
+			ogg123 $alarm3/*.ogg
112
+		fi
113
+	elif [ $bin_avplay -eq 1 ]; then
114
+		if [ $default -eq 1 ]; then
115
+			avplay -nodisp -autoexit $alarm1
116
+		elif [ $default -eq 2 ]; then
117
+			avplay -nodisp -autoexit $alarm2
118
+		else
119
+			for i in $alarm3/*; do
120
+				avplay -nodisp -autoexit $i
121
+			done
122
+		fi
123
+	fi
124
+	sleep $interval
125
+}
126
+
127
+passed=0
128
+while [ $passed -eq 0 ]; do
129
+	if [ `date +"%H%M"` = "$alarm" ]; then
130
+		passed=1
131
+		echo "Rise and shine! It is `date +"%A %b %d, %Y %H:%M"`. (Press ^C to stop the alarm)\n"
132
+		
133
+		while [ 1 ]; do
134
+			playalarm
135
+		done
136
+	fi
137
+	sleep 10
138
+done
139
+
140
+# ChangeLog
141
+# v0.2.0 (Feb 15, 2014) - initial release

Loading…
Cancel
Save