├── .gitignore ├── README.md ├── config └── config.exs ├── lib ├── instagram.ex ├── instagram │ └── config.ex ├── request.ex ├── steal.ex └── url = "https:::api.instagram.com:v1:users:self:med ├── mix.exs ├── mix.lock └── test ├── instagram_test.exs └── test_helper.exs /.gitignore: -------------------------------------------------------------------------------- 1 | /_build 2 | /cover 3 | /deps 4 | erl_crash.dump 5 | *.ez 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # exstagram 3 | 4 | Instagram v1 API wrapper written in Elixir. 5 | 6 | Please note, this is very much a work in progress. 7 | Feel free to contribute using pull requests. 8 | 9 | ## Example usage 10 | 11 | I made this simple phoenix app to show how to use exstagram! 12 | 13 | See it in action on Heroku: 14 | https://exstagram-example.herokuapp.com 15 | 16 | Here is the code for the above Heroku app: 17 | https://github.com/arthurcolle/exstagram_example 18 | 19 | To run it yourself, please run the following commands: 20 | * `git clone https://github.com/arthurcolle/exstagram_example` 21 | * `cd exstagram_example` 22 | * `mix deps.get` 23 | * `npm install` (may not be needed, but if you see any node-esque "throw err;" messages, this is why) 24 | 25 | Before you can run it yourself, you'll have to configure three environment variables: 26 | They are `INSTAGRAM_CLIENT_ID`, `INSTAGRAM_CLIENT_SECRET`, and `INSTAGRAM_CALLBACK_URL` (see `exstagram/lib/instagram.ex` for usage) 27 | Finally, run: 28 | * `mix phoenix.server` 29 | 30 | 31 | ## Contributors 32 | * Clone repo, i.e. `git clone https://github.com/arthurcolle/exstagram` 33 | * Run `mix deps.get` 34 | * To give it a try, run `iex -S mix` 35 | 36 | Put this in your `mix.exs` deps section: 37 | ``` 38 | {:instagram, "0.0.4", [github: "arthurcolle/exstagram"]} 39 | ``` 40 | 41 | See other cool Elixir repos at [awesome-elixir](https://github.com/h4cc/awesome-elixir) 42 | 43 | Not on hex.pm yet, but coming soon! 44 | 45 | -------------------------------------------------------------------------------- /config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | use Mix.Config 4 | 5 | # This configuration is loaded before any dependency and is restricted 6 | # to this project. If another project depends on this project, this 7 | # file won't be loaded nor affect the parent project. For this reason, 8 | # if you want to provide default values for your application for third- 9 | # party users, it should be done in your mix.exs file. 10 | 11 | # Sample configuration: 12 | # 13 | # config :logger, 14 | # level: :info 15 | # 16 | # config :logger, :console, 17 | # format: "$date $time [$level] $metadata$message\n", 18 | # metadata: [:user_id] 19 | 20 | # It is also possible to import configuration files, relative to this 21 | # directory. For example, you can emulate configuration per environment 22 | # by uncommenting the line below and defining dev.exs, test.exs and such. 23 | # Configuration from the imported file will override the ones defined 24 | # here (which is why it is important to import them last). 25 | # 26 | # import_config "#{Mix.env}.exs" 27 | 28 | 29 | 30 | 31 | # config :instagram, :oauth, [ 32 | # consumer_key: "", 33 | # consumer_secret: "", 34 | # access_token: "", 35 | # access_token_secret: "" 36 | # ] 37 | 38 | 39 | -------------------------------------------------------------------------------- /lib/instagram.ex: -------------------------------------------------------------------------------- 1 | defmodule Instagram do 2 | use OAuth2.Strategy 3 | alias Instagram.Request 4 | 5 | # Public API 6 | 7 | def new do 8 | HTTPoison.start 9 | OAuth2.new([ 10 | strategy: __MODULE__, 11 | client_id: System.get_env("INSTAGRAM_CLIENT_ID"), 12 | client_secret: System.get_env("INSTAGRAM_CLIENT_SECRET"), 13 | redirect_uri: System.get_env("INSTAGRAM_CALLBACK_URL"), 14 | site: "https://api.instagram.com", 15 | authorize_url: "https://api.instagram.com/oauth/authorize/", 16 | token_url: "https://api.instagram.com/oauth/access_token" 17 | ]) 18 | end 19 | 20 | def authorize_url!(params \\ []) do 21 | new() 22 | |> put_param(:scope, "basic") 23 | |> OAuth2.Client.authorize_url!(params) 24 | end 25 | 26 | def get_token!(params \\ [], headers \\ []) do 27 | OAuth2.Client.get_token!(new(), params, headers) 28 | end 29 | 30 | # Strategy Callbacks 31 | 32 | def authorize_url(client, params) do 33 | OAuth2.Strategy.AuthCode.authorize_url(client, params) 34 | end 35 | 36 | def get_token(client, params, headers) do 37 | client 38 | |> put_header("Accept", "application/json") 39 | |> OAuth2.Strategy.AuthCode.get_token(params, headers) 40 | end 41 | 42 | def user_recent_media(access_token) do 43 | url = "https://api.instagram.com/v1/users/self/media/recent?access_token=" 44 | req = url <> access_token 45 | case Request.get(req) do 46 | {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> 47 | json_body = Poison.decode! body 48 | # json_body["data"] |> Enum.map fn(x) -> x["images"]["standard_resolution"]["url"] end 49 | json_body["data"] |> Enum.map fn(x) -> x end 50 | {:ok, %HTTPoison.Response{status_code: 404}} -> 51 | IO.puts "Not found :(" 52 | {:error, %HTTPoison.Error{reason: reason}} -> 53 | IO.inspect reason 54 | end 55 | end 56 | 57 | def start do 58 | response = 59 | Instagram.authorize_url! 60 | |> Request.get! 61 | 62 | map_response = 63 | response.headers 64 | |> Enum.into(%{}) 65 | 66 | map_response["Location"] 67 | end 68 | 69 | def get_token(code_dict) do 70 | Instagram.get_token! code_dict 71 | end 72 | end -------------------------------------------------------------------------------- /lib/instagram/config.ex: -------------------------------------------------------------------------------- 1 | defmodule Instagram.Config do 2 | end -------------------------------------------------------------------------------- /lib/request.ex: -------------------------------------------------------------------------------- 1 | defmodule Instagram.Request do 2 | use HTTPoison.Base 3 | 4 | @url "https://api.instagram.com/v1" 5 | def process_url(url) do 6 | case String.downcase(url) do 7 | <<"http://"::utf8, _::binary>> -> url 8 | <<"https://"::utf8, _::binary>> -> url 9 | _ -> @url <> url 10 | end 11 | end 12 | end -------------------------------------------------------------------------------- /lib/steal.ex: -------------------------------------------------------------------------------- 1 | defmodule KV do 2 | def start_link do 3 | Task.start_link(fn -> loop([]) end) 4 | end 5 | 6 | defp loop(list_perm) do 7 | receive do 8 | {:add, url} -> 9 | resp = HTTPoison.get! url 10 | json_body = Poison.decode! resp.body 11 | list = json_body["data"] |> Enum.map fn(x) -> x["images"]["standard_resolution"]["url"] end 12 | list_perm 13 | send self(), json_body["paginate"] 14 | IO.puts list_perm 15 | loop(list_perm ++ list) 16 | end 17 | end 18 | end -------------------------------------------------------------------------------- /lib/url = "https:::api.instagram.com:v1:users:self:med: -------------------------------------------------------------------------------- 1 | url = "https://api.instagram.com/v1/users/self/media/recent?access_token=1531139.f18ce1e.1353009936304f85921167c58a591475" 2 | resp = HTTPoison.get! url 3 | json_body = Poison.decode! resp.body 4 | json_body["pagination"] |> Enum.map fn(x) -> x end -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Instagram.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [app: :instagram, 6 | version: "0.0.4", 7 | elixir: "~> 1.2", 8 | build_embedded: Mix.env == :prod, 9 | start_permanent: Mix.env == :prod, 10 | deps: deps] 11 | end 12 | 13 | # Configuration for the OTP application 14 | # 15 | # Type `mix help compile.app` for more information 16 | def application do 17 | [applications: [:logger, :oauth2, :httpoison]] 18 | end 19 | 20 | # Dependencies can be Hex packages: 21 | # 22 | # {:mydep, "~> 0.3.0"} 23 | # 24 | # Or git/path repositories: 25 | # 26 | # {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"} 27 | # 28 | # Type `mix help deps` for more examples and options 29 | defp deps do 30 | [ 31 | {:oauth2, "~> 0.5"}, 32 | {:httpoison, "~> 0.8.1"}, 33 | {:poison, "~> 1.3"} 34 | ] 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /mix.lock: -------------------------------------------------------------------------------- 1 | %{"certifi": {:hex, :certifi, "0.3.0"}, 2 | "hackney": {:hex, :hackney, "1.4.8"}, 3 | "httpoison": {:hex, :httpoison, "0.8.1"}, 4 | "idna": {:hex, :idna, "1.0.3"}, 5 | "mimerl": {:hex, :mimerl, "1.0.2"}, 6 | "mimetype_parser": {:hex, :mimetype_parser, "0.1.1"}, 7 | "oauth2": {:hex, :oauth2, "0.5.0"}, 8 | "poison": {:hex, :poison, "1.5.2"}, 9 | "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5"}} 10 | -------------------------------------------------------------------------------- /test/instagram_test.exs: -------------------------------------------------------------------------------- 1 | defmodule InstagramTest do 2 | use ExUnit.Case 3 | doctest Instagram 4 | 5 | test "the truth" do 6 | assert 1 + 1 == 2 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | --------------------------------------------------------------------------------