No internet connection
  1. Home
  2. How to

Time tracker app

By Vladimir @poterukha
    2020-02-04 22:34:31.381Z

    As a freelance sound editor, I tried a lot of time tracking apps and services, but I was never 100% satisfied with their abilities in the case of post-production realities. I have a concept of an internal SF app in my mind that might be useful for some post-pro scenarios. The app is not only about creating bills or reports for clients or supervisors. It is also about understanding how much time you spend on each task. Last year I was working on multiple projects at the same time. It was a pain not to forget to switch on the timer in my iOS app for each project when you are jumping from one task or project to another during the shift. As well, when you are a one-man-band professional doing a lot of stuff for a single project. Besides the basic time tracker functions, I think the key feature of the app can read a lot of information from the name of the current project. In my workflow, a session name usually looks like "PRJ-TaskName vOfVideo CurrentDate". It is a more or less common naming scheme. Is it possible to make SF automatically start/stop a timer when the session opens/closes also gathering information on the current task? Next, you can have predefined price tags, for example, for editing, composing, mixing or design that comes to report automatically. In the report, you can see how much you spent on each task. Also, I think an app can check if there are no new Pro Tools file session backups for 30 minutes, it will suspend the timer automatically. As far as we have our own cloud-based SF account the timer data will be accessible wherever you working: at home, editorial or the mixing stage. To summarize what I said:

    To create projects
    To create tasks
    To set the price for tasks
    Manual control for start/stop tracking
    To create reports and to export them as CSV
    To present progress on projects in a calendar view inside the app
    Auto-detect the name of the project, task, and the version of the editing
    To record DAWs activities in the background (auto start/stop)

    Solved in post #18, click to view
    • 24 replies

    There are 24 replies. Estimated reading time: 13 minutes

    1. That's a cool idea! And yes this should be possible to make work today in SF.
      If you feel comfortable diving in to dynamic UI building, I would love to host a session (perhaps with more members) who'd be interested.

      1. Vladimir @poterukha
          2020-03-06 21:31:09.198Z

          Do you have any updated plans on this feature implementation?

          1. Hi @poterukha

            With the current workload we have and the fact that you've been the only person requesting this I don't think we can prioritize doing this development ourselves any time soon.

            However with our growing integrations I think there's a good chance that a different approach to this solution could be made, that wouldn't take us as long to code.
            There are tons of existing time tracking and project management systems out there that we could integrate with via their APIs. In SF 3.5 we're getting new actions that make it much easier to integrate with 3rd party APIs.

            So the quickest and most certain way to get this kind of functionality would be if you choose a specific, online-based project management tool that you like - and that we then create an integration for that.

            This would give you the best of all worlds - ie. you could still have SF scripts detect what you're working on, but you get the full power of reporting, mobile app access, calendar integrations etc. from the project management system.

            Let me know when/if you have a project management system in mind, and we can start collaborating on the scripts needed to make the integrations.

            1. If you're ok with it, I think we should move this request to the public "How to" section so it can be a more public discussion (might also get more traction that way).

              1. Vladimir @poterukha
                  2020-03-06 21:53:30.753Z

                  Yes, let’s move it to public discussion area of the forum. I will look for free time trackers with API. Now I’m using subscription based services.

                  1. Great. Which ones are you using now? It doesn't have to be a free service IMO

                    1. Vladimir @poterukha
                        2020-03-06 22:01:53.146Z

                        I have some bundled with Setapp subscription: https://setapp.com/apps/timemator, https://setapp.com/apps/timing, https://setapp.com/apps/be-focused. Also I like https://hourstimetracking.com, I have bought an iOS version before they moved to subscription.

                        1. In reply tochrscheuer:
                          Vladimir @poterukha
                            2020-03-06 22:22:16.330Z
                            1. Nice. This script (using SF 3.5 preview) should get you started with the TimingApp API:

                              Note you need to insert the API token in the first line - this you generate in your TimingApp account.

                              
                              const API_TOKEN = 'INSERT API TOKEN HERE';
                              
                              function apiCall(method, url, data) {
                                  return sf.net.httpRequest({
                                      url: 'https://web.timingapp.com/api' + url,
                                      method: method,
                                      headers: {
                                          'Authorization': `Bearer ${API_TOKEN}`,
                                          'Accept': 'application/json',
                                          'Content-Type': 'application/json',
                                      },
                                      data: data
                                  }).asJson();
                              }
                              
                              function startTask(project, title, notes) {
                                  return apiCall('POST', '/v1/time-entries/start', {
                                      'start_date': (new Date()).toISOString(), /* Start NOW */
                                      'project': project,
                                      'title': title,
                                      'notes': notes,
                                  });
                              }
                              
                              function stopCurrentTask() {
                                  apiCall('PUT', '/v1/time-entries/stop', undefined);
                              }
                              
                              

                              NOTE: Never publicly post your API token as it would give us access to your account, so if you want to send scripts here for review and troubleshooting, omit that first line.

                              1. Vladimir @poterukha
                                  2020-03-07 20:01:35.684Z

                                  Great! To finally join Timing with SF, can you help me with 2 features I described in the top post?

                                  1. Using regular expression pick up project info from the Pro Tools session name and put it into variables.
                                  2. Send stopCurrentTask to Timing after Pro Tools stopped making session backups with some timeout.
                                  1. Before we do that we should test if the API portion works. It's gonna be easier to track down bugs if we can verify that the API itself works first so that we don't introduce bugs into the integration.
                                    I don't have an account with them but could you try using the above scripts first?
                                    You'd have to call the functions, like this:

                                    startTask('My Project', 'The Title Of My Task', 'Some notes...');
                                    

                                    Remember to enter the API_TOKEN in the first line as well.

                                    1. Vladimir @poterukha
                                        2020-03-07 22:25:03.528Z

                                        Ok, I tried and have got some errors. How it will be easier for you to track it? I can attach a part of the log at this thread or create a separate thread with a standard help/issue feature?

                                        1. Yea probably log those with Help/Issue that would be great.

                                          1. Answering here as well. The error you got is "API_TOKEN is not defined."
                                            Did you remove this line?

                                            const API_TOKEN = 'INSERT API TOKEN HERE';
                                            

                                            You're supposed to insert the API token inside the string. So lets say you got the API token 12345, then your first line should look like this:

                                            const API_TOKEN = '12345';
                                            
                                            1. But ah there's also a different error which I think is a SF bug where you'll need a newer build. I'll get that sent over asap.

                                              1. Vladimir @poterukha
                                                  2020-03-07 23:49:27.795Z

                                                  Yes, I inserted it into quotes.
                                                  Sure, I will try it when the new build arrives.

                                                  1. Thank you for the logs. Please try to change the script to this:

                                                    const API_TOKEN = 'INSERT API TOKEN HERE';
                                                    
                                                    function apiCall(method, url, data) {
                                                        return sf.net.httpRequest({
                                                            url: 'https://web.timingapp.com/api' + url,
                                                            method: method,
                                                            headers: {
                                                                'Authorization': `Bearer ${API_TOKEN}`,
                                                                'Accept': 'application/json',
                                                            },
                                                            data: data
                                                        }).asJson();
                                                    }
                                                    
                                                    function startTask(project, title, notes) {
                                                        return apiCall('POST', '/v1/time-entries/start', {
                                                            'start_date': (new Date()).toISOString(), /* Start NOW */
                                                            'project': project,
                                                            'title': title,
                                                            'notes': notes,
                                                        });
                                                    }
                                                    
                                                    function stopCurrentTask() {
                                                        apiCall('PUT', '/v1/time-entries/stop', undefined);
                                                    }
                                                    
                                                    ReplySolution
                                                    1. Vladimir @poterukha
                                                        2020-03-11 12:38:24.335Z

                                                        It is working with latest updates, SF triggers the start of the existing task thru API!

                                                        1. Amazing! Great stuff :)

                                                          1. Vladimir @poterukha
                                                              2020-04-16 16:49:33.063Z2020-04-16 20:38:48.515Z

                                                              @chrscheuer Can you help me to join the part above with js regular expression I found in web?

                                                              var name = "PRJ Mix v101";
                                                              
                                                              var output = ["Timing Regular Expression test", name + "\n"];
                                                              
                                                              var pattern = /s* \s*\ s*/
                                                              
                                                              var nameList = name.split(pattern);
                                                              
                                                              pattern = /(\w+)\s+(\w+)\s+(\w+)/;
                                                              
                                                              var projectName = [];
                                                              
                                                              output.push("---------- After Split by Regular Expression");
                                                              
                                                              var i, len;
                                                              for (i = 0, len = nameList.length; i < len; i++) {
                                                                output.push(nameList[i]);
                                                                projectName[i] = nameList[i].replace(pattern, "$1");
                                                              }
                                                              
                                                              output.push("---------- Name of project");
                                                              for (i = 0, len = projectName.length; i < len; i++) {
                                                                output.push(projectName[i]);
                                                              }
                                                              
                                                              for (i = 0, len = nameList.length; i < len; i++) {
                                                                projectName[i] = nameList[i].replace(pattern, "$2");
                                                              }
                                                              
                                                              output.push("---------- Name of Task");
                                                              for (i = 0, len = projectName.length; i < len; i++) {
                                                                output.push(projectName[i]);
                                                              }
                                                              
                                                              for (i = 0, len = nameList.length; i < len; i++) {
                                                                projectName[i] = nameList[i].replace(pattern, "$3");
                                                              }
                                                              
                                                              output.push("---------- Version of video");
                                                              for (i = 0, len = projectName.length; i < len; i++) {
                                                                output.push(projectName[i]);
                                                              }
                                                              
                                                              
                                                              log(output.join("\n"));
                                                              
                                                              1. Hi V.

                                                                I think having a complete description of exactly what you want might be easier than reading this regex, which basically just splits up words and puts them back together again.

                                                                Just having this code without context on what you want to achieve with examples of the project name in PT and how you'd like it formatted is not very easy to work with.

                                                                1. Vladimir @poterukha
                                                                    2020-04-16 21:25:48.654Z

                                                                    Earlier you found a way to interact with Timing through API.
                                                                    The code I found on the internet is for splitting and sorting the names from the list in alphabetical order. I just modified it with this output pushes for logging is it working or not in SF.
                                                                    My idea from the original post was to get the name of active Pro Tools session, then using regular expression split the name to blocks and send the first part of the pattern ($1) as project name, the second part ($2) as the task, the third ($3) as notes.
                                                                    Also, I was looking over the web for some examples how to read file creation date

                                                                    an app can check if there are no new Pro Tools file session backups for 30 minutes, it will suspend the timer automatically.

                                                                    to implement this idea. But all examples I have found requires an external node, but I'm not familiar with how to use it in SF.

                                                                    1. Hey V, let's get on a call to talk about this.
                                                                      Send me an email at christian@soundflow.org

                            2. D
                              In reply topoterukha:
                              DJH @DJH
                                2022-04-21 05:44:57.308Z

                                Just stumbled on this thread. Though it’s a bit dated, I think this is generally a cool idea and wanted to throw a little steam behind it. it may be that there’s not so much apparent interest in it bc it’s not the first thing one thinks of or prioritizes when diving into SF. But if auto-tracking time spent on a project was a feature/option that was presented to the user before the user thought to prioritize it, or even imagine it, it may prove to be more popular than is apparent.

                                Fwiw, as one use-case: I’m a setapp user like op, and often don’t granularity track time BC it always seems more trouble than it’s worth (and my contracts don’t generally require it). BUT, having a straighter path toward doing so would be very interesting to consider.