{"id":16062043,"url":"https://github.com/rossta/loop","last_synced_at":"2025-02-23T01:15:37.126Z","repository":{"id":66515671,"uuid":"56899682","full_name":"rossta/loop","owner":"rossta","description":"Social media queue","archived":false,"fork":false,"pushed_at":"2016-04-27T03:15:35.000Z","size":104,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-15T10:57:04.587Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rossta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-04-23T04:06:35.000Z","updated_at":"2016-04-23T04:07:01.000Z","dependencies_parsed_at":"2023-02-20T19:46:10.051Z","dependency_job_id":null,"html_url":"https://github.com/rossta/loop","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rossta%2Floop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rossta%2Floop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rossta%2Floop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rossta%2Floop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rossta","download_url":"https://codeload.github.com/rossta/loop/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240254293,"owners_count":19772393,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-09T04:21:34.024Z","updated_at":"2025-02-23T01:15:36.972Z","avatar_url":"https://github.com/rossta.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Queue Loop\n\nA work-in-progress. Social marketing or something. Ruby on Rails.\n\n## About\n\nThis README would normally document whatever steps are necessary to get the application up and running.\n\nThings you may want to cover:\n\n* Ruby version\n\n* System dependencies\n\n* Configuration\n\n* Database creation\n\n* Database initialization\n\n* How to run the test suite\n\n* Services (job queues, cache servers, search engines, etc.)\n\n* Deployment instructions\n\n* ...\n\n## Development\n\n```\n$ bundle\n$ cp config/database.yml.example config/database.yml\n$ cp config/redis.yml.example config/redis.yml\n$ cp .envrc.example .envrc\n```\n\n## Sending updates\n\nUsers set up \"accounts\" linked to social networks, e.g. Twitter, and \"channels\", e. g. #tech, for distributing content in the form of individual \"posts\".\n\nUser create posts and may assign them to channels for recurring distribution and\nfor delivery for specific timeslots.\n\nChannels have, and belong to, many accounts. Channels represent a queue of\nposts that will loop on repeat until or unless otherwise specified.\n\nUsers establish \"schedules\" for each channel. A schedule consists of one (or more?) recurrence rule(s), i.e., every day at 2pm, and the channel from which to pull content.\n\nChannels have many schedules.\n\nAn hourly? job is run to iterate over all channels and determine if any jobs\nshould be run in the upcoming hour?. If a recurrence rule overlaps with the\nupcoming time interval, a \"timeslot\" record is created for that channel.\n\nA timeslot belongs to a channel schedule or specific post. It represents a one-time job to publish a\nsingle post - either the post it is associated with directly or the \"next post\" from channel.\n\nA timeslot has a publish timestamp and a token. When a timeslot is created,\nit enqueues a job to be run at a specific time (the publish timestamp). The job receives the\ntimeslot's token when enqueued. If timeslot's publish timestamp is edited a new job is a\ngenerated with a new token. For a timeslot job to succeed, its token must match the current timeslot token.\nPreviously-enqueued jobs will no-op since their tokens will not match current token of the timeslot.\n(This technique makes it unnecessary to delete jobs from a Sidekiq, an O(n) operation). If the\ntimeslot is deleted, the job will also no-op. When the post is successfully sent, the timeslot is\nmarked as published and the post it published is recorded.\n\nWhen a schedule is edited, existing, unpublished timeslots must be examined to determine if they are\nstill consistent with the schedule's recurrence rules. (Either they get updated or\ndeleted/regenerated).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frossta%2Floop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frossta%2Floop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frossta%2Floop/lists"}