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.
- data/plugins/shows/lib/showname_parse.rb +529 -0
- data/plugins/shows/links.rb +1 -0
- data/plugins/shows/routes.rb +57 -0
- data/plugins/shows/views/show_list_partial.haml +33 -0
- metadata +65 -0
|
@@ -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
|