File: podracer

package info (click to toggle)
podracer 1.4-4
  • links: PTS
  • area: main
  • in suites: buster, stretch
  • size: 156 kB
  • ctags: 14
  • sloc: sh: 741; ansic: 57; makefile: 2
file content (445 lines) | stat: -rwxr-xr-x 14,669 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
#!/bin/bash
# Podracer v1.4
# By Lorenzo Taylor
#
#  Podracer is based on Bashpodder by Linc Fessenden of The Linux Link Tech Show.
# Bashpodder can be found at:
# http://linc.homeunix.org:8080/scripts/bashpodder
# See the CREDITS file for more information about all the great work that helped
# make Podracer the winner of the pod race.

# This is the name, version and configuration files for this program
progname=podracer
version=1.4
releasedate='19 February 2006'
progdir="$HOME/.$progname"
systemconf=/etc/$progname.conf
userconf=$progdir/$progname.conf

# We respond to version queries here, since we don't want to do anything but
# display the program name and version number if -v, -version, --version or
# version is specified on the command line.
case $1 in	-v|-version|--version|version)
	echo $progname version $version
	echo Released $releasedate
	echo by Lorenzo Taylor \<lorenzo@taylor.homelinux.net\>
	exit 0
esac

# All default configuration values are set here to avoid forcing the user to
# create a configuration file.  However, an example showing the defaults is
# provided for those of us who think outside the box.

# poddir is the directory where you want podcasts to be saved
# Directory names may be created dynamically based on time, date and many other
# possibilities.  Directory names based on feeds are listed in the subscriptions
# file.
poddir=$HOME/podcasts/$(date +%Y-%m-%d)

# incoming is the directory where incoming podcasts are saved before completion
incoming=$progdir/part

# Subscription file - this holds a list of RSS feeds for podcasts
subscriptions=$progdir/subscriptions

# The location of the sample subscription file that will be copied to a user's
# directory when running Podracer for the first time
sample=/usr/share/$progname/sample.subscriptions

# A temporary place to store subscriptions.  It allows for comments in the
# original subscription file.
tempsub=$progdir/tempsub

# Set to the amount of time in seconds you would like to seed torrents, or if
# you don't have the upload bandwidth to seed, set to 0.  I personally recommend
# seeding for at least an hour, (3600 seconds), which is the default.
seedtime=3600

# Set maximum upload speed in kB/s when seeding - defaults to 0 (no limit)
uploadrate=0

# Directory where torrents are stored
torrentdir=$progdir/torrents

# The number of times Podracer will retry a download if an error occurs
retries=2

# Set the minimum download speed in bytes per second for non-torrent downloads.
# Podracer will abort a download to prevent hangs if the connection drops below
# this speed for the time given below in the downloadtimeout option.
minspeed=1

# set the time in seconds after which to abort a download if the connection
# speed drops below the above minspeed value.
downloadtimeout=60

# Logfiles
podcastlog=$progdir/podcast.log
temppodcastlog=$progdir/temp.log

# Many podcasters check their logs to determine how many people use a podcast
# aggregator vs. directly downloading the shows.  This setting will allow
# Podracer to be recognized as a true podcast agregator.
longname="$progname v$version; $(uname -o); $(uname -m)"

# set to a filename to create an m3u playlist which will be saved in $poddir
# If no filename is set, an m3u playlist will not be created.
m3u=$(date +%Y-%m-%d)-podcasts.m3u

# Override defaults with config file settings
test -e "$systemconf" && source "$systemconf"
test -e "$userconf" && 	source "$userconf"

# Check for and create progdir if necessary:
test -d "$progdir" || mkdir -p "$progdir"

# A subscription file is required in order to receive podcasts
# A sample will be created on user request
if test ! -e "$subscriptions"
	then
	echo You haven\'t subscribed to any podcasts.
	until [[ $copysample == [YyNn] ]]
		do
		echo -n "Would you like a sample subscription file? [Y/N] "
		read -n 1 copysample
		echo
	done
	case $copysample in
		N|n)
		echo Please create a file called $subscriptions and add the feeds for the
		echo podcasts you want to receive.  You may also add comments preceeded by
		echo hash marks, "(#)" to make a note of the name of each podcast or any other
		echo information you may wish to add to your subscription file.
		exit 0
		;;
		Y|y)
		if test -e $sample
			then
			cp $sample $subscriptions
			echo The sample subscription file has been saved to
			echo $subscriptions.
			echo -n Please wait while\ 
			case $1 in
				-c | -catchup | --catchup | catchup)
				echo the log is updated
				;;
				*)
				echo your podcasts are downloaded.
			esac
		else
			echo The sample subscription file is missing.  This indicates either improper
			echo installation or misconfiguration.  Please contact your system administrator to
			echo fix this problem.
			exit 2
		fi
	esac
fi

# Check for and create poddir if necessary:
test -d "$poddir" || mkdir -p "$poddir"

# Check for and create incoming directory
test -d "$incoming" || mkdir -p "$incoming"
	
# Each user may only run one copy of Podracer at a time.  It will fail if it is
# already running for the current user.
test -e "$tempsub" && exit 1
touch "$tempsub"

