addic7ed 3.0.0 → 4.0.0.pre.beta.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/addic7ed.rb +5 -10
  3. data/lib/addic7ed/common.rb +13 -1285
  4. data/lib/addic7ed/config.json +1417 -0
  5. data/lib/addic7ed/errors.rb +8 -7
  6. data/lib/addic7ed/models/episode.rb +112 -0
  7. data/lib/addic7ed/models/search.rb +90 -0
  8. data/lib/addic7ed/models/subtitle.rb +109 -0
  9. data/lib/addic7ed/models/subtitles_collection.rb +63 -0
  10. data/lib/addic7ed/models/video_file.rb +147 -0
  11. data/lib/addic7ed/service.rb +13 -0
  12. data/lib/addic7ed/services/check_compatibility.rb +44 -0
  13. data/lib/addic7ed/services/download_subtitle.rb +53 -0
  14. data/lib/addic7ed/services/get_shows_list.rb +29 -0
  15. data/lib/addic7ed/services/{addic7ed_comment_normalizer.rb → normalize_comment.rb} +4 -8
  16. data/lib/addic7ed/services/normalize_version.rb +22 -0
  17. data/lib/addic7ed/services/parse_page.rb +43 -0
  18. data/lib/addic7ed/services/parse_subtitle.rb +79 -0
  19. data/lib/addic7ed/services/url_encode_show_name.rb +46 -0
  20. data/lib/addic7ed/version.rb +1 -1
  21. metadata +63 -50
  22. data/bin/addic7ed +0 -144
  23. data/lib/addic7ed/episode.rb +0 -95
  24. data/lib/addic7ed/parser.rb +0 -105
  25. data/lib/addic7ed/services/addic7ed_version_normalizer.rb +0 -24
  26. data/lib/addic7ed/show_list.rb +0 -61
  27. data/lib/addic7ed/subtitle.rb +0 -72
  28. data/lib/addic7ed/video_file.rb +0 -41
  29. data/spec/lib/addic7ed/common_spec.rb +0 -21
  30. data/spec/lib/addic7ed/episode_spec.rb +0 -165
  31. data/spec/lib/addic7ed/services/addic7ed_comment_normalizer_spec.rb +0 -12
  32. data/spec/lib/addic7ed/services/addic7ed_version_normalizer_spec.rb +0 -73
  33. data/spec/lib/addic7ed/show_list_spec.rb +0 -42
  34. data/spec/lib/addic7ed/subtitle_spec.rb +0 -182
  35. data/spec/lib/addic7ed/video_file_spec.rb +0 -159
  36. data/spec/responses/basic_redirection.http +0 -13
  37. data/spec/responses/homepage.http +0 -921
  38. data/spec/responses/redirection_loop.http +0 -12
  39. data/spec/responses/walking-dead-3-2-1.http +0 -770
  40. data/spec/responses/walking-dead-3-2-48.http +0 -2117
  41. data/spec/responses/walking-dead-3-2-7.http +0 -659
  42. data/spec/responses/walking-dead-3-2-8.http +0 -815
  43. data/spec/responses/walking-dead-3-2-8_best_subtitle.http +0 -1928
  44. data/spec/responses/walking-dead-3-4-8.http +0 -732
  45. data/spec/responses/walking-dead-3-42-8.http +0 -13
  46. data/spec/spec_helper.rb +0 -26
@@ -1,9 +1,10 @@
1
1
  module Addic7ed
2
- exceptions = [
3
- :InvalidFilename, :ShowNotFound, :EpisodeNotFound, :LanguageNotSupported,
4
- :ParsingError, :NoSubtitleFound, :DownloadError, :DownloadLimitReached,
5
- :SubtitleCannotBeSaved, :HTTPError
6
- ]
7
-
8
- exceptions.each { |e| const_set(e, Class.new(StandardError)) }
2
+ class InvalidFilename < StandardError; end
3
+ class ShowNotFound < StandardError; end
4
+ class EpisodeNotFound < StandardError; end
5
+ class LanguageNotSupported < StandardError; end
6
+ class ParsingError < StandardError; end
7
+ class NoSubtitleFound < StandardError; end
8
+ class DownloadError < StandardError; end
9
+ class DailyLimitExceeded < DownloadError; end
9
10
  end
