omnisocials 0.1.0 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d8e63bac3e6cf2774234d627061b6ef9d2f2555329374da55bc37b2dc912593
4
- data.tar.gz: 1f432caac9857e978a539b9382aeb11390a5e02637c97725a84f5b7146f14206
3
+ metadata.gz: cfdc77673c3c6885b9098af3daf33b7393329ed3b6501fd04d28e813585d97b0
4
+ data.tar.gz: 9753cf8ccae71e85a0414fa137d1b201f678c8a7a018edacb2a74df4353dc822
5
5
  SHA512:
6
- metadata.gz: '079b0f69fe85f2317bae07bf58246d49a150d6a5afaed56aac9c4dc3111dfc6713ac250c12591f6f8428923e91003333377b004a6f64fe8eb786660b9fb75eca'
7
- data.tar.gz: 5cced0edb928d0b5600a94ca7a28a8c3a809bfc58eee18ef89683c665f04327aee7d215c7982af068144165718e87468b237e698b7d36a273013cb6503df206e
6
+ metadata.gz: 7d8390a9fb03fb151002f79d55706c43b29506d604fe84a9c4707cbe233166ebaab7ad4d2a552e1db14de26a8eed0e8244879daf148f2f83bf3a83d5fe7d8449
7
+ data.tar.gz: 0376b9f5a46d25a6cfc9ca718f46ffd45d2cbe1deecdd9430f1bc2ac2b7a45e1299b5b93d54e8dcf3cf98f17f32b379c56eaed9fffb1699aa203493d27d5a4b3
data/README.md CHANGED
@@ -65,6 +65,24 @@ post = client.posts.create_and_publish(
65
65
  )
66
66
  ```
67
67
 
68
+ ### Per-media alt text
69
+
70
+ Every `media_urls` / `media_ids` entry accepts either a plain String or a Hash with an `alt` accessibility description (max 1500 chars). Alt text is delivered to Mastodon (media description), Bluesky (embed alt), X (photos and GIFs), Pinterest (pin alt text), Instagram (images), and LinkedIn (images). Strings and Hashes can be mixed, and the same shape works in per-platform Hashes and `thread_parts` media.
71
+
72
+ ```ruby
73
+ post = client.posts.create(
74
+ content: "Sunrise over the harbor",
75
+ channels: ["mastodon", "bluesky"],
76
+ scheduled_at: "2026-08-01T09:00:00Z",
77
+ media_urls: [
78
+ {
79
+ "url" => "https://example.com/harbor.jpg",
80
+ "alt" => "A small sailboat crossing a calm harbor at sunrise, sky in deep orange"
81
+ }
82
+ ]
83
+ )
84
+ ```
85
+
68
86
  ### Post to specific platforms with platform options
69
87
 
70
88
  `content` can be a per-platform Hash (with `default` as the fallback), and each platform has its own options Hash:
@@ -107,6 +125,24 @@ post = client.posts.create(
107
125
 
108
126
  On update, passing `x: { "thread_parts" => nil }` clears the thread and reverts the post to single-tweet mode. Only top-level `nil` values are dropped from request bodies, so nested `nil` values like this one are sent as JSON `null`.
109
127
 
128
+ ### X link posts use credits
129
+
130
+ X bills API posts whose text contains a URL at a premium, and OmniSocials passes that fee through as prepaid credits (20 credits per URL-containing tweet; threads billed per part with a link). When a create targets X and the text contains a URL, the response Hash includes a top-level `"warnings"` array (a sibling of `"data"`):
131
+
132
+ ```ruby
133
+ res = client.posts.create(
134
+ content: "Read the full story: https://example.com/post",
135
+ channels: ["x"]
136
+ )
137
+ (res["warnings"] || []).each do |warning|
138
+ if warning["code"] == "x_url_post_credits"
139
+ puts "#{warning["credits_required"]} credits (balance: #{warning["credits_balance"]})"
140
+ end
141
+ end
142
+ ```
143
+
144
+ From `enforce_from` (2026-08-14) the balance is checked at publish time, but credits are only deducted after the post successfully publishes (a failed publish is never charged). If the balance can't cover it, only the X target fails (other platforms publish normally); top up in the dashboard under Settings -> Organisation -> Billing -> Credits, then call `posts.retry`. Posts without links, analytics, and media on X stay free. There is no API endpoint for credits — they are managed in the dashboard.
145
+
110
146
  ### Other post operations
111
147
 
112
148
  ```ruby
