{"id":16161935,"url":"https://github.com/jessedp/tut","last_synced_at":"2025-08-31T13:39:41.902Z","repository":{"id":101652110,"uuid":"198078619","full_name":"jessedp/tut","owner":"jessedp","description":"Tut - Tablo User Tools","archived":false,"fork":false,"pushed_at":"2023-10-14T17:33:13.000Z","size":217,"stargazers_count":4,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-31T00:57:23.325Z","etag":null,"topics":["dvr","ota-dvr","python","tablo","tablo-user"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jessedp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2019-07-21T16:16:28.000Z","updated_at":"2023-09-28T17:28:42.000Z","dependencies_parsed_at":"2024-11-02T07:41:06.439Z","dependency_job_id":"5e841e56-1e50-4312-bc72-0f2d71682e28","html_url":"https://github.com/jessedp/tut","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jessedp/tut","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jessedp%2Ftut","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jessedp%2Ftut/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jessedp%2Ftut/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jessedp%2Ftut/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jessedp","download_url":"https://codeload.github.com/jessedp/tut/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jessedp%2Ftut/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272988781,"owners_count":25026959,"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","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["dvr","ota-dvr","python","tablo","tablo-user"],"created_at":"2024-10-10T02:28:22.344Z","updated_at":"2025-08-31T13:39:41.884Z","avatar_url":"https://github.com/jessedp.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tut - Tablo User Tools \u003ca name=\"tut\"\u003e\u003c/a\u003e\n\n**Tut** lets you mess with your \n[Tablo](https://www.tablotv.com/). Some things it does:\n\n* automatically finds your Tablo (there are options if you have multiples)\n* builds a library of your recordings\n* display stats about your library/recordings\n* a large number of search options\n* search/display _incomplete_ recordings\n\nMatching searches can than be used to:\n* **delete** recordings from your Tablo\n* **copy** recordings to wherever   \n\nHere's a fun example that _could_ be used to cleanup crappy recordings\non your Tablo:\n```shell script\n./tut.py -L library --incomplete 70 | ./tut.py delete\n```\nThat will find a **show** with one or more recordings that only managed to record 70% of the show and delete them.   \n\n\n##### Requirements\n* Python 3 (tested against Python 3.7.3 on Ubuntu).\n\n* Tested against Tablo firmware:\n    * v.2.2.26   \n\n\n### Installation\nDownload and unpack the \n[zip of this project](https://github.com/jessedp/tut/archive/master.zip) \nor clone it. Go there and...\n* run `pip install -r requirements.xt`\n\n_You maybe want to run this in a [virtualenv](https://virtualenv.pypa.io/en/latest/)_\n\n\n### Kick the wheels\nWith any luck after you've installed it, you can run these commands\nand it'll do/display a bunch of stuff about your Tablo. See below for \ndetails on all sorts of other stuff you can do.\n```\n./tut.py config --discover\n./tut.py library --build\n./tut.py library --stats\n./tut.py search --limit 2\n```\n\n### Detailed Usage\nRun something like:\n\n* `./tut.py`\n* `python tut.py`\n* `python3 tut.py`\n \nand you should see something like:\n\n```\nusage: tut.py [-h] [--dry-run] [-L] [-v] [--version]\n              {config,library,search,copy,delete} ...\n\nAvailable commands:\n  {config,library,search,copy,delete}\n    config              manage configuration options\n    library             manage the local library of recordings\n    search              ways to search your library\n    copy                copy recordings somewhere\n    delete              delete recordings from the Tablo device\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --dry-run             show what would happen, but don't change anything\n  -L, --id-list         if possible, only output a list of matching Object Ids\n                        - Pipe this into other commands. (overrides --full and\n                        any other output)\n  -v, --verbose         amount of detail to display add vs (-vvvv) for maximum\n                        amount\n  --version             show program's version number and exit\n```\n\n### Configure\nFirst things first, get your Tablo set up: \n\n`./tut.py config --discover`\n\nWant to see some gory details of what happened there?\n\n`./tut.py -vvv config --discover`  (more v, more info)\n\nThen try:\n\n`./tut.py config --view`\n\nPossibly you want to look at the config file it told you exists?\n\n### Your Library\nYour \"Library\" is a local copy of recording data **at the time** you _build_ it.\n\n##### Build it\nBefore you can do anything useful, you'll need to build the local cache/library of your recordings:\n\n`./tut.py library --build`\n\nA slow run including 630 recordings takes about 40 sec. \n\n##### General library stats \n`./tut.py library --stats`\n\nAnd you'll see something like:\n```\nOverview\n--------------------------------------------------\nTotal Recordings: 609\nTotal Watched: 65\n\nBy Current Recording State\n--------------------------------------------------\nFinished         : 577\nFailed           : 32\nRecording        : 0\n\nBy Recording Type\n--------------------------------------------------\nEpisodes/Series  : 608\nMovies           : 1\nSports/Events    : 0\nPrograms         : 0\n```\n\n##### Look for Incomplete recordings\nThis attempts to group recordings by the show/episode they belong to help determine what is unsalvageable. \n```shell script\n./tut.py library --incomplete \n```   \n*OR*, just find the obviously unsalvageable ones. (70 means 70% or the full show was recorded) \n```shell script\n./tut.py library --incomplete 70 \n```   \nYou can also pipe the output to delete them like so:\n```shell script\n./tut.py -L library --incomplete 70 | ./tut.py delete \n```\n\n### Search (the Library)\nThere are a number of ways to search your library. This will be useful in specifying recordings you want to work with later.\n\n**Important**: use the **-L** flag with _any_ search to create a list that can be \npiped into other opertaions.\n\nRun `./tut.py search` to see the numerous options available.\n\nA few examples follow. Note the combination of flags. \n\n###### All recordings with \"colbert\" in the title or description:\n\n`./tut.py search colbert`   \n\nor:\n\n`./tut.py search --term colbert`\n\n###### Or limit that to only recordings after a specific date:\n\n`./tut.py search colbert --after 2019-07-19`\n\n###### Return all Failed recordings:\n\n`./tut.py search --state failed`\n\n###### Return at most 3 Failed recordings:\n\n`./tut.py search --state failed --limit 3`\n\n###### Return all the Movies:\n\n`./tut.py search --type movie`\n\n###### Return all the Movies, but dump the full data record:\n\n`./tut.py search --type movie --full`\n\n###### Find all recordings 30 seconds or shorter\n`./tut.py -L search --duration 30s`\n\n### Copy/Archive recordings\nCopy recordings off your Tablo. Currently there are no options to do anything but copy a full recording intact (compress more, downgrade, etc.).\n\nDo a search, add the **-L** flag and pipe it into **copy**:\n\n`./tut.py -L search colbert | ./tut.py copy `\n\nCurrently this doesn't:\n    * try to put incomplete recordings together\n        - as such, doesn't deal with TMS IDs to do that\n        \n\n\n### Delete recordings\nDo a search, add the **-L** flag and pipe it into delete:\n\n`./tut.py -L search --duration 30s | ./tut.py delete `\n\n_Note_: you'll have to add a `--yes` flag to make the delete actually occur.\n\n\n \n### Acknowledgements\n This wouldn't have been made without: \n * [the code for the Kodi add-on](https://github.com/Nuvyyo/script.tablo) from the Nuvyyo folks. You'll find the slightly modified version of it  `tablo` module.\n \n * [TinyDB](https://github.com/msiemens/tinydb)\n ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjessedp%2Ftut","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjessedp%2Ftut","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjessedp%2Ftut/lists"}