From 54e80ca3418523b6380971b25f5b4029be5a81cc Mon Sep 17 00:00:00 2001 From: PianoMan0 <180116946+PianoMan0@users.noreply.github.com> Date: Mon, 7 Jul 2025 20:57:33 -0400 Subject: [PATCH 1/5] Update flavor_text.rb --- lib/flavor_text.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/flavor_text.rb b/lib/flavor_text.rb index 1fd614d..61c80ca 100644 --- a/lib/flavor_text.rb +++ b/lib/flavor_text.rb @@ -220,7 +220,7 @@ class FlavorText "#{%w[est created inited].sample} #{Time.now.to_i - Time.parse("Sun Feb 16 03:21:30 2025 -0500").to_i} seconds ago!".html_safe, "uptime: #{Time.now.to_i - Rails.application.config.server_start_time.to_i} seconds!".html_safe, "It takes a long time to build something good: ".html_safe, - "If you're seeing this, the page is currently .".html_safe, + "If you're seeing this, the page is currently ".html_safe, "time is money!", "in soviet russia, time tracks you!", "tick tock!", From 5cac80567bbfd9323c07c55b03b6268ce85cb1d6 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 21 Jul 2025 12:19:56 -0400 Subject: [PATCH 2/5] filtering by project dedupe --- app/controllers/api/v1/stats_controller.rb | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/app/controllers/api/v1/stats_controller.rb b/app/controllers/api/v1/stats_controller.rb index c35482c..7d11b63 100644 --- a/app/controllers/api/v1/stats_controller.rb +++ b/app/controllers/api/v1/stats_controller.rb @@ -77,6 +77,16 @@ class Api::V1::StatsController < ApplicationController summary = WakatimeService.new(**service_params).generate_summary + if params[:features]&.include?("projects") && params[:filter_by_project].present? + filter_by_project = params[:filter_by_project].split(",") + heartbeats = @user.heartbeats + .coding_only + .with_valid_timestamps + .where(time: start_date..end_date, project: filter_by_project) + unique_seconds = unique_heartbeat_seconds(heartbeats) + summary[:unique_total_seconds] = unique_seconds + end + trust_level = @user.trust_level trust_level = "blue" if trust_level == "yellow" trust_value = User.trust_levels[trust_level] @@ -283,4 +293,20 @@ class Api::V1::StatsController < ApplicationController data.sort_by { |project| -project[:total_seconds] } end + + def unique_heartbeat_seconds(heartbeats) + timestamps = heartbeats.order(:time).pluck(:time) + intervals = timestamps.each_cons(2).map { |a, b| [ a, b ] } + return 0 if intervals.empty? + merged = [ intervals.first ] + intervals[1..].each do |current| + last = merged.last + if current.first <= last.last + merged[-1] = [ last.first, [ last.last, current.last ].max ] + else + merged << current + end + end + merged.sum { |a, b| b - a } + end end From 810bf1de9a7f928c2bc5d8a3c738295d7b1b2398 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 21 Jul 2025 17:17:34 -0400 Subject: [PATCH 3/5] fix range issues --- app/controllers/api/v1/stats_controller.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/app/controllers/api/v1/stats_controller.rb b/app/controllers/api/v1/stats_controller.rb index 7d11b63..e062454 100644 --- a/app/controllers/api/v1/stats_controller.rb +++ b/app/controllers/api/v1/stats_controller.rb @@ -296,17 +296,16 @@ class Api::V1::StatsController < ApplicationController def unique_heartbeat_seconds(heartbeats) timestamps = heartbeats.order(:time).pluck(:time) - intervals = timestamps.each_cons(2).map { |a, b| [ a, b ] } - return 0 if intervals.empty? - merged = [ intervals.first ] - intervals[1..].each do |current| - last = merged.last - if current.first <= last.last - merged[-1] = [ last.first, [ last.last, current.last ].max ] - else - merged << current + return 0 if timestamps.empty? + + total_seconds = 0 + timestamps.each_cons(2) do |prev_time, curr_time| + gap = curr_time - prev_time + if gap > 0 && gap <= 2.minutes + total_seconds += gap end end - merged.sum { |a, b| b - a } + + total_seconds.to_i end end From cee240c1fa4de68e61648762386f0aec4f82bba6 Mon Sep 17 00:00:00 2001 From: "Tom (Deployor)" <129990841+deployor@users.noreply.github.com> Date: Tue, 22 Jul 2025 16:43:07 +0200 Subject: [PATCH 4/5] Update roblox-studio.md The other plugin only works with Wakatime; it only connects to Wakatime, so it doesn't work. Also, the version I made during High Seas is much more advanced; it tracks literally anything a person does, not just scripting and playtesting. --- docs/editors/roblox-studio.md | 76 ++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/docs/editors/roblox-studio.md b/docs/editors/roblox-studio.md index 0dc8440..74d4fc8 100644 --- a/docs/editors/roblox-studio.md +++ b/docs/editors/roblox-studio.md @@ -1,29 +1,77 @@ -# Roblox Studio Setup Guide +# Set Up Hackatime with Roblox Studio ![Roblox Studio](/images/editor-icons/roblox-studio-128.png) -Follow these steps to start tracking your game development in Roblox Studio with Hackatime. +This guide will walk you through setting up **Hackatime** to automatically track your game development time in **Roblox Studio**. -## Step 1: Log into Hackatime +--- -Make sure you have a [Hackatime account](https://hackatime.hackclub.com) and are logged in. +## Step 1: Log In to Your Hackatime Account -## Step 2: Run the Setup Script +First, make sure you have a **Hackatime account** and are logged in. If you don't have an account, you can create one at [hackatime.hackclub.com](https://hackatime.hackclub.com). -Visit the [setup page](https://hackatime.hackclub.com/my/wakatime_setup) to automatically configure your API key and endpoint. This ensures everything works perfectly with Hackatime. +--- -## Step 3: Install Roblox Studio Plugin +## Step 2: Install the Hackatime Roblox Studio Plugin -Follow the detailed plugin installation instructions on the [WakaTime Roblox Studio page](https://wakatime.com/roblox-studio). +Next, you'll need to install the Hackatime plugin directly within Roblox Studio: -The WakaTime plugin will automatically use your Hackatime configuration after running the setup script. +1. Open **Roblox Studio**. +2. Navigate to the **Toolbox**. +3. In the Toolbox search bar, select **"Plugins"** from the dropdown filter. +4. Search for **"HackaTime Roblox"**. +5. Install the plugin published by **"ThisWhity"**. + + ![Toolbox filter showing Plugins selected](https://github.com/user-attachments/assets/65931fad-fa16-4df6-9a07-eadf1e2aaf07) + *Filter the Toolbox by "Plugins"* + + ![Toolbox search results showing HackaTime Roblox plugin](https://github.com/user-attachments/assets/13233bf7-b876-4c29-b690-9ebbcb796488) + *Install the "HackaTime Roblox" plugin by ThisWhity* + +--- + +## Step 3: Configure the Plugin with Your API Key + +Now, you'll connect the plugin to your Hackatime account using your unique API key: + +1. Get your API key by visiting [hackatime.hackclub.com/my/wakatime_setup](https://hackatime.hackclub.com/my/wakatime_setup). It will look something like this: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`. + + ![Screenshot showing API Key on Hackatime website](https://github.com/user-attachments/assets/635cab06-36cb-4351-819b-62403b6c6885) + *Your API key from the Hackatime website* + +2. In Roblox Studio, open the **Hackatime plugin**. You'll usually find it under the "Plugins" tab in the Ribbon bar. + + ![Screenshot showing the Hackatime plugin tab with API key input](https://github.com/user-attachments/assets/c241dbe2-6f9a-44bf-adb9-f0b4780227db) + *Open the Plugin* + +4. Paste your API key into the API key box. And hit "Save API Key" + +--- ## Troubleshooting -- **Not seeing your time?** Make sure you completed the [setup page](https://hackatime.hackclub.com/my/wakatime_setup) first -- **Plugin not working?** Try restarting Roblox Studio after installation -- **Still stuck?** Ask for help in [Hack Club Slack](https://hackclub.slack.com) (#hackatime-v2 channel) +### ERR\_NETWORK: Plugin Cannot Connect to Hackatime -## Next Steps +If you see an **ERR\_NETWORK** message, it means the plugin can't connect to Hackatime. This is likely due to you not allowing HTTP request from the plugin: -Once configured, your activity time will automatically appear on your [Hackatime dashboard](https://hackatime.hackclub.com). Happy game developing! +1. Open the "Manage Plugins". +2. Hit the edit icon. +3. Ensure that **"hackatime.hackclub.com"** is enabled. + + ![Screenshot showing Game Settings with Security tab open and Allow HTTP Requests highlighted](https://github.com/user-attachments/assets/c3533d87-2b06-4ba8-a1c5-7416332578e9) + *Open Plugin Managment* + + ![Screenshot showing Allow HTTP Requests enabled](https://github.com/user-attachments/assets/86bea3e2-dbbe-496f-acd4-f5963c208767) + *Allow HTTP requests* + +### Still Stuck? + +If you're still experiencing issues, don't hesitate to ask for help in the **#hackatime-v2 channel** on the [Hack Club Slack](https://hackclub.slack.com). + +--- + +## What's Next? + +Once the plugin is successfully configured, your Roblox Studio activity time will automatically start appearing on your [Hackatime dashboard](https://hackatime.hackclub.com). + +Happy game developing! From eb60d1d82ccdd1b3e60c714a2bb538401d50c9a2 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 22 Jul 2025 20:55:26 -0400 Subject: [PATCH 5/5] =?UTF-8?q?Revert=20"fix:=20use=20WakatimeService=20wi?= =?UTF-8?q?thout=20filters=20and=20consistent=20time=20ranges=20f=E2=80=A6?= =?UTF-8?q?"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/api/v1/stats_controller.rb | 21 ++++++++++++++++++--- lib/wakatime_service.rb | 19 +++---------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/app/controllers/api/v1/stats_controller.rb b/app/controllers/api/v1/stats_controller.rb index fd36846..6b9d5f8 100644 --- a/app/controllers/api/v1/stats_controller.rb +++ b/app/controllers/api/v1/stats_controller.rb @@ -61,10 +61,25 @@ class Api::V1::StatsController < ApplicationController service_params[:scope] = scope if scope.present? if params[:total_seconds] == "true" - service_params[:boundary_aware] = params[:boundary_aware] == "true" + query = @user.heartbeats + .coding_only + .with_valid_timestamps + .where(time: start_date..end_date) - summary = WakatimeService.new(**service_params).generate_summary - return render json: { total_seconds: summary[:total_seconds] } + if params[:filter_by_project].present? + filter_by_project = params[:filter_by_project].split(",") + query = query.where(project: filter_by_project) + end + + # do the boundary thingie if requested + use_boundary_aware = params[:boundary_aware] == "true" + total_seconds = if use_boundary_aware + Heartbeat.duration_seconds_boundary_aware(query, start_date.to_f, end_date.to_f) || 0 + else + query.duration_seconds || 0 + end + + return render json: { total_seconds: total_seconds } end summary = WakatimeService.new(**service_params).generate_summary diff --git a/lib/wakatime_service.rb b/lib/wakatime_service.rb index 928d178..908de9b 100644 --- a/lib/wakatime_service.rb +++ b/lib/wakatime_service.rb @@ -1,24 +1,18 @@ include ApplicationHelper class WakatimeService - def initialize(user: nil, specific_filters: [], allow_cache: true, limit: 10, start_date: nil, end_date: nil, scope: nil, boundary_aware: false) + def initialize(user: nil, specific_filters: [], allow_cache: true, limit: 10, start_date: nil, end_date: nil, scope: nil) @scope = scope || Heartbeat.all @user = user - @boundary_aware = boundary_aware @start_date = convert_to_unix_timestamp(start_date) @end_date = convert_to_unix_timestamp(end_date) - # apply with_valid_timestamps filter if no custom scope provided-- this is copied from query in stats_controller - if scope.nil? - @scope = @scope.with_valid_timestamps - end - # Default to 1 year ago if no start_date provided or if no data exists @start_date = @start_date || @scope.minimum(:time) || 1.year.ago.to_i @end_date = @end_date || @scope.maximum(:time) || Time.current.to_i - @scope = @scope.where(time: @start_date..@end_date) + @scope = @scope.where("time >= ? AND time < ?", @start_date, @end_date) @limit = limit @limit = nil if @limit&.zero? @@ -47,14 +41,7 @@ class WakatimeService summary[:range] = "all_time" summary[:human_readable_range] = "All Time" - @total_seconds = if @boundary_aware - result = Heartbeat.duration_seconds_boundary_aware(@scope, @start_date, @end_date) || 0 - result - else - result = @scope.duration_seconds || 0 - result - end - + @total_seconds = @scope.duration_seconds || 0 summary[:total_seconds] = @total_seconds @total_days = (@end_time - @start_time) / 86400