@@ -0,0 +1,112 @@
1
+ require "net/http"
2
+ require "open-uri"
3
+
4
+ module Addic7ed
5
+ # Represents a TV show episode.
6
+ #
7
+ # @attr showname [String] TV show name.
8
+ # @attr season [Numeric] Season number.
9
+ # @attr episode [Numeric] Episode number in the season.
10
+
11
+ class Episode
12
+ attr_reader :showname, :season, :episode
13
+
14
+ # Creates a new instance of {Episode}.
15
+ #
16
+ # @param showname [String] TV show name, as extracted from the video file name
17
+ # (_e.g._ both +"Game.of.Thrones"+ and +"Game of Thrones"+ are valid)
18
+ # @param season [Numeric] Season number
19
+ # @param episode [Numeric] Episode number in the season
20
+ #
21
+ # @example
22
+ # Addic7ed::Episode.new("Game of Thrones", 6, 9)
23
+ # #=> #<Addic7ed::Episode
24
+ # # @episode=9,
25
+ # # @season=6,
26
+ # # @showname="Game.of.Thrones",
27
+ # # @subtitles={:fr=>nil, :ar=>nil, :az=>nil, ..., :th=>nil, :tr=>nil, :vi=>nil}
28
+ # # >
29
+
30
+ def initialize(showname, season, episode)
31
+ @showname = showname
32
+ @season = season
33
+ @episode = episode
34
+ @subtitles = languages_hash { |code, _| { code => nil } }
35
+ end
36
+
37
+ # Returns a list of all available {Subtitle}s for this {Episode} in the given +language+.
38
+ #
39
+ # @param language [String] Language code we want returned {Subtitle}s to be in.
40
+ #
41
+ # @return [Array<Subtitle>] List of {Subtitle}s available on Addic7ed for the given +language+.
42
+ #
43
+ # @example
44
+ # Addic7ed::Episode.new("Game.of.Thrones", 3, 9).subtitles(:fr)
45
+ # #=> [
46
+ # # #<Addic7ed::Subtitle
47
+ # # @comment="works with ctrlhd",
48
+ # # @downloads=28130,
49
+ # # @hi=false,
50
+ # # @language="French",
51
+ # # @source="http://addic7ed.com",
52
+ # # @status="Completed",
53
+ # # @url="http://www.addic7ed.com/updated/8/76081/0",
54
+ # # @version="EVOLVE">,
55
+ # # #<Addic7ed::Subtitle
56
+ # # @comment="la fabrique",
57
+ # # @downloads=1515,
58
+ # # @hi=false,
59
+ # # @language="French",
60
+ # # @source="http://sous-titres.eu",
61
+ # # @status="Completed",
62
+ # # @url="http://www.addic7ed.com/original/76081/11",
63
+ # # @version="EVOLVE">,
64
+ # # #<Addic7ed::Subtitle
65
+ # # @comment="la fabrique",
66
+ # # @downloads=917,
67
+ # # @hi=false,
68
+ # # @language="French",
69
+ # # @source="http://sous-titres.eu",
70
+ # # @status="Completed",
71
+ # # @url="http://www.addic7ed.com/original/76081/12",
72
+ # # @version="WEB,DL,NTB,&,YFN">
73
+ # # ]
74
+
75
+ def subtitles(language)
76
+ @subtitles[language] ||= Addic7ed::ParsePage.call(page_url(language))
77
+ end
78
+
79
+ # Returns the URL of the Addic7ed webpage listing subtitles for this {Episode}
80
+ # in the given +language+.
81
+ #
82
+ # @param language [String] Language code we want the webpage to list subtitles in.
83
+ #
84
+ # @return [String] Fully qualified URL of the webpage on Addic7ed.
85
+ #
86
+ # @example
87
+ # Addic7ed::Episode.new("Game of Thrones", 6, 9).page_url
88
+ # #=> "http://www.addic7ed.com/serie/Game_of_Thrones/6/9/8"
89
+
90
+ def page_url(language)
91
+ localized_urls[language]
92
+ end
93
+
94
+ private
95
+
96
+ def localized_urls
97
+ @localized_urls ||= languages_hash { |code, lang| { code => localized_url(lang[:id]) } }
98
+ end
99
+
100
+ def url_encoded_showname
101
+ @url_encoded_showname ||= URLEncodeShowName.call(showname)
102
+ end
103
+
104
+ def localized_url(lang)
105
+ "http://www.addic7ed.com/serie/#{url_encoded_showname}/#{season}/#{episode}/#{lang}"
106
+ end
107
+
108
+ def languages_hash(&block)
109
+ Hash.new { raise LanguageNotSupported }.merge(LANGUAGES.map(&block).reduce(&:merge))
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,90 @@
1
+ module Addic7ed
2
+ # Represents a subtitle search for a +video_filename+ in a +language+ with
3
+ # multiple search +criterias+.
4
+ #
5
+ # @attr video_filename [String] Video file name we're searching subtitles for.
6
+ # @attr language [String] ISO code of language (_e.g._ "en", "fr", "es").
7
+ # @attr criterias [Hash] List of search criterias as a {Hash}.
8
+
9
+ class Search
10
+ attr_reader :video_filename, :language, :criterias
11
+
12
+ # Creates a new instance of {Search}.
13
+ #
14
+ # Currently supported search criterias are:
15
+ # * +no_hi+: do not include hearing impaired subtitles (defaults to +false+)
16
+ #
17
+ # @param video_filename [String] Path to the video file for which we search subtitles
18
+ # (either relative or absolute path)
19
+ # @param language [String] ISO code of target subtitles language
20
+ # @param criterias [Hash] List of search criterias the subtitles must match
21
+ # (will be merged with default criterias as described above)
22
+ #
23
+ # @example
24
+ # Addic7ed::Search.new("Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv", :fr)
25
+ # #=> #<Addic7ed::Search
26
+ # # @criterias={:no_hi=>false},
27
+ # # @language=:fr,
28
+ # # @video_filename="Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv"
29
+ # # >
30
+
31
+ def initialize(video_filename, language, criterias = {})
32
+ @video_filename = video_filename
33
+ @language = language
34
+ @criterias = default_criterias.merge(criterias)
35
+ end
36
+
37
+ # Returns the {VideoFile} object representing the video file we're searching subtitles for.
38
+ #
39
+ # @return [VideoFile] the {VideoFile} associated with this {Search}
40
+
41
+ def video_file
42
+ @video_file ||= VideoFile.new(video_filename)
43
+ end
44
+
45
+ # Returns the {Episode} object we're searching subtitles for.
46
+ #
47
+ # @return [Episode] the {Episode} associated with this {Search}
48
+
49
+ def episode
50
+ @episode ||= Episode.new(video_file.showname, video_file.season, video_file.episode)
51
+ end
52
+
53
+ # Returns the list of all available subtitles for this search,
54
+ # regardless of completeness, compatibility or search +criterias+.
55
+ #
56
+ # @return [SubtitlesCollection] all subtitles for the searched episode
57
+
58
+ def all_subtitles
59
+ @all_subtitles ||= SubtitlesCollection.new(episode.subtitles(language))
60
+ end
61
+
62
+ # Returns the list of subtitles completed and compatible with the episode we're searching
63
+ # subtitles for, regardless of search +criterias+.
64
+ #
65
+ # @return [SubtitlesCollection] subtitles completed and compatible with the searched episode
66
+
67
+ def matching_subtitles
68
+ @matching_subtitles ||= all_subtitles.completed.compatible_with(video_file.group)
69
+ end
70
+
71
+ # Returns the best subtitle for the episode we're searching subtitles for.
72
+ #
73
+ # The best subtitle means the more popular (_i.e._ most downloaded) subtitle among completed,
74
+ # compatible subtitles for the episode we're searching subtitles for.
75
+ #
76
+ # @return [SubtitlesCollection] subtitles completed and compatible with the searched episode
77
+
78
+ def best_subtitle
79
+ @best_subtitle ||= matching_subtitles.most_popular
80
+ end
81
+
82
+ private
83
+
84
+ def default_criterias
85
+ {
86
+ no_hi: false
87
+ }
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,109 @@
1
+ module Addic7ed
2
+ # Represents a subtitle on Addic7ed.
3
+ #
4
+ # This model contains as much information as possible for a subtitle
5
+ # as parsed on Addic7ed website.
6
+ #
7
+ # @attr version [String] Main compatible release group(s)
8
+ # (evenually as a comma-separated list).
9
+ # @attr language [String] Language the subtitle is written in
10
+ # (_e.g._: "French", "English").
11
+ # @attr status [String] Translation/synchronization advancement status
12
+ # (_e.g._: "60%"" or "Completed").
13
+ # @attr source [String] URL of website the subtitle was first published on.
14
+ # @attr downloads [Numeric] Number of times this subtitle has been downloaded.
15
+ # @attr comment [String] Comment manually added by the subtitle author/publisher
16
+ # (usually related to extra-compatibilities or resync source).
17
+ # @attr hi [Boolean] Hearing-impaired support.
18
+ # @attr url [String] Download URL of actual subtitle file (warning: Addic7ed servers
19
+ # won't serve a subtite file without a proper +Referer+ HTTP header which can be
20
+ # retrieved from +episode.page_url+).
21
+
22
+ class Subtitle
23
+ attr_reader :version, :language, :status, :source, :downloads, :comment, :hi
24
+ attr_accessor :url
25
+
26
+ # Creates a new instance of {Subtitle} created using +options+,
27
+ # usually from data parsed from an Addic7ed page.
28
+ #
29
+ # The +options+ hash can have the following keys as symbols:
30
+ # * +version+: main compatible release group(s) as parsed on the Addic7ed website
31
+ # * +language+: language full name
32
+ # * +status+: full-text advancement status
33
+ # * +source+: URL of website the subtitle was originally published on
34
+ # * +downloads+: number of times the subtitle has been downloaded
35
+ # * +comment+: manually added comment from the author or publisher
36
+ # * +hi+: hearing-impaired support
37
+ # * +url+: download URL for the subtitle file
38
+ #
39
+ # @param options [Hash] subtitle information as a {Hash}
40
+ #
41
+ # @example
42
+ # Addic7ed::Subtitle.new(
43
+ # version: "Version KILLERS, 720p AVS, 0.00 MBs",
44
+ # language: "French",
45
+ # status: "Completed",
46
+ # source: "http://sous-titres.eu",
47
+ # downloads: 10335,
48
+ # comment: "works with 1080p.BATV",
49
+ # hi: false,
50
+ # url: "http://www.addic7ed.com/original/113643/4"
51
+ # )
52
+ # #=> #<Addic7ed::Subtitle
53
+ # # @version="KILLERS,AVS",
54
+ # # @language="French"
55
+ # # @status="Completed"
56
+ # # @url="http://www.addic7ed.com/original/113643/4"
57
+ # # @source="http://sous-titres.eu"
58
+ # # @hi=false
59
+ # # @downloads=10335
60
+ # # @comment="works with 1080p.batv"
61
+ # # >
62
+
63
+ def initialize(options = {})
64
+ @version = NormalizeVersion.call(options[:version])
65
+ @language = options[:language]
66
+ @status = options[:status]
67
+ @url = options[:url]
68
+ @source = options[:source]
69
+ @hi = options[:hi]
70
+ @downloads = options[:downloads].to_i || 0
71
+ @comment = NormalizeComment.call(options[:comment])
72
+ end
73
+
74
+ # Returns a human-friendly readable string representing the {Subtitle}
75
+ #
76
+ # TODO: move to the CLI codebase
77
+ #
78
+ # @return [String]
79
+ #
80
+ # @example
81
+ # Addic7ed::Subtitle.new(
82
+ # version: "Version 720p AVS, 0.00 MBs",
83
+ # language: "French",
84
+ # status: "Completed",
85
+ # downloads: 42,
86
+ # url: "http://www.addic7ed.com/original/113643/4"
87
+ # ).to_s
88
+ # #=> "http://www.addic7ed.com/original/113643/4\t->\tAVS (French, Completed) [42 downloads]"
89
+
90
+ def to_s
91
+ str = "#{url}\t->\t#{version} (#{language}, #{status}) [#{downloads} downloads]"
92
+ str += " (source #{source})" if source
93
+ str
94
+ end
95
+
96
+ # Completeness status of the {Subtitle}.
97
+ #
98
+ # @return [Boolean] Returns +true+ if {Subtitle} is complete,
99
+ # +false+ otherwise (partially complete)
100
+ #
101
+ # @example
102
+ # Addic7ed::Subtitle.new(status: "50%").completed? #=> false
103
+ # Addic7ed::Subtitle.new(status: "Completed").completed? #=> true
104
+
105
+ def completed?
106
+ status == "Completed"
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,63 @@
1
+ module Addic7ed
2
+ # Represents a collection of {Subtitle} objects.
3
+ #
4
+ # This collection inherits from {Array} so it behaves exaclty like it,
5
+ # but it also provides some methods to filter, order and choose the best subtitle.
6
+ class SubtitlesCollection < Array
7
+ # Returns only subtitles that are compatible with +group+.
8
+ # @param group [String] Release group we want the returned subtitles to be compatible with
9
+ #
10
+ # @return [SubtitleCollection] Copy of collection with subtitles compatible with +group+ only
11
+ #
12
+ # @example
13
+ # fov = Addic7ed::Subtitle.new(version: "FOV")
14
+ # lol = Addic7ed::Subtitle.new(version: "LOL")
15
+ # dimension = Addic7ed::Subtitle.new(version: "DIMENSION")
16
+ # collection = Addic7ed::SubtitlesCollection.new([fov, lol, dimension])
17
+ #
18
+ # collection.compatible_with("DIMENSION")
19
+ # #=> [#<Addic7ed::Subtitle @version="LOL">, #<Addic7ed::Subtitle @version="DIMENSION">]
20
+
21
+ def compatible_with(group)
22
+ select { |subtitle| CheckCompatibility.call(subtitle, group) }
23
+ end
24
+
25
+ # Returns only completed subtitles.
26
+ #
27
+ # @return [SubtitleCollection] Copy of collection with completed subtitles only
28
+ #
29
+ # @example
30
+ # complete = Addic7ed::Subtitle.new(status: "Completed")
31
+ # wip = Addic7ed::Subtitle.new(status: "50%")
32
+ # collection = Addic7ed::SubtitlesCollection.new([complete, wip])
33
+ #
34
+ # collection.completed
35
+ # #=> [#<Addic7ed::Subtitle @status="Completed">]
36
+
37
+ def completed
38
+ select(&:completed?)
39
+ end
40
+
41
+ # Returns the most downloaded subtitle.
42
+ #
43
+ # @return [Subtitle] Subtitle of the collection with the more downloads
44
+ #
45
+ # @example
46
+ # popular = Addic7ed::Subtitle.new(downloads: 1000)
47
+ # unpopular = Addic7ed::Subtitle.new(downloads: 3)
48
+ # collection = Addic7ed::SubtitlesCollection.new([popular, unpopular])
49
+ #
50
+ # collection.most_popular
51
+ # #=> #<Addic7ed::Subtitle @downloads=1000>
52
+
53
+ def most_popular
54
+ sort_by(&:downloads).last
55
+ end
56
+
57
+ private
58
+
59
+ def select
60
+ SubtitlesCollection.new(super)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,147 @@
1
+ module Addic7ed
2
+ # Represents the video file you're looking a subtitle for.
3
+ #
4
+ # This class will extract from the video file name the show name, season, episode, group, etc.
5
+ #
6
+ # It expects the file to be named according to The Scene rules,
7
+ # but actually supports a wide variety of common naming schemes.
8
+ class VideoFile
9
+ # @!visibility private
10
+ TVSHOW_REGEX = /\A(?<showname>.*\w)[\[\. ]+S?(?<season>\d{1,2})[-\. ]?[EX]?(?<episode>\d{2})([-\. ]?[EX]?\d{2})*[\]\. ]+(?<tags>.*)-(?<group>\w*)\[?(?<distribution>\w*)\]?(\.\w{3})?\z/i # rubocop:disable Metrics/LineLength
11
+
12
+ # @!visibility private
13
+ attr_reader :filename, :regexp_matches
14
+
15
+ # Returns a new instance of {VideoFile}.
16
+ # It expects a video file name, either with or without path and
17
+ # either absolute or relative.
18
+ #
19
+ # @param filename [String] File name of the video file on disk
20
+ # (either relative or absolute).
21
+ #
22
+ # @return [String] Distribution group name
23
+ #
24
+ # @example
25
+ # Addic7ed::VideoFile.new("Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
26
+ # Addic7ed::VideoFile.new("/home/mike/Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
27
+ # Addic7ed::VideoFile.new("../Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
28
+
29
+ def initialize(filename)
30
+ @filename = filename
31
+ @regexp_matches = TVSHOW_REGEX.match(basename)
32
+ raise InvalidFilename if regexp_matches.nil?
33
+ end
34
+
35
+ # Returns the TV show name extracted from the file name.
36
+ #
37
+ # @return [String] TV show name
38
+ #
39
+ # @example
40
+ # video_file = Addic7ed::VideoFile.new("Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
41
+ # video_file.showname #=> "Game.of.Thrones"
42
+
43
+ def showname
44
+ @showname ||= regexp_matches[:showname]
45
+ end
46
+
47
+ # Returns the TV show season number extracted from the file name.
48
+ #
49
+ # @return [Integer] TV show season number
50
+ #
51
+ # @example
52
+ # video_file = Addic7ed::VideoFile.new("Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
53
+ # video_file.season #=> 6
54
+
55
+ def season
56
+ @season ||= regexp_matches[:season].to_i
57
+ end
58
+
59
+ # Returns the TV show episode number extracted from the file name.
60
+ #
61
+ # @return [Integer] TV show episode number
62
+ #
63
+ # @example
64
+ # video_file = Addic7ed::VideoFile.new("Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
65
+ # video_file.episode #=> 9
66
+
67
+ def episode
68
+ @episode ||= regexp_matches[:episode].to_i
69
+ end
70
+
71
+ # Returns the upcased release tags extracted from the file name
72
+ # (like +HDTV+, +720P+, +XviD+, +PROPER+, ...).
73
+ #
74
+ # @return [Array<String>] Release video, audio or packaging tags
75
+ #
76
+ # @example
77
+ # video_file = Addic7ed::VideoFile.new("Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
78
+ # video_file.tags #=> ["720P", "HDTV", "X264"]
79
+
80
+ def tags
81
+ @tags ||= regexp_matches[:tags].upcase.split(/[\. ]/)
82
+ end
83
+
84
+ # Returns the upcased release group extracted from the file name.
85
+ #
86
+ # @return [String] Release group name
87
+ #
88
+ # @example
89
+ # video_file = Addic7ed::VideoFile.new("Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
90
+ # video_file.group #=> "AVS"
91
+
92
+ def group
93
+ @group ||= regexp_matches[:group].upcase
94
+ end
95
+
96
+ # Returns the upcased distribution group extracted from the file name.
97
+ #
98
+ # @return [String] Distribution group name
99
+ #
100
+ # @example
101
+ # video_file = Addic7ed::VideoFile.new("Game.of.Thrones.S06E09.720p.HDTV.x264-AVS[eztv].mkv")
102
+ # video_file.distribution #=> "EZTV"
103
+
104
+ def distribution
105
+ @distribution ||= regexp_matches[:distribution].upcase
106
+ end
107
+
108
+ # Returns the base file name (without path).
109
+ #
110
+ # @return [String] Base file name
111
+ #
112
+ # @example
113
+ # video_file = Addic7ed::VideoFile.new("../Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
114
+ # video_file.basename #=> "Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv"
115
+
116
+ def basename
117
+ @basename ||= File.basename(filename)
118
+ end
119
+
120
+ # Returns the video file name as passed to {#initialize}.
121
+ #
122
+ # @return [String] File name
123
+ #
124
+ # @example
125
+ # video_file = Addic7ed::VideoFile.new("../Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv")
126
+ # video_file.to_s #=> "../Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv"
127
+
128
+ def to_s
129
+ filename
130
+ end
131
+
132
+ # Returns a multiline, human-readable breakdown of the file name
133
+ # including all detected attributes (show name, season, episode, tags, ...).
134
+ #
135
+ # @return [String] a human-readable breakdown of the file name
136
+
137
+ def inspect
138
+ "Guesses for #{filename}:\n" \
139
+ " show: #{showname}\n" \
140
+ " season: #{season}\n" \
141
+ " episode: #{episode}\n" \
142
+ " tags: #{tags}\n" \
143
+ " group: #{group}\n" \
144
+ " distribution: #{distribution}"
145
+ end
146
+ end
147
+ end