* Upload: fix redux key clash
## Issue
`params` is the "final" value that will be passed to the SDK and `channel` is not a valid argument (it should be `channel_name`). Also, it seems like we only pass the channel ID now and skip the channel name entirely.
For the anonymous case, a clash will still happen when since the channel part is hardcoded to `anonymous`.
## Approach
Generate a guid in `params` and use that as the key to handle all the cases above. We couldn't use the `uploadUrl` because v1 doesn't have it.
The old formula is retained to allow users to retry or cancel their existing uploads one last time (otherwise it will persist forever). The next upload will be using the new key.
* Upload: add tab-locking
## Issue
- The previous code does detect uploads from multiple tabs, but it was done by handling the CONFLICT error message from the backend. At certain corner-cases, this does not work well. A better way is to not allow resumption while the same file is being uploading from another tab.
- When an upload from 1 tab finishes, the GUI on the other tab does not remove the completed item. User either have to refresh or click Cancel. Clicking Cancel results in the 404 backend error. This should be avoided.
## Approach
- Added tab synchronization and locking by passing the "locked" and "removed" information through `localStorage`.
## Other considered approaches
- Wallet sync -- but decided not to pollute the wallet.
- 3rd-party redux tab syncing -- but decided it's not worth adding another module for 1 usage.
* Upload: check if locked before confirming delete
## Reproduce
Have 2 tabs + paused upload
Open "cancel" dialog in one of the tabs.
Continue upload in other tab
Confirm cancellation in first tab
Upload disappears from both tabs, but based on network traffic the upload keeps happening.
(If upload finishes the claim seems to get created)
* Settings Page: add warning for unsaved settings
## Issue
When entering Settings Page, sync-loop is disable until user exist Settings Page. If browser is closed, changes will be lost.
## Change
Add the usual browser-level modal popup.
Note that all modern browsers have stopped supporting customized messages, but I still left the message there for clarity. Tried to use our own toast for it, but the handler locks all GUI until it is serviced.
* app: remove unused props
* app: use lighter selectors
When all we need is to know if something exists or their count, use the ID version instead of the url/claim version to avoid the heavy transformation.
* SyncFatalError: show nag instead of hard-crashing.
## Issue
When sync fails, we crash the app.
## Ticket
Maybe closes 39 "Better handle both internal and web backend interruptions / downtime"
## Approach
I'm tackling this from the standpoint that (1) sync errors are not that fatal -- we'll just lost a few recent changes (2) network disconnection is the common cause.
## Changes
- If we are offline:
- Inform user through a nag. All other status is meaningless if we are offline.
- If we are online:
- If api is STATUS_DOWN, show the existing crash page.
- If there is a sync error, show a nag saying settings are now potentially unsynchronized, and add a button to retry sync.
- If there is a chunk error, nag to reload.
* Attempt to detect `status=DOWN`
Previous code resolves the status to either "ok" or "not", which makes the app unable to differentiate between the "degraded" (nag) and "down" (crash) states.
* Publish button: use spinner instead of "Publishing..."
Looks better, plus the preview could take a while sometimes.
* Refactor `doPublish`. No functional change
This is to allow `doPublish` to accept a custom payload as an input (for resuming uploads), instead of always resolving it from the redux data.
* Add doPublishResume
* Support resume-able upload via tus
## Issue
38 Handle resumable file upload
## Notes
Since we can't serialize a File object, we'll need to the user to re-select the file to resume.
* Exclude "modified date" for Firefox/Android
## Issue
It appears that the modification date of the Android file changes when selected, so that file was deemed "different" when trying to resume upload.
## Change
Exclude modification date for now. Let's assume a smart user.
* Move 'currentUploads' to 'publish' reducer
`publish` is currently rehydrated, so we can ride on that and don't need to store the `currentUploads` in `localStorage` for persistence. This would allow us to store Markdown Post data too, as `localStorage` has a 5MB limit per app.
We could have also made `webReducer` rehydrate, but in this repo, there is no need to split it to another reducer. It also makes more sense to be part of publish anyway (at least to me).
This change is mostly moving items between files, with the exception of
1. An additional REHYDRATE in the publish reducer to clean up the tusUploader.
2. Not clearing `currentUploads` in CLEAR_PUBLISH.
* Restore v1 code for livestream replay, etc.
v2 (tus) does not handle `remote_url`, so the app still needs v1 for that. Since we'll still have v1 code, use v1 for previews as well.
* fix type error
fix is subscribed check
- Persist subscription data locally
- add / remove subscription during log in / out
- Use store directly in hook
Add toast error if subscription fails
Revert removal of v2
hotfix linting issue
Add custom notification handler
- fix isSupported flag
- make icon color compatible with light/dark theme
- fix icon on notifications blocked banner
wip: add push notification banner to notifications page.
- ignore failed deletions via internal API
- add ua parsing package
- add more robust meta data to token save
refactor naming + add push toggle to notification button
shift some code around
update css naming o proper BEM notation
update notifications UI
remove now unneeded util function
Update push notification system to sue firebase sdk
separate service worker webpack bundling
update service worker to use firebase sdk
Add firebase config
Add firebase and remove filemanager
Stub out the basics for browser push notifications.
* fix safari
* try smaller image for badge
* add token validation with server, refactor code
* remove param
* add special icon for web notification badge
* add translations
* add missing trans for toast error
* add pushRequest method that will not prompt users who have subscribed but since disabled notifications in the settings.
- It is recommended to use "lowercase + underscore format" for events to keep things neat, since the dashboard will be mixed with Automated and Recommended events.
- GA4 event structure is no longer the same as UA's, and the recommendation is to retructure rather than trying to mimic the old pattern.
- Always check the Recommended events to see if there is an equivalent, and use the exact name. GA4 might add automated features for these events in the future, and we'll benefit from it without code changes and invalidating existing data.
- pageView: use default snippet behavior instead of manually sending
Start converting to GA4...
- Outbound click are automatically handled.
## Issue
44 tor browser crash related to recsys?
## Reproduce the exact error
Block the request for `me|new` in dev tools
## Fix
The code was trying to destructure a null object.
The existing code seems to indicate that null ID is expected (it uses null as fallback), so this change shouldn't impact recsys results (I didn't check the recsys docs to confirm).
## Issue
Part of `7166 improve search metadata`
## Notes
This is an experiment to influence the Sitelinks in our search results. Our current sitemap only consists of claims, so claims appear in Sitelinks more often. We (Julian) want categories to have higher priority, if possible.
For now, the sitemap will be defined in Google Console instead of robots.txt.
If it works, the file should be uploaded to sitemap.odysee.com, alongside the claim list sitemap.
* Add option to pass in url-search params.
Impetus: allow linked comment ID and setting the discussion tab when clicking on the `ClaimPreview`.
* comment.list: fix typos and renamed variables
- Switch from 'author' to 'creator' to disambiguate between comment author and content author. For comment author, we'll use 'commenter' from now on.
- Corrected 'commenterClaimId' to 'creatorClaimId' (just a typo, no functional change).
* doCommentReset: change param from uri to claimId
This reduces one lookup as clients will always have the claimID ready, but might not have the full URI.
It was using URI previously just to match the other APIs.
* Add doCommentListOwn -- command to fetch own comments
Since the redux slice is set up based on content or channel ID (for Channel Discussion page), re-use the channel ID for the case of "own comments". We always clear each ID when fetching page-0, so no worries of conflict when actually browsing the Channel Discussion page.
* Comment: add option to hide the actions section
* Implement own-comments page
* Use new param to remove sort-pins-first.
comment.List currently always pushes pins to the top to support pagination. This new param removes this behavior.
- A side-quest from "7166 improve search metadata".
- The favicon must be from the same domain as the homepage, so the CDN URL couldn't be used, hence the additional upload.
- The favicon also needs to be multiples of 48x48 and above.
- Wanted to use SVG for the smallest size possible, but seems like Safari does not fully support it. Got Dejan to give me a reasonably-sized PNG.
## Reference
https://developers.google.com/search/docs/advanced/appearance/favicon-in-search#guidelines
* Embed: add replay button
Also, changed "Rewatch or Discuss" to "Discuss + external arrow" since there is a dedicated re-watch button.
* Embed: resize "ended message" based on container height
- Reverted #7004 as it ended up preventing the rest of the components from being localized when there is an error. Replaced that with a `setLabel` that simply checks if the component exists before setting the label.
- Fix "Autoplay Next On" not localized on initial load -- it was only localized when the setting changes. It is unfortunate that we need to also set the label in an additional `useEffect` instead of just using vjs events, but so be it.
It was phrased negatively as the feedback back then was the string should match whatever is on the actual dialog (which was "Skip preview and confirmation"). But now it looks odd when we have an additional title string. We think titles should be positively phrased, hence the change.