Class: IMGSrc::API

Inherits:
Object
  • Object
show all
Extended by:
LibXML
Defined in:
lib/imgsrc.rb

Constant Summary collapse

ROOT_HOST =
'imgsrc.ru'
PROTO_VER =
'0.8'
CACHE_DIR =
'.imgsrc'
@@http_conn =

this method does not open the TCP connection

Net::HTTP.new(ROOT_HOST)
@@categories =
nil

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user, passwd_md5) ⇒ API

Returns a new instance of API.



97
98
99
100
101
102
103
104
105
# File 'lib/imgsrc.rb', line 97

def initialize(user, passwd_md5)
    @username   = user
    @Login      = { :login => @username, :passwd => passwd_md5 }
    @storage    = nil           # hostname of imgsrc storge server
    @stor_conn  = nil           # http-connection to storage host
    @albums     = []

    Dir.mkdir( CACHE_DIR ) unless File.directory?( CACHE_DIR )
end

Instance Attribute Details

#albumsObject (readonly)

Returns the value of attribute albums.



95
96
97
# File 'lib/imgsrc.rb', line 95

def albums
  @albums
end

#usernameObject (readonly)

Returns the value of attribute username.



95
96
97
# File 'lib/imgsrc.rb', line 95

def username
  @username
end

Class Method Details

.call_get(method, params = {}, cachable = :nocache) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/imgsrc.rb', line 54

def call_get(method, params = {}, cachable = :nocache)
    uri = "/#{method}#{params.empty? ? '' : '?'}#{params.map{ |key, value| "#{key}=#{value}" }.join('&')}"

    params_string = params.map { |k, v| /passw/ =~ k ? nil : "_#{k}-#{ k == 'create' ? v.encode('UTF-8') : v }" }
    cached_file = "#{CACHE_DIR}/#{method.gsub(/\//, '-')}#{params_string.compact.join}.xml"
    if cachable == :cache && File::exists?( cached_file )
        puts "using cached #{cached_file}"
        return File.read( cached_file )
    else
        # puts "fetching #{uri} to #{cached_file}"
        result = @@http_conn.get( uri ).body
        File.new( cached_file, "w" ).write( result ) rescue nil
        return result
    end
rescue Exception => x
    raise RuntimeError, "can not load #{method.sub(/.*\./, "")}: #{x.message}"
end

.categoriesObject

Get photo categories hash (id=>category)



50
51
52
# File 'lib/imgsrc.rb', line 50

def categories
    @@categories || load_categories
end

.extract_info(response) ⇒ Object

Raises:

  • (RuntimeError)


72
73
74
75
76
77
# File 'lib/imgsrc.rb', line 72

def extract_info(response)
    info = XML::Parser.string(response).parse.find_first '/info'
    raise RuntimeError, "Invalid xml:\r\n#{response}" unless info
    raise InfoError, "Unsupported protocol version #{info['proto']}" unless info['proto'] == PROTO_VER
    info
end

Instance Method Details

#create_album(name, args = {}) ⇒ Object

Create new album. Optional arguments: category, passwd

Raises:



119
120
121
122
123
124
125
126
127
# File 'lib/imgsrc.rb', line 119

def create_album(name, args = {})
    album = get_album(name) rescue nil
    raise CreateError, "Album #{name} already exists: #{album.size} photos, modified #{album.date}" if album

    params = { :create => name.encode('CP1251') }
    params[:create_category] = args[:category] if args[:category]
    params[:create_passwd] = args[:passwd] if args[:passwd]
    parse_info(self.class.call_get('cli/info.php', @Login.merge(params)))
end

#get_album(name) ⇒ Object

Get existing album by name



130
131
132
# File 'lib/imgsrc.rb', line 130

def get_album(name)
    @albums.fetch( @albums.index { |album| album.name == name } ) rescue raise RuntimeError, "no album #{name}"
end

#get_or_create_album(name, args = {}) ⇒ Object

Shortcut for getting exising album or creating new one



135
136
137
138
139
140
# File 'lib/imgsrc.rb', line 135

def get_or_create_album(name, args = {})
    album = get_album(name) rescue nil
    return album if album
    create_album(name, args)
    get_album(name)             # create_album receives full list - additional get_album() call required
end

#loginObject

Login and fetch user info

Raises:



108
109
110
111
112
113
114
115
116
# File 'lib/imgsrc.rb', line 108

def 
    raise LoginError, 'already logined' if @storage
    begin
        parse_info(self.class.call_get('cli/info.php', @Login, :nocache))
    rescue InfoError => x
        raise LoginError, x.message
    end
    self
end

#upload(name, files) ⇒ Object

Upload files to album

Raises:

  • (RuntimeError)


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/imgsrc.rb', line 143

def upload(name, files)
    raise RuntimeError, 'user is not logined (no storage host)' unless @stor_conn
    album = get_album(name)
    uri = "/cli/post.php?#{@Login.map{ |k, v| "#{k}=#{v}" }.join('&')}&album_id=#{album.id}"
    photos = nil
    files.each do |file|    # imgsrc.ru badly handles multi-file uploads (unstable work, unrecoverable errors)
        puts "uploading #{file}..."
        photos, retries = nil, 3
        begin
            photos = do_upload(uri, [file], :nobase64)
        rescue Exception => x
            puts "#{File.basename(file)}: upload failed (#{x.message}), #{retries - 1} retries left"
            retry if (retries -= 1) > 0
            raise UploadError, x.message
        end
    end
    album.photos, album.size = photos, photos.size if photos    # imgsrc returns whole album in response
    pp album
end