addic7ed 3.0.0 → 4.0.0.pre.beta.5

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.
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