├── .gitignore
├── LICENSE.md
├── README.md
├── application
├── apps-ads.txt
├── assets
│ ├── css
│ │ ├── grid.css
│ │ └── main.css
│ ├── fonts
│ │ └── Roboto-Regular.ttf
│ ├── icons
│ │ ├── 23EF.svg
│ │ ├── 25B6.svg
│ │ ├── 2605.svg
│ │ ├── 2B07.svg
│ │ ├── E0AB.svg
│ │ ├── E1D8.svg
│ │ ├── E24F.svg
│ │ ├── E252.svg
│ │ ├── E253.svg
│ │ ├── E261.svg
│ │ ├── E264.svg
│ │ ├── E269.svg
│ │ ├── back.svg
│ │ ├── cancel.svg
│ │ ├── clock.svg
│ │ ├── delete.svg
│ │ ├── eye.svg
│ │ ├── favicon.ico
│ │ ├── icon-112-112.png
│ │ ├── icon-56-56.png
│ │ ├── icon-56-56.svg
│ │ ├── id.svg
│ │ ├── image.svg
│ │ ├── intro.png
│ │ ├── intro.svg
│ │ ├── link.svg
│ │ ├── list.svg
│ │ ├── offline.svg
│ │ ├── online.svg
│ │ ├── option.svg
│ │ ├── person.svg
│ │ ├── play.svg
│ │ ├── reblog.svg
│ │ ├── save.svg
│ │ ├── select.svg
│ │ └── sleep.svg
│ └── js
│ │ ├── helper.js
│ │ ├── kaiads.v5.min.js
│ │ ├── mastodon.js
│ │ └── youtube.js
├── index.html
├── index.js
├── manifest.webapp
├── manifest.webmanifest
├── sw.js
└── worker.js
├── docs
├── E264.ff3d42a6.svg
├── Roboto-Regular.4f1a9903.ttf
├── assets
│ ├── fonts
│ │ └── Roboto-Regular.ttf
│ ├── icons
│ │ ├── 23EF.svg
│ │ ├── 25B6.svg
│ │ ├── 2605.svg
│ │ ├── 2B07.svg
│ │ ├── E0AB.svg
│ │ ├── E1D8.svg
│ │ ├── E24F.svg
│ │ ├── E252.svg
│ │ ├── E253.svg
│ │ ├── E261.svg
│ │ ├── E264.svg
│ │ ├── E269.svg
│ │ ├── back.svg
│ │ ├── cancel.svg
│ │ ├── clock.svg
│ │ ├── delete.svg
│ │ ├── eye.svg
│ │ ├── favicon.ico
│ │ ├── icon-112-112.png
│ │ ├── icon-56-56.png
│ │ ├── icon-56-56.svg
│ │ ├── id.svg
│ │ ├── image.svg
│ │ ├── intro.png
│ │ ├── intro.svg
│ │ ├── link.svg
│ │ ├── list.svg
│ │ ├── offline.svg
│ │ ├── online.svg
│ │ ├── option.svg
│ │ ├── person.svg
│ │ ├── play.svg
│ │ ├── reblog.svg
│ │ ├── save.svg
│ │ ├── select.svg
│ │ └── sleep.svg
│ └── js
│ │ └── kaiads.v5.min.js
├── favicon.3da022ef.ico
├── file-list.json
├── icon-112-112.185b7f3e.png
├── icon-56-56.bda5227e.png
├── index.339e55c4.js
├── index.5671dcd7.css
├── index.63982eba.css
├── index.8d33ff60.js
├── index.f0337e49.js
├── index.html
├── manifest.webapp
├── manifest.webmanifest
├── reblog.a18be2b5.svg
├── sw.js
└── worker.8ac5962b.js
├── example.opml
├── example
├── example.opml
├── example_video.xml
└── how-to.xml
├── generate_file_list.sh
├── image
├── kaios-banner.png
├── mockup.png
├── mockup.xcf
└── screenshoot.png
├── package-lock.json
├── package.json
└── proxy.php
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | node_modules/*
3 | build
4 | build/*
5 | .parcel-cache
6 | node_modules
7 | node_modules/*
8 | .parcel-cache
9 | build/*
10 | dist/*
11 | dist
12 | build
13 | .cache
14 | .env
15 | webpage-uploader.sh
16 | build.sh
17 | .gitignore
18 | webpage
19 | webpage/*
20 | .gitignore
21 |
22 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Feedolin
4 |
5 | 
6 | [](https://store.bananahackers.net/#feedolin)
7 | 
8 |
9 | Feedolin is an RSS / Atom reader and podcast player. It is intended for users who already use an rss reader client and want to read their feeds on a KaiOS device. the list of subscribed websites / podcasts is managed locally or online in an opml.
10 |
11 | **NEW**
12 |
13 | Now it is also possible to load mastodon content, in the settings of the app you will find a login button with which you can log in with your mastodon account.
14 |
15 | ## RSS/Atom/Mastodon reader and Podcastplayer for KaiOS
16 |
17 | - read you favorit rss/atom feeds
18 | - stream your podcasts
19 | - read mastodon publice & home timeline
20 | - open rss feedlink
21 | - offline use (caching)
22 |
23 | 
24 |
25 | ## Installation
26 |
27 | You have to save the list of urls in a .opml file as in the example.
28 | In the settings you can set where the app should get this file from.
29 | It can be stored locally or online on a server.
30 |
31 | if you want to show mastodon public timelines you have to set the type="mastodon" in the link list
32 | For example:
33 | ` `
34 |
35 | https://raw.githubusercontent.com/strukturart/rss-reader/master/example.opml
36 |
37 |
38 | `
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | `
60 |
61 |
62 |
63 |
64 | - 5 feeds will be loaded per source, if you want more you can set it with this attribute: maxEpisodes="8"
65 | - To divide the individual feeds into categories, you have to create nested outlines. In the app, you can then jump between the categories using the key: left/right or swipe
66 |
67 | ## How to install
68 |
69 | - KaiOs Store
70 | - Sideloading step-by-step article by martinkaptein
71 |
72 | You can download the latest version from the Releases page.
73 | The app is not auto-updating. To update it, you have to follow the same steps you took when installing it.
74 |
75 | ## create your own
76 |
77 | `npm -i`
78 |
79 | to use another mastodon instance you need to save the necessary data in application/.env, don't forget to include it in your .gitignore.
80 | https://docs.joinmastodon.org/methods/apps/
81 |
82 | ```
83 |
84 | clientId=xx
85 | clientSecret=xxx
86 | redirect=https://xx
87 |
88 | ```
89 |
90 | ## Mastodon
91 |
92 | Originally I only wanted to write an rss reader for KaiOS, now I have decided to connect the fediverse as well. a mastodon login enables you to display the mastodon home timeline. in mastodon you have the option of subscribing to other sources/instances of fediverse, which will then also find their way to your feature phone.
93 |
94 | ## How to use
95 |
96 | - Enter to show full news
97 | - Backspace to go back
98 | - #-key volume
99 | - \*-key open audioplayer
100 | - streaming audio seeking: cursor left/right
101 |
102 | ## Tips
103 |
104 | RSS-Feed from public Youtube/Soundcloud/Instagram/Twitter.....
105 |
106 | - https://danielmiessler.com/blog/rss-feed-youtube-channel/
107 | - http://tips.slaw.ca/2019/technology/rss-feed-for-a-youtube-channel-or-playlist/
108 | - https://rss.app/rss-feed/create-instagram-rss-feed
109 |
110 | ## Credits
111 |
112 | - bananahackers community 💘
113 |
114 | ## Donation
115 |
116 |
117 |
--------------------------------------------------------------------------------
/application/assets/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/application/assets/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/application/assets/icons/23EF.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
44 |
47 |
56 |
68 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/application/assets/icons/25B6.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
44 |
47 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/application/assets/icons/2605.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/application/assets/icons/2B07.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/application/assets/icons/E0AB.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/application/assets/icons/E24F.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
44 |
47 |
56 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/application/assets/icons/E252.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/application/assets/icons/E253.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/application/assets/icons/E261.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/application/assets/icons/E264.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
34 |
38 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/application/assets/icons/E269.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/application/assets/icons/back.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
17 |
21 |
22 |
25 |
29 |
30 |
31 |
49 |
56 |
59 |
64 |
65 |
--------------------------------------------------------------------------------
/application/assets/icons/cancel.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
34 |
36 |
38 |
40 |
47 |
51 |
52 |
--------------------------------------------------------------------------------
/application/assets/icons/clock.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | clock
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/application/assets/icons/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
33 |
35 |
37 |
39 |
46 |
49 |
51 |
56 |
65 |
70 |
82 |
83 |
85 |
94 |
103 |
115 |
127 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/application/assets/icons/eye.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
39 |
41 |
46 |
49 |
55 |
58 |
70 |
77 |
88 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/application/assets/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/application/assets/icons/favicon.ico
--------------------------------------------------------------------------------
/application/assets/icons/icon-112-112.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/application/assets/icons/icon-112-112.png
--------------------------------------------------------------------------------
/application/assets/icons/icon-56-56.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/application/assets/icons/icon-56-56.png
--------------------------------------------------------------------------------
/application/assets/icons/id.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
39 | #
50 |
51 |
--------------------------------------------------------------------------------
/application/assets/icons/image.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
41 |
47 |
50 |
62 |
71 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/application/assets/icons/intro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/application/assets/icons/intro.png
--------------------------------------------------------------------------------
/application/assets/icons/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
45 |
49 |
50 |
--------------------------------------------------------------------------------
/application/assets/icons/list.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
41 |
43 |
48 |
52 |
58 |
61 |
64 |
67 |
77 |
86 |
95 |
96 |
99 |
109 |
110 |
113 |
123 |
124 |
125 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/application/assets/icons/offline.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
18 |
36 |
40 |
44 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/application/assets/icons/online.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
18 |
36 |
40 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/application/assets/icons/option.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
39 |
41 |
46 |
49 |
55 |
61 |
67 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/application/assets/icons/person.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
17 |
21 |
22 |
25 |
29 |
30 |
31 |
49 |
56 |
59 |
67 |
75 |
83 |
91 |
99 |
101 |
109 |
112 |
115 |
122 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/application/assets/icons/play.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
39 |
42 |
44 |
47 |
48 |
49 |
52 |
54 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/application/assets/icons/reblog.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/application/assets/icons/save.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
34 |
36 |
38 |
40 |
47 |
50 |
62 |
74 |
86 |
95 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/application/assets/icons/select.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
35 |
37 |
41 |
47 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/application/assets/icons/sleep.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
35 |
37 |
41 |
47 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/application/assets/js/mastodon.js:
--------------------------------------------------------------------------------
1 | export let load_context = (url, id, mode) => {
2 | let a = JSON.parse(localStorage.getItem("oauth_auth"));
3 | let accessToken = a.access_token;
4 |
5 | let w = {
6 | Authorization: `Bearer ${accessToken}`,
7 | "Content-Type": "application/json",
8 | };
9 | if (mode == "public") {
10 | w = {
11 | "Content-Type": "application/json",
12 | };
13 | }
14 | return fetch(url + "/api/v1/statuses/" + id + "/context", {
15 | headers: w,
16 | })
17 | .then((response) => {
18 | if (!response.ok) {
19 | console.log("Network response was not OK");
20 | }
21 | return response.json();
22 | })
23 | .then((data) => {
24 | return data;
25 | });
26 | };
27 |
28 | export let reblog = (url, id) => {
29 | let a = JSON.parse(localStorage.getItem("oauth_auth"));
30 | let accessToken = a.access_token;
31 |
32 | let w = {
33 | Authorization: `Bearer ${accessToken}`,
34 | "Content-Type": "application/json",
35 | };
36 |
37 | return new Promise((resolve, reject) => {
38 | fetch(url + "/api/v1/statuses/" + id + "/reblog", {
39 | method: "POST",
40 | headers: w,
41 | })
42 | .then((response) => {
43 | if (!response.ok) {
44 | console.log("Network response was not OK");
45 | reject(new Error("Network response was not OK"));
46 | }
47 | return response.json();
48 | })
49 | .then((data) => {
50 | resolve(data);
51 | })
52 | .catch((error) => {
53 | reject(error);
54 | });
55 | });
56 | };
57 |
58 | export let favourite = (url, id) => {
59 | let a = JSON.parse(localStorage.getItem("oauth_auth"));
60 | let accessToken = a.access_token;
61 |
62 | let w = {
63 | Authorization: `Bearer ${accessToken}`,
64 | "Content-Type": "application/json",
65 | };
66 |
67 | return new Promise((resolve, reject) => {
68 | fetch(url + "/api/v1/statuses/" + id + "/favourite", {
69 | method: "POST",
70 | headers: w,
71 | })
72 | .then((response) => {
73 | if (!response.ok) {
74 | console.log("Network response was not OK");
75 | reject(new Error("Network response was not OK"));
76 | }
77 | return response.json();
78 | })
79 | .then((data) => {
80 | resolve(data);
81 | })
82 | .catch((error) => {
83 | reject(error);
84 | });
85 | });
86 | };
87 |
88 | export let mastodon_account_info = async (url, accessToken) => {
89 | const response = await fetch(url + "/api/v1/accounts/verify_credentials", {
90 | headers: {
91 | Authorization: `Bearer ${accessToken}`,
92 | "Content-Type": "application/json",
93 | },
94 | });
95 | if (!response.ok) {
96 | console.log("Network response was not OK");
97 | }
98 | const data_1 = await response.json();
99 | return data_1;
100 | };
101 |
--------------------------------------------------------------------------------
/application/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | feedolin
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
38 |
39 |
40 |
41 |
48 |
49 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/application/manifest.webapp:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.18",
3 | "name": "feedolin",
4 | "description": "Feedolin is an RSS / Atom / Mastodon reader and podcast player. It is intended for users who already use an rss reader client and want to read their feeds on a kaios device. the list of subscribed websites / podcasts is managed locally or online in an opml file.",
5 | "launch_path": "/index.html",
6 | "type": "privileged",
7 | "fullscreen": "true",
8 | "categories": ["News","Social"],
9 | "userAgentInfo": "Feedolin written by strukturart@gmail.com",
10 |
11 |
12 | "icons": {
13 | "56": "/assets/icons/icon-56-56.png",
14 | "112": "/assets/icons/icon-112-112.png"
15 | },
16 |
17 | "developer": {
18 | "name": "strukturart",
19 | "url": "https://github.com/strukturart/feedolin"
20 | },
21 |
22 | "dependencies": {
23 | "ads-sdk": "1.5.8"
24 | },
25 |
26 | "locales": {
27 | "en-US": {
28 | "name": "feedolin",
29 | "subtitle": "Feedolin is an RSS / Atom reader and podcast player. ",
30 | "description": "Feedolin is an RSS / Atom / Mastodon reader and podcast player. It is intended for users who already use an rss reader client and want to read their feeds on a kaios device. the list of subscribed websites / podcasts is managed locally or online in an opml file."
31 | }
32 | },
33 | "default_locale": "en-US",
34 |
35 | "messages": [
36 | {
37 | "alarm": "/index.html"
38 | },
39 | {
40 | "notification": "/index.html"
41 | },
42 | { "serviceworker-notification": "/index.html" },
43 | { "activity": "/index.html" }
44 | ],
45 |
46 |
47 | "redirects": [
48 | {
49 | "from": "https://feedolin.strukturart.com/",
50 | "to": "/index.html"
51 | }
52 | ],
53 |
54 | "serviceworker": {
55 | "script_url": "sw.js"
56 | },
57 |
58 |
59 |
60 | "permissions": {
61 | "serviceworker": {
62 | "description": "Needed for assocating service worker"
63 | },
64 | "mobiledata": {},
65 | "wifidata": {},
66 | "calllog": {},
67 | "feature-detection": {
68 | "description": "query which keys are available"
69 | },
70 |
71 | "device-storage:sdcard": {
72 | "description": "Read/Write from/to sd-card",
73 | "access": "readwrite"
74 | },
75 |
76 |
77 | "audio-channel-content": {
78 | "description": "Needed to play this app's audio content on the content channel"
79 | },
80 | "desktop-notification": {
81 | "description": "Needed to fire system notifications"
82 | },
83 |
84 | "volumemanager": {},
85 | "browser": {},
86 | "spatialnavigation-app-manage": {
87 | "navigator.spatialNavigationEnabled": false
88 | },
89 |
90 | "systemXHR": {
91 | "description": "Required to load remote content"
92 | },
93 | "alarms": {
94 | "description": "Required to schedule alarms"
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/application/manifest.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Feedolin",
3 | "id": "Feedolin",
4 | "description": "Feedolin is an RSS / Atom / Mastodon reader and podcast player. It is intended for users who already use an rss reader client and want to read their feeds on a kaios device. the list of subscribed websites / podcasts is managed locally or online in an opml file.",
5 | "lang": "en-US",
6 | "start_url": "/index.html",
7 | "short_name": "Feedolin",
8 | "categories": ["News"],
9 | "display": "standalone",
10 | "theme_color": "#ffffff",
11 | "userAgentInfo": "Feedolin written by strukturart@gmail.com",
12 |
13 | "icons": [
14 | {
15 | "src": "assets/icons/icon-56-56.png",
16 | "type": "image/png",
17 | "sizes": "56x56"
18 | },
19 | {
20 | "src": "assets/icons/icon-112-112.png",
21 | "type": "image/png",
22 | "sizes": "112x112"
23 | }
24 | ],
25 |
26 | "b2g_features": {
27 | "version": "1.8.140",
28 | "id": "feedolin",
29 | "subtitle": "RSS Reader and Mastodon Reader",
30 | "core": true,
31 | "type": "privileged",
32 | "display": "fullscreen",
33 | "developer": {
34 | "name": "strukturart",
35 | "url": "https://github.com/strukturart/feedolin"
36 | },
37 |
38 | "dependencies": {
39 | "ads-sdk": "1.5.8"
40 | },
41 |
42 | "messages": [
43 | { "serviceworker-notification": "index.html" },
44 | { "activity": "/index.html" }
45 | ],
46 |
47 | "activities": {
48 | "feedolin": {}
49 | },
50 |
51 | "serviceworker": {
52 | "script_url": "sw.js"
53 | },
54 |
55 | "permissions": {
56 | "desktop-notification": {
57 | "description": "Needed to fire system notifications"
58 | },
59 |
60 | "feature-detection": {
61 | "description": "query which keys are available"
62 | },
63 | "mobiledata": {},
64 | "wifidata": {},
65 | "calllog": {},
66 |
67 | "audio-channel-content": {
68 | "description": "Allow background audio playback."
69 | },
70 | "volumemanager": { "description": "" },
71 | "device-storage:sdcard": {
72 | "description": "Read/Write from/to sd-card",
73 | "access": "readwrite"
74 | },
75 | "spatialnavigation-app-manage": {
76 | "navigator.spatialNavigationEnabled": false
77 | },
78 | "systemXHR": {
79 | "description": "Required to load remote content"
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/application/sw.js:
--------------------------------------------------------------------------------
1 | const sw_channel = new BroadcastChannel("sw-messages");
2 | sw_channel.addEventListener("message", (event) => {
3 | sw_channel.postMessage({
4 | test: event.data.test,
5 | });
6 | });
7 | self.addEventListener("systemmessage", async (evt) => {
8 | // Store evt data early
9 | let activityData;
10 |
11 | if (evt.name === "activity") {
12 | try {
13 | const handler = evt.data.webActivityRequestHandler();
14 |
15 | const { name: activityName, data } = handler.source;
16 |
17 | // Store data for later use
18 | activityData = data;
19 |
20 | if (activityData.name === "feedolin") {
21 | sw_channel.postMessage({
22 | oauth_success: activityData.data,
23 | });
24 | }
25 | } catch (error) {
26 | console.error("Error handling system message:", error);
27 | }
28 | }
29 | });
30 |
31 | const userAgent = navigator.userAgent || "";
32 |
33 | if (userAgent && !userAgent.includes("KAIOS")) {
34 | const CACHE_NAME = "pwa-cache-v0.1217";
35 | const FILE_LIST_URL = "/file-list.json"; // URL of the JSON file containing the array of files
36 |
37 | self.addEventListener("install", (event) => {
38 | event.waitUntil(
39 | caches
40 | .open(CACHE_NAME)
41 | .then((cache) => {
42 | console.log("Opened cache");
43 |
44 | // Fetch the file list JSON and cache the URLs
45 | return fetch(FILE_LIST_URL)
46 | .then((response) => {
47 | if (!response.ok) {
48 | throw new Error(`HTTP error! Status: ${response.status}`);
49 | }
50 | return response.json(); // Parse the JSON response
51 | })
52 | .then((urlsToCache) => {
53 | // Ensure urlsToCache is an array
54 | if (Array.isArray(urlsToCache)) {
55 | return Promise.all(
56 | urlsToCache.map((url) =>
57 | cache.add(url).catch((error) => {
58 | console.error(`Failed to cache ${url}:`, error);
59 | })
60 | )
61 | );
62 | } else {
63 | console.error("Fetched data is not an array:", urlsToCache);
64 | }
65 | });
66 | })
67 | .then(() => {
68 | return self.skipWaiting(); // Skip waiting and activate the new SW immediately
69 | })
70 | );
71 | });
72 |
73 | self.addEventListener("activate", (event) => {
74 | const cacheWhitelist = [CACHE_NAME];
75 | event.waitUntil(
76 | caches.keys().then((cacheNames) => {
77 | return Promise.all(
78 | cacheNames.map((cacheName) => {
79 | if (!cacheWhitelist.includes(cacheName)) {
80 | return caches.delete(cacheName);
81 | }
82 | })
83 | );
84 | })
85 | );
86 | });
87 |
88 | // Serve files from cache when offline
89 | self.addEventListener("fetch", (event) => {
90 | event.respondWith(
91 | caches.match(event.request).then((response) => {
92 | // If the request is in the cache, return it. Otherwise, fetch from the network.
93 | return response || fetch(event.request);
94 | })
95 | );
96 | });
97 | }
98 |
--------------------------------------------------------------------------------
/application/worker.js:
--------------------------------------------------------------------------------
1 | let timerId = null;
2 | let endTime = 0;
3 |
4 | self.onmessage = function (event) {
5 | const { action, duration } = event.data;
6 |
7 | if (action === "start") {
8 | endTime = Date.now() + duration;
9 | clearInterval(timerId); // Clear any previous timer
10 | timerId = setInterval(() => {
11 | const remainingTime = endTime - Date.now();
12 | self.postMessage({ remaining: remainingTime });
13 | if (remainingTime <= 0) {
14 | clearInterval(timerId);
15 | timerId = null; // Reset timerId when the timer completes
16 | self.postMessage({ action: "stop" });
17 | }
18 | }, 1000); // Check every second
19 | } else if (action === "stop") {
20 | clearInterval(timerId);
21 | timerId = null; // Reset timerId so that a new "start" message works correctly
22 | endTime = 0; // Reset endTime to prevent continuing after stopping
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/docs/E264.ff3d42a6.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/Roboto-Regular.4f1a9903.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/docs/Roboto-Regular.4f1a9903.ttf
--------------------------------------------------------------------------------
/docs/assets/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/docs/assets/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/docs/assets/icons/23EF.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
44 |
47 |
56 |
68 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/docs/assets/icons/25B6.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
44 |
47 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/docs/assets/icons/2605.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/assets/icons/2B07.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/assets/icons/E0AB.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/assets/icons/E24F.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
44 |
47 |
56 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/docs/assets/icons/E252.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/assets/icons/E253.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/assets/icons/E261.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/assets/icons/E264.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
34 |
38 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/assets/icons/E269.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/assets/icons/back.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
17 |
21 |
22 |
25 |
29 |
30 |
31 |
49 |
56 |
59 |
64 |
65 |
--------------------------------------------------------------------------------
/docs/assets/icons/cancel.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
34 |
36 |
38 |
40 |
47 |
51 |
52 |
--------------------------------------------------------------------------------
/docs/assets/icons/clock.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | clock
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/assets/icons/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
33 |
35 |
37 |
39 |
46 |
49 |
51 |
56 |
65 |
70 |
82 |
83 |
85 |
94 |
103 |
115 |
127 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/docs/assets/icons/eye.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
39 |
41 |
46 |
49 |
55 |
58 |
70 |
77 |
88 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/docs/assets/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/docs/assets/icons/favicon.ico
--------------------------------------------------------------------------------
/docs/assets/icons/icon-112-112.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/docs/assets/icons/icon-112-112.png
--------------------------------------------------------------------------------
/docs/assets/icons/icon-56-56.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/docs/assets/icons/icon-56-56.png
--------------------------------------------------------------------------------
/docs/assets/icons/id.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
39 | #
50 |
51 |
--------------------------------------------------------------------------------
/docs/assets/icons/image.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
41 |
47 |
50 |
62 |
71 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/docs/assets/icons/intro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/docs/assets/icons/intro.png
--------------------------------------------------------------------------------
/docs/assets/icons/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
38 |
45 |
49 |
50 |
--------------------------------------------------------------------------------
/docs/assets/icons/list.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
41 |
43 |
48 |
52 |
58 |
61 |
64 |
67 |
77 |
86 |
95 |
96 |
99 |
109 |
110 |
113 |
123 |
124 |
125 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/docs/assets/icons/offline.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
18 |
36 |
40 |
44 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/docs/assets/icons/online.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
18 |
36 |
40 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/docs/assets/icons/option.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
39 |
41 |
46 |
49 |
55 |
61 |
67 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/docs/assets/icons/person.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
17 |
21 |
22 |
25 |
29 |
30 |
31 |
49 |
56 |
59 |
67 |
75 |
83 |
91 |
99 |
101 |
109 |
112 |
115 |
122 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/docs/assets/icons/play.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
39 |
42 |
44 |
47 |
48 |
49 |
52 |
54 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/docs/assets/icons/reblog.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/assets/icons/save.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
34 |
36 |
38 |
40 |
47 |
50 |
62 |
74 |
86 |
95 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/docs/assets/icons/select.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
35 |
37 |
41 |
47 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/docs/assets/icons/sleep.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
35 |
37 |
41 |
47 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/docs/favicon.3da022ef.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/docs/favicon.3da022ef.ico
--------------------------------------------------------------------------------
/docs/file-list.json:
--------------------------------------------------------------------------------
1 | [
2 | "/index.html",
3 | "/index.63982eba.css",
4 | "/index.5671dcd7.css",
5 | "/manifest.webapp",
6 | "/index.339e55c4.js",
7 | "/icon-56-56.bda5227e.png",
8 | "/reblog.a18be2b5.svg",
9 | "/Roboto-Regular.4f1a9903.ttf",
10 | "/index.8d33ff60.js",
11 | "/icon-112-112.185b7f3e.png",
12 | "/E264.ff3d42a6.svg",
13 | "/file-list.json",
14 | "/sw.js",
15 | "/worker.8ac5962b.js",
16 | "/index.f0337e49.js",
17 | "/favicon.3da022ef.ico",
18 | "/manifest.webmanifest",
19 | "/assets/icons/save.svg",
20 | "/assets/icons/intro.svg",
21 | "/assets/icons/2605.svg",
22 | "/assets/icons/E269.svg",
23 | "/assets/icons/E1D8.svg",
24 | "/assets/icons/option.svg",
25 | "/assets/icons/intro.png",
26 | "/assets/icons/icon-112-112.png",
27 | "/assets/icons/sleep.svg",
28 | "/assets/icons/delete.svg",
29 | "/assets/icons/online.svg",
30 | "/assets/icons/reblog.svg",
31 | "/assets/icons/icon-56-56.png",
32 | "/assets/icons/E252.svg",
33 | "/assets/icons/person.svg",
34 | "/assets/icons/select.svg",
35 | "/assets/icons/23EF.svg",
36 | "/assets/icons/E261.svg",
37 | "/assets/icons/25B6.svg",
38 | "/assets/icons/cancel.svg",
39 | "/assets/icons/eye.svg",
40 | "/assets/icons/icon-56-56.svg",
41 | "/assets/icons/favicon.ico",
42 | "/assets/icons/link.svg",
43 | "/assets/icons/E0AB.svg",
44 | "/assets/icons/back.svg",
45 | "/assets/icons/2B07.svg",
46 | "/assets/icons/E253.svg",
47 | "/assets/icons/image.svg",
48 | "/assets/icons/E24F.svg",
49 | "/assets/icons/clock.svg",
50 | "/assets/icons/play.svg",
51 | "/assets/icons/list.svg",
52 | "/assets/icons/id.svg",
53 | "/assets/icons/E264.svg",
54 | "/assets/icons/offline.svg",
55 | "/assets/fonts/Roboto-Regular.ttf",
56 | "/assets/js/kaiads.v5.min.js"
57 | ]
58 |
--------------------------------------------------------------------------------
/docs/icon-112-112.185b7f3e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/docs/icon-112-112.185b7f3e.png
--------------------------------------------------------------------------------
/docs/icon-56-56.bda5227e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/docs/icon-56-56.bda5227e.png
--------------------------------------------------------------------------------
/docs/index.5671dcd7.css:
--------------------------------------------------------------------------------
1 | .grid-col-1{min-width:10px;max-width:10px}.grid-col-2{min-width:20px;max-width:20px}.grid-col-3{min-width:30px;max-width:30px}.grid-col-4{min-width:40px;max-width:40px}.grid-col-5{min-width:50px;max-width:50px}.grid-col-6{min-width:60px;max-width:60px}.grid-col-7{min-width:70px;max-width:70px}.grid-col-8{min-width:80px;max-width:80px}.grid-col-9{min-width:90px;max-width:90px}.grid-col-10{min-width:100px;max-width:100px}.grid-col-11{min-width:110px;max-width:110px}.grid-col-12{min-width:120px;max-width:120px}.grid-col-13{min-width:130px;max-width:130px}.grid-col-14{min-width:140px;max-width:140px}.grid-col-15{min-width:150px;max-width:150px}.grid-col-16{min-width:160px;max-width:160px}.grid-col-17{min-width:170px;max-width:170px}.grid-col-18{min-width:180px;max-width:180px}.grid-col-19{min-width:190px;max-width:190px}.grid-col-20{min-width:200px;max-width:200px}.grid-col-21{min-width:210px;max-width:210px}.grid-col-22{min-width:220px;max-width:220px}.grid-col-23{min-width:230px;max-width:230px}.grid-col-24{min-width:240px;max-width:240px}.grid-col-25{min-width:250px;max-width:250px}.grid-col-26{min-width:260px;max-width:260px}.grid-col-27{min-width:270px;max-width:270px}.grid-col-28{min-width:280px;max-width:280px}.grid-col-29{min-width:290px;max-width:290px}.grid-col-30{min-width:300px;max-width:300px}.grid-col-31{min-width:310px;max-width:310px}.grid-col-32{min-width:320px;max-width:320px}.grid-col-33{min-width:330px;max-width:330px}.grid-col-34{min-width:340px;max-width:340px}.grid-col-35{min-width:350px;max-width:350px}.grid-col-36{min-width:360px;max-width:360px}.grid-col-37{min-width:370px;max-width:370px}.grid-col-38{min-width:380px;max-width:380px}.grid-col-39{min-width:390px;max-width:390px}.grid-col-40{min-width:400px;max-width:400px}.grid-col-41{min-width:410px;max-width:410px}.grid-col-42{min-width:420px;max-width:420px}.grid-col-43{min-width:430px;max-width:430px}.grid-col-44{min-width:440px;max-width:440px}.grid-col-45{min-width:450px;max-width:450px}.grid-col-46{min-width:460px;max-width:460px}.grid-col-47{min-width:470px;max-width:470px}.grid-col-48{min-width:480px;max-width:480px}.grid-col-49{min-width:490px;max-width:490px}.grid-col-50{min-width:500px;max-width:500px}.grid-col-51{min-width:510px;max-width:510px}.grid-col-52{min-width:520px;max-width:520px}.grid-col-53{min-width:530px;max-width:530px}.grid-col-54{min-width:540px;max-width:540px}.grid-col-55{min-width:550px;max-width:550px}.grid-col-56{min-width:560px;max-width:560px}.grid-col-57{min-width:570px;max-width:570px}.grid-col-58{min-width:580px;max-width:580px}.grid-col-59{min-width:590px;max-width:590px}.grid-col-60{min-width:600px;max-width:600px}.grid-col-61{min-width:610px;max-width:610px}.grid-col-62{min-width:620px;max-width:620px}.grid-col-63{min-width:630px;max-width:630px}.grid-col-64{min-width:640px;max-width:640px}.grid-col-65{min-width:650px;max-width:650px}.grid-col-66{min-width:660px;max-width:660px}.grid-col-67{min-width:670px;max-width:670px}.grid-col-68{min-width:680px;max-width:680px}.grid-col-69{min-width:690px;max-width:690px}.grid-col-70{min-width:700px;max-width:700px}.grid-col-71{min-width:710px;max-width:710px}.grid-col-72{min-width:720px;max-width:720px}.grid-col-73{min-width:730px;max-width:730px}.grid-col-74{min-width:740px;max-width:740px}.grid-col-75{min-width:750px;max-width:750px}.grid-col-76{min-width:760px;max-width:760px}.grid-col-77{min-width:770px;max-width:770px}.grid-col-78{min-width:780px;max-width:780px}.grid-col-79{min-width:790px;max-width:790px}.grid-col-80{min-width:800px;max-width:800px}.grid-col-81{min-width:810px;max-width:810px}.grid-col-82{min-width:820px;max-width:820px}.grid-col-83{min-width:830px;max-width:830px}.grid-col-84{min-width:840px;max-width:840px}.grid-col-85{min-width:850px;max-width:850px}.grid-col-86{min-width:860px;max-width:860px}.grid-col-87{min-width:870px;max-width:870px}.grid-col-88{min-width:880px;max-width:880px}.grid-col-89{min-width:890px;max-width:890px}.grid-col-90{min-width:900px;max-width:900px}.grid-col-91{min-width:910px;max-width:910px}.grid-col-92{min-width:920px;max-width:920px}.grid-col-93{min-width:930px;max-width:930px}.grid-col-94{min-width:940px;max-width:940px}.grid-col-95{min-width:950px;max-width:950px}.grid-col-96{min-width:960px;max-width:960px}.text-center{text-align:center}.flex{-moz-box-orient:horizontal;-moz-box-direction:normal;flex-flow:wrap;display:flex}.flex-column{-moz-box-orient:vertical;-moz-box-direction:normal;flex-direction:column}.justify-content-start{-moz-box-align:start;align-items:flex-start}.justify-content-end{-moz-box-pack:end;justify-content:flex-end}.algin-item-start{-moz-box-align:start;align-items:flex-start}.algin-item-end{-moz-box-align:end;align-items:flex-end}.align-item-center{-moz-box-align:center;align-items:center}.justify-content-spacebetween{-moz-box-pack:justify;justify-content:space-between}.justify-content-spacearound{align-content:space-around;justify-content:space-around}.justify-content-center{-moz-box-pack:center;justify-content:center}.width-100{min-width:100vw;max-width:100vw}.width-90{min-width:90vw;max-width:90vw}.height-100{min-height:100vh}.width-50{min-width:50%}.width-30{min-width:30%;max-width:30%}.center{transform:translate(50%)}.block{display:block}
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 | feedolin
--------------------------------------------------------------------------------
/docs/manifest.webapp:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.18",
3 | "name": "feedolin",
4 | "description": "Feedolin is an RSS / Atom / Mastodon reader and podcast player. It is intended for users who already use an rss reader client and want to read their feeds on a kaios device. the list of subscribed websites / podcasts is managed locally or online in an opml file.",
5 | "launch_path": "/index.html",
6 | "type": "privileged",
7 | "fullscreen": "true",
8 | "categories": ["News","Social"],
9 | "userAgentInfo": "Feedolin written by strukturart@gmail.com",
10 |
11 |
12 | "icons": {
13 | "56": "/assets/icons/icon-56-56.png",
14 | "112": "/assets/icons/icon-112-112.png"
15 | },
16 |
17 | "developer": {
18 | "name": "strukturart",
19 | "url": "https://github.com/strukturart/feedolin"
20 | },
21 |
22 | "dependencies": {
23 | "ads-sdk": "1.5.8"
24 | },
25 |
26 | "locales": {
27 | "en-US": {
28 | "name": "feedolin",
29 | "subtitle": "Feedolin is an RSS / Atom reader and podcast player. ",
30 | "description": "Feedolin is an RSS / Atom / Mastodon reader and podcast player. It is intended for users who already use an rss reader client and want to read their feeds on a kaios device. the list of subscribed websites / podcasts is managed locally or online in an opml file."
31 | }
32 | },
33 | "default_locale": "en-US",
34 |
35 | "messages": [
36 | {
37 | "alarm": "/index.html"
38 | },
39 | {
40 | "notification": "/index.html"
41 | },
42 | { "serviceworker-notification": "/index.html" },
43 | { "activity": "/index.html" }
44 | ],
45 |
46 |
47 | "redirects": [
48 | {
49 | "from": "https://feedolin.strukturart.com/",
50 | "to": "/index.html"
51 | }
52 | ],
53 |
54 | "serviceworker": {
55 | "script_url": "sw.js"
56 | },
57 |
58 |
59 |
60 | "permissions": {
61 | "serviceworker": {
62 | "description": "Needed for assocating service worker"
63 | },
64 | "mobiledata": {},
65 | "wifidata": {},
66 | "calllog": {},
67 | "feature-detection": {
68 | "description": "query which keys are available"
69 | },
70 |
71 | "device-storage:sdcard": {
72 | "description": "Read/Write from/to sd-card",
73 | "access": "readwrite"
74 | },
75 |
76 |
77 | "audio-channel-content": {
78 | "description": "Needed to play this app's audio content on the content channel"
79 | },
80 | "desktop-notification": {
81 | "description": "Needed to fire system notifications"
82 | },
83 |
84 | "volumemanager": {},
85 | "browser": {},
86 | "spatialnavigation-app-manage": {
87 | "navigator.spatialNavigationEnabled": false
88 | },
89 |
90 | "systemXHR": {
91 | "description": "Required to load remote content"
92 | },
93 | "alarms": {
94 | "description": "Required to schedule alarms"
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/docs/manifest.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Feedolin",
3 | "id": "Feedolin",
4 | "description": "Feedolin is an RSS / Atom / Mastodon reader and podcast player. It is intended for users who already use an rss reader client and want to read their feeds on a kaios device. the list of subscribed websites / podcasts is managed locally or online in an opml file.",
5 | "lang": "en-US",
6 | "start_url": "/index.html",
7 | "short_name": "Feedolin",
8 | "categories": ["News"],
9 | "display": "standalone",
10 | "theme_color": "#ffffff",
11 | "userAgentInfo": "Feedolin written by strukturart@gmail.com",
12 |
13 | "icons": [
14 | {
15 | "src": "assets/icons/icon-56-56.png",
16 | "type": "image/png",
17 | "sizes": "56x56"
18 | },
19 | {
20 | "src": "assets/icons/icon-112-112.png",
21 | "type": "image/png",
22 | "sizes": "112x112"
23 | }
24 | ],
25 |
26 | "b2g_features": {
27 | "version": "1.8.140",
28 | "id": "feedolin",
29 | "subtitle": "RSS Reader and Mastodon Reader",
30 | "core": true,
31 | "type": "privileged",
32 | "display": "fullscreen",
33 | "developer": {
34 | "name": "strukturart",
35 | "url": "https://github.com/strukturart/feedolin"
36 | },
37 |
38 | "dependencies": {
39 | "ads-sdk": "1.5.8"
40 | },
41 |
42 | "messages": [
43 | { "serviceworker-notification": "index.html" },
44 | { "activity": "/index.html" }
45 | ],
46 |
47 | "activities": {
48 | "feedolin": {}
49 | },
50 |
51 | "serviceworker": {
52 | "script_url": "sw.js"
53 | },
54 |
55 | "permissions": {
56 | "desktop-notification": {
57 | "description": "Needed to fire system notifications"
58 | },
59 |
60 | "feature-detection": {
61 | "description": "query which keys are available"
62 | },
63 | "mobiledata": {},
64 | "wifidata": {},
65 | "calllog": {},
66 |
67 | "audio-channel-content": {
68 | "description": "Allow background audio playback."
69 | },
70 | "volumemanager": { "description": "" },
71 | "device-storage:sdcard": {
72 | "description": "Read/Write from/to sd-card",
73 | "access": "readwrite"
74 | },
75 | "spatialnavigation-app-manage": {
76 | "navigator.spatialNavigationEnabled": false
77 | },
78 | "systemXHR": {
79 | "description": "Required to load remote content"
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/docs/reblog.a18be2b5.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/sw.js:
--------------------------------------------------------------------------------
1 | !function(){function e(e,t,n,r,a,o,s){try{var c=e[o](s),i=c.value}catch(e){n(e);return}c.done?t(i):Promise.resolve(i).then(r,a)}"function"==typeof SuppressedError&&SuppressedError;var t,n,r=new BroadcastChannel("sw-messages");r.addEventListener("message",function(e){r.postMessage({test:e.data.test})}),self.addEventListener("systemmessage",(t=function(e){var t,n;return function(e,t){var n,r,a,o={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]},s=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return s.next=c(0),s.throw=c(1),s.return=c(2),"function"==typeof Symbol&&(s[Symbol.iterator]=function(){return this}),s;function c(c){return function(i){return function(c){if(n)throw TypeError("Generator is already executing.");for(;s&&(s=0,c[0]&&(o=0)),o;)try{if(n=1,r&&(a=2&c[0]?r.return:c[0]?r.throw||((a=r.return)&&a.call(r),0):r.next)&&!(a=a.call(r,c[1])).done)return a;switch(r=0,a&&(c=[2&c[0],a.value]),c[0]){case 0:case 1:a=c;break;case 4:return o.label++,{value:c[1],done:!1};case 5:o.label++,r=c[1],c=[0];continue;case 7:c=o.ops.pop(),o.trys.pop();continue;default:if(!(a=(a=o.trys).length>0&&a[a.length-1])&&(6===c[0]||2===c[0])){o=0;continue}if(3===c[0]&&(!a||c[1]>a[0]&&c[1]
2 |
3 |
4 | feedolin
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/example/example.opml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | feedolin
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/example/example_video.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | Sample RSS Video
7 | http://rssvideoplayer.com/sample.xml
8 | en-us
9 | -
10 |
MP4 Video
11 | http://www.bigbuckbunny.org
12 | Sun, 01 Jun 2014 00:00:00 GMT
13 | Big Buck Bunny Animation - Mp4 video]]>
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/example/how-to.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | Sample RSS Video
7 | http://rssvideoplayer.com/sample.xml
8 | en-us
9 | -
10 |
A short guide to feedolin
11 |
12 | Sun, 01 Jun 2022 00:00:00 GMT
13 | Feedolin is RSS/Atom Feeds Reader. This allows you to read short versions of the website, listen to the podcast or watch YouTube channels.How do I add new content?]]
14 | What you can't do with this app]]
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/generate_file_list.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Set the output JSON file name
4 | OUTPUT_FILE="./docs/file-list.json"
5 | DOCS_DIR="./docs"
6 |
7 | # Start the JSON array
8 | echo "[" > "$OUTPUT_FILE"
9 |
10 | # Find all files in the docs directory and its subdirectories
11 | # Exclude directories and format the output as JSON
12 | find "$DOCS_DIR" -type f | while read -r file; do
13 | # Replace the leading "./docs/" with "" to keep the relative path for the JSON file
14 | relative_path=${file#"$DOCS_DIR/"}
15 |
16 | # Escape double quotes and backslashes in file names for JSON format
17 | escaped_file=$(printf '%s\n' "$relative_path" | sed 's/\\/\\\\/g; s/"/\\"/g')
18 |
19 | echo "\"/$escaped_file\"," >> "$OUTPUT_FILE"
20 | done
21 |
22 | # Remove the trailing comma from the last line
23 | sed -i '$ s/,$//' "$OUTPUT_FILE"
24 |
25 | # Close the JSON array
26 | echo "]" >> "$OUTPUT_FILE"
27 |
28 | echo "File list generated: $OUTPUT_FILE"
29 |
30 |
--------------------------------------------------------------------------------
/image/kaios-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/image/kaios-banner.png
--------------------------------------------------------------------------------
/image/mockup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/image/mockup.png
--------------------------------------------------------------------------------
/image/mockup.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/image/mockup.xcf
--------------------------------------------------------------------------------
/image/screenshoot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strukturart/feedolin/30c1dffb36f326ae27c5df6a814e22f9f49a5d3e/image/screenshoot.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "feedolin",
3 | "version": "1.1.0",
4 | "source": "application/index.html",
5 | "browserslist": "Firefox <= 48",
6 | "scripts": {
7 | "build": "rm -rf dist/* && parcel build --no-source-maps --no-content-hash application/index.html && cp application/manifest.webapp dist && mkdir dist/assets && cp -r application/assets/icons dist/assets/ && mkdir -p dist/assets/js/ && cp application/assets/js/kaiads.v5.min.js dist/assets/js/",
8 | "run": "parcel",
9 | "web": "rm -rf docs/* && parcel build --dist-dir docs --public-url ./ --no-source-maps --no-content-hash application/index.html && cp application/manifest.webapp docs && cp application/manifest.webmanifest docs && mkdir -p docs/assets && cp -r application/assets/icons docs/assets/ && mkdir -p docs/assets/js/ && cp application/assets/js/kaiads.v5.min.js docs/assets/js/ && cp -r application/assets/fonts docs/assets/&& ./generate_file_list.sh"
10 | },
11 | "devDependencies": {
12 | "@agragregra/parcel-namer-beautify": "^1.0.1",
13 | "@babel/cli": "^7.18.10",
14 | "@babel/core": "^7.19.1",
15 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
16 | "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.12",
17 | "@babel/plugin-transform-runtime": "^7.18.5",
18 | "@babel/preset-env": "^7.19.1",
19 | "@parcel/packager-raw-url": "^2.12.0",
20 | "@parcel/resolver-default": "^2.12.0",
21 | "@parcel/transformer-html": "^2.13.3",
22 | "@parcel/transformer-webmanifest": "^2.12.0",
23 | "assert": "^2.1.0",
24 | "babel-plugin-transform-async-to-promises": "^0.8.18",
25 | "buffer": "^6.0.3",
26 | "core-js": "^3.39.0",
27 | "crypto-browserify": "^3.12.0",
28 | "events": "^3.3.0",
29 | "https-browserify": "^1.0.0",
30 | "os-browserify": "^0.3.0",
31 | "parcel": "^2.13.3",
32 | "parcel-namer-rewrite": "^2.10.3-rc.2",
33 | "path-browserify": "^1.0.1",
34 | "process": "^0.11.10",
35 | "stream-browserify": "^3.0.0",
36 | "stream-http": "^3.2.0",
37 | "string_decoder": "^1.3.0",
38 | "svgo": "^3.3.2",
39 | "timers-browserify": "^2.0.12",
40 | "url": "^0.11.4"
41 | },
42 | "dependencies": {
43 | "@parcel/reporter-dev-server": "^2.13.3",
44 | "@parcel/service-worker": "^2.8.0",
45 | "dayjs": "^1.11.13",
46 | "dotenv": "^16.4.1",
47 | "fast-xml-parser": "^4.5.0",
48 | "localforage": "^1.10.0",
49 | "mithril": "^2.0.4",
50 | "sanitize-html": "^2.13.0",
51 | "swiped-events": "1.2.0",
52 | "url-search-params-polyfill": "^8.1.1",
53 | "uuid": "^9.0.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/proxy.php:
--------------------------------------------------------------------------------
1 | "PROXY ACCESS DENIED! URL not specified"]);
27 | exit();
28 | }
29 |
30 | // Prepare headers
31 | $headers = [];
32 | foreach (getallheaders() as $key => $value) {
33 | if (in_array(strtolower($key), ['content-type', 'authorization', 'x-requested-with'])) {
34 | $headers[] = "$key: $value";
35 | }
36 | }
37 |
38 | // Prepare CURL options
39 | $curl = curl_init();
40 | switch (strtoupper($method)) {
41 | case 'POST':
42 | $postData = $isJsonRequest ? $requestData : $_POST;
43 | unset($postData['method'], $postData['cors']);
44 | curl_setopt_array($curl, [
45 | CURLOPT_URL => $url,
46 | CURLOPT_POST => true,
47 | CURLOPT_POSTFIELDS => $isJsonRequest ? json_encode($postData) : http_build_query($postData),
48 | ]);
49 | break;
50 |
51 | case 'GET':
52 | $getData = $isJsonRequest ? $requestData : $_GET;
53 | unset($getData['method'], $getData['cors']);
54 | $queryString = http_build_query($getData);
55 | curl_setopt($curl, CURLOPT_URL, $url . ($queryString ? "?$queryString" : ""));
56 | break;
57 |
58 | default:
59 | echo json_encode(["message" => "Proxy only supports POST and GET requests"]);
60 | exit();
61 | }
62 |
63 | curl_setopt_array($curl, [
64 | CURLOPT_RETURNTRANSFER => true,
65 | CURLOPT_SSL_VERIFYPEER => false, // Disable for development, enable in production
66 | CURLOPT_HTTPHEADER => $headers,
67 | ]);
68 |
69 | // Execute CURL request
70 | $response = curl_exec($curl);
71 | $error = curl_error($curl);
72 | curl_close($curl);
73 |
74 | if ($error) {
75 | echo json_encode(["error" => $error]);
76 | exit();
77 | }
78 |
79 | // Set response content type if possible
80 | if (json_decode($response) !== null) {
81 | header('Content-Type: application/json');
82 | } elseif (strpos($response, '