@@ -114,13 +150,18 @@ posts = client.posts.list(status: "scheduled", limit: 50, offset: 0)
114
150
  post = client.posts.get("123")
115
151
  client.posts.update("123", scheduled_at: "2026-08-02T10:00:00Z")
116
152
  client.posts.publish("123") # publish a draft or scheduled post now
153
+ client.posts.retry("123") # retry only the failed platforms of a failed/warning post
117
154
  client.posts.delete("123") # returns nil (204)
118
155
 
119
156
  # Recent posts fetched live from the connected platforms (including content
120
- # published outside OmniSocials). Requires the analytics:read scope.
157
+ # published outside OmniSocials). Requires the analytics:read scope. Video
158
+ # records include duration_seconds (whole seconds; TikTok and YouTube today,
159
+ # null for images and platforms that don't expose it).
121
160
  recent = client.posts.recent_platform(limit: 10, platforms: ["instagram", "tiktok"])
122
161
  ```
123
162
 
163
+ `retry` re-publishes only the platforms that failed, on the same post; platforms that already succeeded are never posted again. It is asynchronous: a 200 means the retry is queued, so poll `get` for the outcome. Max 3 retries per platform.
164
+
124
165
  ## Media
125
166
 
126
167
  ### Upload from a URL (recommended, up to 1GB)
@@ -190,6 +231,36 @@ client.folders.update(sub["data"]["id"], parent_id: nil) # move to top level
190
231
  client.folders.delete(folder["data"]["id"]) # files move to root, subfolders move up
191
232
  ```
192
233
 
234
+ ## Hashtag Sets
235
+
236
+ Save reusable hashtag groups and apply them to posts at create time. Uses the `posts:read` / `posts:write` scopes.
237
+
238
+ ```ruby
239
+ set = client.hashtag_sets.create(
240
+ name: "Launch",
241
+ hashtags: ["saas", "buildinpublic", "startup"] # or one string: "#saas #buildinpublic #startup"
242
+ )
243
+ puts set["data"]["preview"] # "#saas #buildinpublic #startup"
244
+
245
+ client.hashtag_sets.list
246
+ client.hashtag_sets.get(set["data"]["id"])
247
+ client.hashtag_sets.update(set["data"]["id"], hashtags: ["saas", "founder"]) # replaces the full list
248
+ client.hashtag_sets.delete(set["data"]["id"]) # returns nil (204)
249
+ ```
250
+
251
+ Apply a set when creating a post with `hashtag_set` (the set name, case-insensitive) or `hashtag_set_id`. The set is applied once at create time and tags already in the caption are skipped. `hashtag_placement` is `"caption_append"` (default) or `"first_comment"`, and `hashtag_platforms` restricts the hashtags to a subset of the post's channels. Instagram's 30-hashtag cap returns error code `hashtag_limit_exceeded`.
252
+
253
+ ```ruby
254
+ client.posts.create(
255
+ content: "Launch day!",
256
+ channels: ["instagram", "x"],
257
+ scheduled_at: "2026-08-01T09:00:00Z",
258
+ hashtag_set: "Launch",
259
+ hashtag_placement: "first_comment",
260
+ hashtag_platforms: ["instagram"]
261
+ )
262
+ ```
263
+
193
264
  ## Accounts
194
265
 
