├── .gitignore ├── Gemfile ├── assets └── screenshot.png ├── .editorconfig ├── README.md ├── bin └── dev ├── .trmnlp.yml ├── src ├── quadrant.liquid ├── half_vertical.liquid ├── full.liquid ├── half_horizontal.liquid ├── shared.liquid └── settings.yml ├── LICENSE ├── .github └── workflows │ └── build.yml └── Gemfile.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | _build/* 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'trmnl_preview', '0.5.4' 4 | -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhoizey/trmnl-pixelfed-profile/main/assets/screenshot.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.js] 2 | indent_size = 2 3 | indent_style = space 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | 7 | [*.{html,liquid}] 8 | indent_size = 2 9 | indent_style = space 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pixelfed profile plugin for TRMNL 2 | 3 | This is a plugin for [TRMNL](https://usetrmnl.com/) that allows you to view the latest images published on your own [Pixelfed](https://pixelfed.org/) profile. 4 | 5 | ![Screenshot of the plugin in TRMNL](assets/screenshot.png) 6 | 7 | Install is from here: https://usetrmnl.com/recipes/106505 8 | 9 | The code is based on a fork from Stephen Yeargin's [Pixelfed timeline plugin](https://github.com/stephenyeargin/trmnl-pixelfed). 10 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | if command -v trmnlp &> /dev/null 4 | then 5 | echo "Starting trmnlp..." 6 | dotenvx run -f .env -- trmnlp serve 7 | exit 8 | fi 9 | 10 | if command -v docker &> /dev/null 11 | then 12 | echo "Running trmnl/trmnlp container..." 13 | docker run -p 4567:4567 -v .:/plugin trmnl/trmnlp 14 | exit 15 | fi 16 | 17 | echo "Install the trmnl_preview gem: 18 | 19 | gem install trmnl_preview 20 | 21 | Or install Docker: 22 | 23 | https://docs.docker.com/get-docker/" 24 | 25 | exit 1 -------------------------------------------------------------------------------- /.trmnlp.yml: -------------------------------------------------------------------------------- 1 | # TRMNLP configuration 2 | # {{ env.VARIABLE }} interpolation is available here 3 | --- 4 | # auto-reload when files change (`watch: false` to disable) 5 | watch: 6 | - .trmnlp.yml 7 | - src 8 | 9 | # values of custom fields (defined in src/settings.yml) 10 | custom_fields: { 11 | pixelfed_base_url: https://pixelfed.social, 12 | pixelfed_user_id: 406, 13 | pixelfed_api_key: '{{ env.PIXELFED_API_KEY }}', 14 | pixelfed_layout: '4col_x_2row' 15 | } 16 | 17 | # override variables 18 | variables: 19 | trmnl: { 20 | plugin_settings: { 21 | instance_name: 'Pixelfed profile' 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/quadrant.liquid: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {% for status in statuses limit: photos %} 5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 | {% endfor %} 13 |
14 |
15 | 16 | {% if photos > 1 %} 17 |
18 | 19 | @{{ account.username }} 20 | {{ trmnl.plugin_settings.instance_name }} 21 |
22 | {% endif %} 23 |
24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Stephen Yeargin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/half_vertical.liquid: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {% for status in statuses limit: photos %} 5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 | {% endfor %} 13 |
14 |
15 | 16 | {% if photos > 1 %} 17 |
18 | 19 | @{{ account.username }} 20 | {{ trmnl.plugin_settings.instance_name }} 21 |
22 | {% endif %} 23 |
24 | -------------------------------------------------------------------------------- /src/full.liquid: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {% for status in statuses limit: photos %} 5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 | {% endfor %} 13 |
14 |
15 | 16 | {% if photos > 1 %} 17 |
18 | 19 | @{{ account.username }} ({{ account.display_name }}) 20 | {{ trmnl.plugin_settings.instance_name }} 21 |
22 | {% endif %} 23 |
24 | -------------------------------------------------------------------------------- /src/half_horizontal.liquid: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {% for status in statuses limit: photos %} 5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 | {% endfor %} 13 |
14 |
15 | 16 | {% if photos > 3 %} 17 |
18 | 19 | @{{ account.username }} ({{ account.display_name }}) 20 | {{ trmnl.plugin_settings.instance_name }} 21 |
22 | {% endif %} 23 |
24 | -------------------------------------------------------------------------------- /src/shared.liquid: -------------------------------------------------------------------------------- 1 | {% assign instance = IDX_0.data %} 2 | {% assign account = IDX_1 %} 3 | {% assign statuses = IDX_2.data %} 4 | 5 | {% assign layout_name = trmnl.plugin_settings.custom_fields_values.pixelfed_layout %} 6 | {% assign columns = 4 %} 7 | {% assign photos = 8 %} 8 | 9 | {% if layout_name == '1col_x_1row' %} 10 | {% assign columns = 1 %} 11 | {% assign photos = 1 %} 12 | {% endif %} 13 | 14 | {% if layout_name == '2col_x_1row' %} 15 | {% assign columns = 2 %} 16 | {% assign photos = 2 %} 17 | {% endif %} 18 | 19 | {% if layout_name == '3col_x_1row' %} 20 | {% assign columns = 3 %} 21 | {% assign photos = 3 %} 22 | {% endif %} 23 | 24 | {% if layout_name == '4col_x_1row' %} 25 | {% assign columns = 4 %} 26 | {% assign photos = 4 %} 27 | {% endif %} 28 | 29 | {% if layout_name == '4col_x_2row' %} 30 | {% assign columns = 4 %} 31 | {% assign photos = 8 %} 32 | {% endif %} 33 | 34 | {% if layout_name == '2col_x_2row' %} 35 | {% assign columns = 2 %} 36 | {% assign photos = 4 %} 37 | {% endif %} 38 | 39 | {% if layout_name == '3col_x_2row' %} 40 | {% assign columns = 3 %} 41 | {% assign photos = 6 %} 42 | {% endif %} 43 | 44 | {% if layout_name == '3col_x_3row' %} 45 | {% assign columns = 3 %} 46 | {% assign photos = 9 %} 47 | {% endif %} 48 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Set up Ruby 17 | uses: ruby/setup-ruby@v1 18 | with: 19 | ruby-version: '3.4' 20 | bundler-cache: true 21 | 22 | - name: Run trmnlp build 23 | run: bundle exec trmnlp build 24 | 25 | deploy: 26 | needs: build 27 | runs-on: ubuntu-latest 28 | if: github.ref == 'refs/heads/main' 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@v4 32 | 33 | - name: Set up Ruby 34 | uses: ruby/setup-ruby@v1 35 | with: 36 | ruby-version: '3.4' 37 | bundler-cache: true 38 | 39 | - name: Create trmnlp config directory 40 | run: mkdir -p ~/.config/trmnlp 41 | 42 | - name: Create trmnlp config file 43 | run: | 44 | cat > ~/.config/trmnlp/config.yml << EOF 45 | --- 46 | api_key: ${{ secrets.TRMNL_API_KEY }} 47 | EOF 48 | 49 | - name: Run trmnlp push 50 | run: bundle exec trmnlp push --force 51 | -------------------------------------------------------------------------------- /src/settings.yml: -------------------------------------------------------------------------------- 1 | --- 2 | strategy: polling 3 | no_screen_padding: 'no' 4 | dark_mode: 'no' 5 | static_data: '' 6 | polling_verb: get 7 | polling_url: | 8 | {{ pixelfed_base_url }}/api/v2/instance 9 | {{ pixelfed_base_url }}/api/v1/accounts/verify_credentials 10 | {{ pixelfed_base_url }}/api/v1/accounts/{{ pixelfed_user_id }}/statuses 11 | polling_headers: Authorization=Bearer {{ pixelfed_api_key }} 12 | id: 106505 13 | custom_fields: 14 | - keyname: author_bio 15 | name: About This Plugin 16 | field_type: author_bio 17 | description: Shows latest photos from your Pixelfed profile. 18 | github_url: https://github.com/nhoizey/trmnl-pixelfed-profile 19 | learn_more_url: https://pixelfed.org 20 | email_address: nicolas@hoizey.com 21 | - keyname: pixelfed_base_url 22 | field_type: url 23 | name: Pixelfed Instance URL 24 | description: The base URL of your Pixelfed instance 25 | placeholder: https://pixelfed.social 26 | - keyname: pixelfed_user_id 27 | field_type: string 28 | name: Pixelfed user ID 29 | description: Your ID on your Pixelfed instance 30 | help_text: The number at the end of your profile URL (for example my profile) 31 | placeholder: 406 32 | - keyname: pixelfed_api_key 33 | field_type: string 34 | name: Pixelfed API Key 35 | description: Your Pixelfed Personal Access Token (PAT) with "read" permission, found in Settings » Applications. 36 | placeholder: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.xxxxxxxx.xxxxxxxx 37 | - keyname: pixelfed_layout 38 | field_type: select 39 | name: Layout 40 | description: How to present the photos 41 | default: 3col_x_2row 42 | options: 43 | - 1 column x 1 row: 1col_x_1row 44 | - 2 columns x 1 row: 2col_x_1row 45 | - 2 columns x 2 rows: 2col_x_2row 46 | - 3 columns x 1 row: 3col_x_1row 47 | - 3 columns x 2 rows: 3col_x_2row 48 | - 3 columns x 3 rows: 3col_x_3row 49 | - 4 columns x 1 row: 4col_x_1row 50 | - 4 columns x 2 rows: 4col_x_2row 51 | name: Pixelfed profile 52 | refresh_interval: 60 53 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionview (8.0.2) 5 | activesupport (= 8.0.2) 6 | builder (~> 3.1) 7 | erubi (~> 1.11) 8 | rails-dom-testing (~> 2.2) 9 | rails-html-sanitizer (~> 1.6) 10 | activesupport (8.0.2) 11 | base64 12 | benchmark (>= 0.3) 13 | bigdecimal 14 | concurrent-ruby (~> 1.0, >= 1.3.1) 15 | connection_pool (>= 2.2.5) 16 | drb 17 | i18n (>= 1.6, < 2) 18 | logger (>= 1.4.2) 19 | minitest (>= 5.1) 20 | securerandom (>= 0.3) 21 | tzinfo (~> 2.0, >= 2.0.5) 22 | uri (>= 0.13.1) 23 | base64 (0.3.0) 24 | benchmark (0.4.1) 25 | bigdecimal (3.2.2) 26 | builder (3.3.0) 27 | concurrent-ruby (1.3.5) 28 | connection_pool (2.5.3) 29 | crass (1.0.6) 30 | drb (2.2.3) 31 | erubi (1.13.1) 32 | eventmachine (1.2.7) 33 | faraday (2.13.1) 34 | faraday-net_http (>= 2.0, < 3.5) 35 | json 36 | logger 37 | faraday-multipart (1.1.0) 38 | multipart-post (~> 2.0) 39 | faraday-net_http (3.4.0) 40 | net-http (>= 0.5.0) 41 | faye-websocket (0.11.3) 42 | eventmachine (>= 0.12.0) 43 | websocket-driver (>= 0.5.1) 44 | filewatcher (2.1.0) 45 | module_methods (~> 0.1.0) 46 | i18n (1.14.7) 47 | concurrent-ruby (~> 1.0) 48 | json (2.12.2) 49 | liquid (5.8.7) 50 | bigdecimal 51 | strscan (>= 3.1.1) 52 | logger (1.7.0) 53 | loofah (2.24.1) 54 | crass (~> 1.0.2) 55 | nokogiri (>= 1.12.0) 56 | mime-types (3.7.0) 57 | logger 58 | mime-types-data (~> 3.2025, >= 3.2025.0507) 59 | mime-types-data (3.2025.0610) 60 | mini_magick (4.12.0) 61 | minitest (5.25.5) 62 | module_methods (0.1.0) 63 | multipart-post (2.4.1) 64 | mustermann (3.0.3) 65 | ruby2_keywords (~> 0.0.1) 66 | net-http (0.6.0) 67 | uri 68 | nio4r (2.7.4) 69 | nokogiri (1.18.8-aarch64-linux-gnu) 70 | racc (~> 1.4) 71 | nokogiri (1.18.8-aarch64-linux-musl) 72 | racc (~> 1.4) 73 | nokogiri (1.18.8-arm-linux-gnu) 74 | racc (~> 1.4) 75 | nokogiri (1.18.8-arm-linux-musl) 76 | racc (~> 1.4) 77 | nokogiri (1.18.8-arm64-darwin) 78 | racc (~> 1.4) 79 | nokogiri (1.18.8-x86_64-darwin) 80 | racc (~> 1.4) 81 | nokogiri (1.18.8-x86_64-linux-gnu) 82 | racc (~> 1.4) 83 | nokogiri (1.18.8-x86_64-linux-musl) 84 | racc (~> 1.4) 85 | oj (3.16.11) 86 | bigdecimal (>= 3.0) 87 | ostruct (>= 0.2) 88 | ostruct (0.6.1) 89 | puma (6.6.0) 90 | nio4r (~> 2.0) 91 | puppeteer-ruby (0.45.6) 92 | concurrent-ruby (>= 1.1, < 1.4) 93 | mime-types (>= 3.0) 94 | websocket-driver (>= 0.6.0) 95 | racc (1.8.1) 96 | rack (3.1.16) 97 | rack-protection (4.1.1) 98 | base64 (>= 0.1.0) 99 | logger (>= 1.6.0) 100 | rack (>= 3.0.0, < 4) 101 | rack-session (2.1.1) 102 | base64 (>= 0.1.0) 103 | rack (>= 3.0.0) 104 | rackup (2.2.1) 105 | rack (>= 3) 106 | rails-dom-testing (2.3.0) 107 | activesupport (>= 5.0.0) 108 | minitest 109 | nokogiri (>= 1.6) 110 | rails-html-sanitizer (1.6.2) 111 | loofah (~> 2.21) 112 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) 113 | ruby2_keywords (0.0.5) 114 | rubyzip (2.3.2) 115 | securerandom (0.4.1) 116 | sinatra (4.1.1) 117 | logger (>= 1.6.0) 118 | mustermann (~> 3.0) 119 | rack (>= 3.0.0, < 4) 120 | rack-protection (= 4.1.1) 121 | rack-session (>= 2.0.0, < 3) 122 | tilt (~> 2.0) 123 | strscan (3.1.5) 124 | thor (1.3.2) 125 | tilt (2.6.0) 126 | trmnl_preview (0.5.4) 127 | actionview (~> 8.0) 128 | activesupport (~> 8.0) 129 | faraday (~> 2.1) 130 | faraday-multipart (~> 1.1) 131 | faye-websocket (~> 0.11.3) 132 | filewatcher (~> 2.1) 133 | liquid (~> 5.6) 134 | mini_magick (~> 4.12.0) 135 | oj (~> 3.16.9) 136 | puma (~> 6.5) 137 | puppeteer-ruby (~> 0.45.6) 138 | rackup (~> 2.2) 139 | rubyzip (~> 2.3.0) 140 | sinatra (~> 4.1) 141 | thor (~> 1.3) 142 | tzinfo-data (~> 1.2025) 143 | xdg (~> 9.1) 144 | tzinfo (2.0.6) 145 | concurrent-ruby (~> 1.0) 146 | tzinfo-data (1.2025.2) 147 | tzinfo (>= 1.0.0) 148 | uri (1.0.3) 149 | websocket-driver (0.8.0) 150 | base64 151 | websocket-extensions (>= 0.1.0) 152 | websocket-extensions (0.1.5) 153 | xdg (9.2.0) 154 | 155 | PLATFORMS 156 | aarch64-linux-gnu 157 | aarch64-linux-musl 158 | arm-linux-gnu 159 | arm-linux-musl 160 | arm64-darwin 161 | x86_64-darwin 162 | x86_64-linux-gnu 163 | x86_64-linux-musl 164 | 165 | DEPENDENCIES 166 | trmnl_preview (= 0.5.4) 167 | 168 | BUNDLED WITH 169 | 2.6.2 170 | --------------------------------------------------------------------------------