# Delete any temp file when interrupted or terminated:
trap 'echo Signal caught: exiting.;rm -f "$temppodcastlog";rm -f $tempsub;exit 3' hup int quit term

# If catching up, remove podcast log.  This keeps the log's size manageable by
# removing unnecessary old entries.
case $1 in -c|-catchup|--catchup|catchup)
	rm $podcastlog
esac

# Check for and create podcast log to avoid spurious errors
test  -e "$podcastlog" || touch "$podcastlog"

# Read the subscription file and curl or catch up any url not already in the podcast log:
grep -E "^(http|ftp|/)" "$subscriptions" > "$tempsub"
while read podcast feeddir
	do
	test -z "$feeddir" -o  -d "$poddir/$feeddir" || mkdir -p "$poddir/$feeddir"
	file=$(curl -A "$longname" -s -L $podcast | tr '\r' '\n' | tr \' \" | sed 's/>/>\n/g' | sed -n 's/.*url="\([^"]*\)".*/\1/p' | sed 's/&amp;/&/g')
	for url in $file
		do

		if ! grep "$url" $podcastlog > /dev/null
			then

			#Catch up on new subscriptions or after a vacationso every podcast isn't downloaded
			case $1 in -c | -catchup | --catchup | catchup)
				echo "$url" >> "$podcastlog"
			;;
			*)
				#lets get the real url in the case of dynamically generated feeds like lugradio
				realurl=`curl -s -I -L -w %{url_effective} --url "$url" | tail -n 1`

				#we'll need filename to allow us to move the podcast into poddir[/feeddir]
				filename=`echo "$realurl" | awk -F / '{print $NF}' | sed -e "s/%20/ /g" -e "s/%27/'/g" -e "s/%23/#/g" | awk '-F?' '{print $1}'`
				#file is a torrent so use the internal torrent downloader
				if [ "$(echo $filename | grep .torrent)" ]
					then
					gottorrent='Yes'
					#We only need to create torrentdir if we
					#have never downloaded a torrent file or
					#if torrentdir has been removed.
					test -d $torrentdir || mkdir -p $torrentdir
					curl -A "$longname" -s -y $downloadtimeout -Y $minspeed --retry $retries -L "$realurl" -o "$incoming/$filename"
					#try with and without .py extension
					if [ `which btshowmetainfo` ];
						then
						audiofilename=`btshowmetainfo "$incoming/$filename" | grep name | sed 's/file name.....: //'`
						else
						audiofilename=`btshowmetainfo.py "$incoming/$filename" | grep name | sed 's/file name.....: //'`
					fi
					#the embedded python code will download the file referenced in the torrent and then
					#return control to Podracer
					python - --saveas "$incoming/$audiofilename" "$incoming/$filename" << "END" > /dev/null
########## Begin python code ##########
# Written by Bram Cohen
# Modified by Lorenzo Taylor for use in Podracer
# Uses code by Huw Lynes <huw@hlynhes.com>
import sys
from BitTorrent.download import download
from threading import Event
from os.path import abspath
from sys import argv, stdout
from cStringIO import StringIO
from string import find
from time import time

def hours(n):
    if n == -1:
        return '<unknown>'
    if n == 0:
        return 'complete!'
    n = long(n)
    h, r = divmod(n, 60 * 60)
    m, sec = divmod(r, 60)
    if h > 1000000:
        return '<unknown>'
    if h > 0:
        return '%d hour %02d min %02d sec' % (h, m, sec)
    else:
        return '%d min %02d sec' % (m, sec)

class HeadlessDisplayer:
    def __init__(self):
        self.done = False
        self.file = ''
        self.percentDone = ''
        self.timeEst = ''
        self.downloadTo = ''
        self.downRate = ''
        self.upRate = ''
        self.downTotal = ''
        self.upTotal = ''
        self.errors = []
        self.last_update_time = 0

    def finished(self):
        self.done = True
        self.percentDone = '100'
        self.timeEst = 'Download Succeeded!'
        self.downRate = ''
        self.display({})
	self.errors.append("sys.exit(0)")
	sys.exit(0)

    def failed(self):
        self.done = True
        self.percentDone = '0'
        self.timeEst = 'Download Failed!'
        self.downRate = ''
        self.display({})

    def error(self, errormsg):
        noneerror = 0
        self.errors.append(errormsg)
        for errorstr in self.errors:
	    self.display({})
            if find(errorstr, "sys.exit(0)") != -1:
                noneerror = 1

        if noneerror == 1 :
            sys.exit(0)
        else:
            self.display({})
            sys.exit(1)

    def display(self, dict):
        if self.last_update_time + 0.1 > time() and dict.get('fractionDone') not in (0.0, 1.0) and not dict.has_key('activity'):
            return
        self.last_update_time = time()
        if dict.has_key('spew'):
            print_spew(dict['spew'])
        if dict.has_key('fractionDone'):
            self.percentDone = str(float(int(dict['fractionDone'] * 1000)) / 10)
        if dict.has_key('timeEst'):
            self.timeEst = hours(dict['timeEst'])
        if dict.has_key('activity') and not self.done:
            self.timeEst = dict['activity']
        if dict.has_key('downRate'):
            self.downRate = '%.2f K/s' % (float(dict['downRate']) / (1 << 10))
        if dict.has_key('upRate'):
            self.upRate = '%.2f K/s' % (float(dict['upRate']) / (1 << 10))
        if dict.has_key('upTotal'):
            self.upTotal = '%.1f M' % (dict['upTotal'])
        if dict.has_key('downTotal'):
            self.downTotal = '%.1f M' % (dict['downTotal'])
        print '\n\n'
        for err in self.errors:
            print 'ERROR: ' + err + '\n'
        print 'saving:        ', self.file
        print 'percent done:  ', self.percentDone
        print 'time left:     ', self.timeEst
        print 'download to:   ', self.downloadTo
        if self.downRate != '':
            print 'download rate: ', self.downRate
        if self.upRate != '':
            print 'upload rate:   ', self.upRate
        if self.downTotal != '':
            print 'download total:', self.downTotal
        if self.upTotal != '':
            print 'upload total:  ', self.upTotal
        stdout.flush()

    def chooseFile(self, default, size, saveas, dir):
        self.file = '%s (%.1f M)' % (default, float(size) / (1 << 20))
        if saveas != '':
            default = saveas
        self.downloadTo = abspath(default)
        return default

    def newpath(self, path):
        self.downloadTo = path