195
266
  ```ruby
@@ -59,8 +59,8 @@ module OmniSocials
59
59
  ].freeze
60
60
 
61
61
  attr_reader :api_key, :base_url, :timeout, :max_retries,
62
- :posts, :media, :folders, :accounts, :analytics, :locations,
63
- :webhooks
62
+ :posts, :media, :folders, :hashtag_sets, :accounts, :analytics,
63
+ :audio, :locations, :inbox, :webhooks
64
64
 
65
65
  # api_key - API key (omsk_live_* / omsk_test_*). Falls back to the
66
66
  # OMNISOCIALS_API_KEY environment variable. Raises
@@ -88,9 +88,12 @@ module OmniSocials
88
88
  @posts = Resources::Posts.new(self)
89
89
  @media = Resources::Media.new(self)
90
90
  @folders = Resources::Folders.new(self)
91
+ @hashtag_sets = Resources::HashtagSets.new(self)
91
92
  @accounts = Resources::Accounts.new(self)
92
93
  @analytics = Resources::Analytics.new(self)
94
+ @audio = Resources::Audio.new(self)
93
95
  @locations = Resources::Locations.new(self)
96
+ @inbox = Resources::Inbox.new(self)
94
97
  @webhooks = Resources::Webhooks.new(self)
95
98
  end
96
99
 
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniSocials
4
+ module Resources
5
+ # Audio resource: Instagram Reels audio (Meta's licensed catalog).
6
+ class Audio
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ # GET /audio/search?q=&type= - search Meta's licensed audio catalog for
12
+ # Instagram Reels. Omit query for trending audio; type is "music"
13
+ # (default) or "original_sound". Use a result's audio_id as
14
+ # instagram.audio_id on a reel post (with optional
15
+ # instagram.audio_volume / instagram.video_volume, integers 0-100).
16
+ # preview_url is a temporary URL (~1.5 days); never persist it.
17
+ def search(query: nil, type: nil)
18
+ @client.request("GET", "/audio/search", query: { "q" => query, "type" => type })
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniSocials
4
+ module Resources
5
+ # Hashtag sets resource: saved, reusable hashtag groups applied to posts
6
+ # at create time (via hashtag_set / hashtag_set_id on posts.create).
7
+ class HashtagSets
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ # GET /hashtag-sets - list the workspace's saved hashtag sets.
13
+ def list
14
+ @client.request("GET", "/hashtag-sets")
15
+ end
16
+
17
+ # GET /hashtag-sets/{id} - fetch a single hashtag set.
18
+ def get(hashtag_set_id)
19
+ @client.request("GET", "/hashtag-sets/#{hashtag_set_id}")
20
+ end
21
+
22
+ # POST /hashtag-sets - create a hashtag set.
23
+ #
24
+ # `hashtags` is an Array of tags, or a single String of tags. Apply the
25
+ # set on posts.create via hashtag_set (name, case-insensitive) or
26
+ # hashtag_set_id.
27
+ def create(name:, hashtags:)
28
+ @client.request(
29
+ "POST", "/hashtag-sets",
30
+ json: { "name" => name, "hashtags" => hashtags }
31
+ )
32
+ end
33
+
34
+ # PATCH /hashtag-sets/{id} - rename and/or replace the tags.
35
+ #
36
+ # `hashtags` replaces the FULL list.
37
+ def update(hashtag_set_id, name: nil, hashtags: nil)
38
+ body = Internal.drop_nil({ "name" => name, "hashtags" => hashtags })
39
+ @client.request("PATCH", "/hashtag-sets/#{hashtag_set_id}", json: body)
40
+ end
41
+
42
+ # DELETE /hashtag-sets/{id} - delete a hashtag set. Returns nil (204).
43
+ def delete(hashtag_set_id)
44
+ @client.request("DELETE", "/hashtag-sets/#{hashtag_set_id}")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cgi"
4
+
5
+ module OmniSocials
6
+ module Resources
7
+ # Inbox resource: social inbox conversations (DMs, comments, mentions)
8
+ # across connected platforms, plus reading and replying to them.
9
+ #
10
+ # The list endpoints use CURSOR pagination (unlike the offset pagination
11
+ # elsewhere): each response carries pagination["next_cursor"],
12
+ # pagination["has_more"], and pagination["limit"]. Page on by passing the
13
+ # previous response's next_cursor as `cursor` while has_more is true.
14
+ #
15
+ # Conversation ids are URL-encoded for you, so pass them exactly as
16
+ # returned - LinkedIn ids contain ":" and "()" (e.g.
17
+ # "linkedin_comment_urn:li:activity:123").
18
+ class Inbox
19
+ def initialize(client)
20
+ @client = client
21
+ end
22
+
23
+ # GET /inbox/conversations - list conversations, newest activity first.
24
+ #
25
+ # All filters are optional: platform ("instagram", "facebook",
26
+ # "linkedin"), type ("dm", "comment", "mention"), unread (only
27
+ # conversations with unread messages), limit (1-100), and cursor (an
28
+ # opaque cursor from a previous response's pagination["next_cursor"]).
29
+ def list_conversations(platform: nil, type: nil, unread: nil, limit: nil, cursor: nil)
30
+ @client.request(
31
+ "GET", "/inbox/conversations",
32
+ query: {
33
+ "platform" => platform,
34
+ "type" => type,
35
+ "unread" => unread,
36
+ "limit" => limit,
37
+ "cursor" => cursor
38
+ }
39
+ )
40
+ end
41
+
42
+ # GET /inbox/conversations/{id}/messages - full message thread for one
43
+ # conversation, newest first. Cursor-paginated via `limit` / `cursor`.
44
+ def get_messages(conversation_id, limit: nil, cursor: nil)
45
+ @client.request(
46
+ "GET", "/inbox/conversations/#{encode_id(conversation_id)}/messages",
47
+ query: { "limit" => limit, "cursor" => cursor }
48
+ )
49
+ end
50
+
51
+ # POST /inbox/conversations/{id}/read - mark every message in the
52
+ # conversation as read. Returns the count of messages newly marked read.
53
+ def mark_read(conversation_id)
54
+ @client.request("POST", "/inbox/conversations/#{encode_id(conversation_id)}/read")
55
+ end
56
+
57
+ # POST /inbox/conversations/{id}/reply - send a reply into the
58
+ # conversation (a DM message, or a reply to the comment/mention).
59
+ #
60
+ # `text` is required. Optionally attach a single media asset by public
61
+ # URL with `attachment_url` plus `attachment_type` ("image", "video",
62
+ # "audio", or "file"). Returns the created outbound message.
63
+ def reply(conversation_id, text:, attachment_url: nil, attachment_type: nil)
64
+ body = Internal.drop_nil(
65
+ {
66
+ "text" => text,
67
+ "attachment_url" => attachment_url,
68
+ "attachment_type" => attachment_type
69
+ }
70
+ )
71
+ @client.request(
72
+ "POST", "/inbox/conversations/#{encode_id(conversation_id)}/reply",
73
+ json: body
74
+ )
75
+ end
76
+
77
+ private
78
+
79
+ # URL-encode a conversation id for use in a path segment. LinkedIn ids
80
+ # contain ":" and "()", so they must be escaped; spaces become %20
81
+ # (a path segment treats "+" literally, unlike a query string).
82
+ def encode_id(conversation_id)
83
+ CGI.escape(conversation_id.to_s).gsub("+", "%20")
84
+ end
85
+ end
86
+ end
87
+ end
@@ -6,6 +6,13 @@ module OmniSocials
6
6
  #
7
7
  # `content` is a plain String, or a per-platform Hash with a "default" key.
8
8
  # `media_ids` / `media_urls` are a flat Array, or a per-platform Hash.
9
+ # Each entry is a plain String, or a Hash with an "alt" accessibility
10
+ # description (max 1500 chars): `{ "url" => "https://...", "alt" => "..." }`
11
+ # for media_urls, `{ "id" => "...", "alt" => "..." }` for media_ids. Alt
12
+ # text is delivered to Mastodon (media description), Bluesky (embed alt),
13
+ # X (photos/GIFs), Pinterest (pin alt text), Instagram (images), and
14
+ # LinkedIn (images); the same entry shape works inside x/bluesky/mastodon
15
+ # `thread_parts` media.
9
16
  class Posts
10
17
  def initialize(client)
11
18
  @client = client
@@ -36,36 +43,58 @@ module OmniSocials
36
43
 
37
44
  # POST /posts/create - create a post (draft, or scheduled when
38
45
  # scheduled_at is set).
46
+ #
47
+ # hashtag_set (set name, case-insensitive) or hashtag_set_id applies a
48
+ # saved hashtag set once at create time; tags already in a caption are
49
+ # skipped; Instagram's 30-hashtag cap returns error code
50
+ # hashtag_limit_exceeded. hashtag_placement is "caption_append"
51
+ # (default) or "first_comment"; hashtag_platforms restricts the tags to
52
+ # a subset of channels.
53
+ #
54
+ # When the post targets X and its text (or any thread part) contains a
55
+ # URL, the response includes a top-level "warnings" array (sibling of
56
+ # "data") with a "x_url_post_credits" entry carrying credits_required
57
+ # and credits_balance: X's link-post fee is passed through as prepaid
58
+ # credits, debited at publish time (from 2026-08-14). Credits are
59
+ # managed in the dashboard, not the API.
39
60
  def create(content:, channels: nil, scheduled_at: nil, media_ids: nil,
40
61
  media_urls: nil, type: nil, source: nil, link_url: nil,
41
62
  link_title: nil, link_description: nil, link_thumbnail_url: nil,
42
63
  location_id: nil, collaborators: nil, user_tags: nil,
43
- pinterest: nil, youtube: nil, instagram: nil, facebook: nil,
44
- linkedin: nil, linkedin_page: nil, tiktok: nil, x: nil,
45
- bluesky: nil, mastodon: nil, google_business: nil)
64
+ hashtag_set: nil, hashtag_set_id: nil, hashtag_placement: nil,
65
+ hashtag_platforms: nil, pinterest: nil, youtube: nil,
66
+ instagram: nil, facebook: nil, linkedin: nil,
67
+ linkedin_page: nil, tiktok: nil, x: nil, bluesky: nil,
68
+ mastodon: nil, google_business: nil)
46
69
  body = create_body(
47
70
  content: content, channels: channels, scheduled_at: scheduled_at,
48
71
  media_ids: media_ids, media_urls: media_urls, type: type,
49
72
  source: source, link_url: link_url, link_title: link_title,
50
73
  link_description: link_description, link_thumbnail_url: link_thumbnail_url,
51
74
  location_id: location_id, collaborators: collaborators,
52
- user_tags: user_tags, pinterest: pinterest, youtube: youtube,
53
- instagram: instagram, facebook: facebook, linkedin: linkedin,
54
- linkedin_page: linkedin_page, tiktok: tiktok, x: x, bluesky: bluesky,
55
- mastodon: mastodon, google_business: google_business
75
+ user_tags: user_tags, hashtag_set: hashtag_set,
76
+ hashtag_set_id: hashtag_set_id, hashtag_placement: hashtag_placement,
77
+ hashtag_platforms: hashtag_platforms, pinterest: pinterest,
78
+ youtube: youtube, instagram: instagram, facebook: facebook,
79
+ linkedin: linkedin, linkedin_page: linkedin_page, tiktok: tiktok,
80
+ x: x, bluesky: bluesky, mastodon: mastodon,
81
+ google_business: google_business
56
82
  )
57
83
  @client.request("POST", "/posts/create", json: body)
58
84
  end
59
85
 
60
86
  # POST /posts/create-and-publish - create and publish immediately.
87
+ # See #create for the "warnings" array on X link posts.
61
88
  def create_and_publish(content:, channels: nil, media_ids: nil,
62
89
  media_urls: nil, type: nil, source: nil,
63
90
  link_url: nil, link_title: nil, link_description: nil,
64
91
  link_thumbnail_url: nil, location_id: nil,
65
- collaborators: nil, user_tags: nil, pinterest: nil,
66
- youtube: nil, instagram: nil, facebook: nil,
67
- linkedin: nil, linkedin_page: nil, tiktok: nil,
68
- x: nil, bluesky: nil, mastodon: nil,
92
+ collaborators: nil, user_tags: nil,
93
+ hashtag_set: nil, hashtag_set_id: nil,
94
+ hashtag_placement: nil, hashtag_platforms: nil,
95
+ pinterest: nil, youtube: nil, instagram: nil,
96
+ facebook: nil, linkedin: nil, linkedin_page: nil,
97
+ tiktok: nil, x: nil, bluesky: nil, mastodon: nil,
69
98
  google_business: nil)
70
99
  body = create_body(
71
100
  content: content, channels: channels, scheduled_at: nil,
@@ -73,10 +102,13 @@ module OmniSocials
73
102
  source: source, link_url: link_url, link_title: link_title,
74
103
  link_description: link_description, link_thumbnail_url: link_thumbnail_url,
75
104
  location_id: location_id, collaborators: collaborators,
76
- user_tags: user_tags, pinterest: pinterest, youtube: youtube,
77
- instagram: instagram, facebook: facebook, linkedin: linkedin,
78
- linkedin_page: linkedin_page, tiktok: tiktok, x: x, bluesky: bluesky,
79
- mastodon: mastodon, google_business: google_business
105
+ user_tags: user_tags, hashtag_set: hashtag_set,
106
+ hashtag_set_id: hashtag_set_id, hashtag_placement: hashtag_placement,
107
+ hashtag_platforms: hashtag_platforms, pinterest: pinterest,
108
+ youtube: youtube, instagram: instagram, facebook: facebook,
109
+ linkedin: linkedin, linkedin_page: linkedin_page, tiktok: tiktok,
110
+ x: x, bluesky: bluesky, mastodon: mastodon,
111
+ google_business: google_business
80
112
  )
81
113
  @client.request("POST", "/posts/create-and-publish", json: body)
82
114
  end
@@ -130,14 +162,27 @@ module OmniSocials
130
162
  @client.request("POST", "/posts/#{post_id}/publish")
131
163
  end
132
164
 
165
+ # POST /posts/{id}/retry - retry the failed platforms of a "failed" or
166
+ # "warning" (partially failed) post, on the same post.
167
+ #
168
+ # Only the platforms that failed are re-published; platforms that
169
+ # already succeeded are never posted again. Asynchronous: a 200 means
170
+ # the retry is queued - poll `get` for the outcome. Max 3 retries per
171
+ # platform.
172
+ def retry(post_id)
173
+ @client.request("POST", "/posts/#{post_id}/retry")
174
+ end
175
+
133
176
  private
134
177
 
135
178
  def create_body(content:, channels:, scheduled_at:, media_ids:,
136
179
  media_urls:, type:, source:, link_url:, link_title:,
137
180
  link_description:, link_thumbnail_url:, location_id:,
138
- collaborators:, user_tags:, pinterest:, youtube:,
139
- instagram:, facebook:, linkedin:, linkedin_page:,
140
- tiktok:, x:, bluesky:, mastodon:, google_business:)
181
+ collaborators:, user_tags:, hashtag_set:,
182
+ hashtag_set_id:, hashtag_placement:, hashtag_platforms:,
183
+ pinterest:, youtube:, instagram:, facebook:, linkedin:,
184
+ linkedin_page:, tiktok:, x:, bluesky:, mastodon:,
185
+ google_business:)
141
186
  Internal.drop_nil(
142
187
  {
143
188
  "content" => content,
@@ -154,6 +199,10 @@ module OmniSocials
154
199
  "location_id" => location_id,
155
200
  "collaborators" => collaborators,
156
201
  "user_tags" => user_tags,
202
+ "hashtag_set" => hashtag_set,
203
+ "hashtag_set_id" => hashtag_set_id,
204
+ "hashtag_placement" => hashtag_placement,
205
+ "hashtag_platforms" => hashtag_platforms,
157
206
  "pinterest" => pinterest,
158
207
  "youtube" => youtube,
159
208
  "instagram" => instagram,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OmniSocials
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/omnisocials.rb CHANGED
@@ -19,9 +19,12 @@ require_relative "omnisocials/webhooks"
19
19
  require_relative "omnisocials/resources/posts"
20
20
  require_relative "omnisocials/resources/media"
21
21
  require_relative "omnisocials/resources/folders"
22
+ require_relative "omnisocials/resources/hashtag_sets"
22
23
  require_relative "omnisocials/resources/accounts"
23
24
  require_relative "omnisocials/resources/analytics"
25
+ require_relative "omnisocials/resources/audio"
24
26
  require_relative "omnisocials/resources/locations"
27
+ require_relative "omnisocials/resources/inbox"
25
28
  require_relative "omnisocials/resources/webhooks"
26
29
  require_relative "omnisocials/client"
27
30
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omnisocials
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OmniSocials
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-15 00:00:00.000000000 Z
11
+ date: 2026-08-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Schedule and publish social media posts, upload media, and read analytics
14
14
  across Instagram, Facebook, LinkedIn, YouTube, TikTok, X, Pinterest, Bluesky, Threads,
@@ -27,7 +27,10 @@ files:
27
27
  - lib/omnisocials/internal.rb
28
28
  - lib/omnisocials/resources/accounts.rb
29
29
  - lib/omnisocials/resources/analytics.rb
30
+ - lib/omnisocials/resources/audio.rb
30
31
  - lib/omnisocials/resources/folders.rb
32
+ - lib/omnisocials/resources/hashtag_sets.rb
33
+ - lib/omnisocials/resources/inbox.rb
31
34
  - lib/omnisocials/resources/locations.rb
32
35
  - lib/omnisocials/resources/media.rb
33
36
  - lib/omnisocials/resources/posts.rb