osdb 0.0.9 → 0.0.10
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/.travis.yml +9 -0
- data/README.md +2 -0
- data/bin/getsub +88 -38
- data/lib/osdb/sub.rb +24 -8
- data/lib/osdb/version.rb +1 -1
- data/osdb.gemspec +1 -0
- metadata +16 -4
    
        data/.travis.yml
    ADDED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -3,6 +3,8 @@ | |
| 3 3 | 
             
            Client library for the [OSDb protocol](http://trac.opensubtitles.org/projects/opensubtitles/wiki/XMLRPC).
         | 
| 4 4 | 
             
            Currently the implentation is limited to movie identification and subtitles search
         | 
| 5 5 |  | 
| 6 | 
            +
            [](http://travis-ci.org/byroot/ruby-osdb)
         | 
| 7 | 
            +
             | 
| 6 8 | 
             
            ## Examples
         | 
| 7 9 |  | 
| 8 10 | 
             
            Just read the source of `bin/getsub` it is a typical example of OSDb's capacities.
         | 
    
        data/bin/getsub
    CHANGED
    
    | @@ -16,16 +16,23 @@ end | |
| 16 16 | 
             
              opts.separator "Usage: getsub [options] DIRECTORY | VIDEO_FILE [VIDEO_FILE ...]"
         | 
| 17 17 | 
             
              opts.separator ""
         | 
| 18 18 | 
             
              opts.separator "Main options:"
         | 
| 19 | 
            -
             | 
| 20 | 
            -
              opts.on("-l", "--language LANGUAGE", "Sub language ISO  | 
| 21 | 
            -
                 | 
| 19 | 
            +
             | 
| 20 | 
            +
              opts.on("-l", "--language LANGUAGE", "Sub language ISO 639-2 code like fre or eng. Default: env $LANG (#{env_lang.to_iso639_2b})") do |language|
         | 
| 21 | 
            +
                if language.to_s.length != 3
         | 
| 22 | 
            +
                  STDERR.puts "Language should specified as ISO 639-2 (ie, 3 letters, like 'eng' or 'fre')"
         | 
| 23 | 
            +
                  exit 1
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
                @options[:language] = language.to_s
         | 
| 22 26 | 
             
              end
         | 
| 23 | 
            -
             | 
| 27 | 
            +
             | 
| 24 28 | 
             
              opts.on("-d", "--directory DIRECTORY", "Specify a directory to search recursively for movies") do |dir|
         | 
| 25 29 | 
             
                @options[:dir] = dir
         | 
| 26 30 | 
             
              end
         | 
| 27 31 |  | 
| 28 32 | 
             
              opts.on("-f", "--force", "Download sub even if video already has one") { @options[:force] = true }
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              opts.on("-t", "--type FORMATS", "Select only subtitles in specified formats. e.g -t srt,sub") { |formats| @options[:formats] = formats.to_s.split(',') }
         | 
| 35 | 
            +
             | 
| 29 36 | 
             
            end
         | 
| 30 37 | 
             
            @parser.parse!
         | 
| 31 38 |  | 
| @@ -66,44 +73,34 @@ def ask_user_to_identify_movie(movies) | |
| 66 73 | 
             
              print 'id: '
         | 
| 67 74 | 
             
              str = STDIN.gets # TODO: rule #1, never trust user input
         | 
| 68 75 | 
             
              puts
         | 
| 69 | 
            -
              movies[movies.keys[str.to_i]]
         | 
| 76 | 
            +
              movies[movies.keys[str.to_i]] || []
         | 
| 70 77 | 
             
            end
         | 
| 71 78 |  | 
| 72 | 
            -
            def  | 
| 73 | 
            -
               | 
| 74 | 
            -
              imdb_results = server.search_imdb(:query => movie.name)
         | 
| 75 | 
            -
              if imdb_results.any?
         | 
| 76 | 
            -
                if imdb_results.length == 1
         | 
| 77 | 
            -
                  imdb_result = imdb_results.first
         | 
| 78 | 
            -
                  puts "* found on IMDB with ID: #{imdb_result.imdbid}"
         | 
| 79 | 
            -
                else
         | 
| 80 | 
            -
                  movies = Hash[imdb_results.map{ |r| [r.title, r] }]
         | 
| 81 | 
            -
                  imdb_result = ask_user_to_identify_movie(movies)
         | 
| 82 | 
            -
                end
         | 
| 83 | 
            -
                subs = server.search_subtitles(:sublanguageid => @options[:language], :imdbid => imdb_result.imdbid)
         | 
| 84 | 
            -
                if subs.any?
         | 
| 85 | 
            -
                  select_and_download!(subs, movie)
         | 
| 86 | 
            -
                else
         | 
| 87 | 
            -
                  puts "* no sub found for this movie"
         | 
| 88 | 
            -
                end
         | 
| 89 | 
            -
              else
         | 
| 90 | 
            -
                puts "* no movie found on IMDB"
         | 
| 91 | 
            -
              end
         | 
| 79 | 
            +
            def normalize_name(name)
         | 
| 80 | 
            +
              name.downcase.gsub(/[\s\.\-\_]+/, ' ')
         | 
| 92 81 | 
             
            end
         | 
| 93 82 |  | 
| 94 | 
            -
            def  | 
| 95 | 
            -
              return  | 
| 96 | 
            -
              movies = group_by_movie_name(subs)
         | 
| 97 | 
            -
              return movies.values.first.max if movies.length == 1
         | 
| 83 | 
            +
            def select_movie(movies)
         | 
| 84 | 
            +
              return movies.values.first || [] if movies.length <= 1
         | 
| 98 85 |  | 
| 99 86 | 
             
              puts "D'oh! You stumbled upon a hash conflict, please resolve it:"
         | 
| 100 87 | 
             
              puts
         | 
| 101 | 
            -
               | 
| 102 | 
            -
             | 
| 88 | 
            +
              ask_user_to_identify_movie(movies)
         | 
| 89 | 
            +
            end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            def select_format(subs)
         | 
| 92 | 
            +
              return subs unless @options[:formats]
         | 
| 93 | 
            +
              subs.select{ |s| @options[:formats].include?(s.format) }
         | 
| 94 | 
            +
            end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            def select_sub(subs)
         | 
| 97 | 
            +
              subs = select_format(subs)
         | 
| 98 | 
            +
              movies = group_by_movie_name(subs)
         | 
| 99 | 
            +
              subs = select_movie(movies)
         | 
| 100 | 
            +
              subs.max_by(&:score)
         | 
| 103 101 | 
             
            end
         | 
| 104 102 |  | 
| 105 | 
            -
            def  | 
| 106 | 
            -
              sub = select_sub(subs)
         | 
| 103 | 
            +
            def download_sub!(sub, movie)
         | 
| 107 104 | 
             
              sub_path = movie.sub_path(sub.format)
         | 
| 108 105 | 
             
              download!(sub.url, sub_path)
         | 
| 109 106 | 
             
            end
         | 
| @@ -130,17 +127,70 @@ if movies.empty? | |
| 130 127 | 
             
              exit 1
         | 
| 131 128 | 
             
            end
         | 
| 132 129 |  | 
| 130 | 
            +
            def search_by_hash(server, movie)
         | 
| 131 | 
            +
              server.search_subtitles(:moviehash => movie.hash, :moviebytesize => movie.size.to_s, :sublanguageid => @options[:language])
         | 
| 132 | 
            +
            end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
            def search_by_path(server, movie)
         | 
| 135 | 
            +
              server.search_subtitles(:sublanguageid => @options[:language], :tag => movie.path)
         | 
| 136 | 
            +
            end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
            def search_by_name(server, movie)
         | 
| 139 | 
            +
              subs = server.search_subtitles(:sublanguageid => @options[:language], :query => movie.name)
         | 
| 140 | 
            +
              normalized_movie_name = normalize_name(movie.name)
         | 
| 141 | 
            +
              subs.select! do |sub|
         | 
| 142 | 
            +
                normalize_name(sub.filename).index(normalized_movie_name) # MAYBE: Levenshtein ?
         | 
| 143 | 
            +
              end
         | 
| 144 | 
            +
              subs if subs.any?
         | 
| 145 | 
            +
            end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
            def search_by_imdb(server, movie)
         | 
| 148 | 
            +
              imdb_results = server.search_imdb(:query => movie.name)
         | 
| 149 | 
            +
              if imdb_results.any?
         | 
| 150 | 
            +
                if imdb_results.length == 1
         | 
| 151 | 
            +
                  imdb_result = imdb_results.first
         | 
| 152 | 
            +
                  puts "* found on IMDB with ID: #{imdb_result.imdbid}"
         | 
| 153 | 
            +
                else
         | 
| 154 | 
            +
                  movies = Hash[imdb_results.map{ |r| [r.title, r] }]
         | 
| 155 | 
            +
                  imdb_result = ask_user_to_identify_movie(movies)
         | 
| 156 | 
            +
                end
         | 
| 157 | 
            +
                server.search_subtitles(:sublanguageid => @options[:language], :imdbid => imdb_result.imdbid)
         | 
| 158 | 
            +
              end
         | 
| 159 | 
            +
            end
         | 
| 160 | 
            +
             | 
| 133 161 | 
             
            movies.each do |movie|
         | 
| 134 162 | 
             
              begin
         | 
| 135 | 
            -
                puts "* search subs for: #{movie.path}"
         | 
| 136 | 
            -
                 | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 163 | 
            +
                puts "* search subs by hash for: #{movie.path}"
         | 
| 164 | 
            +
                sub = select_sub search_by_hash(server, movie)
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                unless sub
         | 
| 167 | 
            +
                  puts "* could not find sub by hash, trying IMDB"
         | 
| 168 | 
            +
                  sub = select_sub search_by_imdb(server, movie)
         | 
| 169 | 
            +
                end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                unless sub
         | 
| 172 | 
            +
                  puts "* no matches"
         | 
| 173 | 
            +
                  puts "* search subs by path"
         | 
| 174 | 
            +
                  sub = select_sub search_by_path(server, movie)
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                unless sub
         | 
| 178 | 
            +
                  puts "* still no matches"
         | 
| 179 | 
            +
                  puts "* search subs by filename"
         | 
| 180 | 
            +
                  sub = select_sub search_by_name(server, movie)
         | 
| 181 | 
            +
                end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                if sub
         | 
| 184 | 
            +
                  download_sub!(sub, movie)
         | 
| 139 185 | 
             
                else
         | 
| 140 | 
            -
                   | 
| 186 | 
            +
                  puts "Nothing worked, you are very unlucky :'("
         | 
| 141 187 | 
             
                end
         | 
| 142 188 | 
             
                puts
         | 
| 143 189 | 
             
              rescue Exception => e
         | 
| 190 | 
            +
                puts "Something crashed."
         | 
| 191 | 
            +
                puts "Feel free to report the error here: https://github.com/byroot/ruby-osdb/issues"
         | 
| 192 | 
            +
                puts "With the following debug informations:"
         | 
| 193 | 
            +
                puts
         | 
| 144 194 | 
             
                puts "#{e.class.name}: #{e.message}:"
         | 
| 145 195 | 
             
                puts e.backtrace
         | 
| 146 196 | 
             
              end
         | 
    
        data/lib/osdb/sub.rb
    CHANGED
    
    | @@ -1,24 +1,40 @@ | |
| 1 1 | 
             
            require 'uri'
         | 
| 2 2 |  | 
| 3 3 | 
             
            module OSDb
         | 
| 4 | 
            -
             | 
| 4 | 
            +
             | 
| 5 5 | 
             
              class Sub
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                attr_reader :url, :format, :language, :rating, : | 
| 8 | 
            -
             | 
| 6 | 
            +
             | 
| 7 | 
            +
                attr_reader :url, :format, :language, :rating, :user_ranks, :movie_name,
         | 
| 8 | 
            +
                  :filename, :raw_data, :downloads_count, :bad_reports_count
         | 
| 9 | 
            +
             | 
| 9 10 | 
             
                def initialize(data)
         | 
| 10 11 | 
             
                  @url = URI.parse(data['SubDownloadLink'])
         | 
| 11 12 | 
             
                  @format = data['SubFormat']
         | 
| 12 13 | 
             
                  @language = Language.from_iso639_2b(data['SubLanguageID'])
         | 
| 13 14 | 
             
                  @rating = data['SubRating'].to_f
         | 
| 15 | 
            +
                  @user_ranks = data['UserRank']
         | 
| 14 16 | 
             
                  @movie_name = data['MovieName']
         | 
| 17 | 
            +
                  @filename = data['SubFileName']
         | 
| 18 | 
            +
                  @downloads_count = data['SubDownloadsCnt'].to_i
         | 
| 19 | 
            +
                  @bad_reports_count = data['SubBad'].to_i
         | 
| 15 20 | 
             
                  @raw_data = data
         | 
| 16 21 | 
             
                end
         | 
| 17 | 
            -
             | 
| 22 | 
            +
             | 
| 18 23 | 
             
                def <=>(other)
         | 
| 19 24 | 
             
                  rating <=> other.rating
         | 
| 20 25 | 
             
                end
         | 
| 21 | 
            -
             | 
| 26 | 
            +
             | 
| 27 | 
            +
                # Totaly subjective formula to evaluate subtitle quality
         | 
| 28 | 
            +
                # Originaly developed by runa (https://github.com/runa)
         | 
| 29 | 
            +
                # https://github.com/byroot/ruby-osdb/commit/9d71775#L0R122
         | 
| 30 | 
            +
                def score
         | 
| 31 | 
            +
                  uploader_score * downloads_count.next * (rating + 1) - bad_reports_count / downloads_count.next
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def uploader_score
         | 
| 35 | 
            +
                  user_ranks.empty? ? 1 : 2
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 22 38 | 
             
              end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            end
         | 
    
        data/lib/osdb/version.rb
    CHANGED
    
    
    
        data/osdb.gemspec
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: osdb
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.10
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -9,11 +9,22 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2012-08- | 
| 12 | 
            +
            date: 2012-08-26 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 15 | 
            +
              name: rake
         | 
| 16 | 
            +
              requirement: &70311392052000 !ruby/object:Gem::Requirement
         | 
| 17 | 
            +
                none: false
         | 
| 18 | 
            +
                requirements:
         | 
| 19 | 
            +
                - - ! '>='
         | 
| 20 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 21 | 
            +
                    version: '0'
         | 
| 22 | 
            +
              type: :development
         | 
| 23 | 
            +
              prerelease: false
         | 
| 24 | 
            +
              version_requirements: *70311392052000
         | 
| 14 25 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 26 | 
             
              name: rspec
         | 
| 16 | 
            -
              requirement: & | 
| 27 | 
            +
              requirement: &70311392067940 !ruby/object:Gem::Requirement
         | 
| 17 28 | 
             
                none: false
         | 
| 18 29 | 
             
                requirements:
         | 
| 19 30 | 
             
                - - ! '>='
         | 
| @@ -21,7 +32,7 @@ dependencies: | |
| 21 32 | 
             
                    version: '0'
         | 
| 22 33 | 
             
              type: :development
         | 
| 23 34 | 
             
              prerelease: false
         | 
| 24 | 
            -
              version_requirements: * | 
| 35 | 
            +
              version_requirements: *70311392067940
         | 
| 25 36 | 
             
            description: 
         | 
| 26 37 | 
             
            email:
         | 
| 27 38 | 
             
            - jean.boussier @nospam@ gmail.com
         | 
| @@ -32,6 +43,7 @@ extra_rdoc_files: [] | |
| 32 43 | 
             
            files:
         | 
| 33 44 | 
             
            - .gitignore
         | 
| 34 45 | 
             
            - .rspec
         | 
| 46 | 
            +
            - .travis.yml
         | 
| 35 47 | 
             
            - Gemfile
         | 
| 36 48 | 
             
            - README.md
         | 
| 37 49 | 
             
            - Rakefile
         |