instagram_connect 0.3.9 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a9c934d89a0e97c513a99c5352da9227b5133f1011557deb0ea87f4d8a6ce9d
4
- data.tar.gz: a7b0af0a9b85bbeaf6c3015f45f3a467c9f7a23b5f73356ba34819389a887190
3
+ metadata.gz: bea234dd4fd6e4a37c8c06f26c2b5101fc4a3b1b2037ea8c646fa6382e36555b
4
+ data.tar.gz: f4ead074b0eba3f7dc961bacccf661f45ad586a90661243aa465d2e79f4a4212
5
5
  SHA512:
6
- metadata.gz: 35cca9a90ea1822ff47b9b6fbb09addb00c60a0484519842fdd54285b51cb0643f41f64105bd6f9a96e157637dbf6daa3f5e9b5c2ea4dabb07a6436eb9201dcd
7
- data.tar.gz: bdb981d70acbe14a489d95b7ea8ea5c5229aa2462f2998aca1ad8328146e25dec95101c3583da7a77901da5c16429d385b1860366454b5b1c921d6396e1b5ad2
6
+ metadata.gz: 4c793edf0d1f244413a20cf705a277ca8f1927ceb888db77078c93813b208fdcb8f768cf3918c0d027b1ab5a607028481493c0f659ea10e9f09109ad00588752
7
+ data.tar.gz: 0d051c02f9538c9aaeb258e8220f15897042fb333dd63983fd6d3daa29f3dc796aff903dddad2dff4e5563a92c7b215075fb6f62e9b3cb20487fe9b33488b3fe
data/CHANGELOG.md CHANGED
@@ -6,6 +6,17 @@ All notable changes to this project are documented here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.10] - 2026-07-27
10
+
11
+ ### Added
12
+
13
+ - **Comment history sync.** `SyncCommentsJob` walks a post's comments edge — replies expanded,
14
+ cursors followed — and upserts by Meta's id, so webhook-created rows are enriched, never
15
+ duplicated. Webhooks only cover comments made after the subscription existed; this imports
16
+ everything before. `SyncMediaJob`'s full walk now enqueues one comment walk per post that
17
+ actually has comments. Meta stays the source of truth for hidden, both directions.
18
+
19
+
9
20
  ## [0.3.9] - 2026-07-27
10
21
 
11
22
  ### Added
@@ -0,0 +1,74 @@
1
+ module InstagramConnect
2
+ # Imports a post's existing comments — the ones that happened before the
3
+ # webhook subscription existed, which the webhook can never deliver. The
4
+ # comments edge is walked with cursors, replies expanded inline, and every
5
+ # comment upserted by Meta's id, so re-running never duplicates and a
6
+ # webhook-created row is simply enriched.
7
+ #
8
+ # Meta is the source of truth for hidden: a comment hidden from the app on
9
+ # the phone arrives hidden here, and one unhidden there un-hides here.
10
+ class SyncCommentsJob < ApplicationJob
11
+ queue_as :default
12
+
13
+ THROTTLE = 10.minutes
14
+
15
+ REPLY_FIELDS = "id,text,timestamp,username,from,parent_id,hidden,like_count".freeze
16
+ COMMENT_FIELDS = "#{REPLY_FIELDS},replies{#{REPLY_FIELDS}}".freeze
17
+
18
+ # One key per post: opening a busy post's comments repeatedly enqueues one
19
+ # import, not one per page view.
20
+ def self.enqueue_throttled(account, ig_media_id)
21
+ Rails.cache.fetch("instagram_connect:sync_comments:#{account.id}:#{ig_media_id}",
22
+ expires_in: THROTTLE) do
23
+ perform_later(account.id, ig_media_id.to_s)
24
+ true
25
+ end
26
+ end
27
+
28
+ def perform(account_id, ig_media_id)
29
+ account = Account.find_by(id: account_id)
30
+ return if account.nil? || !account.active?
31
+
32
+ result = account.client.collect("/#{ig_media_id}/comments",
33
+ { fields: COMMENT_FIELDS, limit: 50 })
34
+ unless result.success?
35
+ return logger.error("[instagram_connect] comment sync failed for " \
36
+ "account=#{account.id} media=#{ig_media_id}: #{result.error_message}")
37
+ end
38
+
39
+ Array(result.data["data"]).each do |item|
40
+ upsert(account, ig_media_id, item)
41
+ Array(item.dig("replies", "data")).each do |reply|
42
+ # Meta omits parent_id inside the replies expansion — the nesting
43
+ # itself is the statement.
44
+ upsert(account, ig_media_id, reply.merge("parent_id" => reply["parent_id"] || item["id"]))
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def upsert(account, ig_media_id, item)
52
+ comment = Comment.record(
53
+ account: account,
54
+ comment_id: item["id"],
55
+ media_id: ig_media_id.to_s,
56
+ text: item["text"],
57
+ from_username: item["username"] || item.dig("from", "username"),
58
+ parent_id: item["parent_id"]
59
+ )
60
+ comment.update!(
61
+ from_ig_id: item.dig("from", "id") || comment.from_ig_id,
62
+ commented_at: parse_time(item["timestamp"]) || comment.commented_at,
63
+ like_count: item["like_count"],
64
+ hidden_at: item["hidden"] ? (comment.hidden_at || Time.current) : nil
65
+ )
66
+ end
67
+
68
+ def parse_time(value)
69
+ Time.zone.parse(value.to_s)
70
+ rescue ArgumentError, TypeError
71
+ nil
72
+ end
73
+ end
74
+ end
@@ -45,7 +45,14 @@ module InstagramConnect
45
45
  end
46
46
 
47
47
  Array(result.data["data"]).each { |item| upsert(account, item) }
48
- mark_removed(account, started_at) if full
48
+ if full
49
+ mark_removed(account, started_at)
50
+ # The full walk is the moment to fetch comment history too: webhooks
51
+ # only cover comments made after the subscription existed. One extra
52
+ # job per post that actually has comments — bounded by reality, and
53
+ # the walk is operator-triggered.
54
+ backfill_comments(account, result)
55
+ end
49
56
  end
50
57
 
51
58
  private
@@ -78,6 +85,14 @@ module InstagramConnect
78
85
  media.update!(removed_from_instagram_at: nil) if media.removed_from_instagram_at
79
86
  end
80
87
 
88
+ def backfill_comments(account, result)
89
+ Array(result.data["data"]).each do |item|
90
+ next unless item["comments_count"].to_i.positive?
91
+
92
+ SyncCommentsJob.perform_later(account.id, item["id"].to_s)
93
+ end
94
+ end
95
+
81
96
  def mark_removed(account, started_at)
82
97
  marked = MediaItem.where(account_id: account.id, removed_from_instagram_at: nil)
83
98
  .where(synced_at: ...started_at)
@@ -1,3 +1,3 @@
1
1
  module InstagramConnect
2
- VERSION = "0.3.9"
2
+ VERSION = "0.3.10"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: instagram_connect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.3.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kshitiz Sinha
@@ -100,6 +100,7 @@ files:
100
100
  - app/jobs/instagram_connect/refresh_tokens_job.rb
101
101
  - app/jobs/instagram_connect/replay_events_job.rb
102
102
  - app/jobs/instagram_connect/send_message_job.rb
103
+ - app/jobs/instagram_connect/sync_comments_job.rb
103
104
  - app/jobs/instagram_connect/sync_conversations_job.rb
104
105
  - app/jobs/instagram_connect/sync_media_job.rb
105
106
  - app/jobs/instagram_connect/sync_stories_job.rb