def print_spew(spew):
    s = StringIO()
    s.write('\n\n\n')
    for c in spew:
        s.write('%20s ' % c['ip'])
        if c['initiation'] == 'local':
            s.write('l')
        else:
            s.write('r')
        rate, interested, choked = c['upload']
        s.write(' %10s ' % str(int(rate)))
        if c['is_optimistic_unchoke']:
            s.write('*')
        else:
            s.write(' ')
        if interested:
            s.write('i')
        else:
            s.write(' ')
        if choked:
            s.write('c')
        else:
            s.write(' ')

        rate, interested, choked, snubbed = c['download']
        s.write(' %10s ' % str(int(rate)))
        if interested:
            s.write('i')
        else:
            s.write(' ')
        if choked:
            s.write('c')
        else:
            s.write(' ')
        if snubbed:
            s.write('s')
        else:
            s.write(' ')
        s.write('\n')
    print s.getvalue()

def run(params):
    cols = 80

    h = HeadlessDisplayer()
    download(params, h.chooseFile, h.display, h.finished, h.error, Event(), cols, h.newpath)
    if not h.done:
        h.failed()

if __name__ == '__main__':
    run(argv[1:])
########## End python code ##########
END

					#if we've succeeded add file to podcast log and move to poddir[/feeddir]
					if [ $? -eq 0 ]
						then
						mv "$incoming/$audiofilename" "$poddir/$feeddir"
						mv "$incoming/$filename" "$torrentdir"
						echo "$url" >> $podcastlog
					fi

				#not a torrent so directly download the enclosure
				else
					curl -A "$longname" -s -y $downloadtimeout -Y $minspeed --retry $retries -L -C - -o "$incoming/$filename" "$realurl"

					#if we succeeded in the download add the file to the log
					if [ $? -eq 0 ]
						then
						mv "$incoming/$filename" "$poddir/$feeddir"
						echo "$url" >> $podcastlog
					fi
				fi
			esac
		fi
		done
			test $feeddir && rmdir --ignore-fail-on-non-empty "$poddir/$feeddir"
			unset feeddir
	done < "$tempsub"
rm "$tempsub"

# Move dynamically created log file to permanent log file:
cat "$podcastlog" > "$temppodcastlog"
sort "$temppodcastlog" | uniq > "$podcastlog"
rm "$temppodcastlog"

# remove poddir if there are no files
if [[ -z $(ls $poddir) ]]; then
	rmdir $poddir
else
# Create an m3u playlist if configured by the user
#slightly more complicated to deal with
#geeknewscentral who put their stuff in directories
	if [ $m3u ]
		then
		(
		cd "$poddir"
		find . -name \*.mp3 > "$m3u"
		find . -name \*.ogg  >> "$m3u"
		find . -name \*.m4a  >> "$m3u"
		find . -name \*.m4b  >> "$m3u"
		)
	fi
fi

# Relaunch the torrents to seed.  This will timeout automatically, so there is no
# need to find the process and shut it down.
if [ $seedtime -gt 0 ]
	then
	#we only need to do the following if we actually encountered
	#some torrents
	if [ $gottorrent ]
		then
			#Some distributions of BitTorrent remove the .py
			#extention.  We will try both cases.
			if [ `which btlaunchmany` ]; then
				#Screen has the advantage here of letting podracer
				#finish normally while letting torrents seed in
				#the background.
				screen -d -m timeout $seedtime btlaunchmany  --max_upload_rate $uploadrate --saveas "$poddir/$feeddir" "$torrentdir"
			else
								screen -d -m timeout $seedtime btlaunchmany.py --saveas "$poddir/$feeddir" "$torrentdir"
			fi
	fi
fi