quartz_flow_plugin_shows 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,529 @@
1
+ #!/usr/bin/ruby
2
+ # This code is used to parse filenames that have "standard" TV show format, such as
3
+ # Boardwalk.Empire.S02E01.720p.HDTV.x264-IMMERSE.mkv
4
+ # into seasons and episodes.
5
+
6
+ # Information that uniquely identifies an episode of a show.
7
+ class ShowEpisode
8
+ def initialize
9
+ @season = nil
10
+ @episode = nil
11
+ end
12
+
13
+ attr_accessor :season
14
+ attr_accessor :episode
15
+
16
+ def to_s
17
+ "S#{season}E#{episode}"
18
+ end
19
+ end
20
+
21
+ # This class represents a contiguous range of episodes of a show in a single season. For example
22
+ # Season 1 Episodes 1-5, or Season 2 Episodes 7-9
23
+ class ShowEpisodeRange
24
+ def initialize(season, startEpisode, endEpisode)
25
+ @season = season
26
+ @startEpisode = startEpisode
27
+ @endEpisode = endEpisode
28
+ end
29
+
30
+ attr_accessor :startEpisode
31
+ attr_accessor :endEpisode
32
+ attr_accessor :season
33
+
34
+ def size
35
+ @endEpisode - @startEpisode + 1
36
+ end
37
+
38
+ # Given a list of ShowEpisode objects, return an array of ShowEpisodeRange objects
39
+ # that represents the passed episodes.
40
+ def self.createRanges(episodes)
41
+ ranges = []
42
+ sorted = episodes.sort{ |a,b|
43
+ if a.season < b.season
44
+ -1
45
+ elsif a.season > b.season
46
+ 1
47
+ else
48
+ a.episode <=> b.episode
49
+ end
50
+ }
51
+
52
+ firstInRange = nil
53
+ lastProcessed = nil
54
+ sorted.each{ |s|
55
+ if ! firstInRange
56
+ firstInRange = s
57
+ else
58
+ if s.season != lastProcessed.season || s.episode > lastProcessed.episode + 1
59
+ # End of range!
60
+ ranges.push ShowEpisodeRange.new(firstInRange.season, firstInRange.episode, lastProcessed.episode)
61
+ firstInRange = s
62
+ end
63
+ end
64
+ lastProcessed = s
65
+ }
66
+ if firstInRange
67
+ ranges.push ShowEpisodeRange.new(firstInRange.season, firstInRange.episode, lastProcessed.episode)
68
+ end
69
+ ranges
70
+ end
71
+
72
+ end
73
+
74
+ # An object that stores a list of episode ranges for a single show.
75
+ class ShowEpisodes
76
+ def initialize
77
+ @showName = nil
78
+ @episodes = []
79
+ end
80
+
81
+ attr_accessor :showName
82
+ attr_accessor :episodes
83
+
84
+ def episodeRanges
85
+ ShowEpisodeRange.createRanges(@episodes)
86
+ end
87
+
88
+ end
89
+
90
+ class ParsedShowName
91
+ def initialize
92
+ end
93
+
94
+ attr_accessor :showName
95
+ attr_accessor :season
96
+ attr_accessor :episode
97
+
98
+ def self.create(showName, season, episode)
99
+ rc = ParsedShowName.new
100
+ rc.showName = showName
101
+ rc.season = season
102
+ rc.episode = episode
103
+ rc
104
+ end
105
+
106
+ # Given a single episode raw string (as from a filename) in rawName, and given some metaInfo
107
+ # (such as the file's parent directory) returns an array of ParsedShowName objects representing
108
+ # the episodes found in the string.
109
+ #
110
+ # Format 1: Show.Name.S01E01.whatever.avi
111
+ # Format 2: Show.Name.S01E01E02.whatever.avi
112
+ # Format 3: Show Name season 3 episode 2 whatever.avi
113
+ # Format 4: Show.Name.1x2.whatever.avi
114
+ def self.parse(rawName, metaInfo)
115
+ rc = []
116
+
117
+
118
+ if rawName =~ /^(.*)[sS](\d+)((?:[eE]\d+)+)/
119
+ showName = self.fixShowName($1, metaInfo)
120
+ season = $2.to_i
121
+ # Parse the episode part; it might be more than one episode
122
+ episodeStr = $3
123
+
124
+ episodeStr.scan(/[eE](\d+)/){ |ep|
125
+ episode = ep.first.to_i
126
+ rc.push ParsedShowName.create(showName, season, episode)
127
+ }
128
+ # Format 3: "The Vampire Diaries Season 3 Episode 2",
129
+ elsif rawName =~ /^(.*)season[^\d]+(\d+)[^\d]+episode[^\d]+(\d+)/i
130
+ showName = self.fixShowName($1, metaInfo)
131
+ season = $2.to_i
132
+ # Parse the episode part; it might be more than one episode
133
+ episode = $3.to_i
134
+ rc.push ParsedShowName.create(showName, season, episode)
135
+ # Format 4:
136
+ elsif rawName =~ /^(.*)\.(\d+)x(\d+)\./
137
+ showName = self.fixShowName($1, metaInfo)
138
+ season = $2.to_i
139
+ # Parse the episode part; it might be more than one episode
140
+ episode = $3.to_i
141
+ rc.push ParsedShowName.create(showName, season, episode)
142
+ end
143
+ rc
144
+ end
145
+
146
+ private
147
+ def self.fixShowName(name, metaInfo)
148
+ if name.length == 0 && metaInfo
149
+ if metaInfo.parentDir
150
+ name = File.basename(metaInfo.parentDir)
151
+ end
152
+ end
153
+
154
+ name = name.tr('.',' ').strip
155
+ # Strip off trailing and leading wierd characters.
156
+ if name =~ /^[_\-]*([\sa-zA-Z0-9]+)[_\-]*$/
157
+ name = $1
158
+ end
159
+
160
+ parts = name.strip.split(/\s+/)
161
+ parts.collect!{ |e|
162
+ e.capitalize
163
+ }
164
+ parts.join(' ')
165
+ end
166
+ end
167
+
168
+ class FilenameMetaInfo
169
+ def initialize
170
+ @parentDir = nil
171
+ end
172
+
173
+ attr_reader :parentDir
174
+
175
+ def setParentDir(p)
176
+ @parentDir = p
177
+ self
178
+ end
179
+ end
180
+
181
+ # A class that can be used to parse a series of show names into an array of ShowEpisodes objects.
182
+ # To use this class, add shows using addName, then call processNames to get the result.
183
+ class ShowNameInterpreter
184
+ def initialize
185
+ @names = []
186
+ @metaInfo = []
187
+ end
188
+
189
+ def addName(name, metaInfo = nil)
190
+ @names.push name
191
+ @metaInfo.push metaInfo
192
+ end
193
+
194
+ # Process the episode names added with addName and return a Hsah of ShowEpisodes objects, keyed by show name.
195
+ def processNames
196
+ shows = {}
197
+ i = 0
198
+ @names.each{ |n|
199
+ parsedArray = ParsedShowName.parse(n, @metaInfo[i])
200
+ parsedArray.each{ |parsed|
201
+ episodes = shows[parsed.showName]
202
+ if ! episodes
203
+ episodes = ShowEpisodes.new
204
+ episodes.showName = parsed.showName
205
+ shows[parsed.showName] = episodes
206
+ end
207
+ episode = ShowEpisode.new
208
+ episode.season = parsed.season
209
+ episode.episode = parsed.episode
210
+ episodes.episodes.push episode
211
+ }
212
+ i += 1
213
+ }
214
+ shows
215
+ end
216
+ end
217
+
218
+ =begin
219
+
220
+ #########
221
+ # Testing
222
+ #########
223
+
224
+
225
+ if $0 =~ /ShowNameParse.rb/
226
+
227
+ testdata = [
228
+ "A-Ha - Take On Me.Mp3",
229
+ "Boardwalk.Empire.S01E01.Boardwalk.Empire.HDTV.XviD-FQM.avi",
230
+ "Boardwalk.Empire.S01E02.The.Ivory.Tower.HDTV.XviD-FQM.avi",
231
+ "Boardwalk.Empire.S01E03.720p.HDTV.x264-CTU.mkv",
232
+ "Boardwalk.Empire.S01E04.HDTV.XviD-2HD.avi",
233
+ "Boardwalk.Empire.S01E05.Nights.in.Ballygran.HDTV.XviD-FQM.avi",
234
+ "Boardwalk.Empire.S01E06.Family.Limitation.HDTV.XviD-FQM.avi",
235
+ "Boardwalk.Empire.S01E07.Home.HDTV.XviD-FQM.avi",
236
+ "Boardwalk.Empire.S01E08.Hold.Me.in.Paradise.HDTV.XviD-FQM.avi",
237
+ "Boardwalk.Empire.S01E09.Belle.Femme.HDTV.XviD-FQM.avi",
238
+ "Boardwalk.Empire.S01E10.HDTV.XviD-FEVER.avi",
239
+ "Boardwalk.Empire.S01E11.Paris.Green.HDTV.XviD-FQM.avi",
240
+ "Boardwalk.Empire.S01E12.HDTV.XviD-FEVER.avi",
241
+ "Boardwalk.Empire.S02E01.720p.HDTV.x264-IMMERSE.mkv",
242
+ "Boardwalk.Empire.S02E02.HDTV.XviD-ASAP.avi",
243
+ "Boardwalk.Empire.S02E03.720p.HDTV.x264-IMMERSE.mkv",
244
+ "Boardwalk.Empire.S02E04.HDTV.XviD-ASAP.avi",
245
+ "Boardwalk.Empire.S02E05.HDTV.XviD-LOL.avi",
246
+ "DataRescue IDA Pro 5.1.0 Lin Advanced Edition - professional disassembler [h33t] [Original]",
247
+ "DataRescue IDA Pro v5.2.0 Advanced Edition for WindowsLinuxMac professional disassembler, SDK and DataRescue Hex-Rays Decompiler v1.0 [h33t] [Original] [Must have]",
248
+ "Dexter.S05E01.My.Bad.HDTV.XviD-FQM.avi",
249
+ "Dexter.S06E01.HDTV.XviD-ASAP.avi",
250
+ "Dexter.S06E02.Once.Upon.a.Time.HDTV.XviD-FQM.avi",
251
+ "Dexter.S06E03.HDTV.XviD-ASAP.avi",
252
+ "Dexter.S06E04.HDTV.XviD-LOL.avi",
253
+ "Dexter.S06E06.HDTV.XviD-ASAP.avi",
254
+ "download at superseeds.org True.Blood.S04E02.You.Smell.Like.Dinner.HDTV.XviD-XS.avi",
255
+ "Family.Guy.S09E01.HDTV.XviD-LOL.avi",
256
+ "Family.Guy.S09E02.HDTV.XviD-LOL.avi",
257
+ "Family.Guy.S09E03.HDTV.XviD-LOL.avi",
258
+ "Family.Guy.S09E04.HDTV.XviD-LOL.avi",
259
+ "Family.Guy.S09E05.HDTV.XviD-LOL.avi",
260
+ "Family.Guy.S09E06.HDTV.XviD-LOL.avi",
261
+ "Family.Guy.S09E07E08.HDTV.XviD-LOL.avi",
262
+ "Family.Guy.S09E10.HDTV.XviD-LOL.avi",
263
+ "Family.Guy.S09E11.HDTV.XviD-LOL.avi",
264
+ "Family.Guy.S09E12.HDTV.XviD-LOL.avi",
265
+ "Family.Guy.S09E13.HDTV.XviD-LOL.avi",
266
+ "Family.Guy.S09E14.HDTV.XviD-LOL.avi",
267
+ "Family.Guy.S09E15.HDTV.XviD-LOL.avi",
268
+ "Family.Guy.S09E18.HDTV.XviD-LOL.avi",
269
+ "Farscape - Season 1-4+The.Peacekeeper.Wars.Part.1&2",
270
+ "Firefly",
271
+ "Frasier Season 9",
272
+ "Futurama.S06E13.Holiday.Spectacular.HDTV.XviD-aAF.[VTV].avi",
273
+ "Futurama.S06E14.Neutopia.HDTV.XviD-FQM.avi",
274
+ "Futurama.S06E15.Benderama.HDTV.XviD-FQM.avi",
275
+ "Futurama.S06E16.Ghost.in.the.Machines.HDTV.XviD-FQM.avi",
276
+ "Futurama.S06E17.HDTV.XviD-ASAP.avi",
277
+ "Futurama.S06E19.HDTV.XviD-ASAP.avi",
278
+ "Futurama.S06E20.All.the.Presidents.Heads.HDTV.XviD-FQM.avi",
279
+ "Futurama.S06E21.HDTV.XviD-ASAP.avi",
280
+ "Futurama.S06E22.HDTV.XviD-ASAP.avi",
281
+ "Futurama.S06E23.HDTV.XviD-ASAP.avi",
282
+ "Futurama.S06E25.HDTV.XviD-ASAP.avi",
283
+ "Futurama.S06E26.HDTV.XviD-ASAP.avi",
284
+ "Game Of Thrones Season 1 - Complete",
285
+ "Hanna [2011] BRRip XviD - CODY",
286
+ "Homeland.S01E01.HDTV.XviD-ASAP.[VTV].avi",
287
+ "Homeland.S01E02.Grace.HDTV.XviD-FQM.[VTV].avi",
288
+ "Homeland.S01E03.HDTV.XviD-ASAP.[VTV].avi",
289
+ "Homeland.S01E04.HDTV.XviD-ASAP.[VTV].avi",
290
+ "House.S07E17.PROPER.HDTV.XviD-2HD.avi",
291
+ "House.S07E18.HDTV.XviD-LOL.avi",
292
+ "House.S07E19.HDTV.XviD-LOL.avi",
293
+ "House.S07E20.HDTV.XviD-LOL.avi",
294
+ "House.S07E21.HDTV.XviD-LOL.avi",
295
+ "House.S07E22.HDTV.XviD-LOL.avi",
296
+ "House.S07E23.Moving.On.HDTV.XviD-2HD.avi",
297
+ "House.S08E01.HDTV.XviD-LOL.avi",
298
+ "House.S08E02.HDTV.XviD-LOL.avi",
299
+ "House.S08E03.HDTV.XviD-LOL.avi",
300
+ "House.S08E04.HDTV.XviD-LOL.avi",
301
+ "House.S08E05.HDTV.XviD-LOL.avi",
302
+ "How.I.Met.Your.Mother.S05E11.Last.Cigarette.Ever.HDTV.XviD-FQM.[VTV].avi",
303
+ "informants-1hr17min-md5-682bdf4a9c7e1918a286e00c0bc88c16.ogg",
304
+ "KNOPPIX_V6.7.1CD-2011-09-14-EN",
305
+ "Lord of Illusions",
306
+ "Minority_Report.avi",
307
+ "Necessary.Roughness.S01E09.HDTV.XviD-LOL.avi",
308
+ "Nurse.Jackie.S03E06.When.The.Saints.Go.HDTV.XviD-FQM.avi",
309
+ "Nurse.Jackie.S03E07.Orchids.and.Salami.PROPER.HDTV.XviD-FQM.avi",
310
+ "Nurse.Jackie.S03E08.HDTV.XviD-ASAP.avi",
311
+ "Nurse.Jackie.S03E09.HDTV.XviD-FEVER.avi",
312
+ "Nurse.Jackie.S03E10.HDTV.XviD-LOL.avi",
313
+ "Nurse.Jackie.S03E11.Batting.Practice.HDTV.XviD-FQM.avi",
314
+ "Nurse.Jackie.S03E12.HDTV.XviD-ASAP.avi",
315
+ "Rescue.Me.S07E07.Jeter.HDTV.XviD-FQM.avi",
316
+ "Robot.Chicken.S05E01.HDTV.XviD-2HD.avi",
317
+ "Robot.Chicken.S05E02.HDTV.XviD-2HD.avi",
318
+ "Robot.Chicken.S05E03.HDTV.XviD-2HD.avi",
319
+ "Robot.Chicken.S05E04.HDTV.XviD-2HD.avi",
320
+ "Robot.Chicken.S05E05.HDTV.XviD-2HD.avi",
321
+ "SlackerUprising_640x360.avi",
322
+ "Terra.Nova.S01E01.Genesis.HDTV.XviD-FQM.avi",
323
+ "Terra.Nova.S01E03.HDTV.XviD-LOL.avi",
324
+ "Terra.Nova.S01E04.HDTV.XviD-LOL.avi",
325
+ "Terra.Nova.S01E06.HDTV.XviD-LOL.avi",
326
+ "The.Big.Bang.Theory.S04E19.PROPER.HDTV.XviD-FEVER.avi",
327
+ "The.Big.Bang.Theory.S04E20.HDTV.XviD-ASAP.avi",
328
+ "The.Big.Bang.Theory.S04E21.HDTV.XviD-ASAP.avi",
329
+ "The.Big.Bang.Theory.S04E22.HDTV.XviD-ASAP.avi",
330
+ "The.Big.Bang.Theory.S04E23.The.Engagement.Reaction.HDTV.XviD-FQM.avi",
331
+ "The.Big.Bang.Theory.S04E24.The.Roomate.Transmogrification.HDTV.XviD-FQM.avi",
332
+ "The.Big.Bang.Theory.S05E01.HDTV.XviD-ASAP.avi",
333
+ "The.Big.Bang.Theory.S05E02.HDTV.XviD-ASAP.avi",
334
+ "The.Big.Bang.Theory.S05E03.HDTV.XviD-ASAP.avi",
335
+ "The Big Bang Theory S05E03 The Pulled Groin Extrapolation HDTV Xvid DutchReleaseTeam (dutch subs nl)",
336
+ "The.Big.Bang.Theory.S05E04.The.Wiggly.Finger.Catalyst.HDTV.XviD-FQM.avi",
337
+ "The.Big.Bang.Theory.S05E05.The.Russian.Rocket.Reaction.HDTV.XviD-FQM.avi",
338
+ "The.Big.Bang.Theory.S05E06.HDTV.XviD-ASAP.avi",
339
+ "The.Big.Bang.Theory.S05E07.HDTV.XviD-2HD.avi",
340
+ "The.Big.Bang.Theory.S05E08.HDTV.XviD-ASAP.avi",
341
+ "The Big Bang Theory Season 5 Episode 6 - The Rhinitis Revelation",
342
+ "The.Men.Who.Stares.At.Goats.2009.R5.Line.XviD-PrisM.avi",
343
+ "The NeverEnding Story[1984]DvDrip[720x436]AC3[6ch][Eng]-RHooD",
344
+ "The.Simpsons.S23E01.HDTV.XviD-LOL.avi",
345
+ "The.Simpsons.S23E03.HDTV.XviD-LOL.avi",
346
+ "The.Simpsons.S23E04.HDTV.XviD-LOL.avi",
347
+ "The.Vampire.Diaries.S01E18.HDTV.XviD-2HD.avi",
348
+ "The.Vampire.Diaries.S02E15.The.Dinner.Party.HDTV.XviD-FQM.avi",
349
+ "The.Vampire.Diaries.S02E16.HDTV.XviD-2HD.avi",
350
+ "The.Vampire.Diaries.S02E17.HDTV.XviD-2HD.avi",
351
+ "The.Vampire.Diaries.S02E18.HDTV.XviD-2HD.jHONY.avi",
352
+ "The.Vampire.Diaries.S02E19.PROPER.HDTV.XviD-2HD.avi",
353
+ "The.Vampire.Diaries.S02E20.HDTV.XviD-2HD.avi",
354
+ "The.Vampire.Diaries.S02E21.HDTV.XviD-ASAP.avi",
355
+ "The.Vampire.Diaries.S02E22.As.I.Lay.Dying.HDTV.XviD-FQM.avi",
356
+ "The.Vampire.Diaries.S03E01.HDTV.XviD-2HD",
357
+ "the.vampire.diaries.s03e03.hdtv.xvid-2hd.avi",
358
+ "The Vampire Diaries S03E04.avi",
359
+ "The.Vampire.Diaries.S03E05.HDTV.XviD-P0W4.avi",
360
+ "The.Vampire.Diaries.S03E06.HDTV.XviD-2HD.avi",
361
+ "The.Vampire.Diaries.S03E07.HDTV.XviD-2HD.avi",
362
+ "The.Vampire.Diaries.S03E08.REPACK.HDTV.XviD-2HD.avi",
363
+ "The Vampire Diaries Season 3 Episode 2",
364
+ "The.Walking.Dead.S01E01.Days.Gone.Bye.HDTV.XviD-FQM.[VTV].avi",
365
+ "True.Blood.S04E01.HDTV.XviD-LOL.avi",
366
+ "True.Blood.S04E02.You.Smell.Like.Dinner.PROPER.HDTV.XviD-FQM.avi",
367
+ "True.Blood.S04E03.HDTV.XviD-LOL.avi",
368
+ "True.Blood.S04E04.720p.HDTV.x264-IMMERSE.mkv",
369
+ "True.Blood.S04E05.HDTV.XviD-ASAP.avi",
370
+ "True.Blood.S04E06.HDTV.XviD-ASAP.avi",
371
+ "True.Blood.S04E07.HDTV.XviD-ASAP.avi",
372
+ "True.Blood.S04E08.HDTV.XviD-ASAP.avi",
373
+ "True.Blood.S04E09.HDTV.XviD-LOL.avi",
374
+ "True.Blood.S04E10.Burning.Down.the.House.PROPER.HDTV.XviD-FQM.avi",
375
+ "True.Blood.S04E11.HDTV.XviD-LOL.avi",
376
+ "True.Blood.S04E12.720p.HDTV.X264-DIMENSION.mkv",
377
+ "Two.and.a.Half.Men.S09E01.HDTV.XviD-ASAP.avi",
378
+ "Two.and.a.Half.Men.S09E02.HDTV.XviD-ASAP.avi",
379
+ "Two.and.a.Half.Men.S09E03.HDTV.XviD-ASAP.avi",
380
+ "Two.and.a.Half.Men.S09E04.HDTV.XviD-ASAP.avi",
381
+ "Two.and.a.Half.Men.S09E05.A.Giant.Cat.Holding.a.Churro.HDTV.XviD-FQM.avi",
382
+ "Two.and.a.Half.Men.S09E06.HDTV.XviD-ASAP.avi",
383
+ "Two.and.a.Half.Men.S09E07.HDTV.XviD-ASAP.avi",
384
+ "Wild.Boys.S01E01.WS.PDTV.XviD-BWB.avi",
385
+ "YTMND - The Soundtrack (Remastered)"
386
+ ]
387
+
388
+ if ARGV.size > 0
389
+ directory = ARGV[0]
390
+ if ! File.directory?(directory)
391
+ puts "'#{dir}' is not a directory."
392
+ exit 1
393
+ end
394
+
395
+ puts "Processing files under #{directory}"
396
+
397
+ interp = ShowNameInterpreter.new
398
+
399
+ def filesUnder(dir)
400
+ Dir.new(dir).each{ |e|
401
+ next if e[0,1] == '.'
402
+ path = dir + "/" + e
403
+ if File.directory?(path)
404
+ filesUnder(path){ |f,d|
405
+ yield f,d
406
+ }
407
+ else
408
+ yield e, dir
409
+ end
410
+ }
411
+ end
412
+
413
+ filesUnder(directory){ |e, dir|
414
+ if e[0,1] != '.'
415
+ interp.addName(e, FilenameMetaInfo.new.setParentDir(dir))
416
+ end
417
+ }
418
+
419
+ shows = interp.processNames
420
+ shows.each{ |k,v|
421
+ print k + ":"
422
+ ranges = v.episodeRanges
423
+ season = nil
424
+ comma = true
425
+ ranges.each{ |r|
426
+ if ! season || season != r.season
427
+ puts
428
+ print " Season #{r.season}: "
429
+ season = r.season
430
+ comma = false
431
+ end
432
+ print "," if comma
433
+ if r.size > 1
434
+ print " #{r.startEpisode}-#{r.endEpisode}"
435
+ else
436
+ print " #{r.startEpisode}"
437
+ end
438
+ comma = true
439
+ }
440
+ puts
441
+ }
442
+
443
+ exit 0
444
+ end
445
+
446
+ class Test
447
+ def initialize(caption)
448
+ @caption = caption
449
+ end
450
+
451
+ def assert(bool, text = nil)
452
+ if bool
453
+ pass
454
+ else
455
+ fail(text)
456
+ end
457
+ end
458
+
459
+ def equals(expected, actual)
460
+ if expected == actual
461
+ pass
462
+ else
463
+ fail("expected #{expected} but was #{actual}")
464
+ end
465
+ end
466
+
467
+ def pass
468
+ puts "[PASS] #{@caption}"
469
+ end
470
+
471
+ def fail(text = nil)
472
+ rc = "[FAIL] #{@caption}"
473
+ rc = rc << ": #{text}" if text
474
+ puts rc
475
+ end
476
+ end
477
+
478
+ def dotest(shows)
479
+ # Check family guy
480
+ episodes = shows["Family Guy"]
481
+ t = Test.new("Family Guy was parsed")
482
+ t.assert(episodes)
483
+ if episodes
484
+ t = Test.new("Family Guy ranges")
485
+ ranges = episodes.episodeRanges
486
+ t.equals(3,ranges.size)
487
+ if 3 == ranges.size
488
+ t.equals(8,ranges[0].size)
489
+ t.equals(6,ranges[1].size)
490
+ t.equals(1,ranges[2].size)
491
+ t.equals(1,ranges[0].startEpisode)
492
+ t.equals(8,ranges[0].endEpisode)
493
+ t.equals(10,ranges[1].startEpisode)
494
+ t.equals(15,ranges[1].endEpisode)
495
+ t.equals(18,ranges[2].startEpisode)
496
+ end
497
+ end
498
+
499
+ # Check vampire diaries
500
+ episodes = shows["The Vampire Diaries"]
501
+ t = Test.new("Vampire Diaries was parsed")
502
+ t.assert(episodes)
503
+ if episodes
504
+ t = Test.new("Vampire Diaries ranges")
505
+ ranges = episodes.episodeRanges
506
+ t.equals(3,ranges.size)
507
+ if 3 == ranges.size
508
+ t.equals(1,ranges[0].size)
509
+ t.equals(8,ranges[1].size)
510
+ t.equals(8,ranges[2].size)
511
+ t.equals(18,ranges[0].startEpisode)
512
+ t.equals(18,ranges[0].endEpisode)
513
+ t.equals(1,ranges[0].season)
514
+
515
+ t.equals(15,ranges[1].startEpisode)
516
+ t.equals(22,ranges[1].endEpisode)
517
+ t.equals(2,ranges[1].season)
518
+
519
+ t.equals(1,ranges[2].startEpisode)
520
+ t.equals(8,ranges[2].endEpisode)
521
+ t.equals(3,ranges[2].season)
522
+ end
523
+ end
524
+ end
525
+
526
+ dotest(shows)
527
+
528
+ end
529
+ =end
@@ -0,0 +1 @@
1
+ link "Shows", "/#/show_list"
@@ -0,0 +1,57 @@
1
+ require './plugins/shows/lib/showname_parse'
2
+
3
+ get "/show_list" do
4
+ interp = ShowNameInterpreter.new
5
+ def filesUnder(dir)
6
+ Dir.new(dir).each do |e|
7
+ next if e[0,1] == '.'
8
+ path = dir + "/" + e
9
+ if File.directory?(path)
10
+ filesUnder(path){ |f,d|
11
+ yield f,d
12
+ }
13
+ else
14
+ yield e, dir
15
+ end
16
+ end
17
+ end
18
+
19
+ filesUnder(settings.basedir) do |e, dir|
20
+ if e[0,1] != '.'
21
+ interp.addName(e, FilenameMetaInfo.new.setParentDir(dir))
22
+ end
23
+ end
24
+
25
+ shows = interp.processNames
26
+
27
+ showsForDisplay = []
28
+ shows.keys.sort.each do |k|
29
+ # Show name
30
+ heading = k
31
+ # Show episodes
32
+ body = ""
33
+ ranges = shows[k]
34
+ season = nil
35
+ comma = true
36
+ ranges.episodeRanges.each do |r|
37
+ if ! season || season != r.season
38
+ body << "<br/>" if season
39
+ body << " Season #{r.season}: "
40
+ season = r.season
41
+ comma = false
42
+ end
43
+ body << "," if comma
44
+ if r.size > 1
45
+ body << " #{r.startEpisode}-#{r.endEpisode}"
46
+ else
47
+ body << " #{r.startEpisode}"
48
+ end
49
+ comma = true
50
+ end
51
+ showsForDisplay.push [heading, body]
52
+ end
53
+
54
+
55
+ menu = haml :menu_partial, :locals => { :links => settings.menuLinks, :active_link => "Shows" }
56
+ haml :show_list_partial, :views => "plugins/shows/views", :locals => {:menu => menu, :showsForDisplay => showsForDisplay}
57
+ end
@@ -0,0 +1,33 @@
1
+ =locals[:menu]
2
+
3
+ #accordion{:class => "panel-group" }
4
+ - showsForDisplay = locals[:showsForDisplay]
5
+ - num = 0
6
+ - showsForDisplay.each do |head, body|
7
+ %div{:class => "panel panel-default"}
8
+ .panel-heading
9
+ %h4{:class => "panel-title"}
10
+ %a{ "data-toggle" => "collapse", "data-parent" => "#accordion", :href => "#collapse#{num}" }
11
+ = head
12
+ %div{ :id => "collapse#{num}", :class => "panel-collapse collapse #{num == 0 ? "in" : ""}"}
13
+ .panel-body
14
+ = body
15
+ - num += 1
16
+
17
+
18
+ -# Tile-based display:
19
+ -#- showsForDisplay = locals[:showsForDisplay]
20
+ -#- colCount = 6
21
+ -#- showsForDisplay.each do |head, body|
22
+ -# - if colCount >= 6
23
+ -# %div{ :class => :row }
24
+ -# - colCount = 0
25
+ -# %div{ :class => "col-md-2" }
26
+ -# %div{ :class => "list-group" }
27
+ -# %div{:class => "list-group-item" }
28
+ -# %h4{:class => "list-group-item-heading"}
29
+ -# = head
30
+ -# %p{:class => "list-group-item-text"}
31
+ -# = body
32
+ -# - colCount += 1
33
+
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quartz_flow_plugin_shows
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jeff Williams
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: quartz_flow
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.0.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.0.2
30
+ description: Plugin for quartz_flow that displays downloaded shows
31
+ email:
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - plugins/shows/lib/showname_parse.rb
37
+ - plugins/shows/routes.rb
38
+ - plugins/shows/views/show_list_partial.haml
39
+ - plugins/shows/links.rb
40
+ homepage: https://github.com/jeffwilliams/quartz-flow
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 1.8.23
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: Plugin for quartz_flow that displays downloaded shows
64
+ test_files: []
65
+ has_rdoc: false