diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..99d9623 --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1,5 @@ +^.*\.Rproj$ +^\.Rproj\.user$ +^README\.Rmd$ +^data-raw$ +^LICENSE\.md$ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f7a8b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.Rproj.user +.Rhistory +.RData +.Ruserdata +.idea \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..07ea489 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,18 @@ +Package: rescuetimewrapper +Type: Package +Title: RescueTime Wrapper +Version: 1.0.0 +Author: Niko Wenzl +Maintainer: Niko Wenzl +Description: Wrapper for Accessing complete or anonymized data from the RescueTime API +License: MIT + file LICENSE +Encoding: UTF-8 +LazyData: true +RoxygenNote: 7.1.1 +Imports: + dplyr, + httr, + lubridate, + stringr +Depends: + R (>= 2.10) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..151684d --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +YEAR: 2021 +COPYRIGHT HOLDER: Niko Wenzl diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..6ec22e3 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2021 Niko Wenzl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..85734de --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,5 @@ +# Generated by roxygen2: do not edit by hand + +export(get_productivity_index) +export(get_rescue_time_data) +export(get_rescue_time_data_anonymized) diff --git a/R/main.R b/R/main.R new file mode 100644 index 0000000..f3d18a6 --- /dev/null +++ b/R/main.R @@ -0,0 +1,173 @@ +#' Get RescueTime Data based on an API Key. +#' The Data is returned unfiltered +#' +#' @param key string provided by RescueTime +#' @param dateFrom string in iso date format "YYYY-mm-DDTHH:MM:ssZ" +#' @param dateTo string in iso date format "YYYY-mm-DDTHH:MM:ssZ" +#' @param scope string either "Overview", "Category", "Activity", "Productivity", "Document" +#' @param transform boolean transform data to different structure + +#' +#' @return table with complete data +#' @export +#' +#' @examples +#' data <- get_rescue_time_data("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z","Category") +get_rescue_time_data <- function (key, dateFrom, dateTo, scope = "Activity", transform = FALSE) { + library(httr) + params <- list("key" = key, + "format" = "csv", + "restrict_begin" = dateFrom, + "restrict_end" = dateTo , + "resolution_time" = "day", + "perspective" = "interval", + "restrict_kind" = tolower(scope)) + + res <- POST("https://www.rescuetime.com/anapi/data", + body = params, + encode = "form", + verbose() + ) + + # parse data + activity_data <- content(res, "parsed") + + if (transform) { + colnames(activity_data)[colnames(activity_data) == "Time Spent (seconds)"] <- "Time" + colnames(activity_data) <- stringr::str_replace_all(colnames(activity_data),"[:punct:]|[:space:]|[/+]","") + activity_data <- transform(activity_data, Date = strftime(Date, "%Y-%m-%d")) + return(transform_data(activity_data, "Date", scope, c("Time"))) + } else { + return(activity_data) + } +} + +#' Get RescueTime Data based on an API Key. +#' The Data is return anonymized according to the category definitions on package level +#' +#' +#' @param key string provided by RescueTime +#' @param dateFrom string in iso date format "YYYY-mm-DDTHH:MM:ssZ" +#' @param dateTo string in iso date format "YYYY-mm-DDTHH:MM:ssZ" +#' @param scope string either "Category" or "SubCategory" +#' @param transform boolean transform data to different structure +#' +#' @return table with an entry for each category for each day +#' @export +#' +#' @examples +#' data <- get_rescue_time_data_anonymized("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z","Category") +get_rescue_time_data_anonymized <- function (key, dateFrom, dateTo, scope = "Category", transform = FALSE) { + library(dplyr) + activity_data <- get_rescue_time_data(key, dateFrom, dateTo, "Activity", FALSE) + + csv_path <- system.file("categories.csv", package="rescuetimewrapper") + categories <- read.csv(csv_path) + + # join with categories + joined_data <- merge( + categories, + activity_data, + by.x = "SubCategory", + by.y = "Category", + all = TRUE, + ) + + # productivity index + productivity_index <- activity_data %>% + group_by(Date) %>% + summarise(weighted.mean(Productivity, `Time Spent (seconds)`)) + names(productivity_index)<-c("Date","Productivity Index") + productivity_index <- transform(productivity_index, Date = strftime(Date, "%Y-%m-%d")) + + # anonymize data by aggreagting over categories + anomymized_data <- aggregate(x = joined_data$`Time Spent (seconds)`, + by = list(joined_data[,scope], joined_data$Date), + FUN = sum) + colnames(anomymized_data) <- c("Category", "Date","Time Spent (seconds)") + + all_data <- expand.grid(unique(na.omit(categories[,scope])), + unique(na.omit(joined_data$Date)), + "Time Spent (seconds)"=NA) + colnames(all_data) <- c("Category", "Date","Time Spent (seconds)") + result <- select(merge(all_data, anomymized_data, by = c("Category", "Date"), all=TRUE),-"Time Spent (seconds).x") + colnames(result) <- c("Category", "Date","Time") + + # add number of Applications for each row + for (row in 1:nrow(result)) { + current_category <- toString(result[row, "Category"]) + current_date <- result[row, "Date"] + result[row, "Number of Applications"] <- length(which(joined_data[,scope] == current_category & joined_data$Date == current_date)) + } + + if (transform) { + colnames(result)[colnames(result) == "Time Spent (seconds)"] <- "Time" + colnames(result) <- stringr::str_replace_all(colnames(result),"[:punct:]|[:space:]|[+]","") + result <- transform(result, Date = strftime(Date, "%Y-%m-%d")) + transformed_result <- transform_data(result, "Date", scope, c("Time", "NumberofApplications")) + data_with_productivity <- merge(transformed_result, productivity_index, by = "Date", all = TRUE) + return(data_with_productivity) + } else { + return(result) + } +} + +#' Transform data frame based on row and column definitions +#' +#' @param data data.frame with rows and columns +#' @param row_column string the column that contains the values for the transformed row +#' @param col_column string the column that contains the values for the transformed columns +#' @param ignored_columns array list of columns to ignore as value columns +#' +#' @return a data frame that has a row for each entry of the values in the row_column +#' and columns for each value of the col_column +#' +#' @examples new_data <- transform_data(data, "Date", "Category") +transform_data <- function(data, row_column, col_column, value_columns = c("Time")) { + library(lubridate) + # create table with unique values for row_column as rows + transformed_data <- data.frame(unique(na.omit(data[, row_column]))) + colnames(transformed_data) <- c(row_column) + + + # for each column that values are converted to columns themselves + unique_items <- data.frame(unique(na.omit(data[,col_column]))) + colnames(unique_items) <- c(col_column) + + for(i in 1:nrow(transformed_data)) { + for (j in 1:nrow(unique_items)) { + col_value <- unique_items[j, col_column] + current_row <- data[which(grepl(pattern = toString(transformed_data[i, row_column]), x=data[,row_column], fixed=TRUE) + & grepl(pattern = toString(col_value), x = data[, col_column], fixed=TRUE)),] + for (col in value_columns) { + transformed_data[i, paste(col_value, col, sep = "_")] <- current_row[1, col] + } + } + } + return(transformed_data) +} + +#' Function that calculates a productivity index (weighted mean) for a given time period +#' +#' @param key string provided by RescueTime +#' @param dateFrom string in iso date format "YYYY-mm-DDTHH:MM:ssZ" +#' @param dateTo string in iso date format "YYYY-mm-DDTHH:MM:ssZ" +#' +#' @return data.frame with a productivity for each date +#' @export +#' +#' @examples productivity_index <- get_productivity_index("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z") + +get_productivity_index <- function(key, dateFrom, dateTo) { + library(dplyr) + activity_data <- get_rescue_time_data(key, dateFrom, dateTo, "Activity", FALSE) + + # productivity index + productivity_index <- activity_data %>% + group_by(Date) %>% + summarise(weighted.mean(Productivity, `Time Spent (seconds)`)) + names(productivity_index)<-c("Date","Productivity Index") + productivity_index <- transform(productivity_index, Date = strftime(Date, "%Y-%m-%d")) + + return(productivity_index) +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..26ebd40 --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ + + + + +# RescueTime R Wrapper + + + + +The goal of RescueTime Wrapper is to provide access to Rescue Time Data through R. Also it is possible to get anonymized data from here. + +## Installation + +You can install the version via the remotes package. + +``` r +remotes.install_github(repo = "tud-ise/rescuetime-r-wrapper") +``` + +## Example + +After loading the library you have two ways to access the RescueTime API. The Parameters are the same for both functions. +First, you need to supply your RescueTimeAPI Key, second and third the start and enddate provided as string in ISO Format (YYYY-mm-DDTHH:MM:SSZ). +The fourth parameter varies between the function and defines the scope of the data returned. There is an optional fifth parameter that is discussed in the next paragraph. + + +```r +library(rescuetimewrapper) +# complete +data <- get_rescue_time_data("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z", 'Activity') +# anonymized +data <- get_rescue_time_data_anonymized("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z","Category") +``` + +The data returned is a table looking like this + + +```r +data <- get_rescue_time_data("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z", 'activity') +#> Date `Time Spent (seconds)` `Number of People` Activity Category Productivity +#> 1 2021-04-11 00:00:00 1451 1 idea64 Editing & IDEs 2 +#> 2 2021-04-11 00:00:00 924 1 Windows Explorer General Utilities 1 +#> 3 2021-04-11 00:00:00 892 1 discord General Communication & Scheduling 0 +#> 4 2021-04-11 00:00:00 620 1 brave Browsers 0 +#> 5 2021-04-11 00:00:00 574 1 iTunes Music -2 +#> 6 2021-04-11 00:00:00 495 1 youtube.com Video -2 + +data <- get_rescue_time_data_anonymized("XYZ","2021-04-12T00:00:00Z","2021-04-12T23:59:59Z", 'Category') +#> Category Date Time Number of Applications +#> 1 Business 2021-04-12 961 4 +#> 2 Communication & Scheduling 2021-04-12 406 2 +#> 3 Social Networking 2021-04-12 53 1 +#> 4 Design & Composition 2021-04-12 NA 0 +#> 5 Entertainment 2021-04-12 3157 6 +#> 6 News & Opinion 2021-04-12 29 2 +#> 7 Reference & Learning 2021-04-12 301 5 +#> 8 Software Development 2021-04-12 7208 8 +#> 9 Shopping 2021-04-12 60 2 +#> 10 Utilities 2021-04-12 1489 9 +#> 11 Uncategorized 2021-04-12 344 8 +``` + +### Transformed Data +You can also query the data in a transformed way, with an optional Parameter. The transformed data will also contain the productivity index described below. The output will look like this: +```r +data <- get_rescue_time_data("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z", 'activity', TRUE) +#> Date `idea64_Time` `Windows Explorer_Time` ... +#> 1 2021-04-11 00:00:00 1451 924 + +data <- get_rescue_time_data_anonymized("XYZ","2021-04-12T00:00:00Z","2021-04-12T23:59:59Z", 'Category', TRUE) +#> Date `Business_Time` `Business_Number of Applications` 'Communication & Scheduling_Time' ... +#> 1 2021-04-11 00:00:00 961 4 406 +``` + +### Productivity Index +You can also calculate a productivity index (weighted mean) for a given time period. The value varies from -2 (very unproductive) to 2 (very productive) +```r +productivity_index <- get_productivity_index("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z") +#> Date Productivity Index +#> 2021-04-11 1.75 +#> 2021-04-12 0.98 +``` diff --git a/RescueTimeRWrapper.Rproj b/RescueTimeRWrapper.Rproj new file mode 100644 index 0000000..f0d6187 --- /dev/null +++ b/RescueTimeRWrapper.Rproj @@ -0,0 +1,21 @@ +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX + +AutoAppendNewline: Yes +StripTrailingWhitespace: Yes + +BuildType: Package +PackageUseDevtools: Yes +PackageInstallArgs: --no-multiarch --with-keep.source +PackageRoxygenize: rd,collate,namespace,vignette diff --git a/inst/categories.csv b/inst/categories.csv new file mode 100644 index 0000000..79d0012 --- /dev/null +++ b/inst/categories.csv @@ -0,0 +1,69 @@ +Category,SubCategory,Productivity +Business,General Business,2 +Business,Accounting,2 +Business,Administration,2 +Business,Sales,2 +Business,Marketing,2 +Business,Customer Relations,2 +Business,Intelligence,2 +Business,Operations,2 +Business,Project Management,2 +Communication & Scheduling,General Communication & Scheduling,0 +Communication & Scheduling,Calendars,0 +Communication & Scheduling,Email,1 +Communication & Scheduling,Instant Message,1 +Communication & Scheduling,Meetings,1 +Communication & Scheduling,Voice,1 +Social Networking,General Social Networking,-2 +Social Networking,Professional Networking,1 +Design & Composition,General Design & Composition,2 +Design & Composition,3D Graphic Design,2 +Design & Composition,Audio Editing,2 +Design & Composition,Graphic Design,2 +Design & Composition,Presentation,2 +Design & Composition,Engineering & Drafting,2 +Design & Composition,Video Editing,2 +Design & Composition,Writing,2 +Entertainment,General Entertainment,-2 +Entertainment,Comedy,-2 +Entertainment,Games,-2 +Entertainment,Music,-2 +Entertainment,Photos,-2 +Entertainment,Video,-2 +News & Opinion,General News & Opinion,-2 +News & Opinion,Business,-1 +News & Opinion,Entertainment,-2 +News & Opinion,Society,-2 +News & Opinion,Science & Technology,-1 +News & Opinion,Sports,-1 +News & Opinion,Regional,-2 +News & Opinion,International,-2 +Reference & Learning,General Reference & Learning,2 +Reference & Learning,Business & Finance,1 +Reference & Learning,Employment,2 +Reference & Learning,Food,1 +Reference & Learning,Health & Medicine,1 +Reference & Learning,Home & Garden,0 +Reference & Learning,Legal & Gov't,1 +Reference & Learning,Maps & Regional,1 +Reference & Learning,Engineering & Technology,1 +Reference & Learning,Search,1 +Reference & Learning,Travel & Outdoors,1 +Software Development,General Software Development,2 +Software Development,Design & Planning,2 +Software Development,Editing & IDEs,2 +Software Development,Quality Assurance,2 +Software Development,Systems Operations,2 +Software Development,Data Modeling & Analysis,2 +Shopping,General Shopping,-2 +Shopping,Office,-2 +Shopping,Electronics,-2 +Shopping,Clothes & Personal,-2 +Utilities,General Utilities,1 +Utilities,Anti-Virus & Spyware,1 +Utilities,Browsers,0 +Utilities,Internet Utilities,1 +Utilities,File Sharing,-2 +Utilities,Virtualization,0 +Utilities,Other,0 +Uncategorized,Uncategorized,0 diff --git a/man/get_productivity_index.Rd b/man/get_productivity_index.Rd new file mode 100644 index 0000000..fe9bbd0 --- /dev/null +++ b/man/get_productivity_index.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/main.R +\name{get_productivity_index} +\alias{get_productivity_index} +\title{Function that calculates a productivity index (weighted mean) for a given time period} +\usage{ +get_productivity_index(key, dateFrom, dateTo) +} +\arguments{ +\item{key}{string provided by RescueTime} + +\item{dateFrom}{string in iso date format "YYYY-mm-DDTHH:MM:ssZ"} + +\item{dateTo}{string in iso date format "YYYY-mm-DDTHH:MM:ssZ"} +} +\value{ +data.frame with a productivity for each date +} +\description{ +Function that calculates a productivity index (weighted mean) for a given time period +} +\examples{ +productivity_index <- get_productivity_index("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z") +} diff --git a/man/get_rescue_time_data.Rd b/man/get_rescue_time_data.Rd new file mode 100644 index 0000000..c91e603 --- /dev/null +++ b/man/get_rescue_time_data.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/main.R +\name{get_rescue_time_data} +\alias{get_rescue_time_data} +\title{Get RescueTime Data based on an API Key +The Data is returned unfiltered} +\usage{ +get_rescue_time_data( + key, + dateFrom, + dateTo, + scope = "Activity", + transform = FALSE +) +} +\arguments{ +\item{key}{string provided by RescueTime} + +\item{dateFrom}{string in iso date format "YYYY-mm-DDTHH:MM:ssZ"} + +\item{dateTo}{string in iso date format "YYYY-mm-DDTHH:MM:ssZ"} + +\item{scope}{string either "Overview", "Category", "Activity", "Productivity", "Document"} + +\item{transform}{boolean transform data to different structure} +} +\value{ +table with complete data +} +\description{ +Get RescueTime Data based on an API Key +The Data is returned unfiltered +} +\examples{ +data <- get_rescue_time_data("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z","Category") +} diff --git a/man/get_rescue_time_data_anonymized.Rd b/man/get_rescue_time_data_anonymized.Rd new file mode 100644 index 0000000..c06e970 --- /dev/null +++ b/man/get_rescue_time_data_anonymized.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/main.R +\name{get_rescue_time_data_anonymized} +\alias{get_rescue_time_data_anonymized} +\title{Get RescueTime Data based on an API Key +The Data is return anonymized according to the category definitions on package level} +\usage{ +get_rescue_time_data_anonymized( + key, + dateFrom, + dateTo, + scope = "Category", + transform = FALSE +) +} +\arguments{ +\item{key}{string provided by RescueTime} + +\item{dateFrom}{string in iso date format "YYYY-mm-DDTHH:MM:ssZ"} + +\item{dateTo}{string in iso date format "YYYY-mm-DDTHH:MM:ssZ"} + +\item{scope}{string either "Category" or "SubCategory"} + +\item{transform}{boolean transform data to different structure} +} +\value{ +table with an entry for each category for each day +} +\description{ +Get RescueTime Data based on an API Key +The Data is return anonymized according to the category definitions on package level +} +\examples{ +data <- get_rescue_time_data_anonymized("XYZ","2021-04-11T00:00:00Z","2021-04-12T23:59:59Z","Category") +} diff --git a/man/transform_data.Rd b/man/transform_data.Rd new file mode 100644 index 0000000..35f3025 --- /dev/null +++ b/man/transform_data.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/main.R +\name{transform_data} +\alias{transform_data} +\title{Transform data frame based on row and column definitions} +\usage{ +transform_data(data, row_column, col_column, value_columns = c("Time")) +} +\arguments{ +\item{data}{data.frame with rows and columns} + +\item{row_column}{string the column that contains the values for the transformed row} + +\item{col_column}{string the column that contains the values for the transformed columns} + +\item{ignored_columns}{array list of columns to ignore as value columns} +} +\value{ +a data frame that has a row for each entry of the values in the row_column +and columns for each value of the col_column +} +\description{ +Transform data frame based on row and column definitions +} +\examples{ +new_data <- transform_data(data, "Date", "Category") +}