Compare commits

...

1855 commits

Author SHA1 Message Date
zeppi
c3c641b6ba feature: wallet sync export button 2022-07-15 16:49:24 -04:00
Rafael
7e0363a563 Add Comedy icon 2022-07-14 14:24:20 -03:00
infinite-persistence
d41b9ff1e7
Publish: add additional info in the error log 2022-07-14 21:27:46 +08:00
infinite-persistence
f95d5fa62e
config: add commit ID
Primary impetus is to determine whether the reported TUS errors are due to old code, but the commit ID can be re-used in other areas where it makes sense.

The value comes externally from the command line, e.g.:
  `COMMIT_ID=$(git rev-parse HEAD) NODE_ENV=development yarn dev:web`
2022-07-14 20:36:09 +08:00
Raphael Wickihalder
f97f3b380b
Fix edit redirects on file pages 2022-07-13 21:33:09 +02:00
Raphael Wickihalder
a56ddecc0f
Fix action button margin in modal on mobile 2022-07-13 19:01:26 +02:00
Raphael Wickihalder
91f4ce532e
Fix playlist save button on gile page in mobile view 2022-07-13 18:48:17 +02:00
infinite-persistence
ecc6cb8a77 ChannelsFollowingDiscover: exclude followed channels
Note that there is a side effect of the channel going away immediately after Follow button is pressed. More elaborate code is needed like in the Following Manage page if we want the claim to be retained.
2022-07-13 11:22:56 -04:00
infinite-persistence
58d9605033 ChannelsFollowingDiscover: remove Desktop code 2022-07-13 11:22:56 -04:00
infinite-persistence
c563889bf6 Grab Discover IDs from homepage API
Adds ability for homepage team to define the Discover list of IDs.

If undefined, falls back to English's list. If English is also undefined, falls back to LATEST / PRIMARY.
2022-07-13 11:22:56 -04:00
Thomas Zarebczan
9e18b30fdb
force rebuild 2022-07-13 10:46:19 -04:00
Rafael Saes
83dbe8ec7c
Playlists v2: Refactors, touch ups + Queue Mode (#1604)
* Playlists v2

* Style pass

* Change playlist items arrange icon

* Playlist card body open by default

* Refactor collectionEdit components

* Paginate & Refactor bid field

* Collection page changes

* Add Thumbnail optional

* Replace extra info for description on collection page

* Playlist card right below video on medium screen

* Allow editing private collections

* Add edit option to menus

* Allow deleting a public playlist but keeping a private version

* Add queue to Save menu, remove edit option from Builtin pages, show queue on playlists page

* Fix scroll to recent persisting on medium screen

* Fix adding to queue from menu

* Fixes for delete

* PublishList: delay mounting Items tab to prevent lock-up (#1783)

For a large list, the playlist publish form is unusable (super-slow typing) due to the entire list being mounted despite the tab is not active.
The full solution is still to paginate it, but for now, don't mount the tab until it is selected. Add a spinner to indicate something is loading. It's not prefect, but it's throwaway code anyway. At least we can fill in the fields properly now.

* Batch-resolve private collections (#1782)

* makeSelectClaimForClaimId --> selectClaimForClaimId

Move away from the problematic `makeSelect*`, especially in large loops.

* Batch-resolve private collections
1758

This alleviates the lock-up that is caused by large number of invidual resolves. There will still be some minor stutter due to the large DOM that React needs to handle -- that is logged in 1758 and will be handled separately.

At least the stutter is short (1-2s) and the app is still usable.
Private list items are being resolve individually, super slow if the list is large (>100). Published lists doesn't have this issue.
doFetchItemsInCollections contains most of the useful logic, but it isn't called for private/built-in lists because it's not an actual claim.
Tweaked doFetchItemsInCollections to handle private (UUID-based) collections.

* Use persisted state for floating player playlist card body
- I find it annoying being open everytime

* Fix removing edits from published playlist

* Fix scroll on mobile

* Allow going editing items from toast

* Fix ClaimShareButton

* Prevent edit/publish of builtin

* Fix async inside forEach

* Fix sync on queue edit

* Fix autoplayCountdown replay

* Fix deleting an item scrolling the playlist

* CreatedAt fixes

* Remove repost for now

* Anon publish fixes

* Fix mature case on floating

Co-authored-by: infinite-persistence <64950861+infinite-persistence@users.noreply.github.com>
2022-07-13 10:59:59 -03:00
infinite-persistence
5863ea8df4
Sync: operate on 'local' until the first successful sync (#1835)
## Issue
https://github.com/OdyseeTeam/odysee-frontend/issues/1815#issuecomment-1178728712

When settings are changed before the first successful sync, the changes are on top of the default wallet preferences, and becomes the "latest". When sync is possible again later, the bad data is pushed to the cloud.

## Change
Continue to operate on 'local' until the first successful sync. Most of the GUI will warn (or even prevent) the user from changing settings in this scenario, so the amount of "discarded" changes in 'local' is minimal.
2022-07-13 09:36:51 -04:00
Rafael Saes
68ceb7f440
Fix url problems (#1679)
* Fix Uri errors
2022-07-12 16:58:18 -03:00
infinite-persistence
68a4697c7d
ReportContent: add ?commentId support (#1826)
## Ticket
1822

## Changes
- Add `?commentId=` support in the URL.
- `claimId` remains a required parameter so that we can derive the comment URL.
    - The backend will know it's a comment report when both parameters are present.
- The comment URL is added to the top of `additional_details`.
- The backend rejects if `additional_details` is provided for DMCA. Grayed out DMCA for the case of reporting comments.
2022-07-12 13:44:34 -04:00
Raphael Wickihalder
7b89ad8c14
Fix currency select position on settings page 2022-07-12 19:37:45 +02:00
mayeaux
4bc5d25d5a
Revert "update frontend to work with new api return (#1830)" (#1831)
This reverts commit a2a795ae77.
2022-07-12 17:54:15 +02:00
Raphael Wickihalder
dde9f07ed9
Adjust uploading label 2022-07-12 16:27:25 +02:00
Raphael Wickihalder
f974383e7b
Adjust upload label 2022-07-12 16:12:02 +02:00
mayeaux
a2a795ae77
update frontend to work with new api return (#1830) 2022-07-12 14:53:56 +02:00
infinite-persistence
d8571781ed (patch) Don't nudge to refresh in localhost
d16ae73c

## Issue
dev instances are also affected.

## Change
Use another env to enable the feature.

The cleaner solution that avoids the double env is to simply not make MIN_VERSION appear in the default file + define only in production instances. But putting it in the default file makes things clearer, plus easier to "bump + build" by just pushing a new commit.
2022-07-12 18:52:35 +08:00
infinite-persistence
e858cdd88b
(patch) Add "Hide Repost" button in channel page
Fixes the "force repost" behavior in Category Page.

Got the logic wrong when the boolean parameter was inverted from "force" (+ve) to "hideRepostOverride" (-ve) to support the "Hide Repost" button.

hideRepostOverride:
- undefined = follow user setting
- true = always hide
- false = always show << we want this
2022-07-12 16:04:59 +08:00
infinite-persistence
147ac43eac
ReportContent: cleanup and improvements
- Use `finally` instead of an arbitrary timer to clear the spinner when resolving the claim.
- Move away from `makeSelect*`
- `perform`: use object form as there is no customization.
- Effect-dependency cleanup.
2022-07-12 15:08:36 +08:00
infinite-persistence
ed0fb59983 Comment: add hideContextMenu + hide reply button too when hideActions is set 2022-07-12 15:08:04 +08:00
infinite-persistence
8aa6a60acf
Fix v1-publish items not removable (#1823)
## Issue
https://odysee-workspace.slack.com/archives/C02GSHBKYEM/p1657571082411839?thread_ts=1654909550.197639&cid=C02GSHBKYEM

If the user refreshed on a v1 upload, we can't do much but must at least provide a Cancel button for them to remove the entry.

## Change
- Restore the cancel button behavior for v1 like it was before.  The recent changes on the visibility of the Cancel button should only be applied to v2.
- Also fixed missing cancel button on v2 after refresh if the progress reached 100%.
2022-07-12 01:13:58 -04:00
Raphael Wickihalder
62f90ae93e
Fix schedule options. Again. 2022-07-11 20:16:56 +02:00
Raphael Wickihalder
ad8fc035bb
Show balance on large & medium screens 2022-07-11 18:52:04 +02:00
Raphael Wickihalder
59c75c9cec
Fix premium badge position 2022-07-11 18:31:05 +02:00
Raphael Wickihalder
214263d111
Remove update label in new livestream forms 2022-07-11 17:03:04 +02:00
Rave | 図書館猫
b20b24bdb6
Publish revamp (Part 2) (#1781)
* Move menu entries & add publish buttons

* Save

* Separate publish forms

* Make new header dynamic for all screen sizes

* Save some livestream creation changes

* Save more livestream changes

* Save

* Change publish folder structure

* Update paths

* Change position of form elements. Again.

* Move, add & delete form fields

* Clean post form

* Clean post form even more

* Clean publish post component

* Save

* Add custom post form state

* Move price to additional options

* Adjust livestream form

* Adjust headers & titles

* Update key section

* Adjust active header icons

* Adjust toggle menu

* Save

* Adjust active button style

* Change active button selector in header

* Fix header menu links

* Move price section in post form

* Adjust instruction text color

* Adjust replay table

* Revert changes & adjust tag section

* Make more form elements dynamic

* Finalize additional options section

* Update post form

* Set mode in upload form

* Update livestream form

* Add clear button

* Make clear button dynamic

* Set upload mode

* Remove new button

* Clean upload form

* Show disabled key on livestream form

* Remove old key section

* Update channel selector for publish forms

* Add updated channel selector to publish forms

* Add mobile links

* Update mobile header

* Adjust channel selector on mobile

* Adjust livestream form on mobile

* Adjust edit links for livestreams

* Adjust edit links for posts

* Adjust more edit links

* Adjust channel selector

* Update disabled in livestream form

* Add missing change

* Fix sign out function

* Save

* Adjust livestream page on mobile

* Adjust tags section on upload page on mobile

* Adjust publish links in left navigation on mobile

* Add images to accepted filetypes on upload page

* Add autofocus to input fields

* Add autofocus to all publish forms

* Save

* Ignore thumbnail api status

* Put active thumbnail upload label in card

* Fix crashes

* Fix flow

* Fix licence fields

* Adjust wallet in header on smaller screens

* Fix channel selector line break on small screens

* Fix border radius for some buttons

* PublishReleaseDate: fix initial value to reflect what's actually in Redux

'undefined' is a valid value that means "use publish time", but the GUI incorrectly starts off by locking to the mounted timestamp.

* Add and hide channel selector on livestream publish page

* Fix channel selector on livestream setup page

* Fix gif aspect ratio in channel selector

* Make layout more dynamic

* Fix some edit redirects

* Save

* Clean publishFile

* Fix build errors

* Fix more build errors in profile menu button

* Remove console logs

* Remove post form reducer

* Limit publish title length to 200 characters

* Remove totalRewardValue from livestreamCreate index

* Remove console log

* Add tooltip to replay refresh button

* Remove scrollToTop function from publish forms

* Adjust emty wallet value trigger and add error to livestream publish page

* Disable some tabs in edit mode in livestream form

* Fix maxLength typo

* Remove 'as' label

* Remove selectPublishFormValues

* Reenable setup tab

* Remove inactive line

* Remove another inactive line

* Remove flow fix

* Update label switch logic in confirmation modal

Adjust gif margin

Adjust gif margin

Remove navigate from edit link

Remove manual updateLabels execution on init

Remove editLabel function

Fix labels in publish modal

Adjust post livestream setup redirect

Remove setOverMaxBitrate from livestream form

Clean livestream publish

More cleanup

Update post livestream creation redirect

Bring back edit tab for livestreams

Update edit tab

Reset form on livestream edit => clear

Update label switch logic

Readjust channel selector position on mobile

* Make some space adjustments for mobile

Update livestream edit page on mobile

Update action label on publish forms in edit mode

* Hide replay options in edit mode in livestream form

* Update label switch logic in confirmation modal

Adjust gif margin

Adjust gif margin

Remove navigate from edit link

Remove manual updateLabels execution on init

Remove editLabel function

Fix labels in publish modal

Adjust post livestream setup redirect

Remove setOverMaxBitrate from livestream form

Clean livestream publish

More cleanup

Update post livestream creation redirect

Bring back edit tab for livestreams

Update edit tab

Reset form on livestream edit => clear

Update label switch logic

Readjust channel selector position on mobile
Make some space adjustments for mobile

Update livestream edit page on mobile

Update action label on publish forms in edit mode
Hide replay options in edit mode in livestream form

* Make form titles dynamic

* Remove spinner on livestream form

* Remove console log

* Fix double history push

* Fix thumbnail status on post form

* Update error message style

* Handle publish error button behavior

* Clean code

* Fix scheduling & date picker

* Fix calendar overlap

* Add replay selector to livestream claim edit form

* Clean code

* Disable autocomplete

* Show replays in edit & replay tab

* Redesign replay picker

* Fix design details

* Save dynamic replay picker

* Fix autoComplete typo

* Change label text

* Add upload to livestream replay form

* Fix scss structure

* Add comunity guideline link to publish forms

* Fix error

* Fix selectThumbnail index

* Reset form values on replay source change

* Add replay redirect to upload page

* Fix publishError state change

* Remove label effect from publish confirmation modal

* Update labels in publish confirmation modal

* Add ? to chaptersButton

* Remove doPrepareEdit({ name })

* Bring upload redirect back

* Adjust redirects

* Save

* Update edit redirects

* Revert scheduling options

* Replace checkboxes for replays with radio

* Update form on source change

* Rearrange entries in mobile navigation

* Change key position on livestream setup page

* Change label for livestream update without replay change

* Adjust margin below label

Co-authored-by: infinite-persistence <inf.persistence@gmail.com>
2022-07-11 16:12:37 +02:00
infinite-persistence
d16ae73c0d
Don't nudge to refresh in localhost
This will keep appearing if the dev branch is behind master.
2022-07-08 19:06:04 +08:00
infinite-persistence
73e6dfd399
(patch) tus: Fix upload not found scenario (#1814)
Second attempt, this time just hiding the cancel button when the upload is done. If user is impatient and refreshed in between this and `notify`, it will still be resumable later.

Bumped MINIMUM_VERSION to nudge for a refresh so we get a slightly more accurate logging, and also to prevent the issue from lingering.
2022-07-08 06:45:43 -04:00
Thomas Zarebczan
294c5194a4
default fee amount to undefined (don't pass)
>= (and =) are having a filtering issue with reposts. Don't need to pass >= for all content - I think this was some old hackaround that's no longer required.
2022-07-07 16:37:37 -04:00
Thomas Zarebczan
ec745c31de
Revert "tus: Fix upload not found scenario (#1808)" (#1813)
This reverts commit cdcf7e7772.
2022-07-07 15:54:14 -04:00
ktprograms
fc32339d2d
Fix lbry:// URLs in iframes being broken by Safari (#1812)
When Safari parses lbry:// URLs, it breaks them as they are not
compliant with the RFC 3986 URI syntax. This causes iframes in text
posts which link to a lbry:// URL to not display on Safari.

Instead, just use the lbry:// URL matched from the iframe regex instead
of parsing the iframe on Safari.
2022-07-07 10:39:10 -04:00
infinite-persistence
54122f8998
Publish: restore percentage label when uploading (#1809)
Closes #1804

Can't recall why it was removed ... probably something not important.
2022-07-07 08:53:57 -04:00
infinite-persistence
cdcf7e7772
tus: Fix upload not found scenario (#1808)
## Steps
When it upload reaches 100%, click Cancel (not refresh).

## Issue
There was an old hack in b0509bc9 where we decided to wait a while before sending `notify` as the server was not responsive. Since the task was dispatched before the Cancel action, the server cleared the upload first and later received the `notify`.

## Change
Instead of trying to cancel the timer, I think the hack is no longer needed given the throughput and lock fixes. With things running back in sequential mode, the Cancel button will now just show the "upload already completed" modal.
2022-07-07 08:53:47 -04:00
infinite-persistence
acabdb6325
tus-js-client: 2.3.0 to 2.3.2 (#1807) 2022-07-07 08:43:45 -04:00
infinite-persistence
da691f286e
Assume weekly_watch is claimed when data is insufficient (#1806)
## Issue
If the reward-list fetch is slow, the selector assumes the weekly_watch hasn't been claimed yet, causing an unnecessary claim.

## Change
The selector now tells the caller if there is no data -- up to caller on what to do (in this case, don't claim the reward).

It should be harmless if the claim action was missed, since the user can still manually claim it.
2022-07-07 05:16:36 -04:00
Thomas Zarebczan
e073e120a1
temp cache bust for CDN issue
CDN has set a large max cache for some m3u8s the other day, hoping this helps alleviate browser side cache issues. We can remove later
2022-07-06 14:47:59 -04:00
infinite-persistence
7c82110326
(patch) Add "Hide Repost" button in channel page (#1796)
## Issue
Hide reposts gets enabled on channel page by default, on a fresh browser session.

Open Odysee in private tab
Go to some channel page
Go back
Go to some channel page(same or different)
"Hide reposts" is enabled, and settings expanded
Above also works with logging in while having "hide reposts" disabled in global settings. (edited)

## Fix
Forgot to add default value.
2022-07-06 22:04:03 +08:00
Rafael Saes
7ecbb779af
Improve ~more~ comment viewing operation (#1798) 2022-07-06 08:36:14 -04:00
infinite-persistence
3233e3ab64
Remove 'now' in the ad
## Issue
It's a split-string (both in sentence and html) that translators can't translate

## Change
Asked around, and it's not a design requirement to have 2 lines. Feel free to put in a better drive tagline.
2022-07-06 13:07:45 +08:00
Rafael Saes
1e3585f5cc
Fix Livestream Popout Chat not refreshing when closed (#1797) 2022-07-05 14:30:54 -04:00
infinite-persistence
b0e88ff5d1
Add "Hide Repost" button in channel page (#1796)
* Re-organized per 'state->var->func->effect->return' structure.

* Add "Hide Repost" button in channel page

Ticket: 1762

## Change
For the placement of the button, putting it inside the expanded settings group feels the most natural, plus we then don't need to check whether the channel has reposts or not before displaying it (the expanded area is for stuff like this).

## Notes
The tricky part was making the code maintainable w.r.t to the global "Hide Repost" setting. Changed `forceShowReposts` to `hideRepostsOverride`, hopefully makes things more obvious.
- undefined = fallback to global setting
- true/false = use override
2022-07-05 13:20:10 -04:00
infinite-persistence
5638f64831
New version nudge (#1793)
## Ticket
1329

The existing nudge to refresh the webpage only happens when the app cannot find the specific javascript file in the server. As we don't purge the files on each build, the browser typically uses the cached version of the app, which could be weeks behind (based on the error logs).

## Approach
Poll the current version periodically (set to 1 hour for now) and invoke the nudge when a newer version is detected.

We typically don't need to bump `MINIMUM_VERSION` unless there is an urgent need to make users move away from older versions (e.g. API changes, mistakes, etc.)

## Trade-offs
Wanted to put the value in a separate file called `.min.version` so that the env's history won't be polluted with version bumps, but not sure how to implement with minimal code without having to read from the file. Getting from the env is the easiest to implement (per my limited knowledge).
2022-07-05 09:14:32 -04:00
infinite-persistence
769b1cdabb
Fix notification target for some types (#1790)
## Ticket
"1742 Notification popup: incorrect target"

Commentron uses old links for some of the notification types.

## Change
Factored out the code that determines the new target and use it both Notifications Page and Popup Menu.
2022-07-05 06:55:04 -04:00
infinite-persistence
02d017d415
Bump weekly-watch auto claim interval (#1794)
## Ticket
1768 Check reward claiming logic

## Change
- Bump to >6.5 days
- Remove unnecessary `Math.ceil` -- not sure why I added that. It was causing diff to hit earlier than necessary.

> _and I'm 5 days away._

Not sure how to replicate/explain this, though -- the old code would have still covered this range.  One possibility is when `last_claimed` is not defined, where we assume user hasn't claimed yet. We could flip this to assume "claimed" and just let the user manually claim as the fallback -- let me know.
2022-07-05 06:44:40 -04:00
infinite-persistence
6696d32e66
Remove 'many_downloads' auto-claim (let user manually claim) (#1795)
Ticket: 1768
2022-07-05 06:36:23 -04:00
Rave | 図書館猫
da55cdbba8
Part 1 (#1789) 2022-07-04 14:32:30 +02:00
infinite-persistence
dbb9ee7ac6
PremiumBadge: retrieve membership db internally instead of from parent (#1764)
* DRY up membership selector

Selectors should be chained up, not copy/pasted.

* PremiumBadge: retrieve membership db internally instead of from parent

## Ticket
1753 odyseeMembershipByUri function causing unnecessary renders

## Issue
While the rendering issue in the ticket is due to the way the props are defined, it also surfaced a prop-drilling issue with PremiumBadge.

Instead of asking the parent for the membership db, it can retrieve from Redux itself. This prevents the prop from polluting 2 levels of components and causing unnecessary renders.

## Approach
- Make `PremiumBadge` accept `uri` like most other components.
- I still leave the `membership` prop as (i.e. parent can still pass it directly). In some cases (e.g. `livestreamComment`, `page/odyseeMembership`), the parent itself needs the same data, so we don't need to derive it twice.
2022-07-01 15:40:06 -04:00
Thomas Zarebczan
6ceb0d7d8f
use card endpoint for previews
This forces jpeg
2022-07-01 12:28:56 -04:00
Raphael Wickihalder
e04cbcacba
Make timestamp in mini player invisible on mobile 2022-07-01 06:29:23 +02:00
infinite-persistence
640237c630
tus: don't allow 'notify' to be sent again (#1778)
## Ticket
725

## Issue
Upload a video. When `notify` is sent at the end of the tus upload, refresh immediately. The GUI allowed the user to resume the upload, but the ID is no longer present in the server.

## Approach
Until the polling API for `notify` is available, we can only assume the best and let the user know how to handle it.
- Store the "notify was sent" state.
- Show a dialog explaining the situation.

Thought of trying to make `claim_list` calls behind the scenes to clear itself, but it doesn't handle the case of `notify` actually failing. The best is to just let the user handle it for now.

Note that for the case of `onerror` actually received, we still retry since a network error could be the culprit (`notify` wasn't sent).
2022-06-30 19:30:08 -04:00
Thomas Zarebczan
90346599b0
revert to 1280x720 2022-06-30 15:11:54 -04:00
Thomas Zarebczan
18051ec929
test OG image card with smaller 2022-06-30 14:57:41 -04:00
mayeaux
3cae70dd11
bump videojs version (#1775) 2022-06-29 08:59:28 -04:00
infinite-persistence
4569a4f9f8
PublishDate: make widget follow the 24h format setting (#1776)
Closes 1738
2022-06-29 08:34:32 -04:00
infinite-persistence
70ea3f0812
tus: restore higher chunk size (10MB -> 25MB) (#1774)
It was previously reduced to 10MB (d1447083) with the assumption that the slow disk write was causing the "lock" issue.

Now that the backend has implemented a new locking mechanism, restore to a larger chunk to reduce the number of PATCH calls.

```
10MB  ->  2s/call
25MB  ->  6s/call (similar to what I see with Google Drive)
100MB -> 25s/call
```
2022-06-29 08:34:25 -04:00
infinite-persistence
c2b911d73a
Workaround for markdown crash with Google Translate (#1773)
## Issue
Depending on what the markdown content was, React crashes when unmounting the component if Google Translate is active.

## Change
It seems like the content is too dynamic to apply the same workaround used in 1772 for FileReactions (someone else can take a stab).

Until we have a better solution, just make the markdown component (posts, comments, file description, etc.) not participate in Chrome-level translations. It's not a good solution from a user standpoint, but it at least it doesn't crash.
2022-06-29 08:25:21 -04:00
infinite-persistence
f686d86910
FileReactions: make it robust against external DOM manipulation (#1772)
## Issue
Crash when reacting while Google Translate is active.

https://github.com/facebook/react/issues/11538#issuecomment-390386520
2022-06-29 08:25:12 -04:00
infinite-persistence
4b1bf22154
Revert "Fix uploads page cleared/reloaded on each navigation" (#1771)
This reverts commit 1dccc1ac64.

Closes 1770
Re-opens "1515 uploads page cleared/reloaded on each navigation"

1515 is just a minor annoyance, while the current issue is a non-functional page, so reverting for now and revisit later.
2022-06-29 08:04:33 -04:00
mayeaux
3f44b80603
Merge pull request #1756 from OdyseeTeam/dont-dispose-when-switching
Don't dispose switching between video/livestream, chapter button fix, current time not updating quickly fix
2022-06-29 12:47:18 +02:00
Anthony
41905f420e
dont dispose between videos and update current time immediately
fix chapters button not being hidden

add back live ui

fix chapters button showing up when using miniplayer

bugfix race condition for removing chapters button

move chapter loading to videoviewer component

remove unnecessary claim being passed
2022-06-29 12:42:26 +02:00
Thomas Zarebczan
5c41e5da0d
improve sync page clarity, move up button. 2022-06-28 16:07:03 -04:00
infinite-persistence
d3f95e256a
Recsys: add isEmbed to videos in Markdown (posts, comments) (#1765)
* Remove dead-end selector

`playingUri` resides in the `content` slice, so this returns nothing.
Nobody is using it, so should be safe to remove.

* Recsys: add `isEmbed` to videos in Markdown (posts, comments)

It seems like the existing `embedded` needs to specifically mean `/$/embed` (external from odysee.com), so had to add another variable.
2022-06-28 08:10:22 -04:00
infinite-persistence
0a88c6254d
Publish: restore the multiple retries (#1763)
- Previously, we tried to solve the "file locked" problem by only making one retry after a super long delay. This was from an anecdote that it's more likely to lock up if the delay was short.
  - This didn't help at all for our case, and Andrey has made some locking mechanism changes in the backend.
  - The reduced number of retries probably increased the number of "failed to upload chunk" errors (not sure), which is supposedly a normal occurrence and we're expected to keep retrying.

Restoring the retry behavior and monitor...
2022-06-28 06:29:07 -04:00
infinite-persistence
96cdf11567
Fix naming convention and type correctness
- Fixed value props being named like a function/selector.
- Fixed flow type for membership (should be `?string`).
    - It might not matter in the current code, but the whole purpose of type checking to catch usage errors in the future.
- `hasXXX` indicates a boolean, so it doesn't make sense to force the client to input a string.
2022-06-28 13:39:11 +08:00
infinite-persistence
1933997276
Preorder cleanup
Reported issues that weren't completed in de068d36
2022-06-28 13:36:18 +08:00
mayeaux
1bf3f492ff
add lbry_api_url to env defaults (#1760) 2022-06-27 15:46:57 +02:00
mayeaux
de068d36f1
Preorder button touchups (#1755)
* update precommit hook

* touchup code per kps comments
2022-06-24 09:08:46 -04:00
mayeaux
628da8bb04
show controls if both calls to play fail (#1724) 2022-06-24 08:52:01 -04:00
infinite-persistence
7ea73c3f1b
Recsys: improve data stashing frequency
## Issue
The 15s saving interval (hijacking the position-saving code) is too far apart, causing rescys data to be lost when tab is closed/refreshed.

## Change
While I think it is fine to save to redux every second, it is still best to avoid that since a state change will always cause the map-to-props to evaluate.

Chose 5s as the interval and moved away from the position-saving code (the recsys videojs plugin is a better choice to handle this).

Also save it on `t=1` so that at least we know it played prior to the tab refreshing/closing.

## Considered
- Didn't want to do `beforeunload` again since it is unreliable and a pain to test in mobile.
2022-06-24 16:54:55 +08:00
infinite-persistence
8aa831fe49
Recsys: fix resumed-send missing totalPlayTime
Ticket: 1751

## Issue
The `totalPlayTime` resides in the videojs plugin and is only sent to the recsys object in `onPlayerDispose`, so it missed the redux rehydration in the browser close/refresh scenario.

## Change
Update the recsys value for `totalPlayTime` immediately so that it'll be part of the redux stashing (and later, rehydration).

Note that recsys data is currently being saved to redux in a 15s interval. Will change that in the next commit.
2022-06-24 16:52:08 +08:00
infinite-persistence
6b3e03cca4
Recsys: fix missing uuid
Ticket: 1745

## Issue
The search result (and the uuid) won't be ready when a recommendation is clicked, but a stub recsyst entry is created at this point. In the past, the uuid was randomly generated, so it didn't matter.

## Fix
Ensure the uuid field is filled when the recommendations are finally loaded.
2022-06-24 14:02:40 +08:00
mayeaux
4f47779303
Preorder content functionality (#1743)
* adding preorder button

* adding preorder modal

* frontend mostly done

* check if its already purchased

* refresh page after purchase

* smooth out purchase process

* check if user has card saved

* handle case where its the users own upload

* fix transaction listing order bug

* cleaning up code for merge

* fix lint errors

* fix flow errors

* allow eur purchases

* support eur on customer transaction page

* fix css
2022-06-23 20:58:32 -04:00
Thomas Zarebczan
017df02816
Update thumbnail cards URL (#1748)
And function name - was confusing that we had 2 with different paths.

Use 1280x720 to improve caching (used on mobile/tablets). There's no real spec for size.
2022-06-23 18:09:48 -04:00
Rave | 図書館猫
305673999b
Update thumbnail paths (#1747) 2022-06-23 22:33:32 +02:00
Thomas Zarebczan
553a801bc3
fix tip target page 2022-06-23 09:14:47 -04:00
Thomas Zarebczan
29b2a8aeff
use new reporting endpoint
fixes #1698 at least for now
2022-06-23 08:47:34 -04:00
infinite-persistence
7cbb7a54aa
Handle browsers that don't support IntersectionObserver (#1739)
* Remove ad-handling in videojs.jsx

Primary impetus is to remove unnecessary IntersectionObserver usage, but it should be removed anyway because:
- no longer relevant today with Adnimation's script.
- we also globally hide floating ads now, so no more invisible divs.
- the code is wrongly placed -- it's not the responsibility of the Videojs component.

* use-lazy-loaded: skip if IntersectionObserver is not supported

## Issue
Page not loading in older Safari (e.g. ipad air 2)

## Approach
Instead of using a polyfill (which comes with implementation caveats), just not apply the lazy-loading for those old browsers. Not lazy-loading is better than not loading at all, plus this is way easier to test (even by just reading the code) than testing out the polyfill implementation's caveats.

The cons is we would need the polyfill if we use it in other places in the future.

## Code Changes
Factor out the src-setting code, and use it directly when IntersectionObserver is not found.
2022-06-23 08:10:27 -04:00
Raphael Wickihalder
3687292cdf
Fix button padding on mobile 2022-06-23 13:53:19 +02:00
infinite-persistence
053e214c86
PublishReleaseTime widget improvements (#1740)
* PublishReleaseDate: improve calendar error handling

Ticket: 1738

- Report invalid `minute` and `day`. The 3rd-party widget auto-corrects the other fields. Don't think there is a way to make it autocorrect for all.
- Report invalid range (cannot set to future date).

* Block form on releaseDate error instead of silently sending last valid value

which does not tally with what's on screen.
2022-06-23 07:27:08 -04:00
Thomas Zarebczan
b6f9b0e6d4
Add token to help page (internal) (#1737) 2022-06-22 12:32:17 -04:00
Raphael Wickihalder
d1958d3775
Add help button to header in guets mode 2022-06-22 18:25:24 +02:00
infinite-persistence
486a557d75
Recsys: capture and use x-uuid from search results (#1727)
* Recsys/FYP: add documentation.

* Recsys: capture and use `x-uuid` from search results

Ticket: 1717
2022-06-22 09:43:54 -04:00
infinite-persistence
63a2430a7c
ReportContent: redirect back after logging in (#1733)
## Issue
1709 - If you sign in while reporting, you end up in the homepage

## Notes
The other option is to just make `<Header>` always redirect back to where it came from using the full path. But existing code elsewhere seem to always trim off any params (e.g. `location.search`, `location.hash`) when doing redirects.

So, ended up making it generic and let the caller decide where to redirect (and with what params).
2022-06-22 09:07:15 -04:00
infinite-persistence
9e4ac047ca
Str and cleanup 2022-06-22 20:53:34 +08:00
Rave | 図書館猫
3bfdd7e920
Add platforms to share buttons (#1721)
* Add Minds to share buttons

* Add Telegram & WhatsApp

* Adjust style on mobile

* Adjust WhatsApp share url on desktop

* Freeze icon size

* Adjust share buttons
2022-06-22 08:23:40 -04:00
infinite-persistence
e2166b6f03
Change collection item fetch-page from 5 to 50 (#1732)
In `doResolveUri`, if the `uri` is a collection, it will attempt to fetch all items in the collection.

Can't think of any special reason to keep the page-size small, and not seeing any notes in the commits either. It just ends up making several `claim_search` of 5's until all items are fetched.
2022-06-22 08:04:22 -04:00
Rave | 図書館猫
86fcd87f53
Notification Menu Upgrade (#1713)
* Mark notification as seen on hover

* Clean code

* Mark notifications as seen on button click

* Clean code

* Animate bubble
2022-06-21 20:59:37 -04:00
mayeaux
061f4ab08f
fix progress bar hover (#1726) 2022-06-21 11:22:20 -04:00
infinite-persistence
ee3236fe1e
Recommendations: factor out a selector for raw results
1606
2022-06-21 22:14:07 +08:00
infinite-persistence
539cc062b6
DRY: fix duplicate code for Recommended key generation
Must use `getRecommendationSearchOptions`, otherwise there is a chance of some clients deriving the wrong key.
2022-06-21 22:14:07 +08:00
mayeaux
d50f51bd3b
fix plays inline bug on ios (#1723) 2022-06-21 09:55:25 -04:00
Thomas Zarebczan
56ce70cef5
Revert "Undo the hardcoded ad div id (#1719)" (#1722)
This reverts commit 5888b6b7d8.
2022-06-21 06:12:47 -04:00
infinite-persistence
5888b6b7d8
Undo the hardcoded ad div id (#1719)
I previously hardcoded both IDs since the script was not looking the right one at one point, but I guess that was unnecessary.

I don't think it causes any problems, because I'm still just loading 1 script (no double video, just 2 divs for them to choose).

Note that we are still using the `filepage` script since the `homepage` one is not working.
2022-06-21 05:51:07 -04:00
Raphael Wickihalder
3e0f1c63c9
Update snackbar design 2022-06-21 10:11:28 +02:00
Raphael Wickihalder
b53fc3732e
Redesign error nag 2022-06-21 08:34:27 +02:00
mayeaux
63f7a8f15c
bugfix streams continuing to run in the background (#1714) 2022-06-20 18:17:12 -04:00
Rave | 図書館猫
20ff660cb2
Minor design fixes in modals (#1711)
* Minor design fixes in modals

* Adjust button icon color
2022-06-20 13:51:57 +02:00
Rave | 図書館猫
d40260374d
Inject close button into footer banner ad (#1710)
* Make shouldLoadSticky dynamic again

* Adjust of statement

* Update statement again...

* Adjust selector. Again.
2022-06-17 12:07:08 -04:00
infinite-persistence
f9ebd0863d Consolidate the mobile tile to use the poster size for better caching.
It's all approximation anyway.
2022-06-17 11:58:43 -04:00
infinite-persistence
b8fceacb8a Only apply the larger thumbnail width on mobile + tile layout
## Ticket
1526 strange thumbnail size requested on mobile layout (pc only?)

## Notes
The 900px was to account for blur tile thumbnails in mobile homepage (4f4803c6).
Fix to only do that in tile mode.
2022-06-17 11:58:43 -04:00
Raphael Wickihalder
eea0ec16e0
Fix notification menu height / transparency issue in firefox 2022-06-17 12:35:18 +02:00
Raphael Wickihalder
7cdeb9593f Add settings page button to header in guest mode 2022-06-17 18:23:53 +08:00
Raphael Wickihalder
845b70f52c
Adjust ad design 2022-06-17 12:20:35 +02:00
Raphael Wickihalder
8e15f30ace
Fix typo 2022-06-17 11:27:23 +02:00
Raphael Wickihalder
9ad8c31e3f
Adjust ads style in light theme 2022-06-17 11:23:46 +02:00
Raphael Wickihalder
30e16841a5
Adjust ad design 2022-06-17 11:22:18 +02:00
Raphael Wickihalder
70a19d32be
Add preventDefault to notification delete 2022-06-17 06:22:24 +02:00
infinite-persistence
df2a717e8d Change poster-fetch implementation
## Ticket
1526: strange thumbnail size requested on mobile layout (pc only?)

## General Problem
It was trying to fetch based on the exact size of the video container, which would satisfy Core Vitals (in an overkill way), but would bring several issues:
- server-side caching would not work since everyone's window size is different in a responsive layout design.
- the additional 200ms wait for container size to settle down is not good (hardcoded wait time).
- the code did not account for device-pixel-ratio, so it's quite a futile effort.

Aside:  In the past, we used to take the same image url as the tiles, so the video poster would appear immediately from due to browser cache, but the quality is bad because the tile requested a much smaller size.

The embed wrapper was not going through the CDN either as a null `containerRef` was passed in.

## Change
Removed the container-size check and just request for 1280x720. Reasons for this size:
- On average, that would be the ballpark of the final calculated value anyway for the average screen (+DPR consideration).
- That seems to be the current suggested thumbnail size in most recommendations.
- Our YT Sync is grabbing a much smaller size anyway.
2022-06-16 15:18:15 -04:00
Rave | 図書館猫
70dad5e057
Notification menu patch (#1701)
* Add href links to notification menu entries

* Add href link to notification page

* 2nd try
2022-06-16 15:56:39 +02:00
mayeaux
4d849a4821
Revert "Add href links to notification menu entries (#1699)" (#1700)
This reverts commit 268130a913.
2022-06-16 15:22:45 +02:00
Rave | 図書館猫
268130a913
Add href links to notification menu entries (#1699)
* Add href links to notification menu entries

* Add href link to notification page
2022-06-16 14:42:16 +02:00
infinite-persistence
8006cf1bf9
Non-English homepage strings 2022-06-16 17:45:14 +08:00
infinite-persistence
3e5a9ba193
Rename: use-thumbnail --> use-get-poster
This disambiguates the other effect file called `use-get-thumbnail`, and is also clearer.
2022-06-16 12:04:52 +08:00
Thomas Zarebczan
5c939d0e32
Fix YT sync requirement 2022-06-15 10:56:16 -04:00
Anthony
c3fd7ab8d7 show poster on first audio file 2022-06-15 09:59:41 -04:00
Anthony
90c2272720 fixing first thumbnail bug 2022-06-15 09:59:41 -04:00
infinite-persistence
91e83760d4 Enable Sticky on the homepage
This excludes mobile and other scenarios handled by the `should*` variables.
2022-06-15 07:34:36 -04:00
infinite-persistence
e70ed61d4e OBR-hack: move AdsSticky up to make it load first
We are asking Outbrain to make it order-agnostic, but for now, we need to load the Sticky script first before the Banner script.

This is ugly code because the requirement is not obvious unless we put a bunch of comments, but I don't want to pollute `app/view.jsx`. Hopefully they can address this and we can revert in the coming days.
2022-06-15 07:34:36 -04:00
infinite-persistence
6c6aa7a117 AdsBanner: singleton script
Makes it play nice with AdsSticky, both of which uses the same `window.OBR` object.
2022-06-15 07:34:36 -04:00
infinite-persistence
b9af50dede
GoogleVideo: generate instead of fetch the content url (#1691)
Seeing performance issues.
2022-06-15 06:54:53 -04:00
mayeaux
bd9a6ac2bb
Bugfix live status state (#1689)
* fix bug and add some documentation

* Prevent is_live fetching when playing stream and going back to livestream page

Co-authored-by: Rafael <rafael.saes@odysee.com>
2022-06-14 09:33:56 -04:00
mayeaux
e6a563443e
Allow capture of name during adding of card (#1657)
* allow someone to save name during card signup

* regexp to not allow numbers or special characters

* add i8n string

* various touchups
2022-06-14 09:21:47 -04:00
Rave | 図書館猫
4ffec69f25
Mini-Player controls patch (#1688)
* Remove draggable component from mini player on mobile

* Replace draggable disabling method

* Clean code
2022-06-14 08:16:23 +02:00
infinite-persistence
363fe82050
Fix chromecast title handling (#1685)
Fixed the title that did not update from stale closure because we no longer re-initialize the plugin.

We still continue to sever the connection when switching sources for now (although videojs is now single-instance) due to a problem that stops the next remote playback after 5-10 seconds. Unclear whether it is the plugin problem or due to our changes (although I don't see this issue in their repo).
2022-06-14 00:34:35 -04:00
infinite-persistence
94d5c11a71
ChannelThumbnail: remove alt text to prevent from being used as search result (#1687)
1684

While Lighthouse suggests adding `alt`, I think it's just a recommendation that does not affect the Core Vitals score directly -- the large css plays a bigger role at the moment.

Also, these are more "decorative" than "functional", because one could click the channel name navigate.
2022-06-14 00:17:46 -04:00
Rave | 図書館猫
56de3fdd13
Add transform exception for lightbox modal (#1683) 2022-06-13 18:48:45 +02:00
Rave | 図書館猫
cf53fdbc92
Fix missing tile in full grid (#1682) 2022-06-13 18:27:04 +02:00
infinite-persistence
d3365d69f9
Playback-rate: fix popup behavior (#1650)
* Playback-rate: fix popup behavior

- Part of 1637 - invokes the popup menu when clicked.
- This also makes the button consistent with other `MenuButton`s, i.e. to invoke a menu popup when clicked instead of hovered.

* Adjust CSS

Co-authored-by: Raphael Wickihalder <raphael.wickihalder@odysee.com>
2022-06-13 15:55:05 +02:00
Rave | 図書館猫
d5b7f25191
Add cookie spaceman to gdpr banner (#1651)
* Add cookie spaceman to gdpr banner

* Add spaceman graphic to static

* Add graphic to STATIC_ASSET_PATHS

* Add cookie spaceman to gdpr banner

* Add spaceman graphic to static

* Add graphic to STATIC_ASSET_PATHS

* Hide spaceman on mobile

* Adjust gdpr container for medium screens
2022-06-13 15:29:13 +02:00
infinite-persistence
60f48b1a3b
Fix invalid claims ending up with status 500 (#1678)
## Issue
Due the `parseUri` not being used in a try-catch block, the thrown error surfaces all the way up and the 500 catch-all status was used.

The search console was been complaining about this for a while now. I've always thought "what's the problem here, you entered the wrong claim format", but now I realized it's about the error code.

## Change
`try-catch` the call as normal for that function, and return 404. We will still relay the error message it was.
2022-06-13 08:55:45 -04:00
infinite-persistence
075b8bcf62
Handle invalid /$/download and /$/stream with a 404 (#1676)
## Issue
- When `/$/download/:claimname/:claimId` is invalid, it results in a bad redirect loop that keeps requesting the same thing. Eventually it stops, though.
- When `/$/stream/:claimname/:claimId` is invalid, it results in a 302 page that simply says `Redirecting to .`, and is increasing in count in the search console.

## Fix
Return a 404 not found for these.
2022-06-13 08:35:24 -04:00
Rave | 図書館猫
f755423361
Change premium badge position on channel page (#1677) 2022-06-13 12:53:58 +02:00
Rave | 図書館猫
6690880241
Animate modals & improve layout on mobile (#1675) 2022-06-13 09:16:31 +02:00
Rave | 図書館猫
50fb15c7f2
Update notification menu (#1673) 2022-06-11 20:56:43 +02:00
mayeaux
2432cf2fe1
dont show quality selector with default quality on non transcoded (#1670) 2022-06-10 14:48:48 -04:00
Thomas Zarebczan
968db6652a
Fix crash on direct load (anonymous only?) 2022-06-10 13:12:57 -04:00
mayeaux
87c94e3c1c
Reuse videojs instance between video reload, return mobile UI plugin for iOS (#1512)
* add mobile plugin back on ios

* further touchups and fix ios

* finish mobile functionality

* dont show big play button on mobile

* remove logs

* proof of concept

* dont go full screen on rotate

* add back functionality

* replace dispose event with navigate away

* bugfix

* turn off show if you liked button and nag only on homepage

* add back old functionality

* ending event not working

* test here

* working but needs cleanup

* more player touchups

* bugfix

* add settings button on mobile

* more touchups

* more cleanups

* touchup loading functionality

* fix hover thumbnails

* touchup and eslint fix

* fix repopulation bug

* change recsys event name

* bugfix events

* change the way buttons are removed and added

* finish chapters button

* refactor to use videojs methods

* refactor to fix autoplay next

* ux touchups

* seems to be behaving properly

* control bar behaving how it should

* fix control bar on ios

* working on flow and eslint errors

* bugfix and flow fixes

* bring back nudge

* fix playlist button bug

* remove chapter markers properly

* show big play button

* bugfix recsys closed event

* fix analytics bug

* fix embeds

* bugfix

* possible bugfix for kp

* bugfix playlist buttons

* fix issue with mobile ui plugin

* fix firefox autoplay issue

* fix bug for play on floating player closed

* bugfix volume control for ios

* instantiate new player if switching between claim types

* fix flow and lint errors

* fix control bar not showing up when switching sources

* dispose old player if recreating

* bugfix save position

* reset recsys data between videos

* fix audio upload posters

* clear claimSrcVhs on reload

* bugfix errant image previews showing up

* reset player value of having already switched quality

* fix watch position not being used

* bugfix switching between sources not perserving position

* fix save position bug

* fix playlist buttons

* bugfix

* code cleanup and add back 5 second feature
2022-06-10 12:18:58 -04:00
Raphael Wickihalder
85cb741feb
Adjust chapter button width on mobile 2022-06-10 14:09:52 +02:00
infinite-persistence
2a83c7d8ec
GoogleVideo: fix contentUrl and add more metadata (#1659)
* GoogleVideo: add more metadata

* GoogleVideo: fix `contentUrl`

`contentUrl` needs to be the url of the video file itself, not the page or some redirect.  Copied the way the url is generated in the RSS code.
2022-06-10 07:22:09 -04:00
Raphael Wickihalder
86d311f45d
Another padding adjustment on mobile 2022-06-10 08:45:42 +02:00
Raphael Wickihalder
7807bd9dd2
Minor padding adjustment on channels page on mobile 2022-06-10 08:33:14 +02:00
infinite-persistence
4c804af02c
MediaSession: handle null thumbnail
The exception thrown was causing the rest of `onInitPlay` to not run, e.g. "Tap to mute" not appearing, etc.

Closes 1663
2022-06-10 14:10:45 +08:00
infinite-persistence
b12fe2192b
Notification-popup patch
- Rename components per filename changes.
- Fix missing React key.
- Add new strings.
2022-06-10 12:55:30 +08:00
saltrafael
c38e37cd38
Remove polling, still happen on channel pages (#1558) 2022-06-09 14:43:45 -04:00
Rave | 図書館猫
54ee4ee94a
Notification menu (#1652)
* Save notification menu prototype

* Add dynamic links

* Add timestamps

* Mark as seen on click

* Fix guest mode

* Fix discussion links & channel thumbnails

* Adjust some details

* Adjust theme

* Replaxe Menu with MuiMenu

* Fix Mui behavior & transitions

* Adjust Mui menu behavior

* Adjust some padding

* Fix read & see

* Clean code

* Adjust border on top notification

* Add case for comment replies

* Save

* Make alignment pixel perfect

* Clean code

* Adjust gif avatars, stickers & tips

* Add delete function

* Add delete icon hover effect

* Add outline to delete icon

* Fix seeNotification call

* Add case for empty notification listä
2022-06-09 10:29:56 -04:00
infinite-persistence
70695dfd3f
Move Google Video code into another file
html.js is getting messy, and we'll be adding more Google Video stuff
2022-06-09 14:09:52 +08:00
infinite-persistence
baf1058510
Homepage API: add ?format=roku support (#1655)
Formatting changes for Roku to parse the data properly.
`https://github.com/OdyseeTeam/odysee-homepages/issues/1570`
2022-06-09 00:53:58 -04:00
infinite-persistence
e5bea1d0c4
Switch to file-page ad until Adnim fixes the script
Also placed both tag ids in case one breaks again.
2022-06-09 10:07:36 +08:00
mayeaux
e43a44abdd
update yarn version (#1654) 2022-06-08 15:48:32 +02:00
Thomas Zarebczan
707140ccd8
Add missing app string 2022-06-07 16:38:19 -04:00
Rave | 図書館猫
8a16ca03be
Adnim patch (#1647)
* Fix adnim ads

* Adjust ad container width

* Change widget on mobile

* Fix 3 column grid

* Ad ad banner top bar

* Ad ad banner bottom bar on mobile

* Ad ad banner bottom bar radius on mobile

* Adjust ad banners on mobile

* Make some mobile adjustments

* Remove dbeug box

* Combine ad classes
2022-06-07 15:16:26 -04:00
Raphael Wickihalder
688ea696bd
Adjust player quality selector icon width on mobile 2022-06-07 15:09:26 +02:00
infinite-persistence
1ab140c192
ChannelThumbnail: fix quality typo + consolidate 'small' variant sizes
- Fixed quality typo
- Make all the 'small' variants use the same size for better caching.
2022-06-07 14:21:48 +08:00
infinite-persistence
4e35a2e5dc
i18n update 2022-06-07 12:12:23 +08:00
infinite-persistence
df0b65daf1
Volume Bar doc update and cleanup 2022-06-07 11:20:31 +08:00
infinite-persistence
f43577a2dd
Variable naming and doc cleanup
- The function name is good and self-documenting, so removed the redundant comment. Whether it's 'precise' or not, it could change in the future and not worth maintaining a comment like that.
  - Focused on the non-obvious reason for SHIFT key instead.

- Fixed "on scroll" variable naming since it is not just for scrolling (it applies to keyboard up/down too)
2022-06-07 11:19:55 +08:00
infinite-persistence
151749d4c3
LbryVolumeBarClass: add documentation 2022-06-07 11:09:03 +08:00
infinite-persistence
b921547386
Missing yarn.lock commit
This diff came up when building. Probably missed from the eslint update PR.
2022-06-07 10:33:20 +08:00
Thomas Zarebczan
cb06c10f0b
Help hints + channel removal 2022-06-06 16:53:36 -04:00
mayeaux
4893085ee3
bump eslint version (#1640) 2022-06-06 12:19:35 -04:00
mayeaux
045fc2c940
dedupe yarn.lock (#1639) 2022-06-06 11:19:50 -04:00
mayeaux
dcf9b1802f
Styling touchups for image previews (#1582)
* styling touchups for image previews

* update vtt-thumbnails commit hash
2022-06-06 10:28:06 -04:00
mayeaux
8aaa820e2f
Add volume control using scroll wheel from myzel, with flow errors fixed (#1638)
* created function

* removed console logs

* made volume change on mousewheel functional

* improved code

* added precise volume control

* updated behavior

* fixed error

* fix flow errors

Co-authored-by: myzel394 <50424412+Myzel394@users.noreply.github.com>
2022-06-06 09:37:44 -04:00
Rave | 図書館猫
c146ccc432
Resolve player icon hover conflict (#1637) 2022-06-05 15:06:11 +02:00
Rave | 図書館猫
e83d667b25
Player icons patch (#1636)
* Adjust player icon size & position on desktop & mobile

* Adjust control-bar position

* Fix chapter button offset
2022-06-05 13:32:21 +02:00
Rave | 図書館猫
2762d43224
Restructure header navigation (#1611)
* Restructure header navigation

* Hide theme button in guest mode

* Update channel selector width and navigation top in header
2022-06-03 09:43:31 -04:00
Rave | 図書館猫
81eddb2b5d
Publish revamp (Part 1) (#1593)
* Rearrange fields

* Autocomplete title

* Fix class position

* Hide deposit behind advanced settings

* Redesign additional options

* Redesign price section

* Update price section

* Redesign tags section

* Fix title edit

* Make with dynamic

* Redesign thumbnail section

* Redesign description section

* Resedign file section

* Polish sections

* Adjust help text

* Clear title on form reset

* Adjust price section

* Fix help color in light theme

* Polish

* Mobile adjustments

* More mobile adjustments

* Remove border-bottom from publish rows

* Redesign date section

* Adjust some details

* Adjust clear button

* Adjust channel selector on mobile

* Adjust post save button position

* Adjust browse button color

* Adjust channel picker on mobile

* Eenable announcement page

* Remove file title, remove space, redesign licence section

* Fix edit form, existing claim warning, missing title warning

* Adjust light theme

* Adjust icon collor in button
2022-06-03 09:28:12 -04:00
dependabot[bot]
9dc03d816a Bump protobufjs from 6.11.2 to 6.11.3 in /web
Bumps [protobufjs](https://github.com/protobufjs/protobuf.js) from 6.11.2 to 6.11.3.
- [Release notes](https://github.com/protobufjs/protobuf.js/releases)
- [Changelog](https://github.com/protobufjs/protobuf.js/blob/v6.11.3/CHANGELOG.md)
- [Commits](https://github.com/protobufjs/protobuf.js/compare/v6.11.2...v6.11.3)

---
updated-dependencies:
- dependency-name: protobufjs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-03 01:57:01 -04:00
Thomas Zarebczan
547781c07c
Update messaging around bitrates / resolution
Allow for higher bitrates, but still recommend transcode over 8mbps until we have transcode on upload.
2022-06-02 14:47:50 -04:00
Thomas Zarebczan
37d9db9cf2 not sure why this has to be the same
otherwise it just shows the premium driver...tried a few things, and it seemed to work fine like this. Maybe due to some cleanup/styles, etc
2022-06-02 13:02:38 -04:00
Thomas Zarebczan
328c8938c6 Use separate ad for file pages 2022-06-02 13:02:38 -04:00
infinite-persistence
70ddd08df6 Show Sticky in Content and Channel Page for incognito
https://odysee-workspace.slack.com/archives/C02G20Z2AEL/p1654171314724029?thread_ts=1654089384.715699&cid=C02G20Z2AEL

Content: not showing ads for signed-in users because it interferes with commenting.

Channel: same behavior as Categories (i.e. show is not Premium+).
2022-06-02 10:49:42 -04:00
infinite-persistence
9787940bc8 Make MODALS.CONFIRM not dismissed when out of focus
Clicking OK or cancel will be the only way to dismiss this modal.
2022-06-02 10:40:19 -04:00
infinite-persistence
0fb27e7c48 Also apply timeout msg to wallet_send 2022-06-02 10:40:19 -04:00
infinite-persistence
16da04e6b9
SnackBar: pause dismiss timer when mouse is over it 2022-06-02 15:56:45 +08:00
infinite-persistence
d89e04942b
Tweak tip/boost toast message
- Split the friendly text (non-essential) to `subMessage`.
- Put a link to the wallet history for all these tipping toasts.
- Don't say "tip" for the Wallet Send action (Issue_1605)
- Make the link font-size smaller than the main text.
2022-06-02 15:36:05 +08:00
infinite-persistence
f69097b488
Don't block entire router while fetching Categories
This is a follow up for 2b60fe95

## Issues
- Not every page needs the Category data, so only block for Category pages.
- `categoryPages.length` was rendered as a number while blocking for the fetch.

## Change
It's a chicken-and-egg thing because we don't know what the category path is, but fortunately categories and internal pages start with `/$/`, so we can make a reliable guess. The other internal pages would have matched the defined routes and would not reach this function.
2022-06-02 14:11:52 +08:00
infinite-persistence
c677f69c60
CONTRIBUTING.MD: remove electron and other app references 2022-06-02 14:11:09 +08:00
infinite-persistence
227b6e3011
DiscoverPage: re-org, no functional change
- Avoid double loop in `isFollowing` (map + includes).
- Move calculations into functions, as most of the variables are only single-purpose. This makes it easier to find things and tweak. Only shared variables need to be at the top.
- Re-org to 'vars -- funcs -- effects -- return' file structure.
2022-06-02 13:28:15 +08:00
Raphael Wickihalder
c3aaadf4aa
Adjust space between icon and menu in player 2022-06-01 19:49:50 +02:00
Raphael Wickihalder
1b84ac0268
Adjust player playlist icons 2022-06-01 19:41:49 +02:00
Raphael Wickihalder
1efa54c121
Fix player button alignment 2022-06-01 19:38:58 +02:00
Raphael Wickihalder
eeda485bb4
Adjust player icons 2022-06-01 19:23:16 +02:00
Raphael Wickihalder
8a5cf5f71b
Adjust timestamp position 2022-06-01 18:35:40 +02:00
Rave | 図書館猫
c775072e7e
Realign & adjust player icons (#1621) 2022-06-01 18:25:37 +02:00
infinite-persistence
331ae641d0
No sticky in mobile, and only show in Category.
## Code changes
- Switch from blacklist to whitelist.
2022-06-01 21:58:29 +08:00
Thomas Zarebczan
5fe5f7599f Revert "DRY: fix duplicate code for Recommended key generation"
This reverts commit 05376490a8.
2022-06-01 09:55:56 -04:00
Thomas Zarebczan
4cf531b8ad Revert "Recommendations: factor out a selector for raw results"
This reverts commit 2edf1ca564.
2022-06-01 09:55:56 -04:00
Thomas Zarebczan
b6eb580c82 Revert "Recsys: determine the clicked index based on raw results instead of rendered order"
This reverts commit e4214b1c1b.
2022-06-01 09:55:56 -04:00
Raphael Wickihalder
6ee3b34b10 gdpr-theme 2022-06-01 09:13:53 -04:00
infinite-persistence
32f0d1d7a1 Tip: show modal instead of toast when timeout
## Issue
The toast wasn't good enough as the user might miss it and attempt to re-send.

## Change
- Change the tip timeout from Toast to Modal.
- For the case of Comments, add additional info about being unable to re-link the txid to the comment for now. Not really useful to the user, but better than nothing.
2022-06-01 08:40:39 -04:00
infinite-persistence
cfa59507ba doSendTip: pass the err back to the callback
No real users for now, but an error callback so should do that.
2022-06-01 08:40:39 -04:00
infinite-persistence
e4214b1c1b Recsys: determine the clicked index based on raw results instead of rendered order
## Ticket
1606

## Issue
The displayed order of the recs are often re-adjusted -- viewed content are pushed to the bottom to avoid auto-play-next from picking it up again. This was causing recsys to be confused, because the click order does not correspond the results.

## Change
Refactored the selector we can grab the raw results and use that as the index reference.
2022-06-01 08:32:37 -04:00
infinite-persistence
2edf1ca564 Recommendations: factor out a selector for raw results
1606
2022-06-01 08:32:37 -04:00
infinite-persistence
05376490a8 DRY: fix duplicate code for Recommended key generation
Must use `getRecommendationSearchOptions`, otherwise there is a chance of some clients deriving the wrong key.
2022-06-01 08:32:37 -04:00
Rave | 図書館猫
67d0655314
Adjust toggle buttons in modal (#1615) 2022-06-01 12:39:32 +02:00
Rave | 図書館猫
0a3d47edce
Design patch 22 06 01 (#1613)
* Adjust autofill icon color
2022-06-01 09:26:36 +02:00
Raphael Wickihalder
78509a92c4 Fix close button in footer banner 2022-06-01 13:13:49 +08:00
infinite-persistence
d5910c8172
Fix sticky not reliably opening when navigated into page
## Issue
Stickly loads fine when Category Page is opened directly (F5, open), but doesn't load if F5 was at Homepage and then navigated into Category Page.

## Root
There is a bug where AdsSticky cannot be loaded on a page where AdsBanner exists. As long as AdsSticky is loaded in a page without AdsBanner, they both can still be visible together later, says from navigating around.

## Temp fix
Adding inAllowedPath to the logic is a band-aid that relies on AdsBanner only being used in Homepage for now, which we currently happen to not place AdsSticky.
2022-06-01 12:48:14 +08:00
Thomas Zarebczan
487d5c4a86
Add twitch sticker 2022-05-31 15:47:03 -04:00
Raphael Wickihalder
d66bd72b22
Adjust meme position 2022-05-31 18:46:02 +02:00
Rave | 図書館猫
2baddb1b1e
Adjust meme text spacing & fix ad tile title size (#1602) 2022-05-31 17:37:10 +02:00
Myzel394
d4f2236ea3
fixed nudge styling (#1597) 2022-05-31 17:04:43 +02:00
Raphael Wickihalder
a4834706e3
Adjust meme text margin bottom 2022-05-31 17:02:44 +02:00
Anthony
9b2cc7eb79 dont show subs for ios and correct position for actual subs 2022-05-31 10:41:31 -04:00
infinite-persistence
0bcea943d5 Re-implement/enable sticky ad
## Ticket
1583: "add incontent ads to category/channel pages (break up every X claims?), or add back bottom ad in those areas."

## Behavioral changes
- Hide when in homepage (as currently we have ads between categories).
- Fix the light theme (it was transparent).

## Code changes
- While an Effect is the 'right' choice given that there is no jsx to mount, the need to prop-drill from the parent was getting a bit annoying, so converted to a Component instead.
- Remove the delay for Core Vitals avoidance for now -- seems to make the sticky less likely to serve an ad.
- Now that the membership state is correctly populated for incognito (see 9d830615), there is no more need to check for `isAuthenticated`.
2022-05-31 10:34:38 -04:00
infinite-persistence
4ea6b848d1
Fix stray floater in mobile
Oddly, it only appears in Channel Page, not the Home Page. Should be the same thing...
2022-05-31 18:39:14 +08:00
infinite-persistence
a2f15b8348
Player: fix i18n for 'Auto' 2022-05-31 18:12:51 +08:00
Rave | 図書館猫
ea3d8e01ef
Design patch 22-05-31 (#1598)
* Redesign form elements with background

* Adjust list ads

* Fix progress bar in mini player

* Fix progress bar on mobile

* Fix progress bar in theater mode

* Redesign repost modal

* Update channel selector in modal

* Remove border radius from embedded media

* Adjust quality selector

* Adjust updated player theme for light mode

* Rename wrapper class
2022-05-31 11:14:59 +02:00
Raphael Wickihalder
9779c19e88
Fix grid with adnimation (#1584) 2022-05-31 10:39:59 +08:00
Raphael Wickihalder
9eda81db58 Replace state with ref for uriBuffer 2022-05-31 10:38:39 +08:00
Raphael Wickihalder
99a36b6bd6 Clean code 2022-05-31 10:38:39 +08:00
Raphael Wickihalder
c6c824c059 Fix grid with adnimation 2022-05-31 10:38:39 +08:00
infinite-persistence
29431b1074
Revert "Test 'Rich Test' error screenshot"
This reverts commit 8f35f53e7a.
2022-05-30 22:50:40 +08:00
infinite-persistence
8f35f53e7a
Test 'Rich Test' error screenshot
Verifying whether the result screenshot for errors are cached.
2022-05-30 22:28:22 +08:00
infinite-persistence
142d6e0af0
Ad: missing in incognito (1592) 2022-05-30 19:15:12 +08:00
infinite-persistence
9d830615fd
Fix user membership state for incognito.
Run the membership reducer even for incognito.

The GUI needs to differentiate between 'unfetched' (`undefined`) and 'no membership' (`''`), so we must call the action/reducer for the incognito case as well.
2022-05-30 19:03:21 +08:00
infinite-persistence
deb95cd443
Fix stale-closure in ad-detection code
Using that global variable was a bad idea. Stick to redux as the source of truth.

The flag is not listed for rehydration, so it will always start off as `undefined`, which is what we need anyways.

`undefined` indicates we haven't tested for ad-blockers, so we'll run the fetch and update the store with a true|false value.
2022-05-30 19:03:20 +08:00
infinite-persistence
1768e4a5cd
Remove vidcrunch hacks
These are mostly supression of the video floaters.
2022-05-30 16:01:38 +08:00
infinite-persistence
9ff88ecdd1
Ad: fix stray video floaters outside our container.
This was tested to be removed during evaluation, but seems like there are cases where it comes back.

This solution should be more robust: hide for all, except when in our designated container.
2022-05-30 15:55:20 +08:00
infinite-persistence
530433b508
Ad: premium+ check (1589) 2022-05-30 14:17:01 +08:00
infinite-persistence
7dc9c983f8
resolveAdVisibility: wait for premium+ (a fetched status) 2022-05-30 14:15:28 +08:00
infinite-persistence
bd7d2ad621
Revert "Fix ads near recommended on Premium"
This reverts commit f56e552764.

Would like to consolidate logic into resolveAdVisibility, so the fix should be there instead.
2022-05-30 14:15:27 +08:00
Raphael Wickihalder
8b1927b5dd
Move channelTitle to view 2022-05-30 07:27:41 +02:00
Raphael Wickihalder
e4db2d401b
Remove channelName prop 2022-05-30 07:15:07 +02:00
kt programs
c16fb8c906 Fix spelling of SORT_ASCENDING in search constants 2022-05-30 12:04:20 +08:00
infinite-persistence
ba62170ef7
Don't limit livestreams for Following section
https://odysee-workspace.slack.com/archives/C02G20Z2AEL/p1653779545610999
2022-05-30 11:21:33 +08:00
Raphael Wickihalder
a7bbb464d6 Clean code 2022-05-29 09:18:57 -04:00
Raphael Wickihalder
ca135cc7f8 Integrate media session api 2022-05-29 09:18:57 -04:00
Raphael Wickihalder
2b60fe957f Get rid of 'content not found' page in categories 2022-05-29 09:11:35 -04:00
Thomas Zarebczan
f56e552764
Fix ads near recommended on Premium 2022-05-27 15:28:09 -04:00
infinite-persistence
4d7f1c1d42
Adnimation #1447 2022-05-27 20:54:50 +08:00
infinite-persistence
003992e5c6
Add new list of ad configs
Still remain using the 5-tile banner-ad, though. There are theme and other issues with the rest.
2022-05-27 20:49:57 +08:00
Raphael Wickihalder
816c0d9e79
Fix ob-widget position 2022-05-27 20:49:57 +08:00
infinite-persistence
c71c8e1cd0
Remove bottom-ad for now
- Light theme issues
2022-05-27 20:49:56 +08:00
infinite-persistence
c66f597f09
Fix accumulation of ad <style> tags 2022-05-27 20:48:54 +08:00
infinite-persistence
8303856a06
Remove country check
Per Tom, this was just a temporary thing due to vidcrunch.
2022-05-27 20:48:54 +08:00
infinite-persistence
3557e72419
Remount banner on theme-change as their ad can't change theme on the fly.
It would be nice if the individual components can handle the remounting of the ad-script, but there is currently a need to synchronize the cleanup of the `window.OBR` object.

The quickest solution for now is to add a key at the parent side to synchronize the mount-unmounting. Not ideal -- revisit later.
2022-05-27 20:48:53 +08:00
infinite-persistence
551c13251a
Update AR_6 to AR_18
- This increases the amount of ads, filling up the entire width. No more need to restrict with `max-width` ourself.

- Changed the ad-driver to top-right since the "Powered by Outbrain" text is now locked in bottom-right. Also made the container having a minimum height, as the method to "display the driver after ads are loaded" is not future proof -- it depends on the IDs being used by the ad. Reserving some space seems to be easiest, and it also reduces shifts as well.
2022-05-27 20:48:53 +08:00
infinite-persistence
bf7dcbe344
Bottom-Ad: change to only hide for Premium+
Previously, we hide when authenticated.

We still need the `isAuthenticated` flag, because `hasPremiumPlus` stays at the unfetched (`undefined`) state for Incognito.
2022-05-27 20:48:52 +08:00
infinite-persistence
4ae3fe7ea0
Make Category & Channel pages re-fill ads after scrolling every 2 pages 2022-05-27 20:48:52 +08:00
infinite-persistence
327a574982
Create banner ads and add to homepage
## Behavior in homepage
- Mobile: show after every other category
- Desktop: show after first category, then every 2 categories.

## Known issue:
- "FYP" is not part of the categories array at the moment, so it does mess up the behavior.

## Notes
I think this is also called "in-content" by adnim (not 100% sure of the terminology).
2022-05-27 20:48:51 +08:00
infinite-persistence
b1dbac8f9b
Factor out ad-blocker detection into useShouldShowAds
... for it to be re-used on other ad components.
2022-05-27 20:48:51 +08:00
infinite-persistence
6576e8317e
Replace Vidcrunch with Adnimation 2022-05-27 20:48:50 +08:00
infinite-persistence
b8cf1a6c4c RSS: parallel-fetch the stream urls
## Issue
Users are seeing timeout with the RSS calls.
But oddly, odysee.com is significantly slower than the dev instances.
2022-05-27 08:38:18 -04:00
infinite-persistence
7504cf07b3
Geoblock: fix anonymous claims passing through
My bad, added an unnecessary check in the previous change that shorted the logic too early.

Accessing an object using 'null' or 'undefined' as the key won't cause trouble (and is expected in this case), so just suppress flow instead of fixing it using
  `channelId && geoBlockLists.livestreams[channelId]`

https://github.com/OdyseeTeam/odysee-frontend/issues/1100#issuecomment-1138928520
2022-05-27 12:51:47 +08:00
infinite-persistence
f0bf6fa9a0 Homepage: limit livestreams in categories to 3 ...
... but leave Following as "no limit"

The primary reason for this case is due to News and Wild West having lots of livestreams. But instead of just applying the limit to these 2 and polluting the loop, just limit it for all Categories.
2022-05-26 10:59:31 -04:00
infinite-persistence
cc0ed44bf6 Homepage: add "reset" + 'hideByDefault' categories
Requires a related commit from the homepages repo.

## Changes
- Add ability to reset the sort order.
- Make 'News' and 'Wild West' a "hideByDefault" category. It can be made visible in the homepage from the customization dialog.
2022-05-26 10:59:31 -04:00
Thomas Zarebczan
786d9d0253
optimize premium image + add smaller 2022-05-26 09:22:23 -04:00
infinite-persistence
a73694deb4 Fix localStorage crash
## Ticket
1572
Always check for availability before use.

## Changes
- Consolidated the keys into one place for easier tracking.
  - It'll also be easier to code using constant autocomplete.
- Cleaned up the wrapper to be as close as the original.
- Updated existing code to use the wrapper (even if they already handled the availability) to encourage future code to just use the wrapper.
2022-05-26 08:27:35 -04:00
infinite-persistence
3ed05e62a5 Resolve: store repost's original channel too
## Issue
- Closes "1535 bunch of channels (from featured?) resolved on page load"
- It was due to the use of reposts in the Category. As we did not store the repost's original channel claim, `ChannelThumbnail` couldn't find the author and requested a separate `resolve`.

## Change
Store the repost's original channel claim as well.
2022-05-26 08:00:58 -04:00
Rafael
11bdb6a872 Fix wait for prefs on default channel set 2022-05-25 11:52:48 -04:00
Rafael
1dccc1ac64 Fix uploads page cleared/reloaded on each navigation 2022-05-25 09:10:24 -04:00
infinite-persistence
58167210ea Geoblock: show warning for own content
## Issue
Contents aren't block if you own them, but need to tell creator that is it blocked for others.

## Change
- Show a banner on Content and Channel Page for this scenario.
- Hover tooltip is available for the full text. For mobile, tapping it reveals the message.

Note that this only applies to the locale from where the creator is viewing it from. We can ignore locale, but would then need to display _all_ geo-restrictions related to the content in a list.
2022-05-25 08:51:08 -04:00
infinite-persistence
a4add6eab6
Fix geoblocked items appearing in wunderbar suggestion popup
This list is not using ClaimPreview or ClaimPreviewTile, so the filtering was missed.
2022-05-25 14:37:09 +08:00
infinite-persistence
4aa94a7bfd
Fix variable name confusion
Per convention, 'ByUri' would mean it's the array/object that is storing the entire list, but this is actually the specific entry.
2022-05-25 14:30:41 +08:00
Anthony
58270ab758
Fix hover bug on iPad requiring double click (1545) 2022-05-25 09:22:03 +08:00
Anthony
b1516a904d fix list view 2022-05-24 13:55:30 -04:00
Anthony
26bde0a390 fix list view and allow s pen to use 2022-05-24 13:55:30 -04:00
Anthony
ca1515bfa3 fix hover bug on ipad needing double click 2022-05-24 13:55:30 -04:00
infinite-persistence
6d6d95237a 1318: Persist recsys data for send after tab close
- Add ability to store `entries` into Redux.
- Sync to redux in the same interval as when playing position is saved (re-use timer).
- On startup, send any stashed entries and clear them.
2022-05-24 13:52:50 -04:00
infinite-persistence
ac44b771ff 1318: Remove 'visibilitychange' listener
Per 1318, we will only be sending data when user is done with a content, so this listener is no longer needed.

I think it was also not needed when we removed the beacon usage (it's mostly to prevent data loss when beacon is used), but we didn't remove it back then to avoid changing too many things and affecting the dataset.
2022-05-24 13:52:50 -04:00
infinite-persistence
13729a2ed4 Comment: filter geo-restricted channels 2022-05-24 12:53:40 -04:00
infinite-persistence
426d1ea0c9 Factor out geo-restriction logic
No functional change.

Impetus is to make the logic re-usable for comment-blocking.
2022-05-24 12:53:40 -04:00
infinite-persistence
ce9a1c128c
Show-page: fix "no content found" flicker (#1546)
* Show-page: split out some effects

Break apart the large effect for easier tweaking, abiding by the 1-action-per-effect guideline.

This also fixes the dependency list. After checking with Haffa, the exclusion of `pathname` and `hash` from the list is probably to avoid hitting `doResolveUri`. This should no longer be an issue after the split, so no suppression needed.

* Show-page: fix "no content found" flicker

## Issue
1539: "Recently been seeing a flicker of "content not found" when direct loading content or channel links on mobile"

## Cause
`doResolveUri` can only be called after the initial mount (in the effect), so at first render, `isResolvingUri` won't be set yet, so we briefly ended up in the "no content found" path.

## Change
Factor out the logic that determines if we should send `doResolveUri`. This allows us to know that the upcoming effect will be sending `doResolveUri`, so we can hold off displaying "no content found".

* Show-page: don't delay the spinner when resolving

## Reason
The delay causes a blank page + footer, which looks bad.
2022-05-24 06:39:21 -04:00
infinite-persistence
2a0e802f10
Upgrade video.js to 7.19.2 (#1550)
This includes the desired latest `http-streaming`, so no more need to do custom `resolutions`.
2022-05-24 06:27:12 -04:00
saltrafael
f9d1b8de8e
Automatically set default channel on sign up (#1559) 2022-05-24 06:18:26 -04:00
saltrafael
3918906605
Remove clearPosition functions for playlists (#1560)
- Let the position be cleared at the end like regular videos
2022-05-24 06:07:46 -04:00
infinite-persistence
e3e675455a
Recsys: add flow and fix uncovered issues 2022-05-24 14:58:52 +08:00
infinite-persistence
d5c964c208
Additional geoblock support (#1552)
* Remove claim from channel page when geoblock conditions hits

Ticket: 1100

* Handle geoblocked channel page

## Ticket
1100

## Issue
"If a channel is geoblocked, the entire channel page (even showing titles, etc. would be against the law)"
2022-05-24 00:15:18 -04:00
Rafael
600d9a0f94 Fix Drag-and-drop error 2022-05-23 14:31:43 -03:00
saltrafael
b854e32f5c
Fix comment sort change (#1556) 2022-05-23 11:34:32 -03:00
infinite-persistence
cf700c3627 Comment: remove the muted prop
Since the comment list is pre-filtered and includes the muted list, I think this prop will never be true?
2022-05-23 18:37:19 +08:00
Rave | 図書館猫
d207117e5d
Grid patch v1 (#1555)
* Patch v1
2022-05-23 11:32:57 +02:00
infinite-persistence
7d1992d541
Handle CUSTOM_HOMEPAGE=false
This one's been broken for a while, but should only affect `yarn dev-server` and those who does not have access to the homepages.
2022-05-23 15:40:41 +08:00
infinite-persistence
ceca6e3b84
Handle missing announcement file in dev-server 2022-05-23 15:30:40 +08:00
infinite-persistence
8c06dab10f
ClaimPreviewTile: fix render violations and onHidden logic
## Issues
- Not safe to call the parent callback from the render function. It must be called from an effect or
- `onHidden` is only called when blacklisted, but it can also be hidden from other circumstances.
  - While those other circumstances doesn't apply for FYP (the first client that relies on `onHidden`, it's incorrect from a code perspective, unless it is renamed to `onBlacklisted`.

## Change
- Move the callback execution into an effect.
- Ensure `onHidden` is for all situations that it is hidden.
2022-05-23 14:49:53 +08:00
infinite-persistence
cde0c0b2a8
ClaimPreview: restructure
Try to gather the hide/show logic
2022-05-23 14:49:52 +08:00
infinite-persistence
287eb38e7a
ClaimPreviewTile: restructure (no functional change)
Effects cannot be defined after the render function returns early, so it was not possible to add new effects when the derived variables that it depends on are way down below.
2022-05-23 14:01:54 +08:00
infinite-persistence
104dafc1e7
Clean up @odysee membership channel definition 2022-05-23 10:53:24 +08:00
infinite-persistence
8eb6ffd2b9
Rename 'community_channels.js' -> 'channels.js' for re-use
Re-using this file to put more hardcoded channels.
2022-05-23 10:53:23 +08:00
infinite-persistence
676f461a9f
Hide membership debug logs behind a flag
General error logs are ok, but not logs like these ... not helpful for other devs.
2022-05-23 10:53:22 +08:00
infinite-persistence
8e08320e7d
'Show less livestreams' -> 'Show fewer livestreams'
https://discord.com/channels/721806979928162404/936318782085935155/977673908222320670
2022-05-23 10:20:59 +08:00
infinite-persistence
2803323524
Remove relative paths in sass (#1540) 2022-05-20 09:07:32 -04:00
Rafael
e045d7a2ad Fix iframe class 2022-05-20 09:36:29 -03:00
saltrafael
6136ae7d73
Fix touch overlay max-height on mobile (#1541) 2022-05-20 08:23:37 -04:00
infinite-persistence
178b0d751d
astronaut_n_friends.png: fix src and caching
1. Hardcoding breaks any image changes done on dev instances or locally.
2. The relative path is bad, and there are few more instances of it. But continue as is for now, will file a ticket to fix this.
3. Fix caching.
2022-05-20 19:04:35 +08:00
Thomas Zarebczan
38d3fa1186
Oops 2022-05-19 18:13:19 -04:00
Thomas Zarebczan
07b9b2feed
Fix rss URLs for mp4s 2022-05-19 17:54:53 -04:00
Thomas Zarebczan
9a247d3c9f
Mature fixes 2022-05-19 17:40:31 -04:00
saltrafael
28b9e2a4d3
Fix fetch behavior when switching claims (#1533) 2022-05-19 13:54:45 -04:00
infinite-persistence
581ae13c3f
Announcements framework (#1494) 2022-05-20 00:36:29 +08:00
infinite-persistence
14a11aa78a
Clear announcement history using window.clearLastViewedAnnouncement()
This helps testing, and can be eventually removed. No harm leaving it there, though.
2022-05-20 00:04:07 +08:00
infinite-persistence
d70f0f1d6d
Add "What's New" button in the Help Page
This allows user to re-access the modal if they accidentally dismissed it, never got it (bug?), or simply just want to see it again.
2022-05-20 00:04:07 +08:00
infinite-persistence
3719a73c81
Add announcement modal and open it after prefs sync'd.
- Don't want to show it in Incognito.
- Only show it in when entered from homepage, or in the Help page.
- Record the hash of the viewed announcement and update the wallet with it.
2022-05-20 00:04:06 +08:00
infinite-persistence
79eb28cc55
Add 'lastViewedAnnouncement' into wallet.
This stores the hash for the last viewed announcement.

The intention is so that the announcement won't re-appear when logging into another device.

However, this does mean that announcements would need to wait until the first sync to decide whether to appear or not, which can be quite a delay.
2022-05-20 00:04:06 +08:00
infinite-persistence
245eb39892
Add 'announcement' to v2 homepage api
This requires an accompanying commit in the homepages repo (see "Add announcement support").

Using `raw-loader` to import markdown files as a string works for the app-side, but didn't work well in web-side. Falling back to copying the announcement files to `dist` and reading them via `readFileSync`. Don't really like this -- will return with an alternative.
2022-05-20 00:04:05 +08:00
infinite-persistence
b5dd24ff56
ModalRouter: change dispatch map to object
Moving away from the function version to the object version. Trying to track down why the effect that closes the modal ran when the pathname did not change. My only guess is the unstable hideModal reference due to the function mapping. There is no customization needed, so the object version is preferred anyways.

`doOpenModal` isn't used, so I just removed that.
2022-05-19 23:56:34 +08:00
infinite-persistence
5e3effc94d
Wrapper for localStorage 2022-05-19 23:56:33 +08:00
infinite-persistence
b733215c5f
PublishFile: fix render function violation (#1518)
* PublishFile: fix render function violation

Per doc:
> A React component should not cause side effects in other components during rendering.

Even in own render function (allowed to call), it should be avoided as it could cause infinite loops.

* PublishFile: fix useEffect infinite loop due to bad dependency

## Issue
One of the effects was adding an internal wrapper function as a dependency. As this is a functional component, the wrapper is re-created on every render and would spark the effect. That effect also updates redux (depending on the code path), so we end up in a loop.

## Change 1
Two options to fix the dependency:
1. Just remove the wrappers from the list, since we "know" it is essentially the same function (i.e. it's not function-variable that could point to something else at runtime).
2. Peek into the wrapper and determine what are the actual dependencies (usually props or data derived from props).

Solution 2 is the norm.

Aside: wrappers are usually the root-cause of incorrect dependencies, because they mask away the actual code. Need to always peek into it.

## Change 2
Next, change the dispatch-to-props map from function version to object version so that we have stable references to the actions. The object version is also preferred when we don't need to make any customizations to the actions.
2022-05-19 10:41:32 -04:00
saltrafael
0998e3d48c
Support stream updates via claim_id parameter (#1465)
* Support stream updates via claim_id parameter

* Pass claim_id on v2
2022-05-19 08:13:48 -04:00
Rave | 図書館猫
4c25ae721e
Outside us v2 (#1530)
* Disable ads outside the US (again)
2022-05-19 07:38:27 +02:00
infinite-persistence
64225d2b80
Fix selector naming convention
ByUri - returns the storage variable (array or object).
ForUri - returns the specific entry in the storage variable.
2022-05-19 13:10:37 +08:00
infinite-persistence
f245f09d1c
Revert "Temporarily prevent invalid get calls until we figure it out" (#1529)
This reverts commit f6f15531d4.

The root-cause was known (8dd0982f), and I don't think it worked because:
1. The issue happened at the web side which didn't have logging.
2. The `[object Promise]` came after the `get`, not before.
2022-05-18 20:37:53 -04:00
mayeaux
bb065eb408
dont run image preview on mobile (#1527) 2022-05-18 16:50:30 -04:00
Rave | 図書館猫
746d321dfe
Remove Premium+ Tiles when Premium+ is active (#1525) 2022-05-18 20:51:15 +02:00
infinite-persistence
8dd0982f33
Fix bad stream url redirect. (#1524) 2022-05-18 14:32:22 -04:00
Rafael
c46184e6b3 Add bottom right desktop chat resize indicator 2022-05-18 14:53:17 -03:00
infinite-persistence
53079d92b6
Move PremiumPlusTile into Ads (#1522)
* Move `PremiumPlusTile` into `Ads`

This saves the need to repeat the logic everywhere.

* Add option to disable fallback.
2022-05-18 19:52:46 +02:00
infinite-persistence
855d3dae01
ClaimList: fix infinite effect loop (#1523)
`tileUris` is being used as an effect dependency, but it gets re-created on every render (same content, different reference), so the `setUriBuffer` effect ended up in a loop.
2022-05-18 13:30:07 -04:00
saltrafael
b0b2056d78
Allow chat to be resized (#1517)
* Allow drawer to be resized

- Basically re-writes the drag behavior into the Drawer component instead of using SwipeableDrawer, getting more flexibility of where to stop and what to do
- More improvements like the backdrop effect, animations and window resize behavior

* Fix console errors

* Close drawer on unmount so other pages dont load open

* Allow livestream chat to be resized horizontally

* Fix mobile browser size

- address bar etc could be on the way

* Handle popout chat

* Fix pause with floating player
2022-05-18 12:15:12 -04:00
mayeaux
0cf8c181df
Preview image thumbnails (#1514)
working example

use my forked package

touchups to presentation

Make progress bar thumbnail sprite pixel perfect

add vtt path

fix progress bar a bit

add a black background

use odysee team package

fix two issues for merge
2022-05-18 18:02:02 +02:00
infinite-persistence
a53250395f
Strings from grid update 2022-05-18 22:45:00 +08:00
Raphael Wickihalder
77163f5aec
Fix footer ad on mobile 2022-05-18 16:26:10 +02:00
Rave | 図書館猫
c16516fab5
Show premium ads for users outside the US (#1521) 2022-05-18 10:05:58 -04:00
Rave | 図書館猫
ffdb5abf63
Tile Grid Revamp (#1502)
* Save

* Save

* Add pulse

* Adjust footer ad

* Adjust tile ad

* Adjust tile ad hover

* Fix premium badge alignment in tile grid

* Adjust livestream icon

* Adjust livestream icon

* Save scheduled livestreasm & tile ad

* Fix scheduled callback

* Fix playlist icon size on file page

* Fix grid distortion in 3 & 4 column layout

* -

* Fix grid on category & channel page

* Fix Premium Plus Grid

* Add custom tile for adblockers

* Reset env

* Remove collapsed tiles

* Remove setLoaded on scheduled livestreams page

* -

* Make isHidden optional

* Remove px

* Review adjustments

* Inject Premium+ ads

* Fix injection

* Fix injection when using the last tile

* Fix injection when using the last tile

* Enable stripe dev

* Create PremiumPlusTile component and add list view design

* Create PremiumPlusTile component and add list view design

* Adjust ads in list view

* Remove setState from render loop

* Clean code

* Fix livestream margin in list view

* Rewrite & tune some logic - Homepage & Channel page

* Clean details...

* Clean details...

* Requested review changes

Signed-off-by: Raphael Wickihalder <raphael.wickihalder@odysee.com>

* Requested review changes

Signed-off-by: Raphael Wickihalder <raphael.wickihalder@odysee.com>
2022-05-18 13:16:35 +02:00
infinite-persistence
96e704e5d9
Fix ContentState type 2022-05-18 14:32:30 +08:00
Thomas Zarebczan
1d61d80009
more analytics + fixes (#1476)
more analytics + refactor

- passes player with time to start (until we move this api to watchman)
- supports livestream metrics for buffering
- fixes bug with buffering over 10 second period
- less head calls by moving to videojs-events

* review fixes
2022-05-17 10:47:44 -04:00
infinite-persistence
be7193382c
Fix remaining untranslated ctrls
Ticket: 1507
2022-05-17 16:33:11 +08:00
infinite-persistence
97be848554
videojs: refactor i18n (breaking up 'events' file)
## Issue
I couldn't find where the i18n went because the "events" refactor is just as confusing as the original -- unrelated things are still lumped together in a file.

Also, factoring based on events isn't useful -- it is features that drive what events are needed, not the other way around. This forces features to register events here, and do other things elsewhere? It will be more intuitive to have a one-file-per-feature structure.

## Change
Use existing frameworks to encapsulate things to manageable units/features:
(1) the React useEffect files (can be used isolate out React features like 'tap-to-mute' handling).
(2) the videojs plugins framework.
2022-05-17 16:17:04 +08:00
infinite-persistence
5e944499f3
Refactor "Theather Mode" 2022-05-17 16:16:39 +08:00
infinite-persistence
535d02807a
Refactor "Autoplay Next" 2022-05-17 16:16:38 +08:00
infinite-persistence
36ddc69c13
videojs: refactor i18n (breaking up 'events' file)
## Issue
I couldn't find where the i18n went because the "events" refactor is just as confusing as the original -- unrelated things are still lumped together in a file.

Also, factoring based on events isn't useful -- it is features that drive what events are needed, not the other way around. This forces features to register events here, and do other things elsewhere? It will be more intuitive to have a one-file-per-feature structure.

## Change
Use existing frameworks to encapsulate things to manageable units/features:
(1) the React useEffect files (can be used isolate out React features like 'tap-to-mute' handling).
(2) the videojs plugins framework.
2022-05-17 16:16:37 +08:00
infinite-persistence
ddc6c7ac98
Active channel strings 2022-05-17 09:41:42 +08:00
infinite-persistence
a2099482b0 Batch-resolve Watch History
## Issue
Doing individual resolves, even on a small list, is taxing.

## Change
Add infinite scroll and batch-resolve each page.
2022-05-16 07:57:24 -04:00
infinite-persistence
51616956d4 ClaimList: Factor out infinite-scroll and batch-resolve handling into an effect.
It's also possible to move the use of `useClaimListInfiniteScroll` into `claimList` itself, but opted to keep them separate for now so that `claimList` doesn't end up a bloated file like `claimListDiscover`.
2022-05-16 07:57:24 -04:00
Rafael
a4bb276608 Fix crash 2022-05-16 07:41:53 -04:00
Rafael
75df2a5f13 Also add RSS Url 2022-05-16 06:36:50 -04:00
Rafael
7c68fd1e61 Remove active livestream condition
- meaningless since its supposed to be a permanent link either way
2022-05-16 06:36:50 -04:00
Rafael
26d7e9a2b6 Add share buttons on channel page 2022-05-16 06:36:50 -04:00
Rafael
239bde0752 Also add support for embeds 2022-05-16 06:36:50 -04:00
Rafael
6b2427768c Add ability to link to latest or current live channel file pages
- and some changes to activeLivestream redux since it would return undefined if fetching and no claim, so now it returns null when no activeLivestream is found
2022-05-16 06:36:50 -04:00
Rafael
bf158ad696 Refactor
- some cleanups
- uri was being parsed the same way in different places, so do it only once for simplicity
2022-05-16 06:36:50 -04:00
saltrafael
b75a4014b6
Re-design comment threads (#1489)
* Redesign threadline and fetching state

- threadline goes right below channel avatar, mimicking reddits implementation, has a increase effect on hover and is slimmer, creating more space for comments on screen
- fetching state now replaces show/hide button, also mimicking reddit, and now says that it is loading, instead of a blank spinner, and also improves space a bit

* Redesign comment threads

- Allow for infinite comment chains
- Can go back and forth between the pages
- Can go back to all comments or to the first comment in the chain
- Some other improvements, which include:
- add title on non-drawer comment sections (couldn't see amount of comments)
- fix Expandable component (would begin expanded and collapse after the effect runs, which looked bad and shifted the layout, now each comments greater than the set length begins collapsed)
- used constants for consistency

* Fix replying to last thread comment

* Fix buttons condition (only on fetched comment to avoid deleted case)

* Fix auto-scroll

* Bring back instant feedback for Show More replies

* Improve thread back links

- Now going back to all comments links the top-level comment for easier navigation
- Going back to ~ previous ~ now goes back into the chain instead of topmost level

* Clear timeouts due to unrelated issue

* Fix deep thread linked comment case and more scroll improvements

* More minor changes

* Flow

* Fix commentList tile style

* Fix long channel names overflowing on small screens

* More scroll changes

* Fix threadline

* Revert "Fix long channel names overflowing on small screens"

This reverts commit e4d2dc7da5861ed8136a60f3352e41a690cd4d33.

* Fix replies fetch

* Revert "Fix replies fetch"

This reverts commit ec70054675a604a7a5f3764ba07c36bf7b0f49c8.

* Cleanup and make smooth

* Always use linked comment on threads

* Cleanup

* Higlight thread comment

* Fix comment body styles
2022-05-16 06:22:13 -04:00
infinite-persistence
f6f15531d4 Temporarily prevent invalid get calls until we figure it out
No analytics for the server side.
2022-05-13 12:08:28 -04:00
infinite-persistence
e0fee8cb25
Fix broken v1 homepage api
Due to 88740082
2022-05-13 20:48:34 +08:00
infinite-persistence
f79f346c94
Use get instead of generating the stream url (1499) 2022-05-13 20:31:54 +08:00
infinite-persistence
de206162f9
getHtml/routes/rss: fetch streaming_url instead of generating it.
## Issues from the initial attempt
- There are 2 versions of `Lbry` and `buildURI` -- the app and web-server version.  There are subtle differences between them, and for the app case, importing the web-server version results in a query into an invalid URL.
- It changed the function from returning a string to returning a promise.

## Changes
- Since the new function (renamed to `fetchStreamUrl` for clarity) is currently only needed for web-server, I moved it into the `web` folder to avoid misuse in app.
- Await on the promise. Unfortunately, this also means the entire chain of function calls need to be adjusted to be `async`.
2022-05-13 20:23:17 +08:00
infinite-persistence
251187de06
useGetThumbnail: fetch streaming_url instead of generating it.
In the first attempt (PR 1497, 4d44d81f), the `generateStreamUrl` was tweaked to fetch a `Lbry.get`, which returns a promise.  On top of a few async issues on its own, we also can't just simply `await` here since render functions need to be pure.

Fortunately, there is already redux structure for `get`, and Sean happened to already be passing all the required stuff here (sight beyond sight!), so it's just a matter of calling it.

Again, render functions need to be pure, so the fetch has be in an effect, so the component might take several renders to get the image painted. But oddly this seems to avoid the occurrence of showing the fallback spaceman image (just an observation, no proof of correlation).
2022-05-13 18:19:20 +08:00
infinite-persistence
d5e56d20b6
Remove 'app' code to reduce clutter 2022-05-13 16:16:39 +08:00
Thomas Zarebczan
a7493b2c80 rename field 2022-05-12 18:35:20 -04:00
infinite-persistence
13b59037a6 1317: Log and send totalPlayingTime
The current time is quantized to 1s, and `lastTimestamp` is used to prevent duplicate counts because `timeupdate` is fired at ~250ms intervals.
2022-05-12 18:35:20 -04:00
infinite-persistence
cc666a265a 1317: Exclude events in Recsys submission. 2022-05-12 18:35:20 -04:00
infinite-persistence
72b0977817 Recsys: pass isFollowing and incognito
Additional data requested.

isFollowing - is the user following the creator
incognito - authenticated or not
2022-05-12 18:35:20 -04:00
infinite-persistence
e6f432c69d createRecsysEntry: re-arrange for clarity (no functional change)
Easier to see what's different between an entry with and without a parent.
2022-05-12 18:35:20 -04:00
Thomas Zarebczan
6e9b07ec6f Revert "Replace generateStreamUrl for Lbry get call"
This reverts commit 4d44d81f59.
2022-05-12 18:16:03 -04:00
Thomas Zarebczan
4d44d81f59 Replace generateStreamUrl for Lbry get call
+ remove unused config
2022-05-12 15:24:58 -04:00
Thomas Zarebczan
ac0ec4794a
Fix quality selector 2022-05-12 11:48:21 -04:00
Rafael
b2763e4bf0 Fix Kebab 2022-05-12 11:34:05 -04:00
infinite-persistence
b2b1692525 Restore SDK error logging, limiting to support_create.
v1 publishing timeout is already being recorded. Look for the string `publish-v1: timed out after`
2022-05-12 08:43:59 -04:00
infinite-persistence
c4f88ac7e8
Fix 'freshness' filter not working in Category Pages
## Issue
Ticket: 1484

The commit `7622e7a: Fix release time on category pages` passes in the `releaseTime` prop, which usually means we want that value to be override.

## Change
Only pass the prop when there 'freshness' filter is not active.
2022-05-12 15:37:01 +08:00
infinite-persistence
123496e734
Remove old comment - Wild West is now a proper category 2022-05-12 14:51:53 +08:00
infinite-persistence
40a59c53d4
Don't show wallet value until prefs are ready
... because preference might be "Hide wallet = true". This eliminates the gap during login or boot up that temporarily shows the wallet balance.

Ticket: 1365
2022-05-12 14:36:06 +08:00
Raphael Wickihalder
f0f1d0f695
Fix timestamp input pattern and type 2022-05-12 14:35:13 +08:00
Raphael Wickihalder
4fcaf7ba2f
Fix timestamp input type 2022-05-11 18:56:33 +02:00
Raphael Wickihalder
57eae71d12
Fix timestamp input pattern 2022-05-11 18:44:01 +02:00
Raphael Wickihalder
b0e213a2b5
Fix timestamp input pattern 2022-05-11 18:31:18 +02:00
infinite-persistence
6ade6611d9 Suppress latest floater ad 2022-05-11 10:24:43 -04:00
infinite-persistence
c572891590 Update /$/live to use latest API
1480
2022-05-11 07:57:44 -04:00
infinite-persistence
bf6a2e51c1
Band-aid: hide video ad close button until next update is ready 2022-05-11 16:26:27 +08:00
infinite-persistence
9f7a163456
Meta: escape chars when generating keywords from tags
A content page contained `"` as a tag, and that caused the meta generator to  produced a malformed page.
2022-05-11 14:56:07 +08:00
Thomas Zarebczan
18ec09c5b0
clear up about page 2022-05-10 14:10:31 -04:00
Thomas Zarebczan
71894daf49
Fix crash on middle click (and others?) 2022-05-10 13:25:47 -04:00
infinite-persistence
8874008245 Support homepage-specific memes
1446

- Requires an accompanying commit in `odysee-frontend`.
- The change assumes that the `odysee-frontend` is the only project that uses these files directly, i.e. other clients will use the API instead.
2022-05-10 21:43:14 +08:00
Rafael
17868635bd Bring back default channel functionality
- consolidate cases that need to auto set an active channel (like edit page) into channelSelector component
- also for consistency since some components would do it with button click and others on page mount
- prevent clear function on those pages (kind of a manual process to insert each page into the router condition)
2022-05-10 09:06:10 -04:00
Anthony
d6208707b9 remove section about hosting content 2022-05-09 10:18:36 -04:00
Rafael
0afeaa6223 Remove active channel cleanup function
- reverts active channel functionality back to how it was previously, making the default channel simply a sync fallback and removing all complexity and confusion
2022-05-09 07:50:44 -04:00
Rafael
adc3c06803 Fix header icon active channel 2022-05-09 07:50:44 -04:00
Thomas Zarebczan
86819b6876
update background URL 2022-05-06 14:28:04 -04:00
infinite-persistence
dae78c488f Stacked toast view
From the previous commit, we are now showing toasts in the reverse order (latest to oldest).

Next, extend the "hide snack" timer to handle multiple snacks. It will dismiss them one by one, restarting itself until no more toasts.

Show a stacked GUI when there are multiple toasts.

Users can still manually dismiss the toasts.
2022-05-06 13:53:39 -04:00
infinite-persistence
55916f0763 Revert the toast display order
New toasts should be displayed immediately.
2022-05-06 13:53:39 -04:00
Thomas Zarebczan
463e6f5687
Fix wildwest types, add doc to category 2022-05-06 12:00:20 -04:00
infinite-persistence
208b701998 Fix comment channel not checked in Livestreams
## Change
Moved the fetch from `CommentList` to `CommentCreate` instead, which is used by both Content and Livestreams comments.
2022-05-06 11:31:42 -04:00
infinite-persistence
26f9cf3a4f Undo the channel-clamping and let user figure out from Toast
Several issues with the clamping behavior:
- Problems trying to sync with the activeChannel setting.
- Corner-cases like unable to un-react because the comment and react channel was different; global mods not be able to change channels to do certain actions.

Just let the user know what are the channel(s) that they used to comment previously in the Toast.
2022-05-06 11:31:42 -04:00
infinite-persistence
fd12a98b1b Refresh commented-channels list when deleting a comment
Users should be allowed to clear their past comments and switch to another channel.
2022-05-06 11:31:42 -04:00
infinite-persistence
3bb7e21d3c Disallow commenting if failed to determine if commented before.
If we can't confirm that user has not used another channel to comment, then don't allow commenting at all. Otherwise, there's no point doing the check.
2022-05-06 11:31:42 -04:00
infinite-persistence
2bdae7637b Fix comment_create verification
## Why
Lost in a rebase. The GUI clamping was just meant to complement this (so that user knows what's going on), but ended up being the only thing that was pushed.

## Changes
- If the fetch failed or still in progress, we ask the user to wait or simply refresh the page.
- If already commented from another channel, bail and inform via Toast.
2022-05-06 11:31:42 -04:00
infinite-persistence
2698cc7001
Add 'dispatchToast' wrapper
Just to shorten code, and easier to know what the parameters are if it's a function call (instead of an object).
2022-05-06 13:41:47 +08:00
Thomas Zarebczan
6cc85cd39d minor copy changes 2022-05-05 15:47:01 -04:00
Raphael Wickihalder
4022273408 Add code review requests 2022-05-05 15:47:01 -04:00
Raphael Wickihalder
42b456307f Save new signup flow 2022-05-05 15:47:01 -04:00
Raphael Wickihalder
4c1bf27dc1 Save thumbnail uploader 2022-05-05 15:47:01 -04:00
Thomas Zarebczan
a0097dc3ce
fix timeout with remote
f
2022-05-05 13:04:46 -04:00
Thomas Zarebczan
c6856da247
up timeout for now + don't log
Replays have issues since they are on v1 and timeout. This process needs to be improved on the backend.

don't log all
2022-05-05 12:29:21 -04:00
Rafael
f191cf0b88 Fix default channel changing with active channel on header 2022-05-05 11:24:22 -04:00
Rafael
9325a3e03e String change 2022-05-05 11:24:22 -04:00
Rafael
d13c54792e Fix important tags and remove unnecessary styles 2022-05-05 11:24:22 -04:00
Rafael
371ce4a7ff Style fixes 2022-05-05 11:24:22 -04:00
Rafael
33826ea652 Fix style shift 2022-05-05 11:24:22 -04:00
Rafael
ca755d37b3 Fix console errors 2022-05-05 11:24:22 -04:00
Rafael
51746c24b1 Fix background style 2022-05-05 11:24:22 -04:00
Rafael
5e7fac563f Move clear function to page switch 2022-05-05 11:24:22 -04:00
Rafael
aa86815418 Fix menu link 2022-05-05 11:24:22 -04:00
Rafael
f2558f19f9 Add a clear function when a channel selector component is used
- this way, you can choose an active channel for something like commenting but when that component is unmounted, you always go back to the default channel (like leaving page)
2022-05-05 11:24:22 -04:00
Rafael
7eb5eb9996 Add channel selector on HeaderMenuButton
- Moved from reach/ui to material/ui menu components, because reach ui wouldn't work with 2 menus
- This channel selector stores the default on settings
- setActiveChannelIfNotSet was deprecated, if the account has channels, it will always return a channel even if there is no active channel or stored channel
2022-05-05 11:24:22 -04:00
Rafael
fa1f3abbdc Allow selecting an active channel by default 2022-05-05 11:24:22 -04:00
infinite-persistence
b4a76f4169
Allow creators to Creator-Like on top of basic reactions
1456
2022-05-05 22:09:52 +08:00
Raphael Wickihalder
99383272a8
Watch history (#1441) 2022-05-05 21:50:49 +08:00
Raphael Wickihalder
9ff4578eb1 Add requested review changes (2) 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
7045f4ed45 Clean code 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
d3fc96d961 Replace local sorage with redux 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
f3fd0ba08f Add requested review changes 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
ae1bed8135 Update label 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
4604bc4a28 Add help text to watch history 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
bf8199dd05 Update watch history icon & add astronaut to empty list 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
e9b1a32779 Add watch history icon 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
595afa71be Show X in watch history on mobile 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
ea686474fc Remove individual entries 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
1a7b92c4fa Save and load watch history 2022-05-05 09:42:24 -04:00
Raphael Wickihalder
6d4c15f72c Create history page and navigation entry 2022-05-05 09:42:24 -04:00
Rafael
bfb8f0dd28 Fix embed logo links 2022-05-05 09:12:47 -04:00
infinite-persistence
d7d8d3516e Log SDK timeout errors
Logging it so we know when to give the SDKs a kick
2022-05-05 09:06:05 -04:00
infinite-persistence
511097cd67
Player: chapter follow-up tweaks
- Make the chapters button appear consistently.
  - Previously, it was only appearing for Original.
  - We still hide it for mobile, as per previous explanation.
- Changed the Chapters button position and popup aesthetics.
2022-05-05 18:20:59 +08:00
infinite-persistence
a4a20aa8e0
Fix missing txoList when balance is 0 (PR_1459) 2022-05-05 17:24:25 +08:00
infinite-persistence
7500f15fc2
Fix missing txoList when balance is 0
799

## Issue
`TxoList` is not shown when balance is zero. A zero balance doesn't always mean zero transactions.

## Fix
Just like in other components, don't make `YrblWalletEmpty` a mutually-exclusive thing.
2022-05-05 17:15:36 +08:00
infinite-persistence
30977cae96
Fix component naming
Doesn't affect functionality, but shows confusing result in text search.
2022-05-05 17:02:08 +08:00
infinite-persistence
e3996f458f
Relay fund-transfer failure reason to user
## Issue
Was just getting a generic "Transaction failed" and had to check devTools to figure out what's wrong.
2022-05-05 16:42:23 +08:00
Thomas Zarebczan
f550be4306
fix extra "1" appearing on chapters 2022-05-04 13:08:51 -04:00
infinite-persistence
4b6e4db7cd Disable chapters for mobile for now...
- Deemed not useful in mobile, unless you have an S-pen that can hover.
- The chapters button (that invokes the chapters popup) would make more sense in Mobile, but we need to deal with the limited controlbar space first (e.g. overflow menu system)
2022-05-04 10:02:22 -04:00
infinite-persistence
f2495df615 Player: chapter markers 2022-05-04 10:02:22 -04:00
infinite-persistence
9fd890cfc2 Remove orphaned comment and unnecessary flow marker
Was confused on which part of the code this was referring to, but turns our `subCaps` was recently removed.
2022-05-04 10:02:22 -04:00
infinite-persistence
c5e185fa6d DRY: VIDEO_PLAYBACK_RATES 2022-05-04 10:02:22 -04:00
infinite-persistence
a7cf89a977 Limit livestream fetches when failed
We were already limiting the call to once-per-5-minutes (for the succesful case), so just need to put failure cases into the mix.

Retry 3 times before stopping.
2022-05-04 08:44:33 -04:00
infinite-persistence
9b44b7eb91 Add a timeout on SDK calls to allow specific error messages.
## Issue 1263
Previously, we tried to inform the user that when an SDK call such as `support_create` and `publish` fails (specifically, timed out), the operation could be successful -- please check the transactions later.

However, we only covered the case of `fetch` actually getting a response that indicated a timeout, e.g. "status = 524". For our SDK case, the timeout scenario is an error that goes into the `catch` block. In the `catch` block, we can't differentiate whether it is a timeout because it only returns a generic "failed to fetch" message.

## New Approach
Since `fetch` does not support a timeout value, the usual solution is to wrap it with a `setTimeout`. This already exists in our code as `fetchWithTimeout` (yay).

By setting a timeout that is lower than the browser's default and also lower than the SDK operation (90s for most commands, 5m for `publish`), we would now have a way to detect a timeout and inform the user.

Firefox's 90s seems to be the lowest common denominator ... so 60s was chosen as the default (added some buffer).

For the case of 'publish', it is actually called in the backend, so wrap the xhr call with a timeout as well.
2022-05-04 08:10:17 -04:00
infinite-persistence
cd2998d695
Membership-name state updates
- Corrected flow definitions.
- Properly differentiate between "not yet fetched" and "no membership" as "undefined" and "<empty string>", respectively. There are GUI elements that need to know the unfetched case.
2022-05-04 10:45:58 +08:00
Rafael
a770e0a8a9 Add sync yt button on channels page 2022-05-03 11:00:06 -04:00
Thomas Zarebczan
ff238978e9
remove old replay apis 2022-05-03 10:19:23 -04:00
Rafael
0a962b1884 Allow direct linking a repost create component 2022-05-03 09:36:25 -04:00
Rafael
e60813de03 Bring back repost page from previous changes for direct link 2022-05-03 09:36:25 -04:00
Rafael
d79ce20802 Fix polling from fileRenderInitiator logic 2022-05-03 08:12:20 -04:00
Raphael Wickihalder
810692ca29
Adjust player buffer progress color 2022-05-03 08:43:39 +02:00
Raphael Wickihalder
edc4f7abca
Adjust player buffer progress color 2022-05-03 08:30:15 +02:00
Rafael
9c342f56a0 Add Sync youtube channel button on New Channel page 2022-05-02 17:23:22 -04:00
infinite-persistence
a74dbe1e43 1075: Clamp comment channel-selector to commented channels only
## New behavior:
- If you have commented on a claim before, the channel selector will be clamped to that channel.
  - There might be more than 1 channel if commented in the past.
- This includes blocked comments, i.e. if the creator blocked you, you will not see your comment, yet your channel-selector is clamped to the used channel.
- EXCEPTION: you can use other channels if it's your own claim (for now).

## Approach
- Run `comment.List` over all your channels on the specific content. This covers nested replies and pagination (sweet).
  - So, if the total is non-zero, mark that channel(s) as having commented on the claim.
  - Only fetch this once per content claim.
- In the comment channel-selector, clamp the list to this value.
2022-05-02 16:07:00 -04:00
infinite-persistence
29a68eb992 1075: Fetch list of my channels that have commented on a claim 2022-05-02 16:07:00 -04:00
infinite-persistence
d9b1cf6d54 Remove duplicate documentation
It was getting annoying to update 2 files for the same thing.
2022-05-02 16:07:00 -04:00
infinite-persistence
794050c827 Minor cleanup to reduce code. No functional change.
- Re-use available wrapper.
- Don't fight the IDE in terms of doc-wrapping.
2022-05-02 16:07:00 -04:00
infinite-persistence
dcc66f211e Reject reaction if already done from another channel.
## Issue
1075, spam prevention.

## Approach
- When making a reaction, fetch reactions for all my channels for the particular comment id, and reject the reaction is any was found.
- Report the channel name in the toast so that user can at least know which channel to select in order to undo the reaction.
2022-05-02 16:03:53 -04:00
Rafael
27bc209717 Fix crashing when uri has spaces 2022-05-02 09:39:01 -04:00
infinite-persistence
becc1fcaf5 Pause successively-failed claim_search calls for 1 minute
## Ticket
1320

## Approach
- Create a layer on top of the `Lbry` to log failures. `ApiFailureMgr` encapsulates this.
  - Only logging `claim_search` for now as a start. Can be used for all methods.
- When a `claim_search` (with the same options) repeatedly failed for 5 times within 500ms, block subsequent calls for a duration of 1 minute.
  - These values can be adjusted.
2022-05-02 07:34:38 -04:00
infinite-persistence
dc46af34ec Sort livestreams per viewCount, descending 2022-05-02 07:26:47 -04:00
Raphael Wickihalder
61d0d76c1c
Adjust paid embedded content 2022-05-02 08:11:55 +02:00
Thomas Zarebczan
5faabb919f
so much wow 2022-04-29 13:45:42 -04:00
Rafael
129a5819d9 Refactor and fix websocket connection behavior 2022-04-29 10:43:30 -04:00
infinite-persistence
05ec4e5fbe Video-quality string cleanup
- Prevent resolution strings from appearing in `new_strings`.
- Removed unused strings.
- Added missing ones.
2022-04-29 09:42:29 -04:00
infinite-persistence
d60b8fb995 Add 'Lifestyle' string 2022-04-29 08:35:44 -04:00
infinite-persistence
8dedbe88ec Auto-populate category page titles
Completely remove any need to update things on our side when a Category is added or changed.

Will need to inform homepage owners to directly translate the 'label' field, so we don't need to use our translation system.
2022-04-29 08:35:44 -04:00
tonybaca
9b68f936ad added setTextValue to handlePaginateKeyUp function 2022-04-28 10:27:48 -04:00
infinite-persistence
73d68c1db2 Fix tempFileMiddleware that was serving a cached .well-known file
Ticket: 1386

The code was caching the first result and returning that.

We would expand the cache for multiple files, that that also require checking if the file has changed, so just read the content every time -- I think the file is small enough?
2022-04-28 09:09:30 -04:00
Raphael Wickihalder
b9525229f9
Adjust padding bellow confirming label 2022-04-28 10:29:28 +02:00
Rafael
0e8b7d6b4a Show upload menu for no-auth but redirect to sign up 2022-04-27 12:45:42 -04:00
Rafael
b693925fe5 Fix missing uri param for fetchReplies 2022-04-27 08:50:23 -04:00
infinite-persistence
d6a395f9a8 Fix 'content=any' not producing Channels in result
## Issue
1378
> "Content Type: Any" uses `claim_type: [streams, reposts, channels]`,  with `stream_types: ["video", "audio"]`, so channels aren't returned, and not any types of streams either.  Probably shouldn't have `stream_type` filter there.
(This also happens in categories, but maybe wanted in there?)

## Root
Due to this line in `ClaimListDiscover`:
`defaultStreamType = SIMPLE_SITE ? [CS.FILE_VIDEO, CS.FILE_AUDIO] : undefined, // add param for DEFAULT_STREAM_TYPE`

Wanted to check if this fallback was meant for Categories only or any list, but the git history is not preserved because Odysee was a squashed single-commit back in the `SIMPLE_SITE` days.

## Change
Will assume it was meant for Category Page only and moved that line from the component and into the client-side.

This also means that clients of `ClaimListDiscover` without `streamTypes` and `defaultStreamTypes` defined will no longer have `stream_types: ['video', 'audio']` as the automatic fallback (they must define `defaultStreamTypes` themselves). I think this modal is clearer -- it doesn't make sense to have filters like "content=any" but overridden quietly to `video|audio`.
2022-04-27 08:32:30 -04:00
Rafael
4669246b55 Fix switch again 2022-04-26 20:28:54 -04:00
Rafael
3ac57776e9 Revert "Revert "Fix original and livestream quality switch behavior""
This reverts commit 7effcd69e8.
2022-04-26 20:28:54 -04:00
Thomas Zarebczan
7effcd69e8 Revert "Fix original and livestream quality switch behavior"
This reverts commit 7a86d7a895.
2022-04-26 17:35:30 -04:00
Rafael
62fecf0403 Fix broken player state when app is updated and resize failed 2022-04-26 16:37:47 -04:00
Rafael
7a86d7a895 Fix original and livestream quality switch behavior 2022-04-26 16:19:59 -04:00
Rafael
d8ab1eb960
Store quality option and use it on all videos #1356 2022-04-26 22:39:28 +08:00
Rafael
8b443d343c Change logic for original option on livestream 2022-04-26 08:18:41 -04:00
Rafael
daaa787f97 Initial quality notify based on already set setting 2022-04-26 08:18:41 -04:00
Rafael
753c47ace5 Add initial change Toast notify 2022-04-26 08:18:41 -04:00
Rafael
48a703121b Update string value 2022-04-26 08:18:41 -04:00
Rafael
02ac8810d9 Fix auto quality display 2022-04-26 08:18:41 -04:00
Rafael
aa1b75434d Clean up 2022-04-26 08:18:41 -04:00
Rafael
6b1bcb34a7 Fix bandwithSelector and livestream selector broken 2022-04-26 08:18:41 -04:00
Rafael
14fc7bae50 Use a single setting 2022-04-26 08:18:41 -04:00
Rafael
f4567a8984 Remove qualities from strings 2022-04-26 08:18:41 -04:00
Rafael
f1dbfa01ea lint 2022-04-26 08:18:41 -04:00
Rafael
90e20b94a8 Fix app strings 2022-04-26 08:18:41 -04:00
Rafael
69671a93d1 Fix console error 2022-04-26 08:18:41 -04:00
Rafael
ef7e6a56b4 Only change default from settings page 2022-04-26 08:18:41 -04:00
Rafael
524eeff745 Move video quality constants 2022-04-26 08:18:41 -04:00
Rafael
ebad2d746a Fix Original to Auto switch 2022-04-26 08:18:41 -04:00
Rafael
b5f8a849a1 Attempt to show auto video quality 2022-04-26 08:18:41 -04:00
Rafael
73f27cc67e Add ability to store quality settings as default 2022-04-26 08:18:41 -04:00
Rafael
7390c464ac Fix undefined value case 2022-04-25 14:00:55 -04:00
infinite-persistence
5787bfcf2f De-dup packages
Consolidated a few other shared dependencies.
2022-04-25 09:24:07 -04:00
Rafael
34294e5fa2 Bump @mui/material
- Console error for multiline in Autocomplete component was changed into warning
2022-04-25 09:24:07 -04:00
infinite-persistence
7445063405 Use videojs::http-streaming for all except iPhones
## Ticket
31: "quality selector not available on safari browsers"

## Notes
The quality selector isn't populated in some Apple products -- a known issue with videojs as the platform doesn't relay the info.

But it seems like only iPhone is affected, so let's enable the override for all platforms except iPhone.
2022-04-25 09:14:24 -04:00
infinite-persistence
1ad66fccd0 Category: Hide "Repost" from ContentType filter, except for WildWest
## Ticket
1368
> can we remove the repost filter option on categories outside of wildwest/following?

## Approach
Using `context` to:
- reduce the amount of files that need to change.
- avoid prop-drilling.
- allow the ability to dynamically define the Filter's allowed values in a contained manner.

Clients that don't need customization simply does not need to wrap their component with the context.

The context only contains Content Type for now, but can include anything that future clients need to dynamically adjust.
2022-04-25 08:49:46 -04:00
infinite-persistence
1c9d89b250 AirPlay button fixes
Ticket: 1288

1. Move airplay slot away from the first.
2. Fix sizing to match the rest.
2022-04-25 08:36:09 -04:00
Rave | 図書館猫
56a7ad47c4
Design patch 2022-04-25 (#1392) 2022-04-25 10:10:45 +02:00
infinite-persistence
20b5653f95
Fix missing repost ribbon for Tags
Ribbon:
- hide: category pages, except Wild West
- show: Following, Tags, Wild West
2022-04-25 09:42:46 +08:00
Thomas Zarebczan
a6106f7427 Remove old apis 2022-04-22 12:59:34 -04:00
infinite-persistence
e4a88a5e9b SearchInLanguage: honor user's setting before category's setting.
## Ticket
Part of 1368 ("if user overrides the category homepage language with a different language setting + use 'search this language' option, use that instead. It's not typical this will happen, but probably expected.")

## Change
- Refactored to move more logic into `resolveLangForClaimSearch`
- Replaced the ternary version to make it more readable (hopefully).
- Inverted the language filter precedence by honoring the user's setting first.
  - Note: for both User and Category, URLSearchParams will always take precedence.
2022-04-22 09:39:23 -04:00
infinite-persistence
6651663a00
Discover: fix release_time for Tag and Wild West
- I got the previous logic completely wrong.

- Wild West's release time now comes from the homepage definition, but since the definition currently does not support "start of week", continue to hardcode the customization here.

- This logic also fixes the release_time for Tags.
2022-04-22 18:01:18 +08:00
Thomas Zarebczan
e29f26958c
fix channel > channel edit 2022-04-21 14:57:48 -04:00
infinite-persistence
5249e46179 Comment: ignore minAmount when in Fiat 2022-04-21 12:22:26 -04:00
infinite-persistence
a9a2270ae9 LivestreamLink: fix flicker when a child updates
## Ticket
1358 - flicker on livestream tile when viewers updates

## Change
Defining the component that way results in unique Card wrapper on each resolve, so everything gets torn down and re-mounted, causing the flicker.

There is a css side-effect though: the tags changed from red to black. But tags are inconsistent through the app ... sometimes black, sometimes red (I think it should always be red + smaller font from the body).
2022-04-21 10:31:31 -04:00
Rave | 図書館猫
126ecd38fa
Fix theater mode related issues (#1377)
* Adjust theater mode and image pages
2022-04-21 09:31:58 +02:00
Thomas Zarebczan
b832f56929
encode channel names 2022-04-20 16:40:03 -04:00
Thomas Zarebczan
8144a9bb87 livestream new api
Re-used lots of Anthony's code + made fixes to a few areas including the publish page.

a

new videojs

video.js@7.18.1 + http-streaming@2.14.2

remove console log
2022-04-20 15:53:28 -04:00
Raphael Wickihalder
575b8f5aac
Fix theater mode on audio file pages 2022-04-20 18:05:01 +02:00
infinite-persistence
d84d11bc24
f2a63668 broke placeholder tiles 2022-04-20 23:45:39 +08:00
infinite-persistence
8e2ac343b0
Make Wild-West a proper Category + additional features. (1353) 2022-04-20 22:57:35 +08:00
infinite-persistence
e64d661dcd
Support not_channel_ids through Category definition
Mainly only useful for Wild West, which doesn't use `channel_ids` (otherwise, the homepage maintainer could just exclude the id from `channel_ids` directly).
2022-04-20 22:56:16 +08:00
infinite-persistence
9ad73c9878
Hide the "results filtered by language" hint if the Category forced the language-specific search.
The user won't be able to anything about it anyway.
2022-04-20 22:56:15 +08:00
infinite-persistence
7b85d7a585
Allow Category definitions to specify language to search in.
This will be entirely up to the homepage maintainer, and will override the user's "Search only in the this language" setting.
2022-04-20 22:56:15 +08:00
infinite-persistence
778ef649e8
Wild West is now a real category, so can't use dynamicRouteProps === null to identify it.
A bit troublesome to handle, but at least the code is clearer now.
2022-04-20 22:56:14 +08:00
infinite-persistence
d52593f3b2
Move "Wild West" as part of a Category definition
- Router: no need to specify the route directly anymore (will come from definition), but we still need to disable it for certain regions.
- Sidebar: no need to custom addition anymore.

## Ticket
`odysee-homepages :: 1318`
2022-04-20 22:56:14 +08:00
infinite-persistence
f27b68587e
Restore original way to exclude categories in Homepage
It was previously done in `GetLinkData`, but accidentally removed in d854a992.
It is DRY-er to do it here rather than at the client side.

Also needed to filter in the homepage-sort dialog, so move the definition to a constant array.
2022-04-20 22:56:13 +08:00
infinite-persistence
f2a63668b7 ClaimPreviewTiles: hide abandoned tiles by default
## Ticket
1308, 1363 - "Hide/skip "removed" recsys entries"

## Change
Ported the `isAbandoned` handling from the list-layout to the tile-layout (yet another grumble on why tile vs. list is not just a css difference but an entire different component).

## Misc
Because "ClaimList + tileLayout" was showing abandoned claims by default, search around to see if it was still needed. I think only collectionsListMine would require that (or maybe not, can remove later).
2022-04-20 09:38:53 -04:00
Rafael
cbb6e2afe4 Add missing FileGet call 2022-04-20 09:18:43 -04:00
Rafael
0dccabe692 Selector change
- and remove from where it was unused
2022-04-20 09:18:43 -04:00
Rave | 図書館猫
089fc52a7d
Filepage theater fix (#1366)
* Disable theater mode for non-video files

* Add black background to image container
2022-04-20 10:20:15 +02:00
Rafael
20c610e8c9 Fix NaN Tipped 2022-04-19 19:33:12 -04:00
Rave | 図書館猫
764e21c801
Design Patch 2022-04-19 (#1360)
* Fix report page on mobile

* Fix mature tag colors in light theme

* Adjust spacing for badges in navigation

* Fix reply input background for notification on mobile
2022-04-19 21:01:28 +02:00
infinite-persistence
07463312f0 Ad: change to 'insert' mode in Mobile layout.
## Ticket
1074
In mobile, the second livestream tile in Following gets missing because of the Ad being in 'replace' mode.

## Change
Switch from 'replace' to 'insert' mode in Mobile layout.

If missing (replaced) tiles is not a desired behavior, the true fix would be to always use 'insert' mode, and either live with the uneven tiles or wait for our design master's solution.
2022-04-19 10:18:51 -04:00
infinite-persistence
805b607e73
Support callback method to inject items (1351) 2022-04-18 19:15:35 +08:00
infinite-persistence
f7beffaa06
Support callback method to inject items
1341
2022-04-18 19:08:09 +08:00
infinite-persistence
0e233e04a8
Generalize useGetLastVisibleSlot
It was meant to be general-purpose in the first-place, but ended being tied to ads due to time constraint and also bad documentation.

No functional change.
2022-04-18 19:06:02 +08:00
infinite-persistence
f5a0f39f59
Rename file: use-last-visible-item => use-get-last-visible-slot
No functional change, just renaming for clarity.
2022-04-18 19:06:01 +08:00
infinite-persistence
82f278dbde
Fix name-availability-check for Reposts
3f805a61 broke Reposts. The action needs to return whether there are any clashes.
2022-04-18 18:32:00 +08:00
infinite-persistence
65789a26ed
Re-use existing string 2022-04-18 18:24:34 +08:00
dependabot[bot]
ef62ba267d Bump async from 2.6.3 to 2.6.4 in /web
Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-18 06:16:27 -04:00
infinite-persistence
cfc34c5dba
Fix hidden purchases through embeds
## Issue
1345

## Change
The refactor in  04c5ac46 broke the logic, because `!hasCost` would incorrectly include an undefined `costInfo` (haven't fetched) as free content.
2022-04-18 13:48:11 +08:00
infinite-persistence
3f805a6189 doCheckPublishNameAvailability: case-insensitive version
## Issue
??

## Behavioral Changes
- Use `claim_search` instead of `claim_list` to retrieve all all own claims with the same name (case-insensitive).
  - Caveat: annonymous posts will be excluded.
- When a clash occurs, there is a possibility that we have multiple existing entries (e.g. "xxX", "xXx"). Since we don't know which one is best to fall back, I removed the "edit" button for this and replaced with a simpler text

## Code Note
- If not mistaken, the rest of the code still needs `selectMyClaimForUri` to be case-sensitive, so augment the selector to support both through an optional parameter.
2022-04-18 00:44:11 -04:00
dependabot[bot]
4e9e55e32f Bump minimist from 1.2.5 to 1.2.6 in /web
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-18 00:30:51 -04:00
infinite-persistence
389b0ad834
i18n update 2022-04-17 09:19:58 +08:00
infinite-persistence
2f6b7f0ba6 Update app to use v2 homepage api 2022-04-15 09:25:08 -04:00
infinite-persistence
45bb9ad0fa Homepage API v2: includes meme
Ticket: 1318

Had to create v2 as there is no backward-compatible location in the v1 json to place it.

v2 allows any future expansion beyond 'categories' and 'meme'.

One-meme-per-homepage is also supported, but not enabled for now.
2022-04-15 09:25:08 -04:00
infinite-persistence
6e34282cdc Livestream tile/list: show viewer count if data is available
As of this commit, only the Channel Page is fetching the data through the new API, which has the viewer count correctly populated.

For both "0" and "undefined", continue to show as "LIVE".
2022-04-15 08:24:30 -04:00
infinite-persistence
5cb94ace84 Update viewersById after fetching active livestreams
viewersById is usually updated by websocket, but since we have the latest data, might as well use it.
2022-04-15 08:24:30 -04:00
Rave | 図書館猫
175f85995d
Design Fallout Patch 10 (#1340)
* Design Fallout Patch 10
2022-04-15 10:56:50 +02:00
Thomas Zarebczan
eaf1b093ae
Odysee updates 2022-04-14 20:31:16 -04:00
Thomas Zarebczan
2672177cc0
add fire sticker, cleanup 2022-04-14 15:53:54 -04:00
Thomas Zarebczan
7622e7aaf2 Fix release time on category pages 2022-04-14 14:23:22 -04:00
infinite-persistence
934f627c19 Remove isTouch from use-screensize.js -- it's not an effect
It will be confusing for the next person to look at the effects folder for `isTouch`.

Use `platform.isTouch()` instead.
2022-04-14 10:29:01 -04:00
infinite-persistence
49db1fe83b Replace IS_IOS and IS_ANDROID with platform 2022-04-14 10:29:01 -04:00
external
c4d11c6c48 Port navigatorJS - provides platform details 2022-04-14 10:29:01 -04:00
Rave | 図書館猫
c7962a1192
Design fallout patch 9 (#1337) 2022-04-14 10:29:54 +02:00
infinite-persistence
feb499b786
Video: add original quality selection (#1328) 2022-04-14 14:52:55 +08:00
infinite-persistence
dca6c2ebf8 Disable "switch optimized-auto to original" for now.
It might be a user option in the future.
2022-04-14 02:41:23 -04:00
infinite-persistence
257011b62d Use non-VHS link when "auto" matches non-VHS quality
The ideas is that the "optimized" version (same height as original) is badly done, so display the original instead behind the scenes.
2022-04-14 02:41:23 -04:00
external
6478da923f Port bandwidth selector from http-streaming @ v2.0.0
Reference:
https://github.com/videojs/http-streaming/issues/749#issuecomment-606972884

This is a direct copy of the necessary files to replicate `lastBandwidthSelector`. Irrelevant code was removed.
2022-04-14 02:41:23 -04:00
infinite-persistence
c1fb160452 Use non-VHS link when "original" is selected.
Ticket: 638
2022-04-14 02:41:23 -04:00
infinite-persistence
33adf7aab2 Add "original" quality button 2022-04-14 02:41:23 -04:00
infinite-persistence
4f600fbc8e Cleanup; no functional change.
- Handle null `vjsPlayer` so we don't need to add FlowFixMe everywhere.
- Remove redundant comments.
2022-04-14 02:41:23 -04:00
infinite-persistence
99b446a8fe Use baked-in homepages until service is moved elsewhere
The code currently supports both the baked-in homepages, as well as fetching from `/$/api/content/v1/get`.

As the latter is currently a circular round-trip, just use the baked-in version until the service is moved elsewhere. Loading performance will be better.
2022-04-13 13:38:04 -04:00
Thomas Zarebczan
17d5d5c73b partial new livestream api support 2022-04-13 11:52:00 -04:00
infinite-persistence
dbc98e8902
Re-organize env file
No changes to any values, just:
(1) moved things around
(2) removed defunct variables
2022-04-13 22:50:59 +08:00
infinite-persistence
751a9253e9
Hush developmental app-string fetch errors for dev-server 2022-04-13 22:23:09 +08:00
infinite-persistence
57ba9c278b
Move Category Metadata to homepages-repo (#1331) 2022-04-13 22:23:00 +08:00
infinite-persistence
e8e1655a2d
Move Category Metadata to homepages-repo
Requires: 1309 of the homepages-repo
Ticket: 1302
2022-04-13 22:04:13 +08:00
infinite-persistence
3f1417a412
Restore metadata back to simple objects
The fn version was only needed for Search Page, and that was making it hard to move the metadata to the homepage repo.

Revert back to original, then handle Search separately.
2022-04-13 21:57:38 +08:00
infinite-persistence
e9214be2c1 Fix broken Search Page OG
The changes to escape characters causes `ctx.query` to be nulled.

As a quick fix, stash that value early on.
2022-04-13 09:03:54 -04:00
Bradley
a50b538ad5
Make Repost a Modal (#978) 2022-04-12 21:21:22 +08:00
Bradley
233a2b27ba
pass in contentName to repost modal 2022-04-12 21:07:41 +08:00
Bradley
d7506850b3
removed remaining refs to PAGES.REPOST 2022-04-12 21:07:40 +08:00
Bradley
98154a1921
changed repost to open a modal instead of new page 2022-04-12 21:07:39 +08:00
Raphael Wickihalder
f3ff88d74e
Adjust recommended grid 2022-04-12 09:54:11 +02:00
Raphael Wickihalder
096185d424
Adjust collapsed recommendation grid 2022-04-11 18:54:15 +02:00
Raphael Wickihalder
19a4b87225
Adjust tile grid for HiRes screens 2022-04-11 16:05:41 +02:00
infinite-persistence
b03d3305c1 ClaimTilesDiscover: stop repeating claim_search on failure
Just like ClaimListDiscover, stop `claim_search`-ing if the result is a failure (null).

Leaving the placeholder tiles as is for now. Can show the timed out message like ClaimListDiscover -- just toggle SHOW_TIMEOUT_MSG.
2022-04-11 07:45:27 -04:00
infinite-persistence
5288fb3de8 Fix signout sequence not cleaning up correctly
Potentially closes 1319

## Note
- `persistor.purge` returns a promise, we should wait for the resolved results before reloading, instead of just adding an arbitrary `setTimeout`.
  - Perhaps the `setTimeout` method is to ignore a super-long or hanged purge (not sure), but it wouldn't be right since it would end up in a limbo state.
- Log errors to get clues for future.
- Reduced code by moving the reload to `finally`.
2022-04-11 07:36:10 -04:00
Raphael Wickihalder
f7cb0e40cc
Fix comment scroll on mobile 2022-04-10 10:43:14 +02:00
Raphael Wickihalder
e50b8cd936
Update menu animation for notifications 2022-04-09 17:37:27 +02:00
Raphael Wickihalder
a21e75d865
Fix scrollbar bug on markdown page 2022-04-09 17:26:27 +02:00
Rave | 図書館猫
65d0c9c6c3
Design Patch 8 (#1316)
* Design patch 8 - Fixing issues & updating menus
2022-04-09 16:07:06 +02:00
infinite-persistence
4b93be049c OwnComment Page: deleting comment shows failure despite successful
## Change
Due to "Own Comments" being implemented the same way as "Discussion Page", the comment lookup did not work for the abandoning case.

Just skip the local cleanup of `byId` -- it doesn't matter, as the GUI uses `selectCommentsForUri` to grab the per-channel comments, so it would still disappear in the GUI immediately.
2022-04-08 12:50:00 -04:00
infinite-persistence
12a59708e4 doCommentListOwn: clean up docs; add limit assertion 2022-04-08 12:50:00 -04:00
infinite-persistence
95df6fedc0 Fix new categories not showing until Customize is opened
## Ticket
1307 newly added categories aren't adding to existing customized homepage

## Change
In Customize, new categories were appended at the bottom, but forgot to repeat the behavior on the actual homepage itself.
2022-04-08 09:35:43 -04:00
infinite-persistence
5a400ca2fa
Clean homepage and export copy/paste issues, (no functional change) 2022-04-08 18:56:17 +08:00
infinite-persistence
b79b7f9bde Re-enable 'Purchases' page
Closes 1284

## Notes
- Re-used the Library page, but disabled the [Downloads | Purchases] tabs.
- Access from Settings > Accounts > Purchases
2022-04-07 14:28:12 -04:00
Raphael Wickihalder
13bc634482
Remove badge from ribbon 2022-04-07 20:05:57 +02:00
Raphael Wickihalder
010b5c81f4
Adjust tile grid in categories and channel pages 2022-04-07 19:54:41 +02:00
Raphael Wickihalder
14f3195a7f
Adjust tile grid 2022-04-07 19:36:45 +02:00
infinite-persistence
fc50095b36 Make notification titles translatable
## Issue
Desktop 7022: i18n: Notification title localization lost

## Approach
The current code breaks up the string into an array of strings, so i18n is somewhat impossible.

Since 99%¹ of dynamic notifications come with a `dynamic` property for all the replaceable values, we can actually reconstruct the string however we want.

¹ <sub>_as far as I can find, only `fiat_tip` does not provide the value via `dynamic`, i.e. hardcoded in the string. Boo._</sub>

### Benefits of this approach:
- able to localize the string again
- able to customize the string (e.g. making claim titles italic, fix typos, use more concise strings, etc.)

### Problems with this approach:
- if the api overloads a particular notification type with several strings, then the approach is broken.
    - Ex. For the case of `comment` type, the overload is whether the comment is a normal comment or hyperchat. But I was able to replicate the logic to differentiate them, so all is good.
    - For the case of "livestream reminder in 30 minutes", we would have to inspect the string to differentiate against "is live streaming". I think this reminder is not being used, so I didn't do it yet.
- some work is needed to maintain the code when the server side updates something.  But we are already manually maintaining the i18n strings anyway, so it shouldn't be too much of a burden.
- With the exception of the overload problem, any new notification type will simply pass through as un-localized, so things should continue to work, i.e. no need to update the front-end immediately 🤞
2022-04-07 12:30:07 -04:00
Rafael
bab96276b6
Better Portrait videos support (#892) 2022-04-07 23:46:41 +08:00
Rafael
dff64f5a47 Improve plugins format 2022-04-07 11:44:25 -04:00
Rafael
b0f091a589 Fix iPad landscape 2022-04-07 11:44:25 -04:00
Rafael
de93a97af0 Fix icon cutoff 2022-04-07 11:44:25 -04:00
Rafael
800e735115 Mobile file page, comments and player improvements for rotated landscape view
undo plugin changes
2022-04-07 11:44:25 -04:00
Rafael
35c933e7e4 Fix miniplayer size issues
Add another comment
2022-04-07 11:44:25 -04:00
Rafael
9f04370516 Improve resizing screen until it switches to/from Mobile 2022-04-07 11:44:25 -04:00
Rafael
65b9906086 Add dynamic player aspect ratio resizing 2022-04-07 11:44:25 -04:00
infinite-persistence
7e65062613 Skip 'include_is_my_output' for Incognito
Ticket: 1180

I believe the original intention was "if a claim was previously resolved, but without authentication (no `is_my_output` data), then resolve again with `include_is_my_output`"

Update to exclude that logic for Incognito.

## Aside
The check for `!canonicalUrl` is interesting:
- Are there claims that really don't have `canonical_url`?  If yes, would that end up in an infinite `resolve` loop?
2022-04-07 10:48:07 -04:00
infinite-persistence
ee22775c7a
Fix spellcheck (#1293) 2022-04-07 22:39:29 +08:00
David Granado
c2b3904e32 Disable spellchecker which is both broken and has unusual behavior 2022-04-07 10:27:45 -04:00
David Granado
b93426da7c Revert "Revert "Revert "Fix advanced editor spellcheck by upgrading react-simplemde-editor to get updated easymde which contains the regression fix"""
This reverts commit fef73d4445a40b2b9cc7e704573be296211c6f3f.
2022-04-07 10:27:45 -04:00
David Granado
0f4dc51008 Revert "Revert "Fix advanced editor spellcheck by upgrading react-simplemde-editor to get updated easymde which contains the regression fix""
This reverts commit 1380a01e330d30c3d6e392779726085f7ea00e29.
2022-04-07 10:27:45 -04:00
David Granado
cab66d5caf Revert "Fix advanced editor spellcheck by upgrading react-simplemde-editor to get updated easymde which contains the regression fix"
This reverts commit 94944189c8e22b17957cffb5794e52f6cb0d03ad.
2022-04-07 10:27:45 -04:00
David Granado
444403e47e Fix advanced editor spellcheck by upgrading react-simplemde-editor to get updated easymde which contains the regression fix 2022-04-07 10:27:45 -04:00
David Granado
393aba0385 Fix spellcheck in comment simple editor 2022-04-07 10:27:45 -04:00
infinite-persistence
564beb7c90
Medium-layout: more "comment section collapse" fixes
- When collapsing, scroll back to the first comment instead of hanging in the Recommended section.

- Enhancement for 5380bc04: don't show "Collapse/Expanse" if there's only 1 comment. The comment itself is already collapsed to 3 lines, so it won't take up too much height.

- Fix css: recalling what Dan mentioned: if following BEM right (modifiers shouldn't be used standalone), we wouldn't incorrectly use `@extend` in this case and confuse the reader.

- Enlarged the empty spacing to make it symmetrical with the Recommended section below it.
2022-04-07 13:14:49 +08:00
infinite-persistence
a11d8279be ShowPage: remove unused props 2022-04-06 13:18:47 -04:00
Thomas Zarebczan
4643dbd767
page titles fixes + sockety url
sockety
2022-04-06 12:14:20 -04:00
Rafael
30cbe009bc Fix sports icon 2022-04-06 13:08:28 -03:00
infinite-persistence
351eee76b3 VerifyPage: don't enter Sign Up page on failure
Entering the page causes the Sign Up flow to run, which is confusing.
2022-04-06 09:15:45 -04:00
infinite-persistence
13f9f24af7 Fix double email_user/confirm due to language render (patch)
Patches previous attempt at f0ef9261

- The flag needs to be set immediately, not in the `then` block.
- Renamed the flag for clarity.
2022-04-06 09:15:45 -04:00
infinite-persistence
4f4803c638 Crisper file thumbnails for mobile
## Issue
Thumbnails in mobile, especially tablets, is blurry

## Change
Account for the larger thumbnail width in mobile.
Approximation is based on `$breakpoint-small: 900px;`
2022-04-06 06:56:54 -04:00
infinite-persistence
5380bc04f2 Comments: don't show Expand button if no comments
## Issue
In Medium layout, the Expand/Collapse button would still appear even for 0 comments.

## Approach
Hide the button when comments = 0, but didn't hide the section because the separator line feels useful as a visual guide to mark the sections.
2022-04-06 06:47:02 -04:00
infinite-persistence
ee03749574
Patch for outbrain visibility (e68bba1d)
## Issue
- Due to the timer used, the script could be loaded after the path-checking useEffect ran.
- Stale closure is also an issue.

## Approach
Create refs for the props, and listen to `onload` as well to resolve the visibility state.
2022-04-06 11:35:13 +08:00
infinite-persistence
59a0b9d490 Better non-clickable implementation
## Issue
- Adding `content__non-clickable` everywhere probably isn't the right way when we move forward to separating `all.scss`.
- Not intuitive -- easier to use if it's an attribute to `ClaimPreview`.

## Change
- Consolidate to a re-usable `non-clickable` class.
- Made Wallet Send search preview non-clickable as a temporary band aid until the channel-finder is consolidated.
- `listBlocked`: something is overriding the pointer, so non-clickable isn't working. Removed for now -- doesn't really matter.
2022-04-05 19:44:09 -07:00
Raphael Wickihalder
134cef103a
Fix embedded file width on markdown page 2022-04-05 20:47:04 +02:00
Raphael Wickihalder
a2b567889e
Update PWA manifest 2022-04-05 19:14:58 +02:00
infinite-persistence
5d22688acf Watch Later: fix capitalization so we don't need to re-translate 2022-04-05 09:52:29 -07:00
infinite-persistence
97dd01ed38 Uploads Page: fix Repost tab when count is 0
## Issue
The page becomes blank without the filter header when Repost is selected + 0 results.

## Change
Grabbed and modified lbry-desktop's 390bb6df
2022-04-05 12:47:47 -04:00
Rave | 図書館猫
e2a4490d79
Mini Player Fix (#1289)
* Fix mini player controls

* Hide time in mini player
2022-04-05 18:36:33 +02:00
Rave | 図書館猫
a0254740bc
Design patch 7 (#1286)
* Adjust thumbnail hover effect

* Increase thumbnail border transparency
2022-04-05 16:59:38 +02:00
Rave | 図書館猫
63079638a4
Design patch 6 (#1285)
* Adjust embedded file width in comment section

* Fix design issues
2022-04-05 16:02:32 +02:00
Thomas Zarebczan
aad06cdde0
Fix fee estmation 2022-04-05 09:36:06 -04:00
infinite-persistence
e68bba1dc6 Exclude outbrain in certain pages
I don't think these pages should be serving ads.
2022-04-05 08:54:37 -04:00
Raphael Wickihalder
f7a6354399
Fix handle overflow 2022-04-04 21:00:16 +02:00
Rave | 図書館猫
4cf7bf8d06
patch 5 (#1279) 2022-04-04 17:43:10 +02:00
infinite-persistence
1e6f64f235 Uploads: show placeholder when loading 2022-04-04 08:40:41 -04:00
infinite-persistence
2a38f2c177 Fix Paginate click area
https://github.com/AdeleD/react-paginate/ issues/125#issuecomment-276625181

Apparently, the page bubble cannot be made clickable due to accessibility issues, so the click area is very small.

Changed the css as suggested by the maintainer.
2022-04-04 08:40:41 -04:00
infinite-persistence
79a093eb28 Remove abandoned claim from Uploads Page
## Issue
Ticket: 108

## Interesting
Uploads Page uses `claim_list`
Channel Page uses `claim_search

A second `claim_list` would instantly show updated results, but `claim_search` takes a long while to reflect the deletion.

## Change
This PR only handles the `claim_list` (Uploads Page).

The `claim_search` version would be troublesome to handle. If a refresh would bring back the results (due to the `claim_search` slow update behavior), we would need to store the deleted claim persistently. Then ...
  - Store where? rehydrate?
  - When to clear?
  - How to make each `ClaimList` filter this out without polluting the code? etc.
...will be messy. Feels easier to "fix" at the `claim_search` level to make it update faster (maybe a command to clear cache at server or something).
2022-04-04 07:08:46 -04:00
Raphael Wickihalder
108b4a92a8 Merge branch 'master' of https://github.com/OdyseeTeam/odysee-frontend 2022-04-04 13:04:06 +02:00
Raphael Wickihalder
bb868777f8
Fix controls for mini player on mobile 2022-04-04 13:02:27 +02:00
infinite-persistence
89feddee0d Publish: handle failed 'notify' at the server
Ticket: 1256

For `notify`, "file is currently locked" and "no such file or directory" is indication that the previous "failed" SDK call actually worked. Tell the user to check the transactions.

This is the band aid until odysee-api/401 is addressed.
2022-04-04 07:02:23 -04:00
infinite-persistence
234bd2526a
Add backdrop to progress indicator 2022-04-04 17:27:00 +08:00
Raphael Wickihalder
57edddb058 Merge branch 'master' of https://github.com/OdyseeTeam/odysee-frontend 2022-04-03 17:03:12 +02:00
Raphael Wickihalder
85d9de60ca
Add dragging offset exception for Firefox 2022-04-03 17:02:18 +02:00
infinite-persistence
5631c10306
Fix context for translators 2022-04-03 22:13:18 +08:00
Raphael Wickihalder
052c602742
Fix element position when dragged in homepage customizer 2022-04-03 15:51:52 +02:00
Raphael Wickihalder
a6169a80a9
Fix element position when dragged in homepage customizer 2022-04-03 15:19:05 +02:00
Thomas Zarebczan
b7b27136fd Let's try 95... 2022-04-01 23:36:56 -04:00
infinite-persistence
7ccaf06527 Round optimized img dimension to next 100px for better caching.
Doing double `Math.ceil()` just to make it easier to disable the 100px thing in the future.
2022-04-01 23:36:56 -04:00
infinite-persistence
f175a765ae Re-enable image optimizer
My bad, I misintepreted as "disable both proxy/boost and optimizer", when it was just boost that is having issues.
2022-04-01 23:36:56 -04:00
Rafael
8dcac30767 Add sports icon 2022-04-01 21:49:03 -04:00
Raphael Wickihalder
787c49ea98 Add border-top to claim-preview progress bar 2022-04-01 15:37:26 -04:00
infinite-persistence
4e63849061 Don't clear on position on dispose
Otherwise, we'll never see a full progress indicator. The "reset when too near end of video" should only happen when opening a file.
2022-04-01 15:37:26 -04:00
infinite-persistence
84b9bd617a Watch-progress indicator 2022-04-01 15:37:26 -04:00
Rave | 図書館猫
1706ceed81
patch 4 (#1271) 2022-04-01 18:40:04 +02:00
infinite-persistence
e0415ec493 Fix post-editor preview mode
## Cause
It broke because lack of awareness that we can't use our components in preview mode. For some reason, we don't have redux access in SimpleMDE's preview mode.

## Change
- Restore the stub for iframes
- Fix preview for images, and apply the same styling as in posts.
2022-04-01 12:36:49 -04:00
infinite-persistence
a61f943465 inline-attachment: move to local copy + handle xhr errors
(1) Move from Node to local copy
(2) Handle xhr errors more gracefully. Instead of erasing the syntax, we should say that it failed through the URL.
2022-04-01 12:36:49 -04:00
inline-attachment
c41c6bc2bb inline-attachment v2.0.3
Partial copy from https://github.com/Rovak/InlineAttachment

We need to make some changes to handle xhr errors.  Given than the repo hasn't been updated in 7 years, and it's a hassle to push the changes or fork the repo, just copy over the required files.
2022-04-01 12:36:49 -04:00
Thomas Zarebczan
8d4a05157d Paste/drop images directly to markdown editor
Ticket: 1135

- Changed `FileDrop` to only cover the upper 20% of the page, otherwise it will clash with markdown image drop.
2022-04-01 12:36:49 -04:00
Rafael
e765a74eb0 Fix claim switch comment.List fetch behavior 2022-04-01 11:55:30 -04:00
infinite-persistence
3e5290d8b0 Swap pinnedUrls vs. pinnedClaimIds precedence
pinnedUrls = resolve
pinnedClaimIds = claim_search

Make `pinnedClaimIds` take precedence for now, since the homepage is defining both to support Android.

For some reason, I previously made `pinnedUrls` the priority, thinking this should be the "correct" one to use when the SDK is fixed.
2022-04-01 11:35:29 -04:00
infinite-persistence
c36fd425a7 Fix failing video position reset
## Issue
Maybe related to https://github.com/OdyseeTeam/odysee-frontend/issues/99#issuecomment-1042384649

## Notes
`fileInfo` does not contain `metadata` anymore -- not sure what happened. With zero duration, `videoPlayedEnoughToResetPosition` was never true.

But the claim usually contains the duration already, so we can use that. There are some audio/video claims that don't, but those are a minority.
2022-04-01 09:58:09 -04:00
infinite-persistence
491c934119 Fix makeSelectContentPositionForUri memo
- Move away from the leaky makeSelect* pattern.
- No memoization since it's pretty light.
2022-04-01 09:58:09 -04:00
infinite-persistence
fb998208e2 Add flow to Content slice 2022-04-01 09:58:09 -04:00
infinite-persistence
143a3c83e7 Update CQ username 2022-03-31 19:00:08 -07:00
Rafael
075e285bd2 Improve embed end screen 2022-03-31 20:56:26 -04:00
infinite-persistence
f5034f74ca Batch resolve pin urls in 2 ways
Expanded homepage pins to support 2 types of input (if both are passed in, pinnedUrls take precedence):
  (1) pinnedUrls     --> uses doResolveUris (resolve)
  (2) pinnedClaimIds --> uses doResolveClaimIds (claim_search)

Instead of injecting the pinned URLs directly, we inject from `resolvedPinUris`, which will be blank until the uris are resolved, thus preventing it from being resolved individually from the tiles.

There's additional complexity with the `claim_search` method, as the rest of the code deals with uris instead of IDs. Fortunately, it's all contained with `useResolvePins`, so removal would be easier when the batch `resolve` issue is fixed.
2022-03-31 15:58:10 -04:00
infinite-persistence
dd5f4872fc Minor cleanup, no functional change
- Self-documenting variable.
- Remove incorrect comments.
- Remove redundant variables.
2022-03-31 15:58:10 -04:00
Niko Storni
8c20d516cd replace cdn url 2022-03-31 21:28:33 +02:00
infinite-persistence
d482b2d35a Second attempt at preventing "empty homepage" flash
The delay in fetching homepages causes the "empty homepage" splash to appear briefly for the authenticated case.

Part 2 of 61630930
2022-03-31 10:55:11 -04:00
Thomas Zarebczan
8c7c1cfd5c fixes from review
remove config, remove unused app strings + add new, add disabled message
2022-03-31 10:35:24 -04:00
Thomas Zarebczan
db687204a4 livestream for all 2022-03-31 10:35:24 -04:00
infinite-persistence
1a2fefa6ec Option to hide notification count in title bar 2022-03-31 10:23:31 -04:00
infinite-persistence
3b98f73a0f Fix livestream countdown i18n
Ticket: 1228

## Code changes
- Pass through `getTimeAgoStr` so that the value gets localized.
- Pass the simpler `number` around instead of the `moment` object for better memoization.

## Notable differences
Due to how `getTimeAgoStr` is written, we now get to see the time actually counting down, vs "in a few seconds" currently in production.  I think the counting-down behavior was the original intentional, since a 1s timer was used (otherwise, a 1-minute timer could be used) ... or maybe not since streams may not start on the dot.
2022-03-31 08:25:32 -04:00
infinite-persistence
321a6901b4
i18n (#1252) 2022-03-31 18:23:00 +08:00
infinite-persistence
071b86fa06
Make "Send a xxx tip" currency-agnostic so we don't need to re-translate again 2022-03-31 17:54:21 +08:00
infinite-persistence
c232981f0c
Catch up on string changes 2022-03-31 17:54:20 +08:00
infinite-persistence
fae8c6dff4
Don't translate product names
...at least, that is the current decision.
2022-03-31 17:46:12 +08:00
infinite-persistence
aa5e4d6c13
Fix double translation
No need for the macro when `<I18nMessage>` is used.
2022-03-31 17:46:12 +08:00
infinite-persistence
e21db9d58e
Sidebar: add option to not localize certain strings
I think we want to keep Premium as a product name (consistent for all languages). It was popping up in the `window.new_strings` because the current code localizes every link.
2022-03-31 17:46:11 +08:00
Rave | 図書館猫
2c6fb66206
patch 3 (#1251) 2022-03-31 11:19:32 +02:00
infinite-persistence
e9e232f008 Consolidate transaction result strings
## Issue
Accumulation of so many strings for a "successful tip" that it is getting annoying to re-translate them for minor changes.

## Change
- Consolidate and re-use strings.
- Make the tip string currency-agnostic so we don't have to touch it again. The amount and currency is moved to the `subMessage`.
- Fix spacing being incorrectly enforced through i18n (it should be done via code/css).
2022-03-30 21:59:54 -04:00
Rave | 図書館猫
99d730d0e3
Design fallout patch 2 (#1245)
* patch 1
* patch 2
2022-03-30 17:53:05 +02:00
infinite-persistence
49de7b1c64 Fix outbrain not removed after auth'd
The variable name changed. This seems to be the only one left.

Perhaps we need a formal method from Outbrain to remove?
2022-03-30 11:35:51 -04:00
Rave | 図書館猫
b9436def23
patch 1 (#1244) 2022-03-30 16:40:35 +02:00
infinite-persistence
1366f8d3ce Force reposts in Homepage + Category Page, except Following & WW
Ticket: 1220
2022-03-30 09:39:06 -04:00
Anthony
911ccaa07e
Support EUR tipping #1222 2022-03-30 13:43:07 +08:00
Anthony
beaf425068 fix some flow errors and other pointers 2022-03-29 23:00:55 -04:00
Anthony
d70c489163 support eur in transactions 2022-03-29 23:00:55 -04:00
Anthony
e9b1a11e44 fix flow errors 2022-03-29 23:00:55 -04:00
Anthony
fe9b33e42b allow tips in euros 2022-03-29 23:00:55 -04:00
Anthony
631d3cc1f3 supporting EURO icon 2022-03-29 23:00:55 -04:00
infinite-persistence
cc8812d751 ClaimListDiscover: fix broken excludeUris logic 2022-03-29 22:39:36 -04:00
Rafael
8823461ebd Add percentage video duration keybinds› 2022-03-29 22:39:01 -04:00
infinite-persistence
9fe20699a0 doResolveUris, doResolveClaimIds: Return resolved empty results rather than undefined promise for the no-op case.
This allows clients to chain without needs to check if it's undefined.
2022-03-29 21:21:58 -04:00
infinite-persistence
122d561a20 Batch resolve with claim_search | [Recommended, Comments]
Ticket: 1189

## Issue
There is a bug in a batched `resolve` that returns jumbled data. Temporarily switch to `claim_search` until that is fixed.

## Notable differences:
- `resolve` will tell us directly that a claim has been removed or filtered, so redux will mark the ID as such. `claim_search` simply returns nothing, so we will still end up with an extra `resolve` for these items when the component tries to display it.

- The new function currently does not handle Collections (i.e. resolving individual items in the Collection) and Reposts. Given that this is temporarily, I'd like to leave `doClaimSearch` as is, instead of trying to replicate what's in `doResolveUris`.

## Notes:
Since we don't care if the resolve fails (and we weren't doing anything in the `catch` anyways), use `finally` instead.
2022-03-29 21:21:58 -04:00
Anthony
29ec4e3ad6 use BEM 2022-03-29 12:23:20 -04:00
Anthony
13a7785315 fix css bug 2022-03-29 12:23:20 -04:00
infinite-persistence
7660906494 Disable image CDN due to instability 2022-03-29 10:16:52 -04:00
infinite-persistence
0d3f6c2f9e getImageProxyUrl: don't assume IMAGE_PROXY_URL is always defined
This allows us to disable it by not defining.
2022-03-29 10:16:52 -04:00
infinite-persistence
b40160a939 Remove the desktop Welcome Page 2022-03-29 10:05:58 -04:00
infinite-persistence
2fb0e00bc0 Publish Preview: i18n
Fix remaining fields
2022-03-29 09:08:49 -04:00
infinite-persistence
e358f0715d tus: retry only after 2-minute wait
There is anecdote that we need to wait up to 2 minutes to preven the locking scenario.
`https://github.com/tus/tusd/pull/667#issuecomment-1079647640`

## Change
Instead of multiple retries at short intervals, do a one-time retry after a 2-minute wait. We'll do this until the fix is available in tusd v2.
2022-03-29 09:01:10 -04:00
Anthony
4fffb035de reverse string changes 2022-03-28 15:30:36 -04:00
Anthony
0f407914f3 link livestream comments to membership page from badge 2022-03-28 15:30:36 -04:00
Anthony
d64f1c5cc2 bold more text in popup dialog 2022-03-28 15:30:36 -04:00
Anthony
1eb66a6d66 improve tip support functionality 2022-03-28 15:30:36 -04:00
Anthony
d88b14ccc7 add back to premium button 2022-03-28 15:30:36 -04:00
Anthony
5a2684643e allow user to save currency on client 2022-03-28 15:30:36 -04:00
Anthony
fed8fafe6c allow user to select preferred currency 2022-03-28 15:30:36 -04:00
Rafael
f9d32abbf6 Fix embed end links 2022-03-28 14:39:36 -04:00
Thomas Zarebczan
157b6d3f19
fix recommended showing blank on homepage 2022-03-28 10:01:55 -04:00
Thomas Zarebczan
726dc77943 Hide news by default 2022-03-26 16:01:27 -04:00
Thomas Zarebczan
79aa098484 fix: always inject FYP 2022-03-26 16:01:27 -04:00
David Granado
09fc18cc02 Fix 'PAGES.DEPRECATED__DOWNLOADED' value 2022-03-26 00:54:39 -04:00
David Granado
2c3432c9cb Guess at the correct value for 'PAGES.DOWNLOADED' 2022-03-26 00:54:39 -04:00
David Granado
3c20332912 Fix incorrect imports 2022-03-26 00:54:39 -04:00
Thomas Zarebczan
e40b65b975 Revert "send 10 percent of traffic to other server"
This reverts commit 0fcdbc7858.
2022-03-25 15:35:05 -04:00
Anthony
63a4a597a9 passing meme actually isnt required 2022-03-25 14:44:13 -04:00
Anthony
632cce4dbb bugfix 2022-03-25 14:44:13 -04:00
Anthony
b74dc804d6 dont open in a new tab for internal urls 2022-03-25 14:44:13 -04:00
Anthony
e921d58f73 dont open meme link in new tab 2022-03-25 14:44:13 -04:00
Anthony
0fcdbc7858 send 10 percent of traffic to other server 2022-03-25 14:28:57 -04:00
Thomas Zarebczan
087282578f add airplay 2022-03-25 11:31:11 -04:00
infinite-persistence
616309301d Homepage: don't wait for prefs if incognito
It causes the "empty homepage" splash to briefly appear.
2022-03-25 09:14:37 -04:00
infinite-persistence
093594de3f
OptimizedImage: clean up attribute removal
Cleanup for 1e0da661
2022-03-25 10:54:18 +08:00
infinite-persistence
57192305f0
i18n: typos and removal 2022-03-24 16:25:43 +08:00
infinite-persistence
173ab36451
Beautify FYP toast 2022-03-24 16:16:54 +08:00
infinite-persistence
c970176386
Sub-message was hard to read for non-error toasts
- Non-error = pink background, Error = dark red. The former provides bad contrast for --color-text-subtitle.

- Use opacity instead of a hardcoded color.
2022-03-24 16:16:53 +08:00
infinite-persistence
f1ea0b20dd
Fix i18n issues reported
- Changed to "Add a Card" to reuse existing string.
2022-03-24 15:36:09 +08:00
infinite-persistence
c958cb4a40
API message localization map 2022-03-24 15:20:30 +08:00
infinite-persistence
42451e14a8
Split toast wrappers into separate file 2022-03-24 15:19:50 +08:00
infinite-persistence
e0ddd94c01
Rename: [commentron-error.js] -> [api-message.js] 2022-03-24 15:18:13 +08:00
infinite-persistence
f53680ea63
Refactor ERR_MAP to be general purpose
- Remove the need for an object key. Just use an array. It gets hard to maintain as more messages come in, and so far there is no need to access the configs directly.

- Just focus on handling the message and not creating a toast object. Leave the latter to the client.
2022-03-24 15:16:47 +08:00
infinite-persistence
a96db41782 FYP: show placeholder tiles when fetching membership or fyp itself.
This prevents the "no membership" and "no recommendations" message from flashing during load.
2022-03-23 23:21:46 -04:00
Rafael
09557c8ce2 Fix warnings 2022-03-23 17:09:17 -04:00
Raphael Wickihalder
ec6cb7380b Adjust premium splash in homepage customization modal 2022-03-23 15:35:27 -04:00
Thomas Zarebczan
56ae81198a Shorten title
Mobile was cutting off, otherwise worked okay!
2022-03-23 15:35:27 -04:00
infinite-persistence
ec5cd10ab1 Remove hideFyp setting 2022-03-23 15:35:27 -04:00
infinite-persistence
5b16b3b058 Ability to customize homepage
Ticket: 1145

- Limited to premium for now (early access).
- Needed to handle custom categories from non-English homepages.
2022-03-23 15:35:27 -04:00
infinite-persistence
d854a99250 Inject ID into homepage data
This will be used to sorting.
2022-03-23 15:35:27 -04:00
Thomas Zarebczan
aeb475ec2e
temp: pass random param
There are some channels returning 304, and they can't stream without this param
2022-03-23 14:48:45 -04:00
Rafael
192e1d4923 Prevent floating player on geoblock 2022-03-23 14:29:06 -04:00
Thomas Zarebczan
c362efe630
gif support for chat 2022-03-23 10:19:49 -04:00
infinite-persistence
8fd64b2b41 TMP: switch fyp batch-resolve to claim_search
There is an intermittent bug with a batched `resolve`, where results are jumbled up. Switch to `claim_search` until that is resolved.
2022-03-23 09:23:02 -04:00
infinite-persistence
db38cc597f Quick membership override in debug mode 2022-03-23 09:23:02 -04:00
Rafael
dcb19a9f48 Improve wording for CA 2022-03-23 09:16:52 -04:00
Thomas Zarebczan
7477208c4e
Chromecast on Lives
+ remove some dev code that's no longer needed...
2022-03-23 00:19:53 -04:00
Rafael
4cec3ee9b3 Update browser window title when notifications are received 2022-03-22 18:48:53 -04:00
Anthony
2e8039c3d0 fixes for KP 2022-03-22 16:07:05 -04:00
Anthony
70b801e867 cleanup 2022-03-22 16:07:05 -04:00
Anthony
7508dc2970 use window instead of component state 2022-03-22 16:07:05 -04:00
Rafael
c294fda09d Fix params 2022-03-22 16:07:05 -04:00
Anthony
620e5023a8 add livestream icon and channel selector 2022-03-22 16:07:05 -04:00
saltrafael
05b228400e
Fix referrer on embed (#1181)
* Fix referrer on embed

* Fix override

* Fix condition
2022-03-22 14:13:19 -04:00
infinite-persistence
f57dd6af96 Outbrain: remove visibility delay
They have removed the blocking transparent container when ads are not (or not yet) filled.
2022-03-22 11:29:13 -04:00
infinite-persistence
71e9837002 Repost: hide ribbon in Category Pages and Home Section
Allow in Following and Wild West

`index === 0` is not always Following, so compare link instead.
2022-03-22 08:54:22 -04:00
infinite-persistence
429653a7dc More sidebar optimizations
- Remove the odd resolve call that's lingering in `App`. Feels out of place, plus we don't need it now since the "active subs" claim search would contain resolved results.

- Don't search for active subs if Following count is zero.
2022-03-22 08:46:27 -04:00
infinite-persistence
56966ffa31 Fix sidebar active subs not batch-resolving
`Lbry.claim_search` was used, so it doesn't save the resolved results to redux. Use `doClaimSearch`.
2022-03-22 00:18:46 -07:00
infinite-persistence
fe227ba539 FYP: fix scroll destination when collapsing
Since FYP is no longer always at the top, we can't use y=0 anymore.
2022-03-21 22:59:57 -07:00
infinite-persistence
f868e1a3db Sidebar: handle stray separator on empty section
"Lists" section is only for authenticated, and causes stray separator line.
2022-03-21 22:52:38 -07:00
infinite-persistence
d13558297e SettingsRow: filter clicks when grayed out
Also increased opacity a bit as it's hard to read the subtitle which is already grayed out.
2022-03-22 01:06:18 -04:00
Thomas Zarebczan
9af32a0024
move recommendations below following
Until we have the reordering option. Recommended will require it's own page most liklely , the show more is strange in the middle of the page.
2022-03-21 18:53:09 -04:00
Thomas Zarebczan
9ee2db99f0 higher quality on channel page 2022-03-21 13:13:25 -04:00
Thomas Zarebczan
b5630f0ed6 Load gifs through proxy
Continuation of 1009 (2eae20f0)

It can probably be handled inside the existing getThumbnailCdnUrl to reduce 1 function, but since the functionality is somewhat different (the proxy doesn't compress), it's probably clearer to separate it.
2022-03-21 13:13:25 -04:00
infinite-persistence
6fa3638c1b Remove obsolete 'file-render--scheduledLivestream'
`iframe-render` no longer exists, and seems like upcoming streams now use their claim pictures as the poster.
2022-03-21 13:13:25 -04:00
infinite-persistence
1e0da66110 OptimizedImage: simplify implementation
It has been broken for a while, probably since the theme changes?

- Anyway, removed the effort to get the exact mounted size before requesting the image from CDN.
    - When it works, it does prevent blurry image in different screen resolutions, but it's hard to maintain and too expensive.

ChannelThumbnail: use 64 to cover both the 64 and 40 case (the cached image will work on both, potentially reducing a call). I think the size is close enough to not trigger a Core Vital size warning.
2022-03-21 13:13:25 -04:00
Thomas Zarebczan
75478ad18f Thumbnail improvements
- always pass to optimizer, even for speech

- default channel thumb to optimized at 5
50px, original on channel page

- fix misc analytics bug
2022-03-21 13:13:25 -04:00
infinite-persistence
5196468330 Make ClaimListDiscover retain results while searching
Ticket: 946

- Copied the functionality from ClaimTileDiscover. Tried to use the same variable names to help the future consolidation work.

- Removed `excludeUris` from `ClaimList` as it makes the caching harder.
2022-03-21 12:53:56 -04:00
infinite-persistence
67a822d536 Push outbrain below the Nag
This is a quick-fix without having to make the 2 components know about each other.

Ticket: 1165
2022-03-21 12:21:52 -04:00
Rafael
52c15fc004 Fix double call on livestream page 2022-03-21 10:22:02 -04:00
infinite-persistence
c0015ca442 Category: Artists 2022-03-21 09:51:50 -04:00
infinite-persistence
5297978526 Sidebar shortcuts to built-in lists
Ticket: 1107
2022-03-21 09:40:07 -04:00
Rafael
bc3c56b84b Locale Nag Fixes 2022-03-21 09:36:59 -04:00
infinite-persistence
3900d9a049
Following Page: fix redundant livestream data passed in
Clean up for 17a9b84d

We are now using `subSection` for livestreams, so no point passing in `prefixUris`, which causes additional processing.

(It wasn't visible because `showNoSourceClaims` was removed, but processing still happens).
2022-03-21 15:03:47 +08:00
infinite-persistence
e634c728f0 Don't run filters unless necessary
The loop was executed over the entire `tileUris` regardless of whether `excludeUris` existed.
2022-03-20 21:21:58 -04:00
infinite-persistence
c4d6fa9ff0
Revert "Log which method caused Failed to fetch"
This reverts commit 36a63e27c1.

Probably a bad idea, too many
2022-03-19 07:31:14 +08:00
Thomas Zarebczan
7e605f60a2 Only call on not auth
And hide if auth
2022-03-18 14:32:55 -04:00
infinite-persistence
802b5d5a18 Add outbrain
- Only add for unauthenticated users for now. We can change that to look at premium later without having to touch `app/view.jsx`.

- Only show the ad after knowing the ad is filled; this prevents the invisible container from blocking stuff while waiting, or even worse, when not filled.
2022-03-18 14:32:55 -04:00
saltrafael
d2fdcc970f
Fix playlist side column (#1151) 2022-03-18 12:26:15 -03:00
saltrafael
341bd1341d
Fix file page layout shift (#1150) 2022-03-18 11:25:14 -03:00
Thomas Zarebczan
496c90db0e
Fix channel display on Twitter OG 2022-03-18 09:54:03 -04:00
Rafael
8448c8655c Revert "Fix layout shift"
This reverts commit 6d362b19c8.
2022-03-18 10:44:16 -03:00
Rafael
6d362b19c8 Fix layout shift 2022-03-18 09:38:07 -04:00
infinite-persistence
36a63e27c1 Log which method caused Failed to fetch 2022-03-18 09:11:04 -04:00
infinite-persistence
5e2100000d Better handling of SDK errors
## Issue
- Errors like "unexpected token at..." and "failed to fetch" are being logged, rather than the actual call error.
- Publish SDK timeout is sometimes successful, but the user doesn't know, so they re-created the same claim

## Change
- Attempt to make the logs more helpful, and the error message more meaningful to the user.
- Starting off with 'publish' and tip SDK call as an experiment. Can add others if this method works.
2022-03-18 09:11:04 -04:00
infinite-persistence
ce46170b39 Formatting cleanup, no functional change
Reducing diffs in the next commit.
2022-03-18 09:11:04 -04:00
infinite-persistence
f0ef92614d Fix double email_user/confirm due to language render
Add a persistent (per session) flag to skip any actions sparked by future renders after it has already been authenticated.
2022-03-18 08:56:39 -04:00
infinite-persistence
fdb5658df6 Reduce verbosity of tus errors now that we know the locked problem is with tusd 2022-03-18 08:52:49 -04:00
Raphael Wickihalder
c479a18cd8
Fix external link icon size in livestream chat 2022-03-18 11:18:31 +01:00
infinite-persistence
0ecbb3a73b
Make members-only label clickable, per feedback 2022-03-18 15:43:11 +08:00
infinite-persistence
40bd160748
Fix membership splash cls
- Put their intrinsic sizes so the browser can pre-allocate space for them.
2022-03-18 13:19:35 +08:00
infinite-persistence
9482a7f986 Snack: sub-message, close button and duration setting
- Add close button to allow immediate dismissal.

- Add ability to support sub messages. Will be typically used for error codes, etc.

- Add ability to define 'long' auto-dismiss duration (15s) vs. the default of 5s.
    - I didn't add 'off' because there is a comment saying that this scenario should use the Error Modal instead, so respecting that for now.
2022-03-18 00:51:44 -04:00
infinite-persistence
d1d9b116d4 i18n: page titles; collection shortcut; string removals 2022-03-17 18:10:42 -07:00
Thomas Zarebczan
8ae17adde1 update subtitle 2022-03-17 11:42:46 -04:00
infinite-persistence
74345da0fb Go Live: fix missing channel selector
If the active channel doesn't have 50 LBC support, we are stuck in the "you can't stream" state. But I have other channels that are eligible.
2022-03-17 11:42:46 -04:00
infinite-persistence
35f0777320 FYP: fix "ignore" response handling (it's not a json) 2022-03-17 10:34:37 -04:00
infinite-persistence
a31ea6417a FYP: "Don't recommend channel" 2022-03-17 10:34:37 -04:00
infinite-persistence
51079ea611 Consolidate legal/requirements fetch
Ticket: 1128

Requirements:
- Fetch once per refresh. This is to cover the case of switching to VPNs, etc.
- 1 call per refreshed session.
2022-03-17 10:25:59 -04:00
infinite-persistence
f01004e9b6 FYP: setting to hide section 2022-03-17 10:11:50 -04:00
Rafael
ae56058384 Consolidate timeout thumbnail effect 2022-03-17 10:06:50 -04:00
Raphael Wickihalder
bc6ed5d483
Vertically center play button 2022-03-17 12:38:57 +01:00
Raphael Wickihalder
5632624cd9
Center play button 2022-03-17 10:30:50 +01:00
infinite-persistence
ec2bf26817
Fix flow for User/UserState 2022-03-17 13:12:18 +08:00
Thomas Zarebczan
637f191a24
Try different endpoint for geolocation
If this ends up getting blocked, we may need to return in user/me or maybe continue to randomize the api. We can try reaching out to ublock also...
2022-03-16 23:00:40 -04:00
Thomas Zarebczan
ab67e47794
Copy Pasta! 2022-03-16 22:38:18 -04:00
Thomas Zarebczan
b5184078b8
Take 3 og for livestream 2022-03-16 22:24:26 -04:00
infinite-persistence
7dd7aac8d2 fileRenderInitiator: missing timer cleanup 2022-03-16 21:02:07 -04:00
infinite-persistence
32d5eaf8e1 Don't translate 'Premium/Premium+'
- Forgot that we've concluded to not translate 'Premium/Premium+' and keep that as a product name. This is the same as competitors.
- For other instances of "Premium" in a longer string, we'll just have to communicate with translators to not translate it.
- Remove a few old strings.
2022-03-16 20:56:40 -04:00
infinite-persistence
fdd83537a3 SettingsRow: add "members only" tag
Not using the membership icons because that has 2 colors for premium and premium+. Keeping it generic and simple.
2022-03-16 20:37:07 -04:00
infinite-persistence
d3109bd330 Update settings css, hopefully closer to bem 2022-03-16 20:37:07 -04:00
Thomas Zarebczan
a6c832bac1
take 2 twitter live test 2022-03-16 19:28:45 -04:00
Thomas Zarebczan
c1e97ee451
test twitter lives 2022-03-16 18:46:46 -04:00
infinite-persistence
c8bdb33e65 Refactor modals; no functional change
This should be equivalent to the previous, just that the promises are stored in an object rather than variable. Benefits:

- Allows a single "prettier-ignore" to bypass the multiline import.
- Slightly less work when adding new modals by not having to create a named variable and handle the switch-case.

The webpack lazy-load syntax is unfortunately verbose, so this is the best I can come up with for now.
2022-03-16 18:24:32 -04:00
Rafael
57ff910bbb Re-fix layout shift 2022-03-16 18:39:09 -03:00
Thomas Zarebczan
fa1cfc4882 Fix player current time
undo

Fix play

fix play

hide play
2022-03-16 16:36:50 -04:00
Rafael
9ac64eb6a7 Fix layout shift 2022-03-16 16:36:50 -04:00
Rafael
04c5ac460b refactor 2022-03-16 16:36:50 -04:00
Rafael
0682f52d45 fix embed fetching state and geoblocking 2022-03-16 16:36:50 -04:00
Rafael
d3576315f3 Fix button 2022-03-16 16:36:50 -04:00
Rafael
7400b9c12f improve embed events 2022-03-16 16:36:50 -04:00
Rafael
b02f0736fc Fix embed call 2022-03-16 16:36:50 -04:00
Rafael
777937c7d8 Fix thumbnail 2022-03-16 16:36:50 -04:00
Rafael
0934b2fb88 fix embedWrapper liveChannel fetch 2022-03-16 16:36:50 -04:00
Rafael
d4cb51ff2a fix mobile embed 2022-03-16 16:36:50 -04:00
Rafael
e93d734fa3 Fix full url 2022-03-16 16:36:50 -04:00
Rafael
f4fdee8331 socket improvements 2022-03-16 16:36:50 -04:00
Thomas Zarebczan
60c317dedf various fixes 2022-03-16 16:36:50 -04:00
Rafael
05b44fc4ab Fix fetch 2022-03-16 16:36:50 -04:00
Rafael
9298bf1e51 flow 2022-03-16 16:36:50 -04:00
Rafael
ebfe644cb8 Add miniplayer 2022-03-16 16:36:50 -04:00
Rafael
6ce9bd5cf7 Fixes 2022-03-16 16:36:50 -04:00
Rafael
93b70f5e92 unmount on end 2022-03-16 16:36:50 -04:00
Rafael
b7f9152dca Improve livestream external embeds 2022-03-16 16:36:50 -04:00
Rafael
b096aad70e Improve livestream claimLink embeds
- Remove embedPlayButton for fileRenderInitiator
- getThumbnailFromClaim from utils function instead of redux
- Improve playingUri
2022-03-16 16:36:50 -04:00
Rafael
6dea79819d livestream + old APIs 2022-03-16 16:36:50 -04:00
infinite-persistence
f7bceb3734
Geo: fetch after authentication since it needs auth_token (#1119) 2022-03-16 11:09:43 -04:00
infinite-persistence
bffc27e8d0
Just always show homepage segment titles.. (#1116)
## Issue
- "Following" was showing up in place of "Featured"
- "Following" doesn't appear until livestreams are fetched, causing shifts.

When "Upcoming Livestreams" was implemented, it was trying to retain the original behavior of not showing "Following" title if that was the first in the list.

Not only is it a chicken-and-egg problem, but it causes extra renders due to the need to check if the other guys was rendered.

With FYP, there are now more combinations to handle.

## Change
Just show the title...
2022-03-16 08:49:44 -04:00
infinite-persistence
745e40a83e
Move blocker flag to redux
Was trying to save 1 state by assuming the homepage will be in a busy state and the ad-detection code will finish first. But this is not true for those with a small Following count.
2022-03-16 16:48:26 +08:00
infinite-persistence
98d653a8f8
Membership: i18n fixes + add strings
- Variable names are for translators to determine the context, so choose more relevant names. e.g 'displayedInterval' and 'date_range' will not make much sense to a non-programmer.

- No need to localize dev-only strings.

- Various other fixes.
2022-03-16 15:22:19 +08:00
infinite-persistence
f8b54cabbc FYP: update i18n entry for the readme 2022-03-15 21:03:31 -07:00
infinite-persistence
972429b391 FYP: allow mobile to reject + change phrasing
- This allows mobile to reject recommendations.
- Also changed from "I dislike this" to "Not interested". Less negative?
2022-03-15 20:57:28 -07:00
infinite-persistence
e9559efe10
FYP: batch resolve results 2022-03-16 10:57:26 +08:00
infinite-persistence
fc3e3ae844
Fix debug mode fetch of FYP + some formatting cleanup 2022-03-16 10:51:03 +08:00
Thomas Zarebczan
e62031f0a2
don't load FYP endpoint if not Premium 2022-03-15 15:25:08 -04:00
infinite-persistence
1e67a5cc7f
[on hold recsys work] Recommended For You (#782)
* Factor out lighthouse-result processing code for FYP re-use.

The FYP results will be in the same format as LH.

* Recsys: add ability to pass in specific uuid to use

For FYP, we want to pass the UUID as a param when searching for recommendations. The search comes before the recsys entry creation, so we need to generate the UUID first when searching, and then tell recsys to use that specific ID.

* Redux: fetch and store FYP

Note that the gid cannot be used as "hash" for the uri list -- it doesn't necessarily change when the list changes, so we can't use it to optimize redux.  For now, just always update/render when re-fetched.

* UI for FYP

* Mark rendered FYPs

* Pass the FYP ID down the same way as Collection ID

Not ideal, but at least it's in the same pattern as existing code for now. The whole prop-drilling problem with the claim components will be fixed together later.

* Include 'gid' and 'uuid' in recommendation search

* Allow users to mark recommendations that they dislike

* Pass auth-token to all FYP requests + remove beacon use

beacons are unreliable and often blocked

* Only show FYP for members

* FYP readme page

* small fixes

* fyp

Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2022-03-15 15:07:31 -04:00
infinite-persistence
5445a95c9a
Geoblock: support content claim id as well (#1096) 2022-03-15 14:48:26 -04:00
Thomas Zarebczan
58c9209c96
Fix admin icon mouse over 2022-03-15 09:48:25 -04:00
mayeaux
4a9ba6555b
Various touchups/fixes of membership functionality (#1066)
* various cleanups

* more touchups

* select currency to use based on location

* fix sidebar

* fixing strings and other touchups

* refactor and do proper string interpolation

* fix stripe error

* text bugfix

* Adjust help

Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2022-03-14 22:38:45 -04:00
infinite-persistence
99f87e95e3
Geo blocklist - reimplement with backend support (#1089)
Ticket: 1079 Support geoblocking channels/videos

## Changes
- Replaced the .env version with iapi version.
- Includes 'videos' blocking and custom messages.
2022-03-14 15:15:30 -04:00
infinite-persistence
de29e323a8
Homepage-Following: insert instead of replace when ad-blocker is detected (#1092)
* Homepage-Following: insert instead of replace when ad-blocker is detected.

`window.odysee_ad_blocker_detected` was not meant to be used outside of `<Ads>`, since it wouldn't spark a GUI update. But since homepages are rendered several times, perhaps it doesn't matter and we can skip adding to redux for now.

* Handle uBlock origin

If refreshed via "Clear Cache and Hard Reload", the detection method fails, but it does perform an internal redirect, so treat that as a failure.
2022-03-14 14:25:51 -04:00
infinite-persistence
63f19b278d
Replace recsys beacon with regular network call (#1090)
Ticket: 1080
Reason: unreliable; often blocked.
Additional: add auth-token, per suggestion in FYP PR.
2022-03-14 10:27:09 -04:00
Franco Montenegro
69a9245324
6205 remember last used playlist choice odysee (#967)
* Add last used collection to right click menu.

* Small fix for last used collection when it's a published collection.

* Update last used collection when a collection is pending or published.

* Small refactor to get the last used collection.
2022-03-14 09:07:27 -04:00
infinite-persistence
b9d392526c Fix #798: fix action dispatch order in doFetchItemsInCollections
We need to store the resolved claims first before marking COLLECTION_ITEMS_RESOLVE_COMPLETED, otherwise the GUI still sees undefined claims.

798 just accidentally flipped the order due to refactoring, I believe. It's now back to original.
2022-03-12 08:54:43 -05:00
infinite-persistence
5a1ad487f3 Handle case of missing effective_amount
Closes 916 "NaN in Total Staked Amount"

Contemplated putting the fallback into `<CreditAmount>` itself, but decided to minimize testing. Not sure if there are clients that would rely on NaN being used.
2022-03-12 01:02:03 -05:00
infinite-persistence
de9b3b641d Notification bubble: add border since it's the same color as an active button
950 "notifications count clashes with color of the expand button in top right"
2022-03-12 00:56:56 -05:00
infinite-persistence
59591c7695 Playlist: reduce show count to half in mobile.
This is for performance reasons on the horizontal view.
2022-03-12 00:53:03 -05:00
infinite-persistence
2e3f9f94ce ListOverlay: don't loop through all items if we just want 2
`map` does not short-circuit
2022-03-12 00:53:03 -05:00
infinite-persistence
5b2c901496
List Page: use swipe layout for mobile (#1069)
* Add swipe layout support for Collection Tiles

* Lists: use swipe layout for mobile

Ticket: 950 "playlists page - right now we show watch later on top, and if you have stuff here, you have to scroll down to other playlists. Show a selector on top? Whatever other improvements we can make here to improve UX."
2022-03-11 06:53:49 -05:00
infinite-persistence
a3ef81cded
Remove "comment acknowledge" modal + unused strings
Commenting is probably no longer in alpha, but the modal is definitely no longer used.
2022-03-11 12:41:22 +08:00
infinite-persistence
f3f1c1ad5e
Fix comment count not incremented it was previously 0 #1067 2022-03-11 12:31:58 +08:00
infinite-persistence
f7b598a6e0
Fix total comment count selector
- Move away from `makeSelect*`. This selector doesn't need caching since there is no transformation.
2022-03-11 12:27:28 +08:00
infinite-persistence
6b77cb2bfa
Fix comment count not incremented when it was previously 0
It was causing the nudge to add a comment to still appear after one has just entered a comment.

Ticket: 928
2022-03-11 12:27:27 +08:00
infinite-persistence
ca7b98ecf5
Support for creator-requested geoblocking (#1063)
Attempt to fix logic + case

Fix logic

Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2022-03-10 14:28:54 -05:00
Raphael Wickihalder
d52fd8e26e
Fix badge alignment on channels page on mobile 2022-03-10 20:19:55 +01:00
Raphael Wickihalder
1f12cc594c
Realign & resize premium badges on channels page & channel page 2022-03-10 17:44:54 +01:00
infinite-persistence
9ad2dc7519
Ad: simplification and alignment fixes #1064 2022-03-10 22:07:44 +08:00
infinite-persistence
ea7a6cb04f
Fix tile misaligned due to ad-blockers. 2022-03-10 22:03:19 +08:00
infinite-persistence
ea8af5aa89
Handle case where ad-cleanup fails (redo)
The solution didn't work 100%, only reduces the chances of happening significantly. So far, still can happen on hot-reload during development.

- Reverted 15bd26399f.
- Fix by just hiding the unoccupied aniBox
2022-03-10 21:54:12 +08:00
infinite-persistence
2dd0fc283d
Simplify ad-injection logic
Since `<Ads>` is already checking against SHOW_ADS and membershipship details, there is no need for all clients to repeat the same thing.
2022-03-10 21:54:11 +08:00
infinite-persistence
803a779e9e
Fix usages of I18nMessage + missed sign-in verification strings 2022-03-10 13:21:46 +08:00
Raphael Wickihalder
3d2a8b0a0d
Icon size and premium badge adjustments 2022-03-10 11:48:11 +08:00
Raphael Wickihalder
ef28514686
Align premium badge in header 2022-03-09 22:28:37 +01:00
Raphael Wickihalder
d5100b4bf7
Adjust icons in premium splash 2022-03-09 20:30:28 +01:00
Raphael Wickihalder
d1995fa053
Adjust icon size in micro navigation on HiDPI desktop 2022-03-09 20:23:47 +01:00
Raphael Wickihalder
c72f4fe2a1
Adjust icon size in micro navigation 2022-03-09 20:10:39 +01:00
Raphael Wickihalder
03685048f8
Adjust icon size in micro navigation 2022-03-09 20:05:46 +01:00
mayeaux
fb3a73d8a7
Membership subscriptions (#812)
Enter: Odysee Premium.
2022-03-09 13:05:37 -05:00
infinite-persistence
a34e07e970 uriIndicator: calling normalizeURI called without a try-catch
Closes 1048 - "There was a bad URL without a letter after #, and this failed on resolve + crashed the app. Maybe a try/catch for each URL?"
2022-03-09 09:47:31 -05:00
Raphael Wickihalder
ea827b2d31
Replace play icon in playlist 2022-03-09 15:42:35 +01:00
Raphael Wickihalder
bb9afff2d4 Merge branch 'master' of https://github.com/OdyseeTeam/odysee-frontend 2022-03-09 14:48:53 +01:00
Raphael Wickihalder
d68b869469
Adjust play icon size in active element on playlist page on mobile 2022-03-09 14:48:25 +01:00
infinite-persistence
15bd26399f Handle case where ad-cleanup fails
## Issue
Double ads on screen

## Reproduce
- Pre re-design:
    - Change "Only Language" from tne locale nag.
- Post re-design:
    - Follow a bunch of channels with active livestreams. The homepage ad will show 2 ads stack on each other, with second one invisible.

Both should be equivalent, just different UI/style.

## Analysis
In both cases, it is due to `removeIfExists` failing to remove the element if the ad script hasn't run yet.

This can happen when the component is re-mounted immediately after the ad script was added. When the effect-cleanup runs, the script have not started or is running halfway.

Aside: The need to run `removeIfExists` further strengthens my hunch that the script is meant to live throughout the lifetime of the app, with it populating the given div as we navigate. But just my guess.

## Approach
Clean up before adding the script as well. This covers any missed elements from the previous cleanup.

The drawback is that this approach assumes there will only be 1 ad per page, but that's pretty much the case with the existing `removeIfExists` approach.
2022-03-09 08:47:13 -05:00
Rave | 図書館猫
df04f727da
Design patch v2 (#1058)
* Fix design & UI issues

* Fix play icon on active element in playlist
2022-03-09 14:38:59 +01:00
Rave | 図書館猫
2c34e0d857
Fix design & UI issues (#1056) 2022-03-09 14:21:18 +01:00
infinite-persistence
3dd8c1fab5
Fix EU ad fallout #1055 2022-03-09 18:46:08 +08:00
infinite-persistence
a98dc18fc6
Fix EU ad and minor tweaks
- Initially, we did a bunch of forceful CSS to make the ad tile resize properly when the browser resizes. This was causing the EU ad to display incorrectly. Turns out, that css is no longer needed after the BEM-style re-write.

- Changed the floating ad selector to cover both EU and non-EU version. It's probably still not the best given it relies on style rather than ID, but the ID seems dynamic.
2022-03-09 18:44:38 +08:00
infinite-persistence
73552e35f9
Ad: remove unused style ID
- Removed "customAniviewStyling"
    - No longer exists -- it was from the old DOM manipulation method.

- Removed "with no tileLayout it indicates sidebar ad"
    - Misleading and not useful. I can easily set the sidebar ad to Tile if we wanted to (it used to be in Tile, we changed to save space). So, every time we change the style, we need to update the comment??

    - The sidebar is not the only place that List layout is used -- there's Channel and Category pages, which allows either layout.
2022-03-09 16:02:11 +08:00
infinite-persistence
d210e81ded
useBrowserNotifications: don't set state if already unmounted.
Closes 1053

We can't cancel a promise, but we could prevent setting orphaned states by taking advantage of closures to detect if we have unmounted.

Reference: https://juliangaramendy.dev/blog/use-promise-subscription
2022-03-09 13:22:54 +08:00
infinite-persistence
efbbba6958 Channel Search pagination
Closes 605 "Add pagination support to channel search"

## Previous Attempt
The previous attempt (69de63c4) didn't work because the wunderbar is part of the list component, so it is unmounted when we switch between the Normal and Filtered list, causing it to lose focus while typing.

Also, creating another full-blown ClaimList* component is really redundant (we should be consolidating instead).

## Approach
ClaimListDiscover recently added a new `subSection`, so we can place the filtered `ClaimList` here without causing the wunderbar to unmount.

Wrapped the "lighthouse search with channel_id" into `searchResults.jsx` for now as a quick and isolated solution. When we refactor ClaimList*, we can then consider incorporating into `doSearch`.
2022-03-08 19:50:44 -05:00
infinite-persistence
7904e751ac Use the same default spinner style for both Tile and List
The tile placeholder method didn't work well because the component doesn't know how big the page size is, so we always end up rendering 1 placeholder tile, followed by N (= page size) placeholders (if not yet resolved). It's pretty ugly.

Removed comments:
- Incorrect/misleading: "injected item" does not mean "ads". It can be any React component that you want to put at a specific index.
- Redundant: don't explain the syntax. It's very annoying having to maintain the comment when the logic changes.
2022-03-08 19:50:44 -05:00
Anthony
af8d742b75 add some comments for documentation 2022-03-08 10:53:52 -05:00
infinite-persistence
f24f6783d4 Removed background highlight for tile ads
- For https://github.com/OdyseeTeam/odysee-frontend/pull/1046#issuecomment-1061874612
2022-03-08 10:53:52 -05:00
infinite-persistence
0fa20114be Re-enable for Firefox Android
Since we are temporarily disabling the floating ad, it means that the invisible close button issue in Firefox Android is also temporarily not an issue.
2022-03-08 10:53:52 -05:00
infinite-persistence
cdcedb8063 Don't use EU script on mobile as it breaks the app 2022-03-08 10:53:52 -05:00
infinite-persistence
0143b63c74 Ads: replace DOM manipulations with React components
- Instead of 2 ways to display ads (DOM injection + React method) and having both of them clash, just do it the predictable React way.
    - Augment the existing React version to support tile layout + ability to place in last visible slot.
    - Consolidate styling code to scss ... DOM manipulations were making it even harder to maintain.
    - Removed the need to check for ad-blockers for now. It was being executed every time an ad is displayed, and now that we are displaying ads in more places, the gains doesn't justify the performance loss. Also, it wasn't being done for Recommended ads anyway, so the inconsistency probably means it's not needed in the first place.

Other known issues fixed:
- double ad injection when changing language via nag.
- additional "total-blocking-time" due to ads at startup removed.
- fixed ads not appearing in mobile homepage until navigated away and back to homepage.
- enable ads in channel page.
- support for both List and Tile layout.
2022-03-08 10:53:52 -05:00
infinite-persistence
e2f73a30c6 Remove triggerBlacklist
Since `triggerBlacklist` is just a simple boolean and `<Ads>` is not doing any additional logic on top of it, it doesn't make sense to pass as a parameter. Just not mount the component -- it's more concise and obvious at the client side.
2022-03-08 10:53:52 -05:00
infinite-persistence
1b0b9cad94 Cleanup ad container css
- Non hardcoded way to reserve space.
- Replace hardcoded margin.
2022-03-08 10:53:52 -05:00
infinite-persistence
f979f9b575 Code cleanup; no functional change 2022-03-08 10:53:52 -05:00
infinite-persistence
b0b0cd825b Recommended: restore ad location
Ticket: 1018
Reference: 2575c5d

- Restored position of the ad to the 4th slot.
- Moved repeated query out of the map predicate (`droppableProvided ?`)
- For draggables, make the injected item always on top for now. There are draggables with injected items at the moment.
2022-03-08 10:53:52 -05:00
infinite-persistence
65931202b0
Fix missing subs in sidebar on login
At least show the original list
2022-03-07 10:41:54 +08:00
infinite-persistence
5ba7b5e705
Following-Manage: increase size of 'Recently Active' entries for medium/large layout 2022-03-05 23:08:35 +08:00
infinite-persistence
1e7c9ab030 Hide comment thread-line when no replies
No replies when:
- haven't fetched yet
- replies blocked/muted

It's being displayed as a dot in these scenarios.
2022-03-05 08:59:53 -05:00
infinite-persistence
b5bd36839e Sidebar: show "last active subs" instead of "by name"
1003
2022-03-04 11:32:00 -05:00
infinite-persistence
4a5e967628 Recommended: fix "no results found" flashing after search
## Cause
When 'selectRecommendedContentForUri' is filtering results against the blocklist, it relies on claim data which could be unresolved yet. It filters to empty results for this scenario, hence the flashing message.

## Change
Just return raw results when claims are not resolved yet, so that the GUI knows it needs to show the placeholders while resolving. After resolving, it'll go through the blocklist filtering again.
2022-03-04 09:40:58 -05:00
infinite-persistence
de0bc8cf99 Recommended: optimize nextUri calculation
Instead of filtering the entire list for a suitable nextUri and then picking the first one, short-circuit when candidate is found.
2022-03-04 08:35:50 -05:00
infinite-persistence
cc780c95ae SignUp: don't show spinner when in focus (aka GetSync)
## Issue
Closes 1020 strange refresh on signup + youtube sync

It's due to the sync-on-focus.

## Change
Only show the spinner for the initial wallet sync. I thought we can do without the spinner for sync completely, but based on the comments below, better to retain that for the initial sync.  I think the rest of the stages don't need to block over a sync call.

```
// Don't claim the reward if sync is enabled until after a sync has been completed successfully
// If we do it before, we could end up trying to sync a wallet with a non-zero balance which will fail to sync
```
2022-03-04 08:28:32 -05:00
infinite-persistence
79978f026f
Localize the homepage selector too 2022-03-04 12:21:34 +08:00
infinite-persistence
76493d48ee
Missed remaining 'homepages' imports
This is a follow-up for #1016

Still doesn't affect anything at the moment, but this reduce the amount of work needed when we yank out the homepages from our bundle later.
2022-03-04 11:10:08 +08:00
infinite-persistence
8772ebe0ad Update CORS for homepage api so localhost works 2022-03-03 21:22:30 -05:00
Rafael
5dd457d045 Fix live chat 2022-03-03 11:39:42 -05:00
Rafael
fea79d81fb Rename selector 2022-03-03 11:39:42 -05:00
Rafael
c1a67f6864 Fix comment discussion mounted state when switching uris 2022-03-03 11:39:42 -05:00
Rafael
c4a23ff856 Fix batch resolve 2022-03-03 11:39:42 -05:00
Rafael
7c3cbaca15 Fix subs resolving on file page when sidenav closed 2022-03-03 11:39:42 -05:00
Rafael
96e7fda26a Batch-resolve channels on doCommentList fetch 2022-03-03 11:39:42 -05:00
saltrafael
7c304702d6
Fix locale fetch (#1017) 2022-03-03 11:29:23 -05:00
Thomas Zarebczan
71589721ef
Fix logic 2022-03-03 10:23:40 -05:00
infinite-persistence
66e0b84e12
Grab homepages from the content API (#1016)
Currently, homepages are still build as part of the app, so this change doesn't bring much benefit other than to support the wrapper app.

When the service is moved away from the app, we won't have to rebuild the app when homepages change, and also the ui.js bundle would be smaller without the need to code-split.
2022-03-03 09:22:59 -05:00
infinite-persistence
1510c8cf74
When video is playing, save position intermittently (#1013) 2022-03-03 12:21:01 +08:00
David Granado
7263bde491 Revert "Adjust logic to only run interval when video is playing."
This reverts commit 5ce6ab9689c1610f24869c7347b823cc2023b767.
2022-03-02 20:20:27 -08:00
David Granado
3631bdddbc Adjust logic to only run interval when video is playing. 2022-03-02 20:20:27 -08:00
David Granado
0f2eba8733 Switch unnecessary let to const 2022-03-02 20:20:27 -08:00
David Granado
abb92726ab Rename variable to include value units 2022-03-02 20:20:27 -08:00
David Granado
4d438ed62f Widen save interval 2022-03-02 20:20:27 -08:00
David Granado
38f00be231 When video is playing, save position intermittently 2022-03-02 20:20:27 -08:00
Thomas Zarebczan
c4ae797add
Remove deprecated migration 2022-03-02 21:48:40 -05:00
saltrafael
2e87c431ea
Improve logic for different scenarios (#1014) 2022-03-02 13:12:33 -05:00
Thomas Zarebczan
a01e4bad78
update iframe type + sentry 2022-03-02 12:45:26 -05:00
infinite-persistence
2eae20f0bd
Embedded images: serve via CDN for IP protection. (#1009)
## Ticket
536 "Embedding images without proxy is probably not in compliance with data protection regulations in Germany/Europe (GDPR)"
2022-03-02 11:23:34 -05:00
infinite-persistence
27f70d5f90
tus: try longer retry delays to maybe avoid lockups (#1012) 2022-03-02 11:03:49 -05:00
Raphael Wickihalder
fcbaa51df6
Fix OneTrust banner focus 2022-03-02 16:34:33 +01:00
infinite-persistence
5098b7cd87
RecommendedContent: fix ad-words filtering (#1007)
## Issues
Ad-filtering:
- Filtering was done whether or not ads are injected.
- Constants are repeatedly calculated.
- No short-circuiting in the for-loop.
- No memoization (being called 5-6 times on average due to redux updates, can't avoid that).

Others:
- Potentially passing null claimID to recsys (I think this is the issue that Johnny reported in Slack).

## Changes
- Moved 1-time calculations outside of the function.
- Optimized the filtering function and memoize it.
- Reduce unnecessary props since we are passing the whole `Claim` object already.
- Fix recsys being called when claim is not resolved yet (null claimId).
- Move away from the incorrect `makeSelect*` selectors.
2022-03-02 10:10:29 -05:00
saltrafael
712e02db16
Use locale/get response to suggest homepage and language switch (#839)
* Use locale/get response to suggest homepage and language switch

* Fix language modal condition

* Fixes from review

* Fixes from review

* Fix gdpr

* string

* Fix multiple options behavior

* Fix gdpr and use only one fetch

* Only show if no languages set or loaded

* pt-br

* Fix ad

* Fix homepage select

* Fix zh langs
2022-03-02 09:44:01 -05:00
infinite-persistence
f839e0c35d ClaimList: add default page-load indicator | Apply for Search and Following-Manage
Clients can still choose to roll their own way of showing "is fetching", like how ClaimListDiscover displays a whole bunch of placeholder tiles. This just serves as a default.
2022-03-02 09:16:43 -05:00
infinite-persistence
06f7cdbe25 Recommended section: add spinner while searching
It takes a while sometimes, so it feels like not doing anything.
2022-03-01 22:14:14 -08:00
Thomas Zarebczan
0939821963
try new recsys endpolnt
to prevent blocking from ublock
2022-03-02 01:01:11 -05:00
infinite-persistence
83a816bf34 Following Page: make the 2 buttons flow with less space used 2022-03-01 22:07:04 -05:00
infinite-persistence
19dc09b262 ScheduledStreams: don't apply horiz scroll in Medium screen 2022-03-01 22:07:04 -05:00
infinite-persistence
82c4170e64 ScheduledStreams: force horizontal-swipe to tile-only
List-layout is not scrollable, and doesn't look good either. Force to tile-only until we can fix it. If we decide to always use tile-only, then remove the parameter for ScheduledStreams.
2022-03-01 22:07:04 -05:00
Thomas Zarebczan
5048f7a2a1
update recys endpoints 2022-03-01 11:57:09 -05:00
infinite-persistence
bfd4c3bcfd Fix sub-count reducer incorrectly rejecting data
We skip fetching IDs that were just fetched a moment ago, so the array size will be reduced, but the reducer was still expecting all items to be fetched, hence the array size mismatch
2022-03-01 10:50:07 -05:00
infinite-persistence
6c76cff2a0 Fix sidebar subs inefficiencies
- `filteredSubscriptions` was running the filter code whether or not it actually required filtering, because the `!subscriptionFilter` logic is placed in the predicate. While it is a clean one-liner, it is slow when the subs list is huge.
    - While at it, moved the code into `getSubscriptionSection` to isolate things.

- The sidebar was resolving the entire subs list, which is super slow for a list of 500+. Since we now have a "Manage Subscriptions" page, just batch-resolve the N visible subs.
    - TODO: the code should probably be moved from 'app' to 'sideNavigate'.
2022-03-01 10:50:07 -05:00
infinite-persistence
3edb00b99d Manage Subs: change from claim_search to batch-resolve
The idea of using claim_search to indirectly batch-resolve didn't work out well. There's something wrong with the claim_search pagination where some results are duplicated in multiple pages, while some are missing. It's also returning less results that than the given number of claim ids, so sometimes the infinite scroll breaks.
2022-03-01 10:50:07 -05:00
infinite-persistence
0090e9b1ae Manage Subs page 2022-03-01 10:50:07 -05:00
infinite-persistence
1249b0394e claim_search: support ordering by 'name' 2022-03-01 10:50:07 -05:00
infinite-persistence
54f8bd35b3 DebouncedSearch: add inline option + use FormField
Using FormField so that the existing css works.
2022-03-01 10:50:07 -05:00
infinite-persistence
17a9b84df1 Following Page: use horizontal livestream tiles for mobile 2022-03-01 10:27:09 -05:00
infinite-persistence
b99c83a13f Fix "Results boosted by LBC" wrapping unnecessarily 2022-03-01 10:27:09 -05:00
infinite-persistence
d15a0308b2 Category livestreams: re-implement using subSection + use horizontal scroll in mobile
The `useDualLayout` junk is super confusing to maintain and no longer extensible.

At the expense of making the "livestream + regular" list no longer seamlessly continuous when expanded (or when there just a handful of livestreams), use the new `subSection` feature to inject the livestream tiles.  This is far easier to manage and tweak.
2022-03-01 10:27:09 -05:00
infinite-persistence
5f92ccbf47 ClaimListDiscover: add subSection area
This will be an additional area under Header/Meta that clients can put anything with.

Primary impetus is to place the Livestream Tiles in Wild West.
2022-03-01 10:27:09 -05:00
infinite-persistence
6b2d83986b Moved "Dismiss Pin" to the top
If it's a pinned commented, dismissing it is probably the action that the user is looking for, so doesn't make sense to put at the bottom.
2022-03-01 08:53:40 -05:00
Rafael
802dfb0ba8 Fix floating player on auth page 2022-02-28 10:45:54 -05:00
infinite-persistence
fee8e16bd8 Restore spacing between Sort and Filter on mobile
## Ticket
950
2022-02-27 21:38:30 -05:00
infinite-persistence
79a25986ed
Fix ICONS.SUBMIT lost in a prior commit 2022-02-27 18:01:59 +08:00
infinite-persistence
59e83f3fa8
tus: sentry improvements
## Ticket
910

## Changes
- Change the "message" from a generic "tus-upload" to more specific ones like "tus: failed to resume upload". These are grouped as "Events" in sentry, so we can isolate and search for them easily.

- Pass more info to Sentry (previously only available from Slack). It is still good to send to both, since some browsers block Sentry even without blocker extensions.

- Reduce verbosity of Slack's

## Notes
- Was unable to change the "unknown" problem mentioned in the ticket. The API does not accept `new Error('xxx')`, even though that's being mentioned by many in the forums. It might be due to the version of Sentry that we are using.

- To search for tus issues, go to "Issues" and query `message:tus*`. Results are collapsed per event, so click on the item of interest, then click "Events" at the upper right to see all occurrences of the same problem.
2022-02-27 17:40:19 +08:00
Thomas Zarebczan
cfea97dd96
Claim title fixes
Also fixed bug on mentions
2022-02-26 13:48:22 -05:00
infinite-persistence
f88bfcd7f3 Render whole app on language change
## Issues
1. We were manually adding `selectLanguage(state)` as a prop to components used in Settings Page to trigger a render. Flaws:
    - Unclear that the unused prop is just to trigger a render.
    - Manually adding on a case-by-case basis will break over time, especially when language can now be changed outside of the Settings Page.

2. The translation file fetching is delayed and also takes time, so the GUI will end up having mixed strings on F5, depending on when the fetch completed.

## Approach
Make the app wrapper have a key that's tied to the language and translation data, so the entire app renders when language changes. Seems like a common design in most apps.

## Ticket
921 language refresh / selection issues
2022-02-26 13:08:17 -05:00
infinite-persistence
3f8dfd5b21 Stop logging localStorage sizes
The issue has been solved, plus we've collected enough data.
2022-02-26 10:34:12 -05:00
infinite-persistence
5c91d55cbc Fix sub/view count not in compact form for some components
## Ticket
968 Truncate views/subs in other areas

## Changes
- Corrected logic for `minThresholdToApply`, which was ignoring the case of "no threshold", causing it to not be truncated in Channel Page. We want to always truncate there due to the smaller cards.

- Missed out handling `ClaimPreviewSubtitle`.
2022-02-26 10:27:25 -05:00
infinite-persistence
95654079f3
Remove obsolete config flags 2022-02-26 21:21:50 +08:00
infinite-persistence
f88bc697be
README: remove obsolete items + improve formatting
I think the custom homepage instruction might be obsolete too (now pointing to v2?), but leaving as-is for now.
2022-02-26 21:19:01 +08:00
infinite-persistence
7a59976a5d
i18n: context-split "Duration"
Request from Chinese translator.
2022-02-26 20:35:04 +08:00
infinite-persistence
241a6182a2
FormFieldDuration: 'mo' incorrectly hinted as 'month' + i18n fix
The unit is either 'month' or 'b', so the tooltip and placeholder was incorrect.

Also fixed the tooltip to make it localizable.
2022-02-26 20:25:56 +08:00
infinite-persistence
45181c61b8 Highlight the "Search in selected language" if coming from the hint 2022-02-25 16:53:45 -05:00
infinite-persistence
9665f7f4c2 Add ability to highlight a Settings Row 2022-02-25 16:53:45 -05:00
infinite-persistence
1777397f07 Add hint that results are being filtered by language 2022-02-25 16:53:45 -05:00
infinite-persistence
3974ca6322 ClaimListDiscover: if 'uris' is given, there is no need to perform a search
This was causing unnecessary calls that won't be used.
2022-02-25 16:53:45 -05:00
infinite-persistence
99d8d0dbee Discover: fetch livestreams "per-language", if enabled.
Fetch it using the same language parameters for claim_search that is used in the embedded ClaimListDiscover.
2022-02-25 16:53:45 -05:00
infinite-persistence
a14239a9dc Livestream fetch: add language option
The function argument order can be a bit ugly, but putting it at the back as optional param makes it easier to test without affecting existing clients.
2022-02-25 16:53:45 -05:00
infinite-persistence
c6d8687cfa ClaimListDiscover: pull out 'claim_search' language code for re-use, so all clients are sending the same value. No functional change. 2022-02-25 16:53:45 -05:00
Thomas Zarebczan
f1fdfcd329
Fix missing channel name
Easier to use channel name for now, we can add title later to notifications
2022-02-25 15:15:54 -05:00
infinite-persistence
49fc238e4c
Use titles vs names on channel claim previews, but show name in channel areas (#962)
* use titles

* Sidebar: show "title + name"

Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2022-02-25 09:04:23 -05:00
Max Kotlan
d5a91b5917
fixed mobile scrolling issue on settings page (#953) 2022-02-24 12:14:01 -05:00
Rafael
ea43f84347 Fix search replacing 2022-02-24 12:42:43 -03:00
saltrafael
2152583816
[Fix] linked uris (#959)
* Fix live claim uri being passed

* Refactor show page

* Fix linked comment being erased
2022-02-24 10:20:07 -05:00
Thomas Zarebczan
b4b7803684
Remove FB image test 2022-02-24 10:04:37 -05:00
infinite-persistence
77aa405fc6
Increase specificity of og:type (#955)
Doesn't seem to do much, but it is what others do, so might as well be specific.
2022-02-24 00:11:57 -05:00
infinite-persistence
2b271730cc
WildWest: always show boosting message (#957)
## Ticket
948 wildwest: always show boosting message, move next to category name

## Changes
1. Make "Show less livestreams" share the same space as "Boosted by LBC", instead of only showing either 1.
    - It's a bit troublesome to move it next to the filter without tweaking the generic `ClaimListDiscover`, so I think this would be a good compromise.

2. Fix "show less livestreams" being super tiny in mobile.
    - I think it is caused by some component-specific changes are being applied at the global level (not sure).
2022-02-23 23:24:41 -05:00
Thomas Zarebczan
c33f7338c7
Adjust open chat window 2022-02-23 18:26:23 -05:00
Thomas Zarebczan
3d23c7f78b
Test FB preview
Can determine image type dynamically later, just wanted to test out to see if previews are full screen.
2022-02-23 18:17:08 -05:00
saltrafael
17e3fcc27c
[Fix] revert fileRenderFloating vs Mobile change (#937)
* Bump react-draggable

Old version was giving out console errors for outdated react functions

* Refactor fileRenderFloating

* Merge fileRenderMobile into fileRenderFloating

* Fixes from review

* Attempt fix failed to view live
2022-02-23 16:13:22 -05:00
infinite-persistence
d6cd3caa77
Comment: minimum channel age (#940) 2022-02-23 23:06:52 +08:00
infinite-persistence
51d4407002
Don't allow a duration that exceeds Feb 8th
> _Max date it can do is back to : 2022-02-08 - so don't allow a days value that's higher than this. (hint before selection / submission if possible)_

My initial understanding was that it is ok to set beyond this date (e.g. "1 year"), just that any channels created before Feb 7 will still be able to comment even if they are less than a year old.  That feels like ok behavior to me (easier for user to grasp), but turns out setting anything before that date will block all channels.

So, this commit changes the warning message and also blocks the user from finalizing.
2022-02-23 23:01:59 +08:00
infinite-persistence
2e26064d2f
Replace commentron's min-age error message
Hopefully this is more concise, but it's meant more as a placeholder for others to edit easily.
2022-02-23 23:01:58 +08:00
infinite-persistence
f70e631953
Add "min channel age" setting 2022-02-23 23:01:57 +08:00
infinite-persistence
8ace40522e
Add modal to change "min channel age"
It'll be easier to handle through a modal -- we won't need to debounce the values, and it also clears up the clutter from 'settingsCreator'
2022-02-23 23:01:56 +08:00
infinite-persistence
89577950c2
Factor out 'FormFieldDuration' for re-use 2022-02-23 23:01:55 +08:00
infinite-persistence
6be519374a
Readme: remove desktop and useless badges (#947)
- The build status is for desktop. Not sure what our `master` CI link is, so removing for now.
- The other 2 "forthebadge.com" doesn't seem to make sense. Looks like hardcoded stuff rather than reflecting status.
- Remove duplicate `alt` tag
2022-02-23 09:58:52 -05:00
infinite-persistence
db5d0a70aa
Ignore "search in language" setting in Channel Page (#944)
It's confusing to see blank channel pages due to this setting.
2022-02-23 09:43:42 -05:00
infinite-persistence
69de63c436
Revert "Add pagination support to channel search (#791)"
This reverts commit b3c4ce05fa.

The suggested 2-list approach broke the search bar because the bar is part of the list, so it gets unmounted while the user is typing.  Oops.
2022-02-23 21:25:12 +08:00
infinite-persistence
cfd234d615
ClaimPreview & sidebar: strip '@' since channel is implied (#879)
## Ticket
865: Hide @ symbol in areas where channel names are implied
2022-02-23 07:42:43 -05:00
infinite-persistence
39de1d7e84
Band-aid: warn about AdGuard blocking our CDN (#934)
* Band-aid: warn about AdGuard blocking our CDN

Getting 50-100 errors per day. This will be a band-aid until the AdGuard fixes it.

* update message

Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2022-02-22 14:17:41 -05:00
infinite-persistence
c74dbbb68a
tus: QuotaExceededError (#935)
* Move into getLocalStorageSummary + always log

- Move into getLocalStorageSummary to clean up the clutter.
- Always log the localStorage info to get a bigger picture of what's going on with the QuotaExceededError.

* Remove 'findPreviousUploads' - we use the url stored in Redux.

Something I forgot to remove in the past. It also reads from localStorage, so remove since we are trying to avoid touching localStorage.

* Ensure localStorage is not used when uploading

I don't think it's being written when `storeFingerprintForResuming` is disabled, but doing the suggestion nonetheless.

`https://github.com/tus/tus-js-client/issues/315#issuecomment-1046821112`
2022-02-22 10:11:22 -05:00
infinite-persistence
9a95c9f64d
Add "Sync YT Channel" to sidebar (#933)
Closes 915
2022-02-22 07:07:48 -05:00
infinite-persistence
c1fed3f4df
Undo tus-sentry experiment since it completely broke 2022-02-22 00:43:57 +08:00
infinite-persistence
0ae015b7a5
Revert "tus: remove 'uploader' param -- seems to be breaking Sentry."
This reverts commit f14e7ad0ec.
2022-02-21 23:02:59 +08:00
infinite-persistence
f14e7ad0ec
tus: remove 'uploader' param -- seems to be breaking Sentry. 2022-02-21 22:28:03 +08:00
infinite-persistence
79f1b1242d
Clear search cache instead of full reload on homepage 2nd-click (#930)
## Ticket
lbry-desktop 6841

## Issue
If you are already at the homepage and you click the "Home" or "Odysee" logo again, the entire page reloads, causing the whole startup sequence to re-run (lots of fetches).

This can be annoying when not intended (e.g. clicked too many times), as startup is slow for some and we also lose non-persistent Redux data (for debugging).

I believe the requirement was just to reload the homepage tiles, as they might be showing stale ones after a while. A full reload was the quick-and-easy fix.

## Approach
Best not to touch the complicated `ClaimTilesDiscover`, so just clear the search cache key in this scenario. `ClaimTilesDiscover` will then pick this up and perform a new `claim_search`.
2022-02-21 07:54:23 -05:00
infinite-persistence
4314fcd6be
WildWest: fix livestream expansion resetting y-pos (#923)
## Root-cause?
It doesn't happen on the commit before the Theme change. However, it's possible that the y-pos is reset since we are indeed unmounting the dual list and re-mounting the single list.

Maybe the css got more efficient and we ended up painting more frames than before.

## Fix
Fix by stashing and restoring the the y-position during the expansion.
2022-02-21 07:44:26 -05:00
infinite-persistence
5b81346e59 Sentry: fix tus errors
The first parameter should be the error object, not a general label.
2022-02-21 00:12:37 -08:00
dependabot[bot]
7612722263
Bump url-parse from 1.5.3 to 1.5.7 in /web (#926)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-19 14:40:32 -05:00
dependabot[bot]
d31de7e3e2
Bump url-parse from 1.5.3 to 1.5.7 (#927)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-19 14:40:25 -05:00
Raphael Wickihalder
2ee829e8e3 Merge branch 'ravedev' 2022-02-19 17:31:08 +01:00
Raphael Wickihalder
2b16523a39
Fix umlaut cutoff in buttons 2022-02-19 17:29:27 +01:00
Raphael Wickihalder
f16ae357fd
Revert 2022-02-19 00:32:08 +01:00
Raphael Wickihalder
a2dcdfb8ab Merge branch 'ravedev' of https://github.com/OdyseeTeam/odysee-frontend into ravedev 2022-02-19 00:30:45 +01:00
Raphael Wickihalder
f890f0896b
Test signature 2022-02-19 00:30:08 +01:00
Thomas Zarebczan
4fe668900f
Add hungarian - hu 2022-02-18 13:40:33 -05:00
saltrafael
178dec7030
Fix null active channel case (#918) 2022-02-18 12:22:21 -05:00
Max Kotlan
56f8d8b71a
Custom body scrollbar + disable body scroll when overlay or image viewer opened (#897) 2022-02-18 18:03:15 +01:00
Raphael Wickihalder
6a69e02d57 Merge branch 'ravedev' 2022-02-18 18:00:36 +01:00
Raphael Wickihalder
4c27d6673f Fix following button on channel page on mobile in guest mode 2022-02-18 17:57:37 +01:00
Raphael Wickihalder
6e79aa4950 Adjust channel wrapper spacing on file page on mobile 2022-02-18 17:57:36 +01:00
Raphael Wickihalder
4d77d2a6c6 Fix following button on channel page on mobile in guest mode 2022-02-18 17:56:39 +01:00
Raphael Wickihalder
6805e78d2c Adjust channel wrapper spacing on file page on mobile 2022-02-18 17:52:30 +01:00
infinite-persistence
a6316ce71e
Fix header avatar stuck in pending mode when all channels are deleted (#911)
## Issue
535

## Change
- Header: Use the "channel list undefined" instead of "active channel url undefined" to determine if the button should be "pending".
- App: restore the use of `activeChannelClaim` instead of `activeChannelId`. In the existing design, the latter is never cleared is some situations, so the former is more accurate as it takes the current channel list into account. We might want to hide (not export) `activeChannelId` to avoid this mis-use again.
2022-02-18 08:14:54 -05:00
infinite-persistence
636b00f9db
Sync up with recent homepage string changes 2022-02-18 20:00:37 +08:00
infinite-persistence
aedd194be6
Various i18n fixes 2022-02-18 20:00:36 +08:00
infinite-persistence
c04f61d318
Fix incorrect usages of I18nMessage 2022-02-18 20:00:36 +08:00
infinite-persistence
88e0ea5d7d
Missing strings 2022-02-18 20:00:35 +08:00
infinite-persistence
58a1614c92
Fix tip method split string 2022-02-18 20:00:35 +08:00
infinite-persistence
8441bd020a
Corrected 'SuperChat' to 'HyperChat' 2022-02-18 20:00:34 +08:00
Raphael Wickihalder
299c3ff021 Merge branch 'ravedev' 2022-02-18 12:57:03 +01:00
Raphael Wickihalder
a697d70ff9 Fix repost ribbon on search result page 2022-02-18 12:56:03 +01:00
Raphael Wickihalder
09ee8829ed Fix repost ribbon on search result page 2022-02-18 12:55:16 +01:00
Raphael Wickihalder
2d2edf986f Adjust channel wrapper spacing on file page 2022-02-18 12:37:45 +01:00
Raphael Wickihalder
f109ee2db2 Adjust channel wrapper spacing on file page 2022-02-18 12:33:08 +01:00
Raphael Wickihalder
a3f00944d4 Fix top page repost ribbon & buttons on mobile 2022-02-18 11:51:48 +01:00
Raphael Wickihalder
5af52bd032 Fix calendar overflow on livestream setup page on mobile 2022-02-18 11:15:31 +01:00
Raphael Wickihalder
23d4de5457 Merge branch 'ravedev' 2022-02-18 09:26:28 +01:00
Raphael Wickihalder
d0920317ad Adjust comment section width on markdown page on HiDPI screens 2022-02-18 09:23:47 +01:00
Raphael Wickihalder
745148c2dc Fix 'Find new channels' page on mobile 2022-02-18 09:15:56 +01:00
Raphael Wickihalder
e23e0f526d Optimize DMCA page on mobile 2022-02-18 09:03:35 +01:00
Raphael Wickihalder
d95593486f Adjust input focus in reply 2022-02-18 08:50:49 +01:00
Raphael Wickihalder
f18b851edb Optimize comment input section on markdown page on mobile 2022-02-18 08:46:41 +01:00
infinite-persistence
9f7dda0234
Update commentron url 2022-02-18 09:19:53 +08:00
infinite-persistence
678a160f7c
Fix missing homepage placeholder while waiting for livestream data (#904)
## Issue
When loading the homepage, I kept seeing a blank page with footer first. Even Google is picking it up.

## Ticket
572 Slow appearance of tiles

## Notes
The tiles were originally delayed to prevent the "Upcoming Livestream" section from causing layout shifts.

With the new theme, the footer would cause a visible shift anyway.  Hiding the footer is one solution, but I think not showing anything until the fetch is done is bad because the livestream fetch could stall.
2022-02-17 09:18:49 -05:00
infinite-persistence
95f90d8a84
Fix autoplay-next not working on mobile
## Why
The playing URI was being cleared every time we leave the File Page, I believe to prevent the floating from continue playing outside of the File Page.

## Approach
Close FileRenderMobile by checking playingUri/primaryURI instead.
For the case of livestreams, just display it.
2022-02-17 17:37:58 +08:00
infinite-persistence
cb441ef5f4
Don't report thumbnail size errors
These are now checked at client side (not CDN side), so not actually an error worth collecting.

Also removed "Uploading the same file from multiple tabs or windows is not allowed." -- no longer exists.
2022-02-17 13:54:54 +08:00
AsadUmar
50423111af
Fix/use has window width changed enough (#894)
* fix render of toggle.

* Fix useHasWindowWidthChangedEnough

* fix flow

Co-authored-by: Asad Umar <au@visuary.fr>
2022-02-16 14:08:57 -05:00
Evans Lyb
b3c4ce05fa
Add pagination support to channel search (#791)
* Add pagination support to channel search

* fix #605 - channelContent component - replace lighthouse.search() to doSearch()

* #605 - Add pagination support to channel search - create ClaimListSearch component to support channel search instead of ClaimListDiscover

* #605 - Add pagination support to channel search - fix lint errors & component naming error

Co-authored-by: Kyle <kyle.mai@wiredcraft.com>
2022-02-16 23:01:20 +08:00
Rafael
2606758c0d Also hide discover but exclude tag params 2022-02-16 06:53:21 -08:00
infinite-persistence
24d23b8cc9
Fix video thumbnail selector exceeding the modal size (#891)
## Issue
- 655 "Take a snapshot from your video" controls off-screen
- It also exceeds horizontally on mobile.

## Fix
Just add css constraints.
2022-02-16 09:50:41 -05:00
infinite-persistence
80d4d8c57c
Limit channel-creation count from the UI (#886)
## Issue
534 prevent new channel creation over x channels

## Notes
Also handled from the API call (`doCreateChannel`) in case there are other UI components that create channels.
2022-02-16 09:14:08 -05:00
saltrafael
0774090bdc
Remove extra scrollbar (#888) 2022-02-16 07:49:17 -05:00
infinite-persistence
70c05972cc
Fix "key missing in list" errors (#885) 2022-02-16 16:38:48 +08:00
infinite-persistence
c512b1147e
Notification: fix "missing key in list" error 2022-02-16 16:37:05 +08:00
infinite-persistence
d4f26c4272
ClaimList: fix "missing key in list" error
Each list item must have a unique key, and I didn't realize it needs to happen at the `<React.Suspence>` level too.
2022-02-16 16:37:05 +08:00
infinite-persistence
b56dc66f23 Remove i18n on repost ribbon since there is no text. 2022-02-16 00:36:42 -08:00
infinite-persistence
88907901a1 Fix livestream date incorrect if short url is used
## Issue
- "https://odysee.com/LIVE:6dd" yields "Live 3 months ago" (incorrect)
- "https://odysee.com/@RekietaLaw:a/LIVE:6dd" yields "Live 30 minutes ago" (correct)

## Approach
Use claim ID instead of uri when searching `activeLivestreams`
2022-02-15 22:16:46 -08:00
infinite-persistence
a636d7d8c9
UriIndicator: props cleanup, no functional change
- Marked optional props properly.
- Re-ordered to make it easier to differentiate "props used in jsx" vs. "from redux".

Separated the commit to make the upcoming diffs easier to read.
2022-02-16 11:53:53 +08:00
toshikanneko
c2c44f7334 Adjust level indicator star border in header 2022-02-15 20:44:06 +01:00
toshikanneko
dc31c0f8fe Merge branch 'master' of https://github.com/OdyseeTeam/odysee-frontend 2022-02-15 20:38:52 +01:00
saltrafael
381200800e
Revert tips by amount on hyper chat banner (#877) 2022-02-15 14:28:06 -05:00
saltrafael
60d9acfa55
Hide Wild West for DE (#875) 2022-02-15 12:36:33 -05:00
toshikanneko
f60a267b61 Merge branch 'master' of https://github.com/OdyseeTeam/odysee-frontend 2022-02-15 16:58:08 +01:00
David Granado
a38ef1337a
Fix css specificity issue on skip-button. (#853) 2022-02-15 10:40:19 -05:00
saltrafael
6fa12bf237
Fix wrong param for selector (#874) 2022-02-15 10:35:39 -05:00
toshikanneko
df67e4fbd6 Adjust level star border color 2022-02-15 14:11:23 +01:00
toshikanneko
95d8ea6f0d Adjust level star border width 2022-02-15 14:07:44 +01:00
toshikanneko
9d0b7f3e35 Add border to level stars 2022-02-15 14:03:39 +01:00
toshikanneko
98e6487dd8 Adjust font sized in upload modal on mobile 2022-02-15 11:08:22 +01:00
toshikanneko
f79f0b02a0 Fix font color on YouTube sync page 2022-02-15 10:56:20 +01:00
toshikanneko
7a85f410d8 Adjust pending animation position on upload page on desktop 2022-02-15 10:54:24 +01:00
toshikanneko
586ec1e39c Adjust font sizes in modal on mobile 2022-02-15 09:43:39 +01:00
toshikanneko
80335b0e4d Adjust button size & spacing on upload page on mobile 2022-02-15 09:36:26 +01:00
toshikanneko
9e75e2a711 Realign publishing animation on upload page on mobile 2022-02-15 09:33:06 +01:00
toshikanneko
ae86f5df63 Fix items tab on list publish page on desktop 2022-02-15 09:25:07 +01:00
toshikanneko
b5a6a35f64 Adjust font size on upload page on mobile 2022-02-15 09:16:13 +01:00
infinite-persistence
b3020b6cfb
Lazy-load "Beautiful Drag-N-Drop" (#859)
Code-splits the module into "dnd.js", reducing the ui.js bundle size. This module is only needed when viewing lists.

## Room for improvement
`ClaimList` can probably improve further by only using the dnd components in "edit" mode.

## Implementation notes
- The modules are not default exports, so the additional chaining to `React.lazy` was required.
- Experimenting with using an Object to store the import so that a single "prettier-ignore" can be used to make it not wrap.
- The FlowFixMe came from the original code. It is unclear why it is needed to resolve the module, but Haffa mentioned it's something related to .flowconfig.
2022-02-14 14:54:23 -05:00
saltrafael
ecc3599a85
Improve scrolling behavior, fix tips sorting (#863) 2022-02-14 14:28:25 -05:00
dependabot[bot]
5c5b46ddb3
Bump follow-redirects from 1.14.7 to 1.14.8 in /web (#866)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-14 14:23:57 -05:00
infinite-persistence
85ef16026d tus: log reason for QuotaExceededError
We no longer ask tus to save the upload URL since December, so there should no reason for it to be writing to localStorage.

Adding more logs to determine what is the actual cause -- localStorage being full, or not available. Neither should affect the upload but they are the only known causes for that error message, so try to narrow down the investigation path.
2022-02-14 09:41:46 -08:00
toshikanneko
7bbfd81762 Realign stars in channel level indicator 2022-02-14 16:28:24 +01:00
toshikanneko
9cd80ee41e Realign stars in channel level indicator 2022-02-14 16:24:56 +01:00
toshikanneko
e41c2141a2 Remove black background from channel level 2022-02-14 16:22:12 +01:00
toshikanneko
9d325d5c59 Adjust reload button position in comment section on mobile 2022-02-14 15:18:55 +01:00
toshikanneko
f94f7e0b1c Add hover effect to player buttons 2022-02-14 15:03:45 +01:00
toshikanneko
7c0b84d497 Adjust colors in comment/chat swipe button on mobile 2022-02-14 14:09:40 +01:00
toshikanneko
ff6d335bb0 Adjust ratio bar width on dekstop 2022-02-14 13:53:18 +01:00
toshikanneko
de56aeec09 Adjust snack bar position on mobile 2022-02-14 13:50:04 +01:00
toshikanneko
8298f41526 Adjust some spacing on upload page on mobile 2022-02-14 13:17:22 +01:00
toshikanneko
1ef68c1472 Fix ratio bar width bug on livestream page 2022-02-14 12:54:13 +01:00
toshikanneko
3140c103ad Adjust textarea in upload form on mobile 2022-02-14 12:40:42 +01:00
toshikanneko
90c2a60799 Adjust spaces in upload form on desktops 2022-02-14 12:21:35 +01:00
toshikanneko
895be3fff3 Adjust active tab indicator 2022-02-14 11:48:55 +01:00
toshikanneko
64ffc5a0e1 Adjust handle link color in markdown 2022-02-14 11:26:23 +01:00
toshikanneko
f0efd7afdb Fix long label ratio bar distortion bug 2022-02-14 11:23:21 +01:00
toshikanneko
f1b95ce05c Adjust ratio bar width on markdwon page 2022-02-14 11:21:15 +01:00
toshikanneko
4c293b7ae5 Increase mardown page width on large screens 2022-02-14 11:17:50 +01:00
toshikanneko
98dd6c6adf Fix handle font sizes on markdown page on desktop & mobile 2022-02-14 11:13:06 +01:00
toshikanneko
569e4fb334 Fix login hover bug in light theme 2022-02-14 10:38:43 +01:00
infinite-persistence
0947393912
Comments: inline image not working for level4/5 channels
## Ticket
852 Markdown inline images in comments don't work for any channel level

## Change
The prior commit simplified the props from individual comment fields to just 1 `Comment` object, but there was a typo in the parameter where it should be `channel_url` instead of `author_uri`.
2022-02-14 13:15:28 +08:00
Thomas Zarebczan
c34840a4d4
Fix some RSS issues 2022-02-13 15:25:18 -05:00
toshikanneko
11338170e7 Fix playlist remove item label on playlist page 2022-02-13 16:00:24 +01:00
toshikanneko
778940193e Hide unmute button on mobile 2022-02-13 11:58:22 +01:00
toshikanneko
e537679624 Hide unmute button on mobile 2022-02-13 11:44:22 +01:00
toshikanneko
6c178993af Adjust position of play button on active element in playlist on mobile 2022-02-13 11:21:55 +01:00
toshikanneko
162b77a078 Fix video poster misaligned on mobile 2022-02-13 11:18:28 +01:00
toshikanneko
04137b4ec8 Fix video poster misaligned 2022-02-13 11:09:46 +01:00
toshikanneko
d4f0d99fe1 Temp show repost ribbon on category pages 2022-02-12 19:54:24 +01:00
toshikanneko
6537fc855e Hide repost ribbon on category pages 2022-02-12 19:31:54 +01:00
toshikanneko
06782c0e31 Hide repost ribbon on category pages 2022-02-12 19:30:55 +01:00
toshikanneko
9703ba2eb3 Adjust hyperchat row on mobile 2022-02-12 17:55:27 +01:00
toshikanneko
a0a664baf5 Adjust font size in chat on mobile 2022-02-12 17:48:03 +01:00
toshikanneko
28a1bfefab Adjust font size in comment section on mobile 2022-02-12 17:38:37 +01:00
toshikanneko
559ab774f6 Adjust frozen avatar size in comment section on mobile 2022-02-12 16:55:50 +01:00
toshikanneko
9573f30b8d Adjust avatar size in comment section on mobile 2022-02-12 16:54:46 +01:00
toshikanneko
039cccba87 Remove markdown font size from comment section on markdown page 2022-02-12 09:48:09 +01:00
infinite-persistence
d102cbe802
Fix broken resolves due to escaped characters (#849)
## Issue
`/$/embed/尾崎豊----大阪球場ライブ%E3%80%801_6/bfd63daa9453bb1a11674ca8a7c5f5dd6b49d024?r=2ituZftpdG18f1TBADDbCaaEZ9ecYYYm` wasn't working

## Change
Probably need to revisit this properly, but for now, grab the `requestPath` that's needed for resolving before escaping the characters.

Tested that `http://localhost:1337/$/search?q=%22\/%3E%3Cimg%20s+src+c=x%20on+onerror+%20=alert(1)+\%3E` would still be blocked.
2022-02-11 21:26:36 -05:00
toshikanneko
f17662cf46 Fix top page subscribe button icon color 2022-02-12 01:09:29 +01:00
toshikanneko
ee8791004b Fix top page subscribe button color 2022-02-12 01:03:51 +01:00
toshikanneko
e7e7d143e3 Fix top page support button position & color 2022-02-12 00:58:19 +01:00
Thomas Zarebczan
d6d3328201
Fix edit from claim menu 2022-02-11 17:27:25 -05:00
Rave | 図書館猫
2001d769ac
theme-hotfix (#846) 2022-02-11 20:41:53 +01:00
mayeaux
0c4f85fe53
MAKE ODYSEE EVEN MORE BEAUTIFUL (#539)
WE LOVE YOU RAPHAEL FOR MAKING THIS HAPPEN!
2022-02-11 13:50:55 -05:00
infinite-persistence
0cdf6e1970 i18n : mobile revamp and more 2022-02-11 09:39:01 -05:00
Rafael
2d39325a24 Fix edit 2022-02-09 15:39:15 -05:00
Thomas Zarebczan
f943affb19
update reports endpoint. 2022-02-09 15:06:38 -05:00
Rafael
5c028fea7f Fix commentCreate focus and blur issues 2022-02-09 14:00:11 -05:00
Rafael
63cc5da092 Expand override for mobile livestream layout 2022-02-09 11:48:40 -05:00
Rafael
2a7b9364e4 Fix missing navigate on Edit mobile menu button for own claims 2022-02-09 11:48:40 -05:00
Rafael
aaf36e88dd Cleanup Comment and CommentsList and fix new pages
- Fixes new pages not fetching at all inside a drawer component
- Fixes fetching multiple pages at once some times
2022-02-09 11:48:40 -05:00
infinite-persistence
f9a1fcc6a7 Bump thumbnail size to 5MB & check size before upload.
- The previous 2MB was a CDN limit (more of a mistake). That has been increased to a far greater number, so we're setting a more reasonable 5MB limit.
- The previous code checks/shows the "size exceeded" message after the file has been uploaded ... in the `catch` block. This will not work since the CDN now allows a 5MB file.
    - Fixed by checking the size before actually uploading.
2022-02-09 11:14:46 -05:00
infinite-persistence
0f5948d871 Don't upload file if "Use URL" is selected
## Issue
When pressing "Done", it will call the upload function, which usually results in a "please select a file" error, or the file being uploaded if a file was selected prior to switching to "Use Url".
2022-02-09 11:14:46 -05:00
infinite-persistence
02accb5c79 Strip timestamp from url when resolving for OG
`Lbry.resolve` won't work with timestamps in the url.
2022-02-09 10:11:31 -05:00
Thomas Zarebczan
56c39cf60e
update search domain 2022-02-08 14:39:45 -05:00
Thomas Zarebczan
bb14fe30b4
update videoplayer 2022-02-08 13:34:37 -05:00
Rafael
07eaba5a89 Unscape uri for resolve 2022-02-08 13:34:26 -05:00
Rafael
dae0f9c3d5 Fix keyboard & comment selectors open affecting scroll 2022-02-08 12:35:40 -05:00
Rafael
e42090d3b6 Change scroll behavior 2022-02-08 12:35:40 -05:00
Rafael
b5c7f9cd8a Focus on Tap at the end of the line 2022-02-08 12:35:40 -05:00
Rafael
0394211021 Fixes 2022-02-08 12:35:40 -05:00
Rafael
1f367c641e Cleanup Form-Field
- avoid declaring components inside the body function of parent components https://dev.to/borasvm/react-create-component-inside-a-component-456b
2022-02-08 12:35:40 -05:00
Rafael
ba5d96bb71 fixes 2022-02-08 12:35:40 -05:00
Rafael
59a06dbc3b Fix redux actions 2022-02-08 12:35:40 -05:00
Rafael
c758c59066 Improve comment selectors 2022-02-08 12:35:40 -05:00
Rafael
2b56ca8599 Cleanup CommentCreate 2022-02-08 12:35:40 -05:00
Rafael
67053beda9 Fix drawer resize 2022-02-08 12:35:40 -05:00
Rafael
6bb7a155cd Add help tip notice to input 2022-02-08 12:35:40 -05:00
Rafael
83a535928d Allow adding tip to sticker chats 2022-02-08 12:35:40 -05:00
Rafael
9067a024ab Improve unauth 2022-02-08 12:35:40 -05:00
Rafael
0399250906 Add drawer subtitle (ex view count for livestreams) 2022-02-08 12:35:40 -05:00
Rafael
3a511d0647 Fix recent comments 2022-02-08 12:35:40 -05:00
Rafael
1a87fb6239 Fix Autoplay 2022-02-08 12:35:40 -05:00
Rafael
575e73dccd Fix empty comments disabled message 2022-02-08 12:35:40 -05:00
Rafael
6bf4add07c Fix outline style 2022-02-08 12:35:40 -05:00
Rafael
87523570cf Fix unrecognized prop 2022-02-08 12:35:40 -05:00
Rafael
25182c7dcf Fix chat scroll 2022-02-08 12:35:40 -05:00
Rafael
6a9b9247ce Fix linked comment scroll 2022-02-08 12:35:40 -05:00
Rafael
c90efc2078 Add CommentCreate to Modal on Mobile
- Move stickers and emojis to a single menu comment-selectors on both mobile and desktop
- More style improvements
- Some fixes
- Fix livechat scrolling
2022-02-08 12:35:40 -05:00
Rafael
eef6691557 More comment create and textarea improvements 2022-02-08 12:35:40 -05:00
Rafael
b3ed0027ff SwipeableDrawer improvements
Fix css stuf

Split mobile and small popout window styles

Fix failed logic that broke desktop player
2022-02-08 12:35:40 -05:00
Rafael
55e0a7effe Improve CommentCreate style on mobile view 2022-02-08 12:35:40 -05:00
Rafael
c1b84368a9 Fixes
Rename FileReactions index import

Fix fileAction undefined logic

Fix live comment menu

Fix superchats
2022-02-08 12:35:40 -05:00
Rafael
baf51f9c32 Create swipeableDrawer component
- CommentsList needs to return a title with comment amounts
- mobile player dimensions needed to fill in the cover
- hid livestream header for now until figuring out a better presentation
- ~colum-reverse~ was causing problems with MUI's drawer scrolling, so reversed the chat order and made it ~column~ by default
- Hid bottom expand navigation if component not yet opened
- some other style changes in the middle
2022-02-08 12:35:40 -05:00
Rafael
ce11a4b9c1 Use modal for tip selection 2022-02-08 12:35:40 -05:00
Rafael
b1c1263cca Improve comments on mobile view 2022-02-08 12:35:40 -05:00
Rafael
8c3e376873 File Page and Player style changes on mobile view
- Biggest change: Moved mobile player logic outside of fileRenderFloating into its own component fileRenderMobile, since there is no need for all that extra resizing and dragging code (for now, as mobile doesn't have a floating player)
- Moved player to the header height
- Removed rounded borders and margins
2022-02-08 12:35:40 -05:00
Rafael
0c47f1daa9 Refactor fileRenderIninitiator component
- Only pass necessary props
- Created new initialize play redux action
- Removed deprecated ~file app download~ keyboard functionality, moved preventDefault to videojs keyboard events to prevent ~space~ moving down the page
2022-02-08 12:35:40 -05:00
Rafael
a84ebbc68f File Page style improvements on mobile view
Improve channel preview info display on mobile view

- Slightly smaller profile pic
- smaller font size
- smaller follow button
2022-02-08 12:35:40 -05:00
Rafael
48e2de6ca4 Refactor file page
- doFetchFileInfo used for App only
- avoid repeting right side content
2022-02-08 12:35:40 -05:00
Rafael
6443af34a0 Refactor claimAuthor
- channelUrl to cached selector also using claimForUri cached selector
2022-02-08 12:35:40 -05:00
Rafael
7b89db17bc Refactor fileDescription
- user was unused
- only pass needed claim props
2022-02-08 12:35:40 -05:00
Rafael
bc68207f40 Refactor fileTitleSection
- selectInsufficientCreditsForUri unused
- used util function instead of redux selector for title
- only pass needed claim props
2022-02-08 12:35:40 -05:00
Rafael
fc30a74cd1 Improve fileActions Buttons style on mobile view
- Move label to bottom instead of to the side
- Decrease font, sizes and spacings
- Make sure all fit in a single line even on smallest screen size
2022-02-08 12:35:40 -05:00
Rafael
416238db29 Switch some file action buttons to menuItems
So everything can fit better on mobile view
2022-02-08 12:35:40 -05:00
Rafael
5794432288 Refactor fileActions
- moved doPrepareEdit incognito and channel calls to separate action
- same with download
- Tooltips
- No major differences between mobile or default returned components so removed condition since mobile style will be changed later on this branch
2022-02-08 12:35:40 -05:00
Rafael
1fb154f7fe Refactor claimCollecitonAddButton
- claim makeSelect to select
- only interested in claim's stream_type
- Tooltip
2022-02-08 12:35:40 -05:00
Rafael
c9fbf197f9 Refactor claimSupportButton
- Tooltip
- only interested in repost value from claim
2022-02-08 12:35:40 -05:00
Rafael
21a5e27cd2 Refactor fileReactions component
- makeSelectReactionsForUri and selectThemePath were not being used
- isLivestreamClaim from redux
- Reduce repetition, make single reaction component
2022-02-08 12:35:40 -05:00
infinite-persistence
dbeb102dc4
clean up URLs 2022-02-08 11:04:25 -05:00
infinite-persistence
1e7e7a7b7a
Notifications: use fetched urls instead of resolving (#820)
* Fix avatar occasionally stuck in spaceman

## Issue
Sometimes, we'll see a channel profile (e.g. in upper-right, in channel selector) stuck in the fallback Spaceman image.

This is due to OptimizedImage always starting with a blank src, and updated later when the mounted size has been determined. ChannelThumbnail, which uses OptimizedImage, captured the `onError` due to blank src.

## Fix
Don't mount the <img> until the optimum size has been determined.

* FileThumbnail: skip resolve if thumbnail url is specified

* UriIndicator: skip resolve if channel info is specified

* Notifications: disable batch resolve + use fetched data if available + fallback to resolve if n/a

The fallback is using the individual resolve when no direct data is provided and claim is undefined.
2022-02-07 15:59:20 -05:00
AsadUmar
d73504d69c
fix render of toggle. (#819)
Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2022-02-07 13:35:17 -05:00
infinite-persistence
c67893815b
i18n updates and fixes (#822)
FileExporter - fix double translation. Just let the client provide the string to use.

Collection - translate built-in lists
2022-02-07 13:15:22 -05:00
David Granado
ce903c9280
Patch to restore position upon returning to video until more fully fleshed out fix can be introduced (#817)
* Patch to restore position upon returning to video until more fully fleshed out fix can be introduced

* Add code to notify other open tabs of position saving

* Fix typo

* Wrap localStorage access in try/catch in event browser settings make it unavailable

* Remove formatting changes

* Move constant from 'pages' to 'player'

* Move dispatch out of try/catch

* Fixed typo
2022-02-07 12:51:26 -05:00
AsadUmar
65ad2df643
fix RESOLVE_URIS_COMPLETED, to have one large action instead of hundr… (#798)
* fix RESOLVE_URIS_COMPLETED, to have one large action instead of hundreds of small ones

* Addressed comments.

* Addressed comments.

* Addressed comments.

Co-authored-by: Asad Umar <au@visuary.fr>
2022-02-07 12:39:12 -05:00
infinite-persistence
231ac139d4 Move recsys endpoint to .env for easier debugging
Easier to point to a localhost server to capture the beacons for debugging.
2022-02-07 11:13:30 -05:00
infinite-persistence
57bcf6bc03 Update description in PWA 2022-02-07 07:29:11 -08:00
infinite-persistence
e879cd3968 Update chat channel
There is no #help in the new odysee Discord.  Closest I can find is #support
2022-02-07 10:22:20 -05:00
infinite-persistence
bfb8e90b1e Limit embed generation to just Audio and Video
## Ticket
761 Should Posts have embed links

The original code also supported all text modes like PDF, all of which looked really bad, so it's unlikely someone is utilizing it.

Disabling them until a designer can fix 'em.
2022-02-07 10:21:33 -05:00
Asad Umar
373f7f75e0 useHasWindowWidthChangedEnough 2022-02-07 10:18:50 -05:00
Asad Umar
bdc5c2e9fb optimize useWindowSize 2022-02-07 10:18:50 -05:00
Asad Umar
df320a2375 fix useWindowSize (again) 2022-02-07 10:18:50 -05:00
Asad Umar
e45ef63d41 fix useWindowSize 2022-02-07 10:18:50 -05:00
Asad Umar
00c9410253 fix useScreensize 2022-02-07 10:18:50 -05:00
Asad Umar
e0f01a58d2 fix expandable view 2022-02-07 10:18:50 -05:00
Asad Umar
b2093e822a hook made for listening to resize events ie use-on-resize.js, with a debounced callback as to make performance even better. 2022-02-07 10:18:50 -05:00
Asad Umar
e4abc7ef41 WIP
fixed the issue by removing the useRect, and putting in a resize event, going to try and make the code cleaner by removing all that logic and putting it in a hook.
2022-02-07 10:18:50 -05:00
Thomas Zarebczan
fd1ee4f43c
recsys take 99 2022-02-04 18:38:42 -05:00
Thomas Zarebczan
ffcf09efd0 category updates
thx Drew
2022-02-03 11:02:59 -05:00
infinite-persistence
fae68d40fd Category: Featured 2022-02-03 11:02:59 -05:00
infinite-persistence
18cdba65cf i18n weekly 2022-02-03 11:02:59 -05:00
infinite-persistence
fe3a55ff95 Remove custom comments server
- Not used by Web.
- It's basically a revert of Desktop 5459.
2022-02-03 10:24:58 -05:00
Rafael
9b7dbc97b2 Add Featured Icon 2022-02-02 23:53:12 -05:00
David Granado
63a3602464 Case insensitive subscription filter 2022-02-02 09:50:55 -05:00
Thomas Zarebczan
fc99d85efc Add max bitrate messaging
Disable form on error

Fix resetting
2022-02-01 17:26:09 -05:00
Rafael
e37a6c66be Fix embed params regex again 2022-02-01 15:52:39 -05:00
David Granado
c7a23058c8 Only show subscription filter when more subs than initial limit 2022-02-01 10:20:00 -05:00
David Granado
652d98f6c6 Factor out input to isolate component updates 2022-02-01 10:20:00 -05:00
David Granado
5048c460f1 Add padding around search input 2022-02-01 10:20:00 -05:00
David Granado
8e94044904 Adjust 'no results' styling 2022-02-01 10:20:00 -05:00
David Granado
d7845f2988 Remove unneeded class 2022-02-01 10:20:00 -05:00
David Granado
a869e9dc2c Add channel list filter 2022-02-01 10:20:00 -05:00
Rafael
e1b6c5149a Fix Regex for claimUrl embed url params 2022-02-01 09:02:57 -05:00
Rafael
e9a003328d Avoid persistent lone question mark on url 2022-02-01 09:02:57 -05:00
Rafael
df360f7ccc Fix player error 2022-01-31 17:27:41 -05:00
Rafael
3d4a4cd960 Add escapeHtmlProperty on url params 2022-01-31 14:22:39 -05:00
Rafael
1628d4901c Revert encode share embed url 2022-01-31 14:22:39 -05:00
Rafael
b30a8568e5 Fix embed url param parsing 2022-01-31 14:22:39 -05:00
Thomas Zarebczan
92f0fd8745
More cleanup 2022-01-31 11:39:03 -05:00
David Granado
f09c6d7a50 Fix play btn calcs as audio tag was not measuring as expected 2022-01-31 11:32:44 -05:00
Thomas Zarebczan
5ee2f40608
Take 2 encoding test 2022-01-29 15:24:35 -05:00
Thomas Zarebczan
185c2d8496
encode oembed full url 2022-01-29 15:04:19 -05:00
Thomas Zarebczan
b3d9fe5473 Force stop event on dispose 2022-01-28 16:19:27 -05:00
infinite-persistence
1d8105a84a Stop autoplay-next countdown when any input is in focus.
## Issue
On large screens, the comment field and autoplay countdown can both be visible at the same time. The currently code only stops the timer when the countdown component is not visible on screen.

The page annoyingly navigates away while typing.

## Change
When servicing the timer, check if the current active element is an input type. As far as I know, there is no React equivalent for this.
2022-01-28 09:11:15 -05:00
Rafael
898376888d Fix 2022-01-27 11:32:01 -05:00
Rafael
6544f4c0b6 Fix resolve mentioned_channels 2022-01-27 11:32:01 -05:00
Rafael
44213fbad2 Properly parse URIs for invalid terms 2022-01-27 11:32:01 -05:00
Rafael
e4d5d69524 Use uri from props instead of location
- which was causing it to fail on popout chat for example
2022-01-27 11:32:01 -05:00
David Granado
cab4b3aba8 Return empty array rather than null from selectRepliesForParentId 2022-01-27 09:51:45 -05:00
David Granado
7dfbe5a539 Fix null property access bug 2022-01-27 09:51:45 -05:00
Thomas Zarebczan
a8418025db
Clean up buy page 2022-01-26 11:13:46 -05:00
infinite-persistence
47fa736bdc Channel Thumbnail: handle json errors
1. Added size-specific error message.
2. Route whatever Vanwa's error instead of showing "unexpected json token". It's ugly, but at least it contains the reason string.
2022-01-26 08:32:40 -05:00
Thomas Zarebczan
ed0f574339 Respect disable download button tag
Fixes https://github.com/OdyseeTeam/odysee-frontend/issues/742
2022-01-25 15:51:45 -05:00
David Granado
a417cc3aca Correctly encode the path for query string 2022-01-24 11:21:43 -05:00
David Granado
04aa77253f Only send search request when string length enough for api expectation. 2022-01-24 11:16:30 -05:00
infinite-persistence
8b06c3df19
i18n 2022-01-24 17:33:59 +08:00
infinite-persistence
d68be6e9af
tus: route errors to sentry
Per discussion with Andrey
2022-01-24 12:25:54 +08:00
infinite-persistence
7fc66aecb6 Defer user/invite_status from startup
## Issue
Closes 385

## Approach
As mentioned in the ticket, the current places where that info is needed is in the Invites Page and Social Share Component.

1. Invites Page: it is already doing the fetch on mount, so no issue there.
2. Social Share: show spinner until the data is fetched.
2022-01-21 09:19:17 -05:00
Rafael
2340138ab5 Fix failed resolve 2022-01-20 14:02:39 -05:00
infinite-persistence
aef3c346a0
Remove store.user.accessToken (#740) 2022-01-20 08:20:58 +08:00
infinite-persistence
a8a666383a Remove 'store.user.accessToken' now that we've confirmed nobody uses it. 2022-01-19 13:12:09 -05:00
infinite-persistence
0c9859e3ac Remove <UserEmail> -- I think it was a Desktop thing 2022-01-19 13:12:09 -05:00
infinite-persistence
71328274ec Remove unused FIRST_SUBSCRIPTION modal -- it is now just a toast. 2022-01-19 13:12:09 -05:00
infinite-persistence
fc20f6ab0b Remove unused 'accessToken' props 2022-01-19 13:12:09 -05:00
infinite-persistence
89b46265ab Help Page: remove 'app' to get rid of old 'accessToken' calls 2022-01-19 13:12:09 -05:00
Thomas Zarebczan
784711c4e3
Mobile ads on Android too 2022-01-19 10:20:07 -05:00
infinite-persistence
801d24ae10
Update remaining chat link (#741) 2022-01-19 09:27:11 -05:00
infinite-persistence
adc9575504
Category-metadata: add stub for Education + cleanup old categories (#735) 2022-01-19 09:04:15 -05:00
infinite-persistence
18c7469d25
Top Search: handle view count for Repost (#736)
## Issue
Closes "87 Repost - Top result should show followers properly"

The winning url for "bret" search is "lbry://bret", which is a repost.

## Change
We need to use the canon url to retrieved the fetched view count.
2022-01-19 09:04:01 -05:00
infinite-persistence
3338f9142c
ClaimList: fix missing key (#737)
## Issue
From the Draggable PR, the draggables retained the key but regular lists lost it.
2022-01-19 08:48:20 -05:00
infinite-persistence
b72127411c
Comment options: hide "Remove" when comment is removed. (#738)
## Issue
Closes 295 Livestream chat: Deleting comment that was already deleted by someone else, makes chat blank.
2022-01-19 08:42:39 -05:00
Thomas Zarebczan
24d53cd7d8
Formatting improvements (#731) 2022-01-18 13:30:43 -05:00
infinite-persistence
b0d9127b78
Remove CHANGELOG.md (#722)
- Doesn't really apply to web since it's a rolling release and we don't have versioning.
2022-01-18 12:34:26 -05:00
David Granado
179bd44665
Clean invisible chars and adjust "__" for server and client use (#715)
* Rewrite __ to be usable on server side

* Add changelog entry

* Clean invisible characters from primaryModValue

* Revert "Rewrite __ to be usable on server side"

This reverts commit 53f63c01f3b56c5530955323612826c0ac5dc5d3.

* Make pass-through placeholder for __ fn until it can be adapted for node.

* Switch messagages to inline interpolation until i18n done

Co-authored-by: Thomas Zarebczan <tzarebczan@users.noreply.github.com>
2022-01-18 12:09:59 -05:00
Thomas Zarebczan
2eadd986b4
ad adjustments per vidcrunch
confirming what to do with the mobile tag...
2022-01-18 09:56:58 -05:00
infinite-persistence
e4658bb044
Fix missing claims in large collection (#726)
## Issue
A huge list like http://localhost:9090/$/list/d91815c1bc8c80a1f354284a8c8e92d84d5f07a6 (193 items) often produces fewer results in the final rendered list.

## Cause
The same list of IDs was passed into `claim_search`, and we just increment the `page`. However, it seems like `claim_search` does not honor the order between each call, and some results from the previous page took the place of the results in the next page.  The total is the same, but there are now duplicates.

## Fix
When batching, slice the ID list ourselves to bypass the problem for now.
2022-01-18 09:33:01 -05:00
Thomas Zarebczan
e890e2f4f8
Fix crash 2022-01-17 23:24:59 -05:00
infinite-persistence
bdb83b5295
Commentron: *Delegates was failing silently
Added toasts to indicate errors instead of failing silently.
2022-01-18 10:46:18 +08:00
infinite-persistence
c1cb9345ad
Commentron: param updates for moderation.*Delegates
## Reason
https://odysee-workspace.slack.com/archives/C02FMSYF51B/p1642435815038000?thread_ts=1642129696.024400&cid=C02FMSYF51B
Due to unaligned parameters not compliant with Authenticate, ModAuthenticate APIs.

It will still work without this PR as there is a compatibility layer, but should use the correct params moving forward.
2022-01-18 10:43:58 +08:00
David Granado
783520f734
Adjust meta data to allow search pages to reflect search term (#713)
* Adjust meta data to allow search pages to reflect search term

* Update changelog

* Address empty query string case and pass query string to append to og:url

Co-authored-by: Thomas Zarebczan <tzarebczan@users.noreply.github.com>
2022-01-17 12:40:18 -05:00
Thomas Zarebczan
df2ed078b3
Fix collection filter 2022-01-17 12:06:59 -05:00
Thomas Zarebczan
507d34dd8c
Odysee chat updates 2022-01-17 11:19:01 -05:00
David Granado
93d7597739
Upgrade @reach/rect ui to address "observe" warning (#711)
* Upgrade reach ui to latest to address "observe" warning

* Amend changelog
2022-01-17 10:07:51 -05:00
infinite-persistence
4f8a4d30d8
Fix "don't cache html" meta tags (#721)
In 36fe7366, the approach to fix the "missing chunk" error and user using old code was to disable caching on the html so that user always grabs the one that's pointing to the latest ui.js.

But https://cristian.sulea.net/blog/disable-browser-caching-with-meta-html-tags/ says 3 sets of `meta` is needed to, and we missed out one. That probably explains why refreshing sometimes does not work, although I've also read that some browsers simply ignores these meta.
2022-01-17 08:48:45 -05:00
infinite-persistence
7989020a04
Corrected mentioned_channels parameter name (#719)
Commentron json params are usually underscored instead of camel-cased.

Double-checked commentron code:

```
// MentionedChannel channels mentioned in comment
type MentionedChannel struct {
	ChannelName string `json:"channel_name"`
	ChannelID   string `json:"channel_id"`
}
```

The parameter should probably also be skipped instead of sending empty array, but leaving as-is for now since that is minor.
2022-01-17 08:44:45 -05:00
David Granado
2b9fd723f9
Upgrade nodemon to latest and add --inspect flag for remote debugging (#714) 2022-01-17 08:41:44 -05:00
David Granado
0865aabda4
Ignore .vscode directory to allow disabling js typechecking. (#712) 2022-01-17 08:39:40 -05:00
infinite-persistence
5dc1d416ef
CHANNEL_UNSUBSCRIBE: handle colon vs. hash uris (#706)
## Ticket
644 investigate following vs subscription preference data

## Issue
- iOS app uses colon for following/subscriptions.
- Front-end code handled the "colon vs. hash" for CHANNEL_SUBSCRIBE, but not for CHANNEL_UNSUBSCRIBE
2022-01-17 08:39:06 -05:00
dependabot[bot]
73c3737ef4
Bump follow-redirects from 1.13.0 to 1.14.7 (#710)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.13.0 to 1.14.7.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.13.0...v1.14.7)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-17 08:32:37 -05:00
infinite-persistence
ee71caf2bc
Comment api: re-format to single-line.
This will be an exception where the non-wrapped version is easier to read.
2022-01-17 14:34:41 +08:00
infinite-persistence
9743f4b49e
Move commentron error mapping to separate file 2022-01-17 10:25:06 +08:00
infinite-persistence
c1af19c7b9
Creative Arts strings 2022-01-17 09:28:02 +08:00
infinite-persistence
1edb62b3d1
i18n weekly
- Put back the "--end--" entry to cover the "no trailing comma" part. This would reduce mistakes and also reduce diffs on the comma part.

- Updated with new strings; deleted some unused ones.
2022-01-17 09:27:24 +08:00
Thomas Zarebczan
62dd12ab78
New discord for rewards 2022-01-15 23:45:14 -05:00
dependabot[bot]
e57ebbc74f
Bump follow-redirects from 1.13.0 to 1.14.7 in /web (#709)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.13.0 to 1.14.7.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.13.0...v1.14.7)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-15 13:02:05 -05:00
infinite-persistence
d14470830c
tus: reduce chunk size (25MB -> 10MB)
With the throughput tweaks at the backend, it seems like the number of "file is locked" errors have reduced.

The next thing to try is to reduce the chunk size, hoping that file writes would be faster, reducing the lock duration from causing a timeout.
2022-01-15 14:44:15 +08:00
Thomas Zarebczan
0b5f10c508
Allow hide chat on mobile 2022-01-14 18:51:33 -05:00
Thomas Zarebczan
e545cae537
Force update 2022-01-14 16:22:47 -05:00
saltrafael
031a3a2f0a
Fix sidebar on mobile (#703) 2022-01-14 16:07:44 -05:00
saltrafael
a1a7ca321f
Fix livestream key listeners (#702) 2022-01-14 16:07:21 -05:00
saltrafael
ea9c7a4a27
[Live Chat] Break down componets for Page Layout + Add ability to Pop Out chat window + Hide chat option (#681)
* Refactor CommentBadge

* Refactor livestreamComment component

* Refactor and split livestreamComment CSS

* Refactor livestreamComments component

* Refactor and split livestreamComments CSS

* Remove never used spinner

* Refactor livestream Page

* Refactor page component

* Refactor livestreamLayout component

* Break apart livestreamComments into separate sibling components

- This helps separating LivestreamComments to deal with only the comments, and the LivestreamLayout to be used for its own Page as a Popout option, and also for a layered approach for mobile

* Create Popout Chat Page, Add Popout Chat Menu Option

* Add Hide Chat option

* sockety improvements

* Websocket changes

Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2022-01-14 15:24:16 -05:00
saltrafael
b810e07053
Fix doAbandonClaim (#699)
* Refactor doAbandonClaim parameters to only claim

- Gets txid and nout by default now, and passing claim allows using more data to verify ownership in case of txid:nout failing again
- Unused on modalRemoveCard
- Edited the comment on doCollectionDelete to explain better

* Fix doAbandonClaim failing to select my claim
2022-01-14 14:26:03 -05:00
mayeaux
ae976c377e
EU ads (#700)
* add new ad

* bugfix

* prioritize eu ad over mobile ad

* replace frontpage ad with EU ad

* bugfix checking for EU
2022-01-14 14:21:17 -05:00
saltrafael
83378174b7
Prevent Up and Down keys being overriden by MUI listeners when not in use (#698) 2022-01-14 12:55:42 -05:00
Thomas Zarebczan
53155bd7d6
Add back sorting on tags page 2022-01-14 12:39:33 -05:00
infinite-persistence
344da194ca
Resolve claim and stream types when there is a filter (#696)
* Resolve claim and stream types when there is a filter

## Symptom
Channel Page 'Content Type' filter not working

## Issue
The Advanced Filter work by placing a `?content=` URL param. The list component then parses it and makes the `claim_search` params accordingly. But:

1. There is a mix up in how the list component treats `?content=`.
    - The original code seems to treat this as a way to define the type externally but only for a list without `claimType` defined via code. In other words, if `claimType="something"`, `?content=` is ignored.
    - On the other hand, the Advanced Filter relies on `?content=` being used.

2. `?content=` is then split between `claimType` and `streamType`. The current code does not check if the split makes sense, e.g. if `?content=channel` and `streamType=['video']`, these 2 are incompatible and produces no results.

## Change
1. I'm not really sure what's the original intention, but let's just make `?content=` as an override/filter.

2. `?content=` should probably be limited to always be a subset of `claimType` and `streamType`. But this seems complicated to do, so for now let's just make always override/filter everything.  For that, we need to make sure the filtered `claimType` -- `streamType` combo makes sense.

* Fix 'Channel' filter not working in Wild West

## Cause
The Wild West list defines `release_time` to be 1 week ago. As long as this parameter exists, a channel `claim_search` produces no results (I thought channels have creation dates?). That is why an unfiltered Wild West never showed Channel Tiles.

## Change
The existing `release_time` handling does seem to hint that we should not set the parameter when searching for Channels. Expanded that to consider the final (filtered) claim type, not just the original.
2022-01-14 11:06:13 -05:00
saltrafael
f3892325ce
Find and Pass mentioned channel name + claim id on comment_create (#690) 2022-01-14 09:50:09 -05:00
infinite-persistence
0d6cd21457
Fix ignored 'Content Type' filter (#694)
## Issue
After enabling Advanced Filter in Category Pages, the 'Content Type' filter only works for "repost/video/list".

## Root-cause
When `streamType` is not provided, it defaults to 'Video|Audio', making it always "defined":

```
streamType = SIMPLE_SITE ? [CS.FILE_VIDEO, CS.FILE_AUDIO] : undefined,
```

This seem to override the purpose of `defaultStreamType`, which will not be used unless the client explicitly set `streamType=null`, which currently is only being applied for `RECENT_FROM_FOLLOWING[]`.

```
  const streamTypeParam =
    streamType || (CS.FILE_TYPES.includes(contentTypeParam) && contentTypeParam) || defaultStreamType || null;
```
2022-01-13 22:03:04 -05:00
infinite-persistence
7affa8b7a1
Fix advanced filter showing up in Wild West (#695)
Behavior we want:
- hide Advanced Filter for Wild West
- show Advanded Filter & Filter for everything else
2022-01-13 22:00:41 -05:00
Thomas Zarebczan
e2f414f98c
filtering improvements (#692)
+ limit wild west to 3 claims per channel
+ hide language for now until we can sync homepages + settings
2022-01-13 16:13:49 -05:00
Thomas Zarebczan
d94f86aec4
update urls for cards/thumbs 2022-01-13 15:07:54 -05:00
saltrafael
e1bbd9984a
Fix mentioning with enter (#691) 2022-01-13 13:36:07 -05:00
infinite-persistence
4ae1df4eb9
Thumb: make CDN limit an env so we can change easily 2022-01-13 13:18:41 +08:00
infinite-persistence
eb420af865
Thumb Generator: switch to jpeg + lower quality when needed
The quality API doesn't work on the default PNG but works on JPG.

- Switching to JPEG (100%) produces a smaller image than the default PNG. This covers most scenes.

- For some scenes, the size could still be larger than 2MB, so retry with JPEG (80%). For a 1080p image, this action produces the file at <1MB range. The quality still looks ok, I think.
2022-01-13 12:50:26 +08:00
infinite-persistence
3c3d73a189
tus: delay adjustments + clean up error messages #687 2022-01-13 12:08:27 +08:00
infinite-persistence
91d0eb30b8
tus: remove multi-tab assumption + pass original err msg
Completely remove any assumptions of multi-tab uploading from server status (should have done it previously, but wanted to be conservative). This should make it less confusing to the user.

The real issue still remains -- the upload is somehow locked at the backend.

Also, when we override the error to present a user-friendly message to the user, pass the original error to the log (just in case it gives extra info).
2022-01-13 09:57:45 +08:00
infinite-persistence
238f6b2eda
tus: adjust retry delay + remove logging
From the logs, it seems like the second retry (5s) fixes the "normal" cases, so just remove the first retry (0s).

Also from the logs, if a retry doesn't work by the third attempt (10s), it's most likely the "locked" case and retrying further doesn't help. So, reduce one more useless retry attemp.

Removed logging since we've gathered enough data, and that this hook is expected to be hit a lot, so we don't want to clog the logs.
2022-01-13 09:43:29 +08:00
Thomas Zarebczan
9e70629ada
Fix comment disabling on MD (#685)
Also restore reactions
This is only an internal tag
2022-01-12 16:26:28 -05:00
saltrafael
2575c5d448
[Playlist] Pull in sorting changes from desktop + Add Drag-n-Drop + Handle unavailable/deleted claims (#641)
* Add ordering Icons

* Refactor doCollectionEdit

- It required claims as parameter, when only uris are used to populate the collection, so that was changed to pass down the uris instead.
- There were unused and mostly unnecessary functions inside, for example the parameter claimIds was never used so it would never enter the claimSearch function which again would be used to generate uris, so it's better to just use uris as parameter

* Add List Reordering changes

* Add toggle button for list editing

* Add toggle on content page collection sidebar

* Enable drag-n-drop to re-order list items

https://www.youtube.com/watch?v=aYZRRyukuIw

* Allow removing all unavailable claims from a List

* Fix <g> on icons

* Fix section buttons positioning

* Move preventDefault and stopPropagation to buttons div instead of each button, preventing clicking even if disabled opening the claim

* Change dragging cursor

* Fix sizing

* Fix dragging component

* Restrict dragging to vertical axis

* Ignore shuffle state for ordering

* Fix console errors

* Mobile fixes

* Fix sidebar spacing

* Fix grey on mobile after click
2022-01-12 14:14:12 -05:00
infinite-persistence
c90c5bcc2a
Route markdown to v1 (#680)
I think I just forgot to do it the first time.
2022-01-12 10:31:46 -05:00
infinite-persistence
431f55ef26
Delete pixel experiment (#683) 2022-01-12 10:14:44 -05:00
infinite-persistence
3d246a30ba
Fallback to main language (xx) when sub-language (xx-yy) is not supported. (#682)
## Issue
656 Automatic language detection can't recognize de-DE as de

## Note
We do fallback to the main language, but seems like the code got lost ... not sure when, but probably during the CN/TW or PT-BR support. The refactor in  81e47300 still did that, but the refactor was reverted due to some compilation issue (should revisit that someday).

## Change
Put back equivalent code.
2022-01-12 09:46:57 -05:00
Dan Peterson
1f596e963d
Make sure to specifically query for streams (#671) 2022-01-11 12:08:55 -05:00
Dan Peterson
dcfb64d907
Make the hide setting optional and don't use it on the channel page. (#670) 2022-01-11 11:46:13 -05:00
infinite-persistence
e58ddbc809
View/Follower count: only use compact when > 10k (#664)
* Tooltip: add 'followCursor' and 'placement' option

When used on a `<span>` with short text but large empty area, the location of the tooltip was at the bottom-center of the area, which isn't ideal.

I think 'followCursor' should be the default, but making it optional for now to minimize testing.

Also added the 'placement' prop -- for the span case again, the mouse cursor is blocking the tooltip.

* View/Follower count: only use compact when > 10k

## Issue
Received complaints -- some people prefer to see full resolution.

## Changes
- As a compromise, we'll only apply the compact notation when the value is greater than 10k, with the exception of Tile View Count, where we'll always apply it due to space limitation.
- Also added Tooltip for Follower count.

## Fixes
- The string was always in 'en' locale in some instances, so it wasn't grouping up digits properly in Japanese (groups of 4), for example.
2022-01-11 11:42:12 -05:00
Dan Peterson
1a57b02f80
Enable the new scheduled tag filtering and set the buffer back to 35 minutes (#669) 2022-01-11 11:33:33 -05:00
infinite-persistence
3bba4ab630
Fix infinite scroll when "Upcoming livestream" appears (#665)
## Issue
When "Upcoming livestream" appears in a list, infinite scroll stops working.

## Cause
The difference between `mainEl.getBoundingClientRect().bottom` and `window.innerHeight` became slightly greater than 0.5, so it was deemed as "haven't reached the bottom".

## Change
Coincidently, I've been wanting to make the inf scroll load earlier (instead of after reaching the absolute bottom) to make the experience smoother, so added a 200px threshold, which is roughly the height of a tile. This gets us the new behavior while also fixes the original problem.
2022-01-11 08:26:44 -05:00
mayeaux
373766c5b5
Fix vidcrunch on ios to only show ad when its scrolled to (#651)
* fix vidcrunch on ios to only show ad when its scrolled to

* clean up and optimize code
2022-01-10 22:21:55 +01:00
Max Kotlan
c9108f530c
mobile menu fix animation close on page load (#652) 2022-01-10 13:14:46 -05:00
infinite-persistence
6bd384b01a
TUS: retry on 423_locked to try address "failed to upload chunk"
## Background
Per developer of `tus-js-client`, it is normal to occasionally encounter upload errors. The auto-retry mechanism is meant to address this.

While implementing tab-lock to prevent multiple uploads of the same file, 423_locked was used to detect this scenario. But 423_locked could also mean "the server is busy writing the chunk" (per discussion with Randy), so we kind of disabled the auto-retry mechanism accidentally.

Meanwhile, from a prior discussion with Randy, one of the chunk-writing duration took 3 minutes. Our current maximum of "retry after 15s" wouldn't help.

## Change
1. Given that tab-locking was improved recently and no longer reliant on the server error messages (we use secure storage to mark a file as locked), reverted the change to "skip retry on 409/423". This is now back to normal recommended behavior.
2. `tus-js-client` currently does not support variable retry delay, otherwise we could prolong the delay if the error was 423. Since we know it could take up to 3 minutes, and that we don't know if it's file-size dependant, just add another 30s retry and put a friendlier message asking the user to retry themselves after waiting a bit.
2022-01-10 16:46:57 +08:00
infinite-persistence
e6a21dc14f
More tus logging (#659) 2022-01-10 11:57:34 +08:00
infinite-persistence
46c7c193be
Log the status code for the retry 2022-01-10 11:50:29 +08:00
infinite-persistence
47043bc965
Remove 'retryTimeout' - that's just the timer ID, nothing useful 2022-01-10 11:39:34 +08:00
infinite-persistence
6fffae6d46
File page: compact form for View and Follower Count (#658) 2022-01-10 11:16:45 +08:00
infinite-persistence
0147af156c
File page: use compact follower count 2022-01-10 11:13:33 +08:00
infinite-persistence
1d4e1296ec
File page: use compact view count (w/ tooltip for full res) 2022-01-10 11:05:49 +08:00
infinite-persistence
df4d142370
Factor out 'toCompactNotation' 2022-01-10 10:42:56 +08:00
infinite-persistence
b859283f82
i18n weekly (#657) 2022-01-10 10:07:32 +08:00
infinite-persistence
1b503f7903
i18n - remove some Desktop strings 2022-01-10 10:04:09 +08:00
infinite-persistence
4a84c80daa
i18n - catch up and removals
Also removed the '--end--' marker. No longer used, since we are not updating the file directly from Web.
2022-01-10 09:35:37 +08:00
infinite-persistence
8507d07d3e
Remove incorrect comments
- activeChannelClaim is the comment creator, not receiver.
- doSeeNotifications marks a notification as "seen", and not "send a notification".
- Removed comments that are just explaining the syntax.
2022-01-10 09:18:11 +08:00
Thomas Zarebczan
ac93e0c22c
2MB max thumb size messaging (#650) 2022-01-07 14:39:27 -05:00
mayeaux
b822fbdac8
fix ios can autoplay bug (#640) 2022-01-06 22:20:42 +01:00
Dan Peterson
a89cb17ce4
Add horizontal layout (#636)
* Test out a horizontal scroll for upcoming (tile only for now)

* - add support for list layout
- add following label on home page
- clan up css and naming conventions

* Update header type + show only if scheduled streams are showing
2022-01-06 16:13:26 -05:00
mayeaux
58bdcbd1ed
Reduce triple call to single call, improve video loading, fix embed play button being off-center (#546)
Lots of optimizations and cleanup for the player. If we run into any strange issues, can revert.
2022-01-06 14:28:27 -05:00
saltrafael
0a986b1603
Fix future date string (#637) 2022-01-06 14:09:17 -05:00
Dan Peterson
bc38466abf
Add a better solution for 304 browser bug + update naming conventions to better articulate what's happening (#603) 2022-01-06 12:49:49 -05:00
saltrafael
1eaa172a1b
Fix remark emote (#635) 2022-01-06 09:34:00 -05:00
Rafael
fc58dc5ef4 Remove localization from stickers 2022-01-06 03:54:47 -08:00
Rafael
78fde47577 Remove localization from emotes and make all names lower case by default 2022-01-06 03:54:47 -08:00
infinite-persistence
50550bfa99
Thumbnail uploads: don't show the extra error info in the GUI 2022-01-06 15:39:52 +08:00
infinite-persistence
57f48f462e
Thumbnail uploads: handle non-JSON responses 2022-01-06 15:39:52 +08:00
infinite-persistence
01459d906a
tus: Get more information from publish errors 2022-01-06 15:39:51 +08:00
infinite-persistence
555bde87f8
tus: make chunk size multiples of 256KiB
Our current chunk size is 25,000,000.

Google and S3 documentation suggests the chunk size to be multiples of 256KiB. MongoDB too.  We aren't using any of those, but I guess no harm doing the same.  From the logs, the values "25,000,000" and "50,000,000" seems to be common.
2022-01-06 15:39:51 +08:00
infinite-persistence
ad07ee0de3
Error: add support to log additional info (not shown in Modal)
`doError` supported either a string or object, and so far there are no instances where the object version is used, so this enhancement should be safe to do without affecting anyone.

## Change
For the object version, support an additional `cause` parameter that will be logged but not show in the GUI.
2022-01-06 15:39:50 +08:00
infinite-persistence
a4d2c6b0a6
Fix: account header doesn't refresh on sign up / log in (#629)
## Issue
Closes 627 account header doesn't refresh on sign up / log in

## Changes
Looking back at "[Header] Changes, fixes and improvements (#493)", noticed that old code was looking at `has_verified_email` instead of just checking whether an email exists. So, restored original code.

This does have a side-effect of the Logout button not showing any email address underneath it immediately after sign up (with the flow cancelled). But I vaguely recall it was that way previously. A refresh cleans it up.

Perhaps another `user/me` when leaving the Sign Up page can make everything in sync, but this PR simpler to test.
2022-01-05 21:56:17 -05:00
infinite-persistence
96c3b727fe
Thumbnail uploads: report file details (#628)
I'm leaving the generic "Unexpected JSON" error alone for now, as I think this should be fixed at Nick's end.
2022-01-05 21:07:54 -05:00
Thomas Zarebczan
468cf866c3
Dummy force push 2022-01-05 18:40:25 -05:00
Dan Peterson
bbe68a3319
Add a setting to hide scheduled livestreams from home/following (#626)
* Add a setting to hide scheduled livestreams from home/following

* Add a hide button in the scheduled stream header.

* Fix typo + make sure pref is synced
2022-01-05 16:20:43 -05:00
Thomas Zarebczan
4624188a85
fix new channel creation crash 2022-01-05 13:58:36 -05:00
infinite-persistence
a0e073b416 Remove the delayed thumbnail message for ChannelEdit
Not necessary now that we don't need confirmations for thumbnails (direct upload to CDN)
2022-01-05 11:49:41 -05:00
infinite-persistence
39a4cb3d77 Switch thumbnail server: spee.ch --> vanwanet 2022-01-05 11:49:41 -05:00
Dan Peterson
a021475128 Add an isScheduled state to publish form + use it to set the initial state of the date/time controls 2022-01-05 11:20:57 -05:00
Dan Peterson
cb562ef27d - fix issue where upload didn't show for users without replays
- better define if the form is in edit or create mode
- improve some naming conventions
2022-01-05 11:20:57 -05:00
Dan Peterson
6b809e76c4 Default to replay view when editing a liveststream 2022-01-05 11:20:57 -05:00
Dan Peterson
16e99fc063 Additional filtering of internal tags 2022-01-05 11:20:57 -05:00
Dan Peterson
2eb6af10ba Update date/time cmpnts to reset any chnages they made on umount. Update schedule date/time cmpnt to clear release time when selecting anytime option. 2022-01-05 11:20:57 -05:00
Dan Peterson
fef289e4fe Reset any set release time if switching to live stream mode. 2022-01-05 11:20:57 -05:00
Dan Peterson
4ec4942d8c move publish source state up, when editing livestream only show scheduling option when source is none. 2022-01-05 11:20:57 -05:00
Dan Peterson
6da73f6bc4 Fix bug where upload tools may remain visible upon switching upload type, even when no option to upload is available. 2022-01-05 11:20:57 -05:00
Dan Peterson
7671d12e42 Update publish form when editing livestream + update to radios for liveststream release time 2022-01-05 11:20:57 -05:00
Thomas Zarebczan
d4866b09bb
update embedly referrer param 2022-01-05 10:58:23 -05:00
Rafael
336c9288bf Small margin fix 2022-01-05 09:27:52 -05:00
Rafael
c96db56f33 Fix negative time duration 2022-01-05 09:27:52 -05:00
Rafael
9c75378310 Update app-strings 2022-01-05 09:27:52 -05:00
Rafael
1638f8e2f1 Improve future date localized strings 2022-01-05 09:27:52 -05:00
Rafael
caff432c0b Use generic string for seconds ago when needed 2022-01-05 09:27:52 -05:00
Rafael
18a054747a Fix some scheduled live string localization 2022-01-05 09:27:52 -05:00
Rafael
78e7eaa689 Fix scheduled live stream 2022-01-05 09:27:52 -05:00
Rafael
350aa8240a Update timestamps in background 2022-01-05 09:27:52 -05:00
Rafael
ab9252e06f Refactor dateTime component and getTimeAgoStr function to prevent displaying comments as 'in a few seconds' 2022-01-05 09:27:52 -05:00
Rafael
2c8ad2b89a Use Memo on markdown-preview component to avoid re-render 2022-01-05 09:27:52 -05:00
Rafael
f568f97e5e Fix content toggles and Header Title 2022-01-05 09:27:52 -05:00
Rafael
09ba036380 Improve header title and change icon to cog 2022-01-05 09:27:52 -05:00
Rafael
6f3dbad6e2 Remove unnecessary class for stickers 2022-01-05 09:27:52 -05:00
Rafael
ec68f102a7 Add toggle for timestamps 2022-01-05 09:27:52 -05:00
Rafael
4a73fbf688 Add timestamp on mouseover 2022-01-05 09:27:52 -05:00
infinite-persistence
c6fb204d11 Skip checking DIST_ROOT twice
f0cd1592 did an additional call instead of replacement.

Aside: the 1 hour value only has effect in dev instances. For prod, CloudFlare seems to override that to 4 hours.
2022-01-05 09:00:28 -05:00
infinite-persistence
6583b6a636 Sync: fix new user sign up flow
## Issue
- When signing up, the "channel suggestions" page was stuck because `prefsReady` was never set as `preference_get` was never called.
- It was never called due to the optimizations to skip it when there is no difference between the local and server wallet.

## Change
- The first ever `sync/get` will result in a "no wallet" error, and there is already a `catch` to handle it. But the change in 38c13cf5 caused the `catch` to be skipped and went directly to `sync_apply` instead. Although the `catch` is also doing the same thing (`sync_apply`), it also has an additional callback to call `preference_get`.
    - Fixed by ensuring this scenario ends up in the `catch` block like it was originally intended.
- We also did some optimization in the callback to skip the final `preference_get` if there is no difference in hash. But for the case of signing up, we do want to run it (so that `prefsReady` and other stuff gets initialized), so pass `hasNewData = true` to the callback.
2022-01-05 04:00:12 -05:00
infinite-persistence
128e51a4f6 Add env to auto report new strings in console
Need to debounce to prevent over-reporting. 2s seems to be the minimum.
2022-01-05 00:26:31 -08:00
Anthony
ec5a9802fc
Refactor ad implementation, fix two bugs (#616) 2022-01-05 16:15:08 +08:00
Anthony
cac05d5714 more touchups 2022-01-04 18:05:10 -05:00
Anthony
e3395e31ba refactor ad implementation 2022-01-04 18:05:10 -05:00
Anthony
28bcb96ec7 autoscroll on home page and dont run ads js at all for firefox android 2022-01-04 18:05:10 -05:00
Dan Peterson
24cc07c09b escape referrerQuery in the oEmebed xml generator 2022-01-04 17:19:55 -05:00
Dan Peterson
3744f26295 Escape/encode referrerQuery 2022-01-04 17:19:55 -05:00
Dan Peterson
5cf78e792b
Make sure view count fetch runs when claim ID changes. (#617) 2022-01-04 12:40:31 -06:00
Rafael
b0dbdeae27 Allow to remove my superchats 2022-01-04 09:04:59 -05:00
infinite-persistence
d03f80c6b1 Skip 'install/new' if web already exists
## Issue
Part of 385 "Defer api.odysee.com calls to their respective pages / install new"
2022-01-04 08:54:30 -05:00
infinite-persistence
1f5f8f1213 Remove unused firebase and domain parameter 2022-01-04 08:54:30 -05:00
infinite-persistence
e5a2e3961e Remove unused items 2022-01-04 08:54:30 -05:00
infinite-persistence
7a4866b269
Temporarily disable Buy due to Moonpay integration down 2022-01-04 09:37:11 +08:00
infinite-persistence
1cc2132a28 Uploads: prevent perpetual locked upload
## Issue
- Closes 592 Force clear stuck upload
- It was possible for an upload to stay "locked" e.g. when browser is killed.

## Change
When refreshing or opening a new tab, always clear the locks. The on-going sessions will re-lock them immediately.
2022-01-03 12:10:55 -05:00
infinite-persistence
fad3f6ed78 Notifications: handle view while fetching categories
## Issue
"No notifications" briefly appear when your previous filter is not "All".

## Change
When splitting up the category-fetch, the render logic was not updated accordingly.
2022-01-03 11:58:48 -05:00
infinite-persistence
449398b88f
Lint/format 2022-01-03 17:01:10 +08:00
infinite-persistence
4dcabd67a7
i18n: restore ability to retrieve new i18n strings (#607) 2022-01-03 10:51:44 +08:00
infinite-persistence
5948ee0d80
i18n: restore ability to retrieve new i18n strings
## Issue
In the original Desktop code, new strings encountered during runtime will be automatically added to the local `app-strings.json` file. The feature is unavailable in Web because writing to file would require explicit permissions.

## Change
Partially restore the functionality by saving the strings to memory and retrieving it from the console via `copy(window.new_strings)`. It's a little bit of manual work, but I think it is good as it forces a sanity check before committing (previously, experimental/developmental strings are committed and being translated in Transifex).
2022-01-03 10:36:12 +08:00
infinite-persistence
2e50497bc1
i18n: add flow + some cleanup 2022-01-03 09:50:19 +08:00
infinite-persistence
49c6559049
i18n: remove unused 'app' code
We'll be adding a 'web' version next...
2022-01-03 09:50:19 +08:00
Thomas Zarebczan
77ebb7111e
Force update 2022-01-01 14:37:01 -05:00
Thomas Zarebczan
ce37e06e10 Revert "Fix publish form when editing livestream (#565)"
This reverts commit da06c14e60.
2021-12-31 13:28:19 -05:00
Dan Peterson
da06c14e60
Fix publish form when editing livestream (#565)
* Update publish form when editing livestream + update to radios for liveststream release time

* Fix bug where upload tools may remain visible upon switching upload type, even when no option to upload is available.

* move publish source state up, when editing livestream only show scheduling option when source is none.

* Reset any set release time if switching to live stream mode.

* Update date/time cmpnts to reset any chnages they made on umount. Update schedule date/time cmpnt to clear release time when selecting anytime option.

* Additional filtering of internal tags

* Default to replay view when editing a liveststream
2021-12-31 11:20:54 -06:00
Rafael
e94f66a5fe Fix stakedLevel looking looking for wrong prop 2021-12-31 05:52:56 -08:00
Thomas Zarebczan
5d1e6a8f7c
fix crash
https://odysee.com/@ShapeShiftDAOLatam:e/giveth-es:a
2021-12-30 16:08:34 -05:00
Dan Peterson
78d8446a0b Strip internal tag prefix from form labels 2021-12-30 16:05:51 -05:00
Dan Peterson
a96d2a47be Create new anytime form state to explicitly set to release to now. Clear internal scheduled tag when editing. 2021-12-30 15:21:59 -05:00
Dan Peterson
399c4eb56d revert commit - wrong branch 2021-12-30 15:21:59 -05:00
Dan Peterson
a92e9c9973 clear/reset release time if switching to livestream mode 2021-12-30 15:21:59 -05:00
Dan Peterson
1c58b6a10c remove prefix from disable-support 2021-12-30 15:21:59 -05:00
Dan Peterson
fcd2157050 update prefix to c: 2021-12-30 15:21:59 -05:00
Dan Peterson
194d42bf8c Update tag prefix to be consistent with "internal" naming convention used in code. 2021-12-30 15:21:59 -05:00
Dan Peterson
a8209ee38b Temporarily remove tag filter on upcoming (will be added back soon) 2021-12-30 15:21:59 -05:00
Dan Peterson
563e6b2c2f Add prefix to all internal tags 2021-12-30 15:21:59 -05:00
Dan Peterson
33cce4bbcd Update so that any edited streams without a date/time change still get the tag if needed. 2021-12-30 15:21:59 -05:00
Dan Peterson
356c5bf30f - Add a system-level tag for scheduled live streams
- Query for that tag in the upcoming section
- Improve special tag organization
- Filter out the internal tags in the UI
- Add missing types to publish state
2021-12-30 15:21:59 -05:00
infinite-persistence
0ccf9f2c05 Handle removed livestream comments 2021-12-30 11:55:44 -05:00
infinite-persistence
12eeb06c40 LivestreamComment: pass Comment prop instead of individual values
The number of props to pass is getting out hand, so just pass the Comment object directly.

Also, moved the "is my comment" check into LivestreamComment, so we don't need to pass it as a prop from the parent.
2021-12-30 11:55:44 -05:00
infinite-persistence
5aa6827258
NagNoUser i18n update 2021-12-30 20:42:53 +08:00
infinite-persistence
39a0beb4ee Remove channel_list from end of Sync Loop
## Issue
- Slow for users with many channels.
- The need to do it in Sync Loop is more applicable to Desktop.

## Approach
- Just remove it from sync loop.
- It will still be called when entering `/$/channels`, so that's an alternative to fix things when it is out of sync.
2021-12-29 21:16:20 -05:00
Rafael
cd9dc5cf96 Highlight chat message if your channel is mentioned 2021-12-29 16:13:57 -05:00
Dan Peterson
60430b5267 clean up dupe code + make sure failing analytics doesn't throw subscription error. 2021-12-29 15:45:10 -05:00
Dan Peterson
c22a3048dc Make sure user is available (ie. backend api not down) 2021-12-29 15:45:10 -05:00
Rafael
2c43076497 Fix header menu on password reset page 2021-12-29 15:40:15 -05:00
infinite-persistence
b6d21692e6 Fix broken startup sync-lock
## Issue
In 38c13cf5, an additional `doGetAndPopulatePreferences` was added in `doSignIn` to ensure we have populated the preferences at least once. With that, `doHandleSyncComplete` can skip `doGetAndPopulatePreferences` is there is no change in the hash.

The addition broke the "initial sync lock", thus incorrectly allowing users to change preferences when the process is not completed.

## Change
I think the additional call is no longer needed since we now store a local hash for comparison, so `doGetAndPopulatePreferences` wouldn't be incorrectly skipped in the first ever `doHandleSyncComplete`.
2021-12-29 10:32:38 -05:00
infinite-persistence
2ea37e7708 Settings: Change button from "Back" to "Save"
Changes aren't being saved until user leaves the page, so this change would reflect that better.
2021-12-29 10:32:38 -05:00
infinite-persistence
d7e3127e65 Sync: handle fast-actions being reverted
## Repro
1. Follow a channel.
2. When `preference_set` is sent, unfollow the channel.
3. A few seconds later, the final setting reflects (1) instead of (2).

The current sync loop involves doing a final `sync/get` at the end. While not necessary for the scenario above, the code flow covers various cases, so it's still needed for now.

## Approach
Implement an abort mechanism to the sync-loop.

When syncing from the `buildSharedStateMiddleware` loop, generate an ID for each sync session, and only store the latest one. Pass the ID to the completion-callback (and other places as needed), so we can check if our session is still the latest one before executing the callback.

The check for invalidation can also be placed in more places to cut off the sync process earlier, but it's only done for 2 critical places for now.
2021-12-29 10:32:38 -05:00
Rafael
2d1b876acc Improve Sticker Superchat display 2021-12-29 09:37:05 -05:00
Rafael
1578810013 Fix scroll re-rendering issues and improve superchats 2021-12-29 09:37:05 -05:00
infinite-persistence
c50cc422b7 Don't refresh tiles while fetching and if same results
## Ticket
555 Don't refresh tiles/claim search after blocking results are in + don't change
2021-12-29 09:32:01 -05:00
infinite-persistence
b0bea66b1d ClaimTilesDiscover: optimize props to reduce renders
Props: either use primitives, stable references or memoized objects to reduce renders. This update will simplify the existing `areEqual`. It is still needed though as some props are hard to memoize from where they are called, or should simply be ignore.
2021-12-29 09:32:01 -05:00
infinite-persistence
b1f4a2a590 Defer notification/categories
## Ticket
Part of "#385 Defer api.odysee.com calls to their respective pages / install new"

## Change
Pull out `notification/categories` from `doNotificationList` and fetch it in Notifications Page. I don't there there are other places that need it for now.
2021-12-29 09:15:06 -05:00
infinite-persistence
c5e690c657 Fix: unsubsribe action removes all with same name
## Repro
- Do a search like "Test" and filter to "Channels Only".
- Follow a bunch @test channels
- Unfollow any one of them. All of them gets unfollowed.

## Notes
The change in b9fc9b63 to compare the lower-case channel name probably made it even worse, since "@TeSt" would be removed too.

## Change
Not sure why channel name was used in the first place ... perhaps it was to cover canon vs perm uri?

Anyway, comparing uri makes more sense, so doing that instead.
2021-12-29 09:11:27 -05:00
infinite-persistence
c04023948b Replace weekly watch search loop with new last_claimed 2021-12-29 09:04:26 -05:00
Thomas Zarebczan
283ea69a6e
Fix crash with no channel 2021-12-28 13:40:16 -05:00
Thomas Zarebczan
d8123bd372
dummy rebuild commit 2021-12-28 10:39:41 -05:00
Rafael
ac88f3c8c1 Fix component sizing for overlap and better component positioning (like centering) 2021-12-28 08:56:42 -05:00
Rafael
256820aa03 Fix avatar background 2021-12-28 08:56:42 -05:00
infinite-persistence
98126e90b2 Fix 'weekly watch reminder' target path 2021-12-28 08:31:03 -05:00
Dan Peterson
ea1691609b throw cust error only when failing to parse json 2021-12-23 20:59:08 -05:00
Dan Peterson
8887996718 temporary hotfix for live api resp handling 2021-12-23 20:59:08 -05:00
infinite-persistence
3040b9ea12
Add flow types to Sync. No functional change. 2021-12-23 16:29:46 +08:00
infinite-persistence
3bce2e656f
Remove unused doSyncWithPreferences 2021-12-23 16:29:46 +08:00
infinite-persistence
06bfe60c54 Show view counts on uploads page
## Ticket
556
2021-12-23 03:16:11 -05:00
infinite-persistence
87e4fa5c6c i18n livestream 2021-12-23 03:16:11 -05:00
infinite-persistence
379b9341ef Render: must return null instead of undefined 2021-12-23 00:04:12 -08:00
infinite-persistence
198c191fd2 Skip connect until it is needed.
It seems to subscribe to the store if connected.
2021-12-23 00:04:12 -08:00
infinite-persistence
abff1f3259 Change logic for daily reward claiming to weekly
Closes 531
2021-12-23 02:40:58 -05:00
Dan Peterson
d382671616 Add stream start to active live streams, and refactor how data active claim is stored in redux 2021-12-22 13:50:49 -05:00
infinite-persistence
72c1a8ae25 OG: Skip 'data:image' when generating cards.odysee.com urls
## Issue
513 Meta: Invalid "card.odysee.com" used as thumbnailUrl
2021-12-22 10:03:43 -05:00
saltrafael
e2b8573269 Update spanish channels 2021-12-22 10:01:55 -05:00
Rafael
f7a6a767ab Fix conflicting svg styles 2021-12-22 08:44:05 -05:00
infinite-persistence
7d6c91c15a
Fix "you are offline" nag being stuck
Was trying to save one event listener in the previous implementation and rely on other redux state-changes to spark a GUI update, but turns out there are scenarios where nothing is updated and the "offline" nag is stuck on screen.

## Change
Do it properly using the event listeners. The nag should now update promptly.
2021-12-22 12:41:05 +08:00
infinite-persistence
74126623c7
i18n: more 'livestream scheduling' strings 2021-12-22 09:07:48 +08:00
infinite-persistence
33ddccb3c5
i18n: revert string so translators don't need to redo
Changing the string means it will stay in English until retranslated. Reverting so that it can re-use existing translated database.

I don't think there is a clash in the `followingCount` variable, so the change was probably unnecessary.
2021-12-22 09:07:47 +08:00
Rafael
ebcbc8cdb8
[Header] Changes, fixes and improvements (#493) 2021-12-22 08:43:02 +08:00
Rafael
45de6ab822 Fix Yt sync page 2021-12-21 16:36:16 -05:00
Rafael
7757960d96 Fix wallet cut off on mobile 2021-12-21 16:36:16 -05:00
Rafael
f5ba2d5425 Switch Logo from images to icons 2021-12-21 16:36:16 -05:00
Rafael
4158b99453 Fix header profile button for no channels, use it as an icon for mobile unath instead of big login/signup buttons 2021-12-21 16:36:16 -05:00
Rafael
7001c27ed0 Apply changes from #528 2021-12-21 16:36:16 -05:00
Rafael
75a922b0c9 Add smaller Mobile size values 2021-12-21 16:36:16 -05:00
Rafael
79a4fa55e0 Set logo img width and height 2021-12-21 16:36:16 -05:00
Rafael
89d84e0776 Refactor Logo 2021-12-21 16:36:16 -05:00
Rafael
5c6fb9de66 Improve header components that need to be loaded in to display Skeleton and avoid layout shifting 2021-12-21 16:36:16 -05:00
Rafael
76147d89c6 Refactor and split Header CSS 2021-12-21 16:36:16 -05:00
Rafael
56603be2f9 Decrease --header-height by 20% 2021-12-21 16:36:16 -05:00
Rafael
75b441e7cb Add Tooltips to header buttons and replace reach/ui 2021-12-21 16:36:16 -05:00
Rafael
80a375fecb Refactor notificationHeaderButton 2021-12-21 16:36:16 -05:00
Rafael
254fff208d Refactor header Component, split into smaller components and remove what is unused 2021-12-21 16:36:16 -05:00
Shiba
a196f7a3b0
Fixed vars.scss being imported multiple times (#528)
- Seperated breakpoints into a different file
2021-12-20 20:27:25 -05:00
infinite-persistence
9a0fde3f33
Publish: fix Resume button not appearing after 'conflict' (#543)
## Issue
Apparently, a user is experiencing 423 locked errors from the server, which should not happen given the locking mechanism plus the user wasn't trying to do concurrent uploads.

## Fix
Anyway, fix the Resume button so that at least they can try to resume.
2021-12-20 20:25:15 -05:00
Thomas Zarebczan
dcf0e903ba
force rebuild 2021-12-20 15:49:57 -05:00
saltrafael
8c32b36aa0
Add language based channels to Auto follow (#523)
* Refactor userChannelFollowIntro

* Add community based channels to signup auto follow

* Add German channels

* Remove main english channels and leave only community ones for auto follow
2021-12-20 15:35:59 -05:00
Dan Peterson
2be14c86c3
Add ability to have claim searches auto-fetch up to 3 pages. (#504)
* Add ability to have claim searches auto-fetch up to 3 pages.

* make total_items and total_pages optional

* use auto pagination strategy when determining live claim

* Bump page size back to 50
2021-12-20 13:25:16 -05:00
Thomas Zarebczan
3b6d3bf107
remove dave and nick stickers 2021-12-20 12:13:42 -05:00
Thomas Zarebczan
36855143b7
dave and nick 2021-12-17 21:51:29 -05:00
Dan Peterson
350524114a
Fix the view more/less functionality by properly reporting the total number of claims (#530) 2021-12-17 16:28:11 -05:00
Dan Peterson
f0fdcb6a6e
Hotfix livestream datetime (#527)
* Temporarily adjust upcoming buffer to 15 min + 5 min cache time

* Make sure datetime is shown on regular claims
2021-12-17 10:23:49 -05:00
Dan Peterson
accbde78e0
Temporarily adjust upcoming buffer to 15 min + 5 min cache time (#518) 2021-12-16 17:54:12 -05:00
Dan Peterson
038692cafc
Feature livestream scheduling (#458)
Add livestream scheduling feature
Also supports back to back streams, and will notify on a non-active stream of an active one.
2021-12-16 16:59:13 -05:00
Anthony
f112721398 fix cookie settings footer being hidden 2021-12-16 16:10:29 -05:00
Anthony
c2c782f6e6 fix script data attribute 2021-12-16 16:07:54 -05:00
Anthony
27012f0c8d add comment 2021-12-16 14:18:55 -05:00
infinite-persistence
fe3bbb0c70 Home: prevent layout shift from ads
## Issue
The ad tile causes a layout shift on certain screen/zoom, pushing CLS from green to red.

## Change
- Do replacement instead of insertion.
- Fixed "null lastCard" flow warning instead of suppressing it.
2021-12-16 14:18:55 -05:00
infinite-persistence
d2385b70ec
Revert "Switch thumbnail server: spee.ch --> vanwanet #497"
Reverting until vanwa can provide us failure details to handle accordingly.
2021-12-16 16:18:01 +08:00
infinite-persistence
50d1d062ad
Revert "Switch thumbnail server: spee.ch --> vanwanet"
This reverts commit 1a0a62058c.
2021-12-16 16:16:22 +08:00
infinite-persistence
7d9e8bffae
Revert "Remove the delayed thumbnail message for ChannelEdit"
This reverts commit a7e571c3b9.
2021-12-16 16:16:16 +08:00
infinite-persistence
f5cce18a55 Disable placeholder animation
## Issue
https://www.notion.so/Performance-Fixes-927f825a5d674bd09323830be1d263af#1beab2fee011421492b56b88f68681a3

We currently lazy-load the tiles in the category sections (but not the sections themselves, because we want to retain scroll position on Back action). This puts gray placeholders until the section is visible on screen.  which turns out to be quite expensive, because the placeholders are animated, so we have a perpetual animation in the background after the homepage loads + user did not scroll.

## Change
Just disable the barely-noticeable animation for now.

There are alternatives, but probably not worth polluting the code with:
- Just like the thumbnails, use intersection observer to decide when to animate.
- Find solution to the "lazy load section + need to retain scroll position".
2021-12-16 03:01:03 -05:00
Shiba
24a6f00835 Changed max inline player height
Changed the max player size, so in theater mode like/dislike buttons are visible without scrolling down.
2021-12-15 17:59:18 -05:00
Max Kotlan
e3394bf8b2 simplified transform 2021-12-15 15:31:57 -05:00
Max Kotlan
202cbd4499 center footer items + minheight fix for footer 2021-12-15 15:31:57 -05:00
Max Kotlan
9503829e18 shouldRenderLargeMenu 2021-12-15 15:31:57 -05:00
Max Kotlan
9022ab6020 menu can close completely 2021-12-15 15:31:57 -05:00
Max Kotlan
f5ef6cdd57 remove livestream enabled 2021-12-15 15:31:57 -05:00
Max Kotlan
66fe78e5f1 boxshadow 2021-12-15 15:31:57 -05:00
Max Kotlan
7418e27994 Added new menu animations 2021-12-15 15:31:57 -05:00
Anthony
bc514b1d5c fix lint errors 2021-12-15 15:00:28 -05:00
Anthony
c214209747 disable preroll ads 2021-12-15 15:00:28 -05:00
infinite-persistence
a7e571c3b9 Remove the delayed thumbnail message for ChannelEdit
Not necessary now that we don't need confirmations for thumbnails (direct upload to CDN)
2021-12-15 13:59:45 -05:00
infinite-persistence
1a0a62058c Switch thumbnail server: spee.ch --> vanwanet 2021-12-15 13:59:45 -05:00
infinite-persistence
2e7e14b83c Disable ads in Wild West until ads fail more gracefully
## Issue
- Log out
- Wild West
- Click "Show more livestreams"
- Click "Show less livestreams" (top-right corner)
- Crash
2021-12-15 09:49:06 -05:00
infinite-persistence
a0aa3c99b2 OG_HOMEPAGE_TITLE: 'odysee.com' --> 'Odysee'
I'm trying to figure out what's causing our "odysee" search term to show simple results, while "odysee.com" shows the rich results. It is less likely for someone to type "odysee.com" in a search, I think.

Even if OG_HOMEPAGE_TITLE is not the culprit, I think the cards look better since it is currently showing double URLs.
2021-12-15 08:24:12 -05:00
infinite-persistence
33fda0d581
Fix Verify Page being cut-off in Sign Up loop
Too lazy to de-couple the css, so this is the best minimal work to reduce scrollingin Sign In while not cutting off Verify Page.
2021-12-15 19:34:54 +08:00
infinite-persistence
76c9f576d3
More env updates from production 2021-12-15 14:44:00 +08:00
infinite-persistence
60198d154e
Fix "show less livestream" appearing when not needed. 2021-12-15 13:19:44 +08:00
infinite-persistence
1766b418c6
Remove old mobile chromecast css hack
lbry-desktop--6844

This negates 49abbecb.

Now that we have a dedicated chromecast button, we don't need to hack Chrome's default cast button to appear on top of vjs-mobile-ui.  The hack no longer works anyway, since the CSS exposure has been deprecated around mid 2020 -- it is still available, but its abilities has become less and less.
2021-12-15 09:44:09 +08:00
github
8500846654
Replace SecurePrivacy with OneTrust (#468) 2021-12-15 09:40:58 +08:00
Anthony
dfaa848ab7 change the way checking if onetrust is available 2021-12-14 15:09:31 -05:00
Anthony
d675d3234c use production script for odysee 2021-12-14 15:09:31 -05:00
Anthony
aef8e2eba7 sidebar ad hiding fixed 2021-12-14 15:09:31 -05:00
Anthony
c011145029 bugfix typo 2021-12-14 15:09:31 -05:00
Anthony
863b4bfdea hide bottom left widget 2021-12-14 15:09:31 -05:00
Anthony
cafc3d676f switch footer to onetrust 2021-12-14 15:09:31 -05:00
Anthony
561bcbe545 replace secureprivacy with onetrust 2021-12-14 15:09:31 -05:00
Anthony
1c20027b62 add onetrust widget 2021-12-14 15:09:31 -05:00
infinite-persistence
bbdab2274a Split MUI and Emoji-Lib
460

ui.js: 4.44MB -> 3.94MB
2021-12-14 12:59:36 -05:00
infinite-persistence
c556b88f37 Update LOGIN_IMG_URL and FAVICON to faster version
- LOGIN_IMG_URL: no need to grab full size + faster from direct url.
- FAVICON: not much benefit resizing an already-small image.
2021-12-14 09:37:54 -05:00
infinite-persistence
7c7bf23761 Update image urls from production as default
Putting it in git makes it easier to tweak and track changes.
2021-12-14 09:37:54 -05:00
infinite-persistence
20ba4b9b13
Sign-up page optimization (#489) 2021-12-14 18:02:01 +08:00
infinite-persistence
569ff3077f
UserSignUp: skip user fetch
Talking to Tom, we think this can be removed, since the regular startup could would eventually call `new` to get a token.
2021-12-14 17:40:44 +08:00
infinite-persistence
eccb542610
AuthPage: css fixes
- The graphic was meant to be 50% of the card width, but was squished.
- Try to reduce scrolling by making everything fit in a 100% zoom on a 1080p screen.
2021-12-14 17:25:05 +08:00
infinite-persistence
fea13bdc88
LoginGraphic: remove image resizing
The previous version was trying to fetch an optimized image with the exact size required, but the URL given was pre-optimized, so it wasn't working correctly. The additional work is also slow (seems to lock up mobile a bit), and since it wasn't functional, just removed it entirely.

It will be easier to just pre-reduce the image size to something suitable for a 1080p screen (the most common screen size at the moment).
2021-12-14 17:25:04 +08:00
infinite-persistence
50cbd9716a
i18n cleanup 2021-12-14 17:19:11 +08:00
Anthony
5f874e44a7 disable ads on android firefox 2021-12-13 12:31:41 -05:00
Anthony
b34de2d5cf dont run sidebar ad on android firefox 2021-12-13 12:31:41 -05:00
infinite-persistence
3b87f0aba6 Remove content_tags and related functions
No longer necessary.

Also removed a few doToggleTagFollowDesktop props (unused by the View).
2021-12-13 11:54:53 -05:00
infinite-persistence
f3634c881d
Dev instance changelog button. 2021-12-13 16:46:29 +08:00
infinite-persistence
9c723b3db3
tus: skip fingerprint storage
## Ticket
418 TUS: skip fingerprint storage

- Fingerprints for canceled uploads are not being cleared by tus-js-client. It's in localStorage, and there is limit for that.
- We are storing the confirmed fingerprint (from the backend) in redux anyway, so we don't need that functionality.
2021-12-13 15:35:21 +08:00
infinite-persistence
e3956150a3
Disable file selector when upload is locked from another tab. 2021-12-13 15:33:39 +08:00
Rafael
392e7c37a4 Fix replaceAll 2021-12-10 15:40:23 -05:00
infinite-persistence
561ed0ea23 -- experiment with forcefully closing the session on dispose 2021-12-10 14:16:03 -05:00
infinite-persistence
42a8f3180d Pass the title and channel name to Chromecast.
As noted in a comment, we need to be careful when adding props to `VideoJs` to avoid renders.

Used primitive strings (title, channelName) instead of passing the entire `claim`, which could have its reference invalidated.
2021-12-10 14:16:03 -05:00
infinite-persistence
4c84fde31b Add Chromecast support on Google Chrome. 2021-12-10 14:16:03 -05:00
Thomas Zarebczan
8710b1334f new player domain 2021-12-10 12:58:36 -05:00
Rafael
c7790693df Fix named capturing groups not supported in most browsers 2021-12-10 10:17:40 -05:00
Anthony
132d6ba50c only load ima when needed 2021-12-10 09:44:39 -05:00
infinite-persistence
224f10663d Prevent concurrent uploads with same lbry name
## Ticket
426

## Issue
Currently, we check if we have any existing claims with the same name when uploading, i.e. "lbry://<name>". It does not include claims that you are still uploading, so you might end up with duplicate claims.

In the ticket, there is also the issue of 2 uploads sharing the same slot, causing the progress indicator to jumpy between the uploads. That has been fixed by using a guid instead of using `name`.

## Aside
I think there is another request to allow the same name but on different channel ... next time, next time ....
2021-12-10 08:48:16 -05:00
infinite-persistence
cb78d568c5 Update default env closer to production's 2021-12-10 08:23:35 -05:00
infinite-persistence
316ce220bf
PageShow: fix isSubscribed always false
- Using `selectIsSubscribedForUri` instead, because the given uri is in Canon while the subscription list is in Permanent, so the result was always `false`.
2021-12-10 14:24:31 +08:00
infinite-persistence
70a339c5d4
Fix selectModal always returning a new reference
Never use `state` as an input to `createSelector` as it is _always_ invalidated per immutability pattern.
2021-12-10 12:58:44 +08:00
infinite-persistence
9307511c88 Move MAIN_CLASS to constants file for better code-splitting.
Cross-importing was making things hard to code-split efficiently, because the entire file gets evaluated when imported.
2021-12-09 20:58:23 -08:00
Rafael
0d59ce4f8c Stickers display improvements 2021-12-09 23:49:35 -05:00
Rafael
d51b8cc670 Fix no name after @ error 2021-12-09 15:35:40 -05:00
Rafael
a729c7ab3a Fix blur and focus commentCreate events 2021-12-09 15:35:40 -05:00
Rafael
c9898ad833 Fix livestream updating state from both websocket and reducer and causing double of the same comments to appear 2021-12-09 15:35:40 -05:00
Rafael
9ea89f7b1b Fix text color on darkmode 2021-12-09 15:35:40 -05:00
Rafael
cf23149ab4 Remove unused topSuggestion component 2021-12-09 15:35:40 -05:00
Rafael
37ee60aca1 Filter default emojis with the same name as emotes 2021-12-09 15:35:40 -05:00
Rafael
5feaa30e58 Add back support for Winning Uri 2021-12-09 15:35:40 -05:00
Rafael
c2a3698015 Fix and Improve searching 2021-12-09 15:35:40 -05:00
Rafael
e8e1c7e3b4 Fix Popper positioning to be consistent 2021-12-09 15:35:40 -05:00
Rafael
cdc1c0dce4 Fix dispatch props 2021-12-09 15:35:40 -05:00
Rafael
1751f78028 Add key to groups and options 2021-12-09 15:35:40 -05:00
Rafael
d2e4f46abd Fix non concatenated strings 2021-12-09 15:35:40 -05:00
Rafael
1695312833 Add support for suggesting emojis 2021-12-09 15:35:40 -05:00
Rafael
db5f24ae28 Add back and improved support for searching while mentioning 2021-12-09 15:35:40 -05:00
Rafael
6faaf78fc0 Improve label to display matching term 2021-12-09 15:35:40 -05:00
Rafael
4ce3881636 Add support for suggesting Emotes while typing ':' 2021-12-09 15:35:40 -05:00
Rafael
ea84d1af56 Move channel mentioning to use @mui/Autocomplete combobox without search functionality 2021-12-09 15:35:40 -05:00
Rafael
a459e98cab Install @mui/material packages 2021-12-09 15:35:40 -05:00
Rafael
aeb9536a4e Refactor channelMention suggestions into new textareaSuggestions component 2021-12-09 15:35:40 -05:00
Rafael
fcd72799b7 Refactor scrollbar CSS for portal components outside of main 2021-12-09 15:35:40 -05:00
Thomas Zarebczan
af5757b53d
add new stickers
remove 2nd pants
2021-12-09 10:35:39 -05:00
infinite-persistence
d8dd860e04
Livestream page prop optimization
- Remove unused prop.
- Use primitives whenever possible, since object references could change.
2021-12-09 17:42:41 +08:00
infinite-persistence
a9be97108c
Fix view count appearing in Recommended. 2021-12-09 16:53:51 +08:00
infinite-persistence
dc91bcad9c
Follow-up tweaks for 'Videojs css fix (#445)'
- More css consolidation.
- More size and padding restoration (it wasn't 445's main intention to change sizes).
- Handle padding for mobile to hopefully make everything fit, especially for Playlists. We'll need an overflow menu to truely fix this for all screens.
2021-12-09 16:34:54 +08:00
infinite-persistence
a9e1308151
Fix missing livestream in Category Pages
I accidentally over-limited it to Wild West when trying to exclude Tag Searches from showing livestreams.
2021-12-09 08:45:12 +08:00
infinite-persistence
2a4a84197a
Add ads to category pages (#451) 2021-12-09 08:32:17 +08:00
Anthony
f012ba7d73 dont run ads on channel page 2021-12-08 15:49:06 -05:00
Anthony
30cd0644fa only insert ad if its the content view 2021-12-08 15:49:06 -05:00
Anthony
1b6dc0fd8b add ad to channel page 2021-12-08 15:49:06 -05:00
Anthony
22f2053324 trigger scroll event to show ad 2021-12-08 15:49:06 -05:00
Anthony
46fc0ab47f add ad to channel pages 2021-12-08 15:49:06 -05:00
infinite-persistence
ccf0d8e163 Fix double-render of Category Pages when unauthenticated
## Scenario
`selectHasUnclaimedRefereeReward` updated --> `AppRouter` re-render --> `dynamicRoutes` regenerates (re-mounts) list of `DiscoverPage`s

## Fix
I think `selectHasUnclaimedRefereeReward` can be moved elsewhere and would solve the problem, but avoided that since I'm not familiar with rewards enough to do minimal testing.

Memoize the Category Page routes instead.
2021-12-08 13:59:33 -05:00
infinite-persistence
eb5a6ccde9 Memoize GetLinksData for performance
`GetLinksData` is somewhat expensive.  The value won't change until user changes the window size or selects another homepage.

As we can't call an `effect` within a `memo`, we had to extract out `isLargeScreen` as an input parameter, which is fine as it makes `GetLinksData` more functional (functional programming).
2021-12-08 13:59:33 -05:00
infinite-persistence
ece9f9ceae
Enlarge the play icon size
per Anthony's comment. It's still not as large as before, as I believe the size should match the other icons (which the previous version did not).
2021-12-09 00:25:27 +08:00
saltrafael
9ec1b17515
Fix cancel sending sticker (#447) 2021-12-08 09:17:22 -05:00
infinite-persistence
89cf411d18
Fix popup auto dismiss when the gap is hovered
This was previously fixed, but I forgot to add it back when doing #445.
2021-12-08 17:50:35 +08:00
infinite-persistence
62cb26b4bf
Videojs css fix (#445) 2021-12-08 16:05:59 +08:00
infinite-persistence
d08af5c63c
Duration: center text; fix uneven space for "/" time divider 2021-12-08 15:55:23 +08:00
infinite-persistence
627b01c664
Icon and popup css fixes
## Issues
- So many `!important` overrides that makes it hard to customize.
- Weird "813px max-width" check -- it feels random, plus does not adjust accordingly to zoom-levels.
- The button text is not always vertically centered for all layout and zoom-levels because it is being centered using hardcoded margins.
- The 2 popups don't have consistent fonts and styling, plus their customizations are all over the place.

## Changes
- Try to remove as many unnecessary "!important" as possible. Adding specificity is sufficiently, and won't block other customizations.
- Try using `rem` instead of hardcoded margins. The icons/text/margin should resize accordingly per zoom-levels.
    - I didn't replicate the "813px max-width" media check. If it is really necessary, please use `vjs-layout-*` to customize them instead.
- Consolidate the 2 popup menu customizations.
2021-12-08 15:55:22 +08:00
infinite-persistence
47c5882ac5
Add note on removing !important when we upgrade vjs later. 2021-12-08 15:48:11 +08:00
infinite-persistence
61c73f1572
ControlBar: use specificity instead of !important
The color should also be a variable...
2021-12-08 15:48:08 +08:00
infinite-persistence
7e1c0c53e4
TheaterMode: fix button size and offset
It's too small compared to the rest and off-centered.
2021-12-08 15:48:04 +08:00
infinite-persistence
90c4cee9ad
Autoplay-Next: fix area size so that all buttons are evenly-spaced
Each button should have the same touch area and roughly the same left-right margins.  Currently, the Theater Button (or the Chromecast button) looks too far from Speed and too close from Autoplay.  They should be evenly-spaced.
2021-12-08 15:48:00 +08:00
infinite-persistence
6afddc9b8a
Removed css that has no effect
These doesn't seem to have any effect due to higher specificity somewhere in the base vjs css.
2021-12-08 15:47:55 +08:00
infinite-persistence
aef8c5da7b
Upload: tab sync and various fixes (#428) - w/ commits
No code changes, just putting back the commits in case we need to do partial revert in the future. Also helps in debugging.
2021-12-08 09:17:53 +08:00
infinite-persistence
b73edf2822
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)
2021-12-08 09:16:28 +08:00
infinite-persistence
82bb785f9d
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.
2021-12-08 09:16:27 +08:00
infinite-persistence
ded021cc76
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.
2021-12-08 09:16:27 +08:00
infinite-persistence
994d9c6027
Temp revert to allow putting back the commits
This reverts commit 157b50c58e.
2021-12-08 09:16:12 +08:00
saltrafael
fcf19a07e8
Fix some certain wordings breaking page (#440) 2021-12-07 14:03:19 -05:00
infinite-persistence
157b50c58e
Upload: tab sync and various fixes (#428)
* 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)
2021-12-07 09:48:09 -05:00
mayeaux
e982d9c13c
fix linter (#438) 2021-12-06 13:46:45 -05:00
mayeaux
20ca590684
force everything to lower case (#437) 2021-12-06 13:22:09 -05:00
mayeaux
1bfe9e2eda
Ad blacklist terms (#434)
* coming along well

* working properly

* check claim name and dont have side effect if the environment vars are not set

* check against claim name
2021-12-06 13:01:40 -05:00
saltrafael
62122f6a96
Only allow to resubmit a tip when a previous has completed or failed (#429) 2021-12-06 09:51:07 -05:00
infinite-persistence
08ebedb4cc
Settings Page: add warning for unsaved settings (#430)
* 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.
2021-12-06 09:38:26 -05:00
saltrafael
fb7c5d0fff
Fix category page labels not being translated (#423) 2021-12-04 12:08:13 -05:00
mayeaux
82643b1f4a
Finish cleaning out DOM (#413)
* finish cleaning out dom

* lint
2021-12-02 13:22:51 -05:00
mayeaux
a842a58608
Persist ads (#411)
* persist homepage ads

* persist all ads
2021-12-02 12:04:40 -05:00
infinite-persistence
afefd5f4f5
Skip pending-channels loop if there are no pending channels. 2021-12-02 21:36:53 +08:00
infinite-persistence
8eff3dca21
Use the lighter activeChannelId
- No need to generate the full claim since we are only using the ID.
2021-12-02 21:00:17 +08:00
infinite-persistence
36c10a9c78
Remove unused props 2021-12-02 20:41:02 +08:00
infinite-persistence
428c00901b
Fix double pause button in mobile (#408)
Restored css load-order that was changed from a recent refactor.
2021-12-01 22:06:22 -05:00
infinite-persistence
2ecf04a2e5
Sort languages (no functional change)
Just to spark a build
2021-12-02 09:32:56 +08:00
Max Kotlan
1eeacadbf2
updated the transform origin (#395) 2021-12-01 13:01:21 -05:00
infinite-persistence
f6b17909f2
File description (collapsed): show ~3 lines instead of ~1 (#403)
## Ticket
- Closes https://github.com/lbryio/lbry-desktop/issues/7222
- Also felt it's too squished for the longest time. Previously fixed comments but didn't handle this.
2021-12-01 10:52:09 -05:00
saltrafael
c492204e26
[oEmbed] some changes and fixes (#392)
* Fix query selection

* Fix xml format

* Fix link url and author_url

* Refactor repeated components

* Refactor repeated embed iframe string

* Add support for passing referrer queries to src

* Change iframe id from lbry to odysee

* Improve replace logic understanding

* Fix URL

Co-authored-by: Thomas Zarebczan <tzarebczan@users.noreply.github.com>
2021-12-01 10:36:52 -05:00
infinite-persistence
787ebd9588
Blacklist: use existing map instead of looping (#400)
We already have a pre-calculated map, but not used except for comments.

At the expense of pre-calculating it, the subsequent queries are instantaneous compared to the loop.

We are still not perfect in term of reducing re-renders, so this helps a lot.
2021-12-01 10:24:27 -05:00
infinite-persistence
7e9e213974
Add pinning in Category Pages's Trending Tab (#399)
Closes https://github.com/OdyseeTeam/odysee-homepages/issues/427
2021-12-01 10:18:57 -05:00
mayeaux
6d3ec149b3
use second card on small screens and dont load script if authenticated (#406) 2021-12-01 09:52:03 -05:00
infinite-persistence
935eaa6edb
Add persistence to live tile expansion in Wild West (#398)
* Discover: add persistence to the livestream section's fold state

The persisted value should only apply when livestream section is needed, hence the need for 2 state variables.

Also renamed the variables for clarity.

* Discover: add "show less livestreams" at upper-right

Wanted to put it as an injected tile, but requires more work to do it in a general-purpose way, as opposed to a hardcoded way like how ads are currently injected. It also needs to work on both Tile and List format.

So ... just place the button at the upper-right for now. Although a bit odd, at least it'll be a consistent place (i.e. position won't be affected by live tile count).
2021-12-01 09:36:35 -05:00
infinite-persistence
dd96d1222d
Fix inability to unblock and unsubscribe an abandoned claim (#405) 2021-12-01 21:33:03 +08:00
infinite-persistence
8bc6718a4a
Fix selectIsSubscribedForUri not handling abandoned claims
I yanked out the parseURI part in a prior commit ... the comment was misleading me to think it was redundant. But it had another hidden function, which is to handle abandoned claims which `claim` will be `null`.
2021-12-01 21:21:31 +08:00
infinite-persistence
dcd93af6eb
Fix inability to unblock an abandoned claim
The recent change to parse the channel from a Repost using a `claim` ended up breaking the case for abandoned claims, which `claim` will be `null`.

Fix by looking at `claim` first (faster), and falling back to the `parseURI` method if it remains inconclusive.
2021-12-01 21:21:09 +08:00
infinite-persistence
beeec64271 i18n ads 2021-11-30 22:53:47 -08:00
infinite-persistence
6fb2e02e3a
Change ad script injection method + fix effect dependency (#396)
## Issue
Tom seeing crashes on the line that was trying to remove the script, saying it's not a child of that node.

## Changes
- I'm guessing the found `fjs` sometimes is not in `head`, but we always remove from `head` during cleanup. Just append to the bottom of head, and remove from head. I think script order doesn't matter if we are injecting at runtime?

- Fixed effect dependency while at it (the latest PR removed the need to check for `type`).
2021-11-30 22:17:28 -05:00
infinite-persistence
0aff130ea4
Fix lint and formatting (#394) 2021-11-30 19:53:23 -05:00
John B Nelson
fcb70c8e8b
FIX recsys endpoint fix (#393) 2021-11-30 19:35:04 -05:00
mayeaux
1e071550ae
Add ad to the homepage as a card (#362)
* coming along well

* coming along well

* adding custom react element

* coming along well

* coming along well

* coming along well

* working pretty well

* almost done

* essentially working just could use a couple touchups

* cleanup and lint errors

* fix lint errors

* fix flow errors

* possible bugfix

* dynamically set width and height

* only run when rowdata is populated

* trying using ref

* better way to check for card population

* working implementation

* working implementation

* clean up flow and clean up script

* fix typo in comment and logs
2021-11-30 17:01:03 -05:00
John B Nelson
873ac4dc5d
Change clickstream endpoint for brave's shield (#391)
Brave's shield blocks the clickstream endpoint. uBlock origin
does not (it seems).
2021-11-30 15:47:48 -05:00
saltrafael
4fd4309829
add Player.js Support (#378)
* Reorder video.js imports and props

* Install player.js

* Add player.js adapter for video.js
2021-11-30 15:46:03 -05:00
jbn
a7b991efb1 Change clickstream endpoint
It seems like `clickstream` is blocked by brave's sheilds.
2021-11-30 14:28:13 -05:00
infinite-persistence
bfccca9aaf
Mobile: move 'Notifications' to the top (#389)
## Behavioral changes
- Moved Notifications to the top for mobile.
- Added separate lines between sections.

## Code changes
The array method is too restrictive (hard to move things with display logic around). It's also hard to read.

Instead of trying to populate an array, just directly populate the return tree. Added `getLink` to make things readable. It's now easier to see the sections in a glance.
2021-11-30 10:27:37 -05:00
infinite-persistence
e96807fa6d
Restore 'https' to dmca link and remove actual dup 2021-11-30 14:21:33 +08:00
Thomas Zarebczan
6d4c93968f
Update README.md 2021-11-29 21:57:23 -05:00
saltrafael
34eaccdbee
add oEmbed Support for video claims (#376)
* Refactor html.js

* Fix Favicon

* Refactor rss.js

* Create oEmbed.js
2021-11-29 21:27:56 -05:00
Thomas Zarebczan
7613d07c35
Misc updates 2021-11-29 20:32:39 -05:00
Thomas Zarebczan
27d8f4174c
fix thumbnail URLs 2021-11-29 19:31:23 -05:00
infinite-persistence
f5f3b08cca
Debounce volume and muted state update.
## Ticket
189: Overall React Lag or Extra Re-renders / Volume slider laggy since v0.48

## The problem
Every redux update results in each mounted component's prop mapping function (the `select` and `perform` stuff) to be recalculated. This is normal per redux, but we do lots of heavy stuff there.

The slider was sending tons of redux update for the Volume and Muted setting.

## Changes
The redux volume/muted setting is just used to restore vjs to the user's setting on the next video, so it doesn't need to be updated immediately/constantly -- vjs keeps it's own video settings.  Debounced that action.
2021-11-29 23:12:38 +08:00
infinite-persistence
71fc850df4
Settings Page: maximize width usage in mobile 2021-11-29 21:01:29 +08:00
infinite-persistence
ac11dec484
Trailing spaces should not be part of translation. 2021-11-29 08:45:57 +08:00
infinite-persistence
c15a52cb46
i18n update 2021-11-29 08:45:57 +08:00
infinite-persistence
56ecdec2cb
Restore "don't run SP script on iframe (368)" + lint/format (#373) 2021-11-26 09:24:51 -05:00
Thomas Zarebczan
406d91948d
Move around for Roku prod app 2021-11-25 11:51:39 -05:00
Thomas Zarebczan
11c8024c2a
Revert "dont run on iframe (#368)" (#370)
This reverts commit 823fdcdd97.
2021-11-25 11:08:21 -05:00
mayeaux
823fdcdd97
dont run on iframe (#368) 2021-11-25 10:42:26 -05:00
infinite-persistence
fd17ab4c8b
Route recommendation search to recsys + add user_id (#353)
* Route recommendation search to recsys 5% of the time + add `user_id`

## Ticket
334 send some recommended requests to recsys

## Approach
`doSearch`:
    - If the search options include `related_to`, route that to the new `searchRecommendations` which performs the 5% check + appends `user_id` at the end. This way, we don't need to alter the function signature of `doSearch`.
    - Else, run proceed as normal.

* Always go to alt provider

f

Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2021-11-24 15:25:22 -05:00
mayeaux
2adbbc2899
bugfix embed errors (#366) 2021-11-24 15:20:36 -05:00
infinite-persistence
5c643cc796
Re-enable reposts on homepages (#352)
* Add remove_duplicates to tile/list claim_search except for Channel Page

This removes the any duplicates from reposts.

* Re-activate the "Hide reposts" setting

* Category Rows: default to ['stream', 'repost'] unless specified otherwise.
2021-11-24 11:11:25 -05:00
infinite-persistence
781f1b712e
GA: entered livestream (#364)
## Issue
85: "user joined livestream"

## Approach
Add it into the existing "player :: action" event, so we can compare it againts `loaded_video | loaded_image | loaded_markdown | loaded_audio`.
2021-11-24 11:03:21 -05:00
infinite-persistence
6bbf310348 GA: browser notification subscription 2021-11-24 07:28:25 -08:00
infinite-persistence
7ea74cfa0d
Fix livestream tiles reloading placeholders then scrolled (#360)
## Issue
9: Wild west + scroll down tries to reload livestreams
2021-11-24 09:35:47 -05:00
infinite-persistence
4267c1ccf7
Un-authenticated resolve (#341)
* apiCall: add option to not send the auth header

## Why
Want an option to make un-authenticated `resolve` calls where appropriate, to improve caching.

## How
All `apiCall`s are authenticated by default, but when clients add NO_AUTH to the params, `apiCall` will exclude the X_LBRY_AUTH_TOKEN. It will also strip NO_AUTH from the param object before sending it out.

* Add hook for 'resolve' and 'claim_search' to check and skip auth...

... if the params does not contain anything that requires the wallet.

* doResolveUri, doClaimSearch: let clients decide when to include_my_output

- No more hardcoding 'include_purchase_receipt' and 'include_is_my_output'
- doResolveUri: include these params when opening a file page. This was the only place that was doing that prior to this PR.

* is_my_output: use the signing_channel as alternative

## Notes
`is_my_output` is more expensive to resolve, so it is not being requested all the time.

## Change
Looking at the signing channel as the additional fallback, on top of `myClaimIds`.

## Aside
I think using `myClaimIds` here is redundant, as it is usually populated from `is_my_ouput`. But leaving as is for now...
2021-11-24 09:33:34 -05:00
infinite-persistence
c74dd49bc5
Fix livestream tiles appearing in Tag Search
## Ticket
155 All live streams show on tag explore/discovery page + content type filters don't work there

`!dynamicRouteProps` wasn't good enough to determine if it's Wild West. Use direct path instead.
2021-11-24 17:32:49 +08:00
infinite-persistence
b762cac50b
i18n fixes for new category and page titles 2021-11-24 11:11:46 +08:00
mayeaux
84e75fdfe8
Workaround for SecurePrivacy issues with VPNs (#357)
* workaround for secureprivacy issues with vpn

* fix flow issues
2021-11-23 17:26:23 -05:00
saltrafael
f8b694d7d7
Add Pop Culture Icon (#355) 2021-11-23 15:31:28 -05:00
saltrafael
bc64802f6e
Add Education Icons (#354) 2021-11-23 12:35:25 -05:00
mayeaux
f2715fa97b
Adds GDPR support (#311)
* add gdpr support

* only run on production

* testing implementation

* just needs last touches then ready

* ready for merge

* add cookies to sidebar

* hide button when secureprivacy not available

* switch over to loading script as a react hook

* conditionally add secureprivacy script

* save gdpr status on session

* better design
2021-11-23 10:21:33 -05:00
infinite-persistence
3c4ccdd2fe
Kill makeSelectClientSetting
## Why
- No memo required (no transformation).
- `makeSelect*` is an incorrect pattern.

## Changes
- Replaced makeSelectClientSetting with selectClientSetting.
- Remove unused selectShowRepostedContent.
2021-11-23 12:29:53 +08:00
infinite-persistence
eb83a834a1
TUS: handle remaining locked file error messages 2021-11-23 11:28:32 +08:00
infinite-persistence
605a8f371d
TUS: Skip logging "423/409 concurrent upload" errors. 2021-11-23 09:30:55 +08:00
Thomas Zarebczan
a3111003a2
Add new stickers (#347) 2021-11-22 17:52:46 -05:00
saltrafael
e2c7337d11
[Report Page] Fix GitHub URL and improve strings (#340)
* Refactor

* Fix github URL and Improve strings
2021-11-22 09:32:33 -05:00
infinite-persistence
87c3dcc057
SyncFatalError: show nag instead of hard-crashing. (#331)
* 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.
2021-11-22 09:30:43 -05:00
infinite-persistence
13cbbc8342
TUS: Detect and disallow concurrent uploads (#339) 2021-11-22 16:41:32 +08:00
infinite-persistence
2d3057d5cf
Detect concurrent uploads and stop it. 2021-11-22 16:12:11 +08:00
infinite-persistence
b6e9c7aabf
TUS: handle URL removal on 4xx errors
## Issue
The TUS client automatically removes the upload fingerprint whenever there is a 4xx error. When we try to resume later, we couldn't find the the fingerprint and ended up creating a new upload ID.

## Changes
Since we are also storing the uploadUrl ourselves, provided that to override the tus client's default behavior of restarting a new session on 4xx errors.
2021-11-22 16:12:10 +08:00
Thomas Zarebczan
352ee7bfaa
fix syntax 2021-11-19 11:30:28 -05:00
Thomas Zarebczan
95d7582f08
remove adsense 2021-11-19 10:57:55 -05:00
infinite-persistence
21cb405965
ClaimLink: skip blacklist check (#329)
## Issue
- It was checking the blacklist on every render.
- Finding opportunities to improve performance

## Changes
Since the final destination will be a dead end anyways, skip the blacklist check so that livestreams can render a bit faster when there lots of mentions.

The only downside is that a claim preview for a blacklisted item would now appear (vs. being a text previously)
2021-11-19 09:46:52 -05:00
infinite-persistence
328b60d021
Notifications: skip resolve during boot (#330)
## Issue
- Large resolve count (albeit batched) on bootup.

## Changes
- Skip the call on bootup. The same call will happen when you click the notification bell, so it's not too late to resolve at that time.
- Added `true` to `doResolveUris` to return cached results, otherwise it will keep resolving the same channels every time we enter Notifications Page.
2021-11-19 09:46:31 -05:00
infinite-persistence
6a33ed337b
Cost Info selector fixes (#328) 2021-11-19 16:31:45 +08:00
infinite-persistence
0941667150
Cost Info selector fixes
- no memo required since they are just directly accessing the store.
2021-11-19 16:01:25 +08:00
infinite-persistence
b351617d2f
Add flow 2021-11-19 16:00:06 +08:00
infinite-persistence
ff20663b8d
byId: update only if claim has new data
This was already being done for Content claims, and repeated for Channels, Collections, and other reducers.
2021-11-19 15:59:48 +08:00
infinite-persistence
7515d21510
claimsByUri: update only if changed 2021-11-19 15:59:47 +08:00
infinite-persistence
d48a7c7295
TUS: reduce chunk size from 100MB to 25MB.
The stalling behavior has changed a bit, probably with the removal of CF.

The stall difference between 10MB and 50MB is not too noticable, so picking 25MB as a start.
2021-11-19 14:40:03 +08:00
Dan Peterson
314b63705d
get active viewers even when not live (we want waiting count) (#322) 2021-11-18 18:41:43 -05:00
Dan Peterson
3269b84385
Remove claim search long poll + introduce pending state that blocks render + avoid polling status for non-owned claim (#320) 2021-11-18 14:43:39 -05:00
infinite-persistence
4a2305dca1
Notifications filter changes (#319)
## Issue
312 Save notification on back navigation, enable filter on mobile

## Changes
- Don't clear then filter when mounted and there are unread notifications.
   - We previously clear the filter because the user could be clicking the notification bell (which is showing some number) and we ended up with a blank page because of the filter.
- Allow the filter in mobile.
   - Previously, it was intentionally removed for mobile (see bd42418f). I believe it was just because we don't have the style set up for mobile. Here's my quick attempt.
2021-11-18 10:55:33 -05:00
infinite-persistence
e288833085
Fix blacklisted claims appearing in tiles
## Mistake
Tried to simplify the logic between checking Channel vs Content claim, and ended up always checking against Channel. This is correct for commentron blocklists, but not blacklists where the txid is per claim.

## Changes
- Restored original logic.
- While at it, restore the usage of `selectClaimForUri` (i.e. no need to split into 4 selectors anymore), since we've updated the reducer to prevent invalidation from things like 'confirmation' and 'is_my_output'.
2021-11-18 10:21:21 +08:00
jessopb
4cf9309ee1
facilitate admin temp files (#313) 2021-11-17 13:28:36 -05:00
infinite-persistence
e35069de1c
Cache the processing of ChannelMentionSuggestions (#309)
## Issue
One of the bottlenecks of livestream page.

The component probably needs a re-design:
- Don't perpetually mount -- only mount when activated by the user through "@". This would avoid the heavy processing entirely.
- Better way of resolving uris (too many arrays, too many loops).
- Tom also mentioned that we should not be resolving every commenter as we see encounter them in a livestream. This is currently the case because the component is always mounted.

## Changes
Until the re-design occurs, attempt to cache the heavy processing. Also, trimmed down the amount of loops.
2021-11-17 11:47:56 -05:00
infinite-persistence
47c316e0ad
Reduce livestream chat size to 50 2021-11-17 21:04:17 +08:00
infinite-persistence
75bde149cf
Fix url selectors
No memo required.
2021-11-17 19:57:04 +08:00
infinite-persistence
6382238834
Incremental livestream performance fixes (#307) 2021-11-17 18:16:52 +08:00
infinite-persistence
b69c1ec5fe
Reduce the chain of renders when Viewer Count is updated
3 layer of components were rendered because of the viewer-count update.  Only `fileViewCount` needs the value, so let it grab from redux directly.
2021-11-17 18:16:01 +08:00
infinite-persistence
01f771c6ca
Simplify makeSelectViewersForId 2021-11-17 18:16:00 +08:00
infinite-persistence
6b6879ba64
Cache subscription uris if we're gonna map it often. 2021-11-17 18:16:00 +08:00
infinite-persistence
91f1f588e6
Slice the comments before filtering to avoid going through everything.
For the case of livestreams, the comments are added incrementally via websocket. The selector returns everything, which grows as a user watches the livestream.

We could even make it a bit more efficient by passing in `maxCount` to `filterComments`, and do a `for` loop there, but decided to keep things readable by not changing the `filter` usage.
2021-11-17 18:15:59 +08:00
infinite-persistence
5204bb366e
Fix ChannelMention double-constructing the comment list.
As long as the input parameters are the same, the selector will return the cached value so that we don't construct the list twice, which involves blocklist filtering.
2021-11-17 18:15:58 +08:00
infinite-persistence
e6caa8c7ff
Don't use the obsolete selectCommentsByUri
- Same reason as d211450b.
- Also removed an unused selector.
2021-11-17 18:15:58 +08:00
Thomas Zarebczan
51546436ce
remove tag sync 2021-11-17 03:09:26 -05:00
infinite-persistence
ac93b379a9
Fix annoying hierarchy error with Yrbl
`<div>` cannot be a descendend of `<p>`, and `{subtitle}`s sometimes need to have `<div>`s.

Just switch from `<p>` to `<div>`, and let the client decide when the actual text paragraphs are.
2021-11-17 10:27:11 +08:00
Thomas Zarebczan
abbeb45d17
Update README.md 2021-11-16 10:01:52 -05:00
Thomas Zarebczan
4af72806dc
Update README.md 2021-11-16 10:01:42 -05:00
infinite-persistence
39baf1a3c9
ClaimPreviewTile state-map optimizations
## Issue
Lots of time is spent mapping the state to props for this component (since there are lots of tiles).

## Changes
Using this component as a starting point, go through the selectors and make the usual cleanup/fixes:
- Move away from the `makeSelect*` model, which creates a new selector on every call instead of actually re-using the cached version.
- Do proper caching for multi-param selectors using `re-reselect`.
- Don't cache simple functions or direct access to states.
2021-11-16 15:04:29 +08:00
infinite-persistence
201a826381
Simplify makeSelectIsUriResolving
- Memo not required. `resolvingUris` is very dynamic and is a short array anyways.
- Changeg from using `indexOf` to `includes`, which is more concise.
2021-11-16 14:32:58 +08:00
infinite-persistence
bf324a1b79
Simplify makeSelectTitleForUri
No need to memo given no transformation.
2021-11-16 12:23:18 +08:00
infinite-persistence
d03b3fd50d
Simplify selectShowMatureContent 2021-11-16 12:04:40 +08:00
infinite-persistence
8deac56e40
Fix memo: isLivestream & isLivestreamActive 2021-11-16 11:52:35 +08:00
infinite-persistence
dae0e3ccae
Use a lighter selector that doesn't re-create an array of claims.
Although selectClaimsByUri is memoized, it is often invalidated. Why create the array when all we need is the claim?
2021-11-16 10:47:59 +08:00
infinite-persistence
73f208923a
Optimize makeSelectClaimIsNsfw (and it's surrounding friends) 2021-11-16 10:14:01 +08:00
infinite-persistence
4aea0081ea
Remove duplicate claim utilities
These are already brought in from redux prior to the consolidation.
2021-11-16 08:59:07 +08:00
infinite-persistence
27dffaaf2f
Remove unused prop 2021-11-16 08:20:25 +08:00
infinite-persistence
652ec4b69b
Fix memo: makeSelectViewCountForUri, makeSelectSubCountForUri
- switch to a lighter selectClaimIdForUri
- also, these 2 don't need to memo because they are just simple accessors.
2021-11-16 08:15:24 +08:00
infinite-persistence
c8ad9718bb
Floating player position-listener fixes (#289)
## Issues
- 251 Dragging the floating player is super laggy

Recent changes and/or refactoring combined the effects or added dependancies into the effects, causing them to re-run excessively.

## Changes
- Restored effects to their original behavior.
- Don't perform the position check when dragging -- only do it when released.
- Do proper debouncing for the 'resize' listener -- the previous method was incorrect as a new function is created on each render.
2021-11-15 16:13:48 -05:00
Dan Peterson
cb104017ad
adjust livestream interval (#294) 2021-11-15 12:34:21 -06:00
Dan Peterson
0c28f3c6f1
reverse livestream status check (#293) 2021-11-15 11:52:00 -05:00
Dan Peterson
e02bc6cc03
Hotfix livestream status (#292)
* Fix livestream status on upcoming livestream

* update fix
2021-11-15 10:58:29 -05:00
infinite-persistence
70d18eba59 Remove "same array" check now that USER_STATE_POPULATE only runs when there is new data. 2021-11-15 07:06:39 -08:00
infinite-persistence
38c13cf5ef Skip USER_STATE_POPULATE when sync_hash is the same
## Changes
- doHandleSyncComplete: only call doGetAndPopulatePreferences when there is new data.
- But for that to work, we'll need to populate preferences at least once. We'll do that in doSignIn.
- We can also remove the "sync/prefs ready" mechanism that was mainly meant for Desktop.

Then came another problem: while trying to spark changes between 2 tabs, `sync/get` was saying "no change" despite the local and server hash being different. I think it is because the both `sync_hash + sync/get` combo is operating on server data, so the hash is the same. I'm guessing this is why we ended up just running doGetAndPopulatePreferences every time before PR, since this flag wasn't correct in this scenario.

- Updated `data.changed` to consider both API results and comparison with local hash.
2021-11-15 07:06:39 -08:00
infinite-persistence
342fcb4024 doSignIn: cleanup, no functional change
Seems unlikely that we'll need to disable notifications, so cleaned up the code a bit.
2021-11-15 07:06:39 -08:00
mayeaux
6546eaeb63
refactor ad code and dont show ads on embeds (#290) 2021-11-15 10:01:42 -05:00
infinite-persistence
f084288ac9
Fix unable to clear muted list
## Issue
When the muted list was being cleared from another app, the web version ended up restoring the previous muted list.

## Change
- As long as `blocked` is defined, return that since an empty array is a valid result.
- If undefined, something went wrong when calling the reducer, so retain the muted list. I believe this was the original intention of that line.
2021-11-15 13:36:08 +08:00
infinite-persistence
93c28b24bb Remove desktop video start time analytics 2021-11-15 09:25:58 +08:00
Dan Peterson
c242c37869
Add initialization status to push notification hook. Can be used to better control render strategy in cmpnts utilizing it. (#284) 2021-11-12 12:06:07 -05:00
infinite-persistence
6d217dbc50
Attempt to speed up sidebar menu for mobile (#283)
* Exclude default homepage data at compile time

The youtuber IDs alone is pretty huge, and is unused in the `CUSTOM_HOMEPAGE=true` configuration.

* Remove Desktop items and other cleanup

- Moved constants out of the component.
- Remove SIMPLE_SITE check.
- Remove Desktop-only items

* Sidebar: limit subscription and tag section

## Issue
Too slow for huge lists

## Change
Limit to 10 initially, and load everything on "Show more"

* Fix makeSelectThumbnailForUri

- Fix memo
- Expose function to extract directly from claim if client already have it.
2021-11-12 10:59:11 -05:00
mayeaux
529a9cbc40
Videojs component refactor (#240)
* pull out ads into its own file

* final touchup

* pull out lbry volume class

* using curried function

* coming along well

* almost done keyboard shortcuts

* pulling the guts out

* finishing keyboard shortcuts

* coming along well

* running but needs some testing

* almost done but could still use some testing

* all code working with some flow fixes needed

* fixing flow errors

* finishing flow errors
2021-11-12 09:56:46 -05:00
infinite-persistence
6f8758c819
Fix and optimize makeSelectIsSubscribed (#273)
## Issues with `makeSelectIsSubscribed`
- It will not return true if the uri provided is canonical, because the compared subscription uri is in permanent form. This was causing certain elements like the Heart to not appear in claim tiles.
- It is super slow for large subscriptions not just because of the array size + being a hot selector, but also because it is looking up the claim twice (not memo'd) and also calling `parseURI` to determine if it's a channel, which is unnecessary if you already have the claim.

## Changes
- Optimize the selector to only look up the claim once, and make operations using already-obtained info.
2021-11-12 09:47:07 -05:00
infinite-persistence
53406a60cf
Bump to rebuild with new v2 PUBLISH endpoint 2021-11-12 20:21:20 +08:00
infinite-persistence
b0509bc990
Band-aid: wait a while before sending notify
## Issue
The status = 0 is due to unresponsive backend right after the tus-upload. No root-cause found yet.

## Change
It may or may not help, but adding a delay to account for the unresponsive stage for now.
2021-11-12 18:43:57 +08:00
infinite-persistence
d8080a9fda
Notify: log retry attempts 2021-11-12 16:30:41 +08:00
infinite-persistence
62e7fe06a5
TUS: Don't retry on 4xx
## Issue/Steps
From Randy:
- started the upload then open a new tab of the same page
- one of the tab finished the upload and successfully published the file, and the other tab received 404 error on patch and head request, because the file is already removed on the server

## Changes
Use the default onRetry code that ignores all 4xx, except for LOCKED and CONFLICT. Had to duplicate some code from tus because I still need to inject the 'retry' progress for the GUI to update the string.
2021-11-12 14:32:41 +08:00
infinite-persistence
dfe30b6d78
TUS: fix parallel uploads of the same file
## Issue
If you make 2 claims from the same source file, the second upload thinks it's trying to resume from the first one. They should be unique uploads.

## Approach
Stash the upload url for comparison when looking up existing uploads to resume.

Stash that in `params` to minimize code changes. We'll just need to ensure it is cleared before we generate the SDK payload.
2021-11-12 14:32:40 +08:00
infinite-persistence
861aaf4cde Notify: Re-enable delay but only for initial connection problem
We want to avoid the double `notify`, and also to confirm whether the SDK is timing out.
2021-11-12 11:19:26 +08:00
infinite-persistence
9bfa1a3577
Notify: Disable retry + try to report status code 2021-11-12 09:01:36 +08:00
mayeaux
d047a748b7
Test ads (#277)
display ad in related sidebar for video view page

Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2021-11-11 17:15:50 -05:00
infinite-persistence
ef0329e03b Lazy-load comment components
## Issue
~300KB savings in `ui.js` size (production, uncompressed). Mostly coming from the emoji library.

## Notes
Most of the `Comment*` components are under `CommentsList` or `LivestreamComments`, so deferring these 2 covered most of it. The exceptions are Notification and OwnComments.
2021-11-11 15:09:28 -05:00
infinite-persistence
0f68bad3eb
Optimize selectClaimIsMine
## Why
Frequently used; top in perf profile

## Changes
Most of the time, you already have the claim object in the current context. `selectClaimIsMineForUri` will retrieve the claim again, which is wasteful, even if it is memoized (looking up the cache still takes time).

Break apart the logic and added the alternative `selectClaimIsMine` for faster lookup.
2021-11-11 16:10:06 +08:00
infinite-persistence
827a08ac26
Fix memo: stake indicator 2021-11-11 10:23:28 +08:00
infinite-persistence
6492fe1c66
Upload: remove "download app" suggestion for large files. 2021-11-11 10:16:31 +08:00
infinite-persistence
7ef5975ee8
Notify: auto-retry once after 10 seconds
Also:
- Show the resume button on notify errors.
- Changed the error message to differentiate against v1's.
2021-11-11 09:55:48 +08:00
infinite-persistence
b5f1ae1291
Tus-retry: widen delay gap + add 1 more retry 2021-11-11 09:54:25 +08:00
infinite-persistence
a90b6415de
Support resume-able upload via tus (#186) - w/ commits 2021-11-11 08:01:16 +08:00
infinite-persistence
77087d2916
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.
2021-11-11 08:00:12 +08:00
infinite-persistence
38f511c2fb
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.
2021-11-11 08:00:12 +08:00
infinite-persistence
9d25d82bed
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.
2021-11-11 08:00:12 +08:00
infinite-persistence
bef7ff4a2d
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.
2021-11-11 08:00:12 +08:00
infinite-persistence
fa48b4a99b
Add doPublishResume 2021-11-11 08:00:11 +08:00
infinite-persistence
5b630d6a20
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.
2021-11-11 08:00:11 +08:00
infinite-persistence
236e2cfe8e
Publish button: use spinner instead of "Publishing..."
Looks better, plus the preview could take a while sometimes.
2021-11-11 08:00:11 +08:00
infinite-persistence
263c09500f
-- Revert to allow restoring commits ---
This reverts commit cb6a044584.
2021-11-11 08:00:05 +08:00
Thomas Zarebczan
d649e3563f
Adjust channel mention regex (#269) 2021-11-10 14:53:42 -05:00
Thomas Zarebczan
5c23c6d88e
Default to trending for homepages (#267) 2021-11-10 14:36:54 -05:00
Dan Peterson
5639e4c1ff
Adjust some initial states to optimize initial render (#265) 2021-11-10 14:15:40 -05:00
Thomas Zarebczan
8fd6382bf4
Update README.md 2021-11-10 13:33:44 -05:00
infinite-persistence
cb6a044584
Support resume-able upload via tus (#186)
* 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.
2021-11-10 13:16:16 -05:00
infinite-persistence
b508fe8679 Enable BundleAnalyzerPlugin + remove 'yarn analyze'
Use the env to opt in.
2021-11-11 00:07:18 +08:00
infinite-persistence
d211450b5b
Fix selectCommentIdsForUri
- memo not required.
- start to not use the confusing and wrongly-named 'selectCommentsByUri' (per comment from Sean);  use the existing 'selectClaimIdForUri' instead.  This works because currently we do fetch any comments without first visiting a claim/uri, so we'll always have fetched the required claim, and can be queried in 'selectClaimIdForUri'.
2021-11-10 17:35:30 +08:00
infinite-persistence
81d77da17e
Fix states not updated in an immutable way.
It's technically incorrect and was causing the GUI to not update sometimes because the reference did not change, despite the array contents did. The GUI just happens to update most of the time due to other state changes.
2021-11-10 17:35:29 +08:00
infinite-persistence
7cefb0fadc
Simplify 'selectClaimIdForUri'
Memoization is not needed. But note that it is now a 2 parameter selector.
2021-11-10 16:50:26 +08:00
infinite-persistence
ece2312ec5 selectClaimIsMineForUri to replace makeSelectClaimIsMine
## Issue
`normalizeUri` | `parseURI` is expensive and has been causing sluggish operations when called repeatedly or within a loop.

## Change
Since I'm not confident enough to remove the call entirely from makeSelectClaimIsMine (although I've yet to find a scenario that the uri is not already normalized), we'll try caching the calls instead.

## Results
- in a simple test of toggling between 2 category pages, we saved 20ms from `parseURI` calls alone.

- in a test of opening all categories one time, the memory usage remained similar. This makes sense since we removed a `makeSelect*` (which creates a selector for each call + not memoizing), and replaced that with a cached selector that's actually memoizing.
2021-11-10 16:49:12 +08:00
infinite-persistence
97b9b733c6
Fix memo: selectMyActiveClaims, selectAbandoningIds
## Issue
- selectMyActiveClaims memo problem -- being recalculated on every click -- high workload for wallet with large uploads.
- Mistake in handling abandoning IDs (it was trying to extract keys from an array)

## Changes
- selectAbandoningIds: never use `state` as an input selector. Breaks memo.
- Don't use selectMyClaimsRaw and then reduce it back to IDs. Use selectMyClaimIdsRaw instead.
- selectAbandoningIds is already in array form, so don't run Object.keys.
- Fix abandoningById never clearing when succeeded.
2021-11-10 09:58:26 +08:00
infinite-persistence
c681d95ad7
Fix livestream state issues. Create unified long polling mechanism. #246 2021-11-10 08:43:26 +08:00
Dan Peterson
baa15d0c42
add long polling to reset component 2021-11-10 08:21:16 +08:00
Dan Peterson
1d8753e2ba
Revert claim preview + fix small css issue + export named function 2021-11-10 08:21:16 +08:00
Dan Peterson
60f06dac52
Fix livestream state issues. Create unified long polling mechanism. 2021-11-10 08:21:15 +08:00
saltrafael
a7c7881795
Fix string (#257) 2021-11-09 15:25:19 -05:00
infinite-persistence
ef1ebfc491
Allow admins to delete comments as well. (#250)
This is a follow-up to #235
2021-11-09 09:47:49 -05:00
infinite-persistence
bc67379c26
Block: pass comment ID for deletion when being blocked. (#255)
* Simplify dispatch map

Since none of dispatches are doing any custom transformation, just use a direct map. The number of arguments for the comment function are getting crazy.

* Block: pass comment ID for deletion when being blocked.
2021-11-09 09:43:02 -05:00
infinite-persistence
0e2bb350c0
Remove mouse-back/forward listeners
- Not needed for web since the browser does it, and should have been gated under 'app'
- This reverts lbry-desktop 3744.
2021-11-09 16:53:11 +08:00
infinite-persistence
f0591b8956
Incremental removal of Desktop code #252 2021-11-09 16:17:00 +08:00
infinite-persistence
9fc417edfa
Remove 'web' preprocessor 2021-11-09 16:08:13 +08:00
infinite-persistence
45ad08ec32
Remove use-history-nav.js
For electron.js only
2021-11-09 16:03:37 +08:00
infinite-persistence
d7fc5069be
Remove .env.ody again
Accidentally brought back in when porting over the Redux consolidation PR.
2021-11-09 15:57:13 +08:00
infinite-persistence
b9a5dc3c70
Remove use-zoom
It's only needed for electron
2021-11-09 15:57:12 +08:00
infinite-persistence
1426dd5b83
Remove skin support and lbry.tv scss
## Issue
211 - CSS load-order problem

## Notes
It is unlikely that we'll need to support different brands in the future, so simplifying the code and number of files so that we don't have to handle the various import paths. Will probably make things easier for the css-splitting work too.
2021-11-09 10:36:08 +08:00
Thomas Zarebczan
d80cea1caa
new Stickers! (#248) 2021-11-08 18:07:55 -05:00
infinite-persistence
7a6a8c2fd7
Comment: Fix missing author highlight in Community Tag (#249)
## Issue
238 Comments: author-name not highlighted when in Channel Community tab

## Changes
- Channel claims don't have a signing channel. Use `getChannelFromClaim`, which handles both content and channel claim.
2021-11-08 18:05:54 -05:00
infinite-persistence
ebf81a61c3
byId[] fixes to reduce invalidation (#239) - w/ commits
Retaining individual commits to ease tracking and partial reverts in the future.
2021-11-09 07:04:38 +08:00
infinite-persistence
07750bfb4c
Fix memo: selectMyChannelClaims, selectActiveChannelClaim
## Issue
These should never recalculate after `channel_list` has been fetched, but they do because of poor selector dependency.

## Change
With the `byId` changes from the previous commit, we are now able to memoize these selectors correctly.
2021-11-09 07:03:20 +08:00
infinite-persistence
0736723200
Don't update 'byId' if no changes + add 'selectClaimWithId'
## Ticket
116 Claim store optimization ideas (reducing unnecessary renders)

## Changes
- Ignore things like `confirmations` so that already-fetched claims aren't invalidated and causes re-rendering. The `stringify` might look expensive, but the amount of avoided re-renders outweighs it. There might be faster ways to compare, though.

- With `byId[claimId]` references more stable now, memoized selectors can now use 'selectClaimWithId' to pick a specific claim to depend on, instead of 'byId' which changes on every update.
2021-11-09 07:03:20 +08:00
infinite-persistence
de2bec4425
Don't update 'pendingById' if no changes.
'pendingById' isn't frequently updated, but using it as a proof-of-concept to fix how reducers should be written to avoid unnecessary updates.

ImmutableJS apparently does all of this for us, but there are cons to using it as well, so using own wrappers for now.
2021-11-09 07:03:19 +08:00
infinite-persistence
121b0f0cd6
~~ Revert to allow restoring to commits ~~
This reverts commit c97cab0ebb.
2021-11-09 07:03:19 +08:00
infinite-persistence
c97cab0ebb
byId[] fixes to reduce invalidation (#239)
* Don't update 'pendingById' if no changes.

'pendingById' isn't frequently updated, but using it as a proof-of-concept to fix how reducers should be written to avoid unnecessary updates.

ImmutableJS apparently does all of this for us, but there are cons to using it as well, so using own wrappers for now.

* Don't update 'byId' if no changes + add 'selectClaimWithId'

## Ticket
116 Claim store optimization ideas (reducing unnecessary renders)

## Changes
- Ignore things like `confirmations` so that already-fetched claims aren't invalidated and causes re-rendering. The `stringify` might look expensive, but the amount of avoided re-renders outweighs it. There might be faster ways to compare, though.

- With `byId[claimId]` references more stable now, memoized selectors can now use 'selectClaimWithId' to pick a specific claim to depend on, instead of 'byId' which changes on every update.

* Fix memo: selectMyChannelClaims, selectActiveChannelClaim

## Issue
These should never recalculate after `channel_list` has been fetched, but they do because of poor selector dependency.

## Change
With the `byId` changes from the previous commit, we are now able to memoize these selectors correctly.
2021-11-08 12:25:29 -05:00
infinite-persistence
cfd67b1c8d
Allow moderators to delete comment (#235)
## Ticket
223 Add ability for delegated moderators to delete comments

## Changes
- Refactored doCommentAbandon's signature so we don't end up converting between "uri" and "Claim" several times and needing to lookup redux when the client can already provide us the exact values that we need.

- Pass the new moderator fields to the API.

- Remove the need to call 'makeSelectChannelPermUrlForClaimUri' since it's a simple field query when we already have the claim.
2021-11-08 12:22:40 -05:00
saltrafael
9138e508c6
[Markdown] Fixes Quote and Fixes Images not showing (#242)
* Refactor and fix blockquote filling the full message content

* Fix images not showing on markdown
2021-11-08 09:08:22 -05:00
maxime peabody
d7ada7904b
Fixes the play/pause on drag issue with the floating player. (#221)
I tried to use event.preventDefault on the click handler but that didn't 
work. So instead I'm using css 'pointer-events: none' to disable click 
events on the player while the player is being dragged.

https://github.com/OdyseeTeam/odysee-frontend/issues/206
2021-11-08 12:51:03 +01:00
infinite-persistence
0f1d4039a9
Use 'selectHasChannel' instead of the full 'selectMyChannelClaims'
- selectMyChannelClaims depends on `byId`, which currently is always invalidated per update, so it is not memoized.

- Most of the use-cases just needs the ID or the length of the array anyways, so avoid generating a Claim array (in selectMyChannelClaims) unnecessarily -- the client need to reduce it back down to IDs again :/

- The simpler boolean also removes the need to memoize the selector, which saves a bit of memory.
2021-11-08 15:02:44 +08:00
infinite-persistence
9c5fbe5521
Remove lbry-desktop strings that were accidentally brought in. 2021-11-06 21:39:35 +08:00
Thomas Zarebczan
cd0ec4dbcd
Add script for google ads 2021-11-05 21:01:22 -04:00
jessopb
238a64bca9
improve playlists display (#232)
* improve playlists display

* fix pagination

* reset page on filter button

* pagination updates if page param changes

* carry collection active tab to playlists page
2021-11-05 21:00:27 -04:00
saltrafael
fc2e2d2cfc
Stickers/emojis fall out / improvements (#220)
* Fix error logs

* Improve LBC sticker flow/clarity

* Show inline error if custom sticker amount below min

* Sort emojis alphabetically

* Improve loading of Images

* Improve quality and display of emojis and fix CSS

* Display both USD and LBC prices

* Default to LBC tip if creator can't receive USD

* Don't clear text-field after sticker is sent

* Refactor notification component

* Handle notifications

* Don't show profile pic on sticker livestream comments

* Change Sticker icon

* Fix wording and number rounding

* Fix blurring emojis

* Disable non functional emote buttons
2021-11-05 15:31:51 -04:00
mayeaux
7cae754867
smarter tab selection functionality (#231) 2021-11-05 15:27:43 -04:00
mayeaux
6cb011ff96
bugfix persisted state issue (#228)
* bugfix persisted state issue

* bugfix and also set defaults properly
2021-11-05 11:45:19 -04:00
infinite-persistence
21e1af8ce5
Handle huge superchat list #224 2021-11-04 17:03:35 +08:00
infinite-persistence
17903f6c15
Limit to 10 superchats initially; batch-resolve when opening full list. 2021-11-04 16:30:51 +08:00
infinite-persistence
a65e68d023
Comments: use the lighter selectMyClaimIdsRaw
`selectMyActiveClaims` includes pending claims, so it gets invalidated often.

For the case of comment-filtering, we don't care about pending or abandoned own claims.
2021-11-04 16:30:50 +08:00
infinite-persistence
61a2ed2583
Simplify superchat selectors - memo not required
... since there are no transformations.
2021-11-04 16:06:06 +08:00
infinite-persistence
4876ad8671
Don't invalidate myClaimIds everytime 2021-11-04 16:06:05 +08:00
infinite-persistence
59db2860d7
Comments: use the lighter selectMyClaimIdsRaw
`selectMyActiveClaims` includes `byId`, which gets invalidated on each resolve. Having this as an input selector breaks memoization.

For the case of comment-filtering, we don't really care about pending or abandoned own claims (I think), so just grab the raw IDs.
2021-11-04 16:06:04 +08:00
infinite-persistence
531a87e969
channelThumbnail: don't resolve if already in process 2021-11-04 16:04:29 +08:00
infinite-persistence
60a0d6d31a
Use replace instead of replaceAll for browser compatibility (#222)
Also, moved the `replaced` outside of the find-loop so that we don't re-run it each time.
2021-11-04 00:56:29 -04:00
Dan Peterson
11d3f88654
WIP: live stream kill switch (#209)
* WIP: live stream kill switch

* Update hint layout / style

* update livestream API endpoint

* use the no-cors option
2021-11-03 17:52:18 -04:00
Thomas Zarebczan
db12a4b991
Odysee specific changes and other misc improvements (#219) 2021-11-03 15:47:19 -04:00
Rodion Borisov
6d8e265f50
Transform route-leading menu items to hyperlinks (#191) 2021-11-03 15:50:03 +01:00
Florence Jay Munar
842431feaf
Update README.md (#215) 2021-11-03 09:40:16 -04:00
infinite-persistence
7b621b7417
Add option to hide buildUri warnings
No point for it to keep appearing if nobody cares?

Anyway, added option to hide it via environment variable for those who are annoyed by it.
2021-11-03 13:01:13 +08:00
infinite-persistence
3d1d448afb
Fix crash with ModalError
## Issue
There was one instance of ModalError that wasn't wrapped in the Suspense.

## Fix
- Moved `getModal` outside to make the code cleaner. Due to the length of `getModal`, I didn't notice the early return statement.
- Fix ModalError's Suspense.
2021-11-03 10:09:01 +08:00
infinite-persistence
bf0aac2339
URI parsing improvements (#207)
* Prevent multiple parseURI calls

## Ticket
129

## Issue
Code was shortened to use `isURIValid` during the consolidation. `isURIValid` calls `normalizeURI`, which calls another `parseURI`.

`parseURI` is pretty expensive.

## Approach
- Add optional parameter to `isURIValid` to skip the normalization.
- Set those that were converted during the consolidation to skip the normalization. Also covered a few other instances where it is obvious to me that normalization is not required.
- For the rest, I can't tell for sure if it's safe to remove the normalization, so the default `normalize=true` will leave things as is.

The whole `parseURI` probably needs a refactoring, or a few lighter version for specific needs.

* Simplify isURIEqual

## Issue
`parseURI` is too expensive to be used in a loop, plus `normalizeURI` itself is calling `parseURI`.

## Approach
Not sure if it covers all cases, but just try convert colons to hashes before comparing.
2021-11-02 12:37:53 -04:00
Dan Peterson
704452732a
Add hints if an error occurs subscribing to notifications (#143)
* Add hints if an error occurs subscribing to notifications

* Update import (type/linting issue)

* disable optimization for debugging

* Revert "disable optimization for debugging"

This reverts commit 5b837f94e97b7488a7dc565e7f74d399e19c286f.

* improve detection of notification support + improve ux / ui surrounding that

* update translations
2021-11-01 14:51:23 -04:00
jessopb
fa029e0c09
channel parsing bugfix (#199) 2021-11-01 09:58:28 -04:00
Florence Jay Munar
994a39b0df
Readme fixes (#192)
* Update README.md

* Update README.md

* Update --say-thank-you.md
2021-11-01 09:54:35 -04:00
infinite-persistence
56b800cd33
Fix 'secondary.js' code coverage
## Issue
95% of `secondary.js` is unused code.
  - It was meant to reduce network overhead by chunking up files needed after bootup, and also to reduce the number of `vendor-*.js` files.
  - But it ended up accidentally grabbing everything, defeating the purpose of code-splitting.
2021-11-01 15:25:40 +08:00
infinite-persistence
b8399f10b2
Fix lint/auto-formatting... 2021-11-01 15:23:08 +08:00
jessopb
0aa6cc7e5a
limit collections to show to 24 (#147)
* limit collections to show to 24

A user had many collections. 
Since we have a search field, we can limit to 24.

* const
2021-10-29 10:53:56 -04:00
jessopb
f956f9d2fe
Fix cover upload ux (#184)
* do not block submit on thumb or cover error

* improve cover upload UX

* p padding
2021-10-29 10:53:46 -04:00
infinite-persistence
08c6df434e
Add "Go Live" to mobile (#183)
* Add "Go Live" button to mobile menu

* Move "Go Live" all the way to the top
2021-10-29 09:04:43 -04:00
infinite-persistence
11bbd58e33
General-purpose "Confirm" modal
Added a re-usable "yes/no" confirmation modal where the client just sets the question string and gets a callback "OK" or "Cancel" is clicked.

It doesn't make sense to create one modal for each confirmation, especially when the modal is only used in one place.

Replaced one of the existing modal as an example.
2021-10-29 13:36:27 +08:00
saltrafael
4bfb4fb55d
Fix a wrong emote (#182) 2021-10-28 18:18:23 -04:00
saltrafael
5f1f702490
[New Feature] Stickers (#131)
* Refactor filePrice

* Refactor Wallet Tip Components

* Add backend sticker support for comments

* Add stickers

* Refactor commentCreate

* Add Sticker Selector and sticker comment creation

* Add stickers display to comments and hyperchats

* Fix wrong checks for total Super Chats
2021-10-28 16:25:34 -04:00
Thomas Zarebczan
a77e59cb53
Adjust video state clearing settings
What's strange is that this only occurs when you refresh odysee in between the plays. Might be a bug there.
2021-10-28 11:48:39 -04:00
infinite-persistence
4b0a06cef7
Ensure filter is not expanded when disabled (#153)
## Issue
- Go to a channel page
- Go to Wild West
- Back
- Expand the search filter (valid here)
- Forward

## Fix
Resolve the 'expanded' setting on mount to ensure it is never true when 'hideAdvancedFilter' is set.
2021-10-28 10:51:13 -04:00
mayeaux
00d28fe26e
fix bug where scrolling on video player page changes volume (#154) 2021-10-28 10:46:24 -04:00
infinite-persistence
5dd5826b33
doFetchSubCount: batch support; fetch interval gap;
1. The API supports batching -- updated the code to use that. Retained string as the parameter (instead of changing it to array) so that existing clients won't be affected.

2. Make `doFetchSubCount` a batched command by default through an idle timer. This way, none of the clients need to collect IDs -- it's all done behind the scenes.

3. Added minimum of 5 minutes between each sub-count fetch for a claim ID.
2021-10-28 13:16:06 +08:00
infinite-persistence
cbedc4b933
ClaimPreviewSubtitle: fetch sub count only for channels 2021-10-28 13:11:25 +08:00
infinite-persistence
6b39fc1bbb
Make it easier for the next person to add View Count in specific pages. 2021-10-28 13:11:24 +08:00
infinite-persistence
f8f9b86cb4
FileViewCountInline: fix incorrect logic
4a22814c broke the intention of if-block (it essentially breaks the functionality in Search page if we enable view counts there in the future).

It also seems completely unrelated to the PR.
2021-10-28 13:11:23 +08:00
jessopb
1a5fb5fa51
improve channel mentions (#146)
something like @; was crashing the app.
this should be better.
2021-10-27 21:21:40 -04:00
saltrafael
c24153c6ca
[New Feature] Comment Emotes (#125)
* Refactor form-field

* Create new Emote Menu

* Add Emotes

* Add Emote Selector and Emote Comment creation ability

* Fix and Split CSS
2021-10-27 14:20:47 -04:00
Dan Peterson
762bddb158
Don't instantiate messaging SDK if service worker is unavailable (Firefox/Private) (#142) 2021-10-27 13:34:50 -04:00
infinite-persistence
2922f0f2dc Revert "Code-split homepages"
This reverts commit 310fc81bd9.

Was breaking the `get` api
2021-10-28 01:33:46 +08:00
mayeaux
3849683a59
Lots of player UI improvements (#134)
* various control bar fixes

* fixes for mobile

* hide advertisement div by default

* fix duration bar

* more frontend touchups

* more styles

* fix for advertisement bar showing

* dont use ima on each re-render
2021-10-27 11:08:12 -04:00
infinite-persistence
247ee757d1
ChunkLoadError: ask user to reload instead of automatically reloading (#139)
## Issue
We previously automatically reload when there is a chunk error. This works fine if it's the case of new code was pushed recently while the user was active. But if the failure was caused by other things like network problems or the file IS actually missing, we end up in an infinite loop of refreshes.

## New approach
Tell the user to reload instead of automatically doing it.
2021-10-27 11:07:06 -04:00
Dan Peterson
03f69eff86
Browser push notifications (#133)
* 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.
2021-10-27 10:38:10 -04:00
Thomas Zarebczan
08adb805e9
Fix syntax 2021-10-27 09:55:57 -04:00
infinite-persistence
3788ef58ec
Analyze all .js files to get the full picture. 2021-10-27 09:19:52 +08:00
infinite-persistence
310fc81bd9
Code-split homepages
## Ticket
97

## Issue
8% of the ui.js chunk consists of the 5 custom homepages
2021-10-27 07:55:24 +08:00
infinite-persistence
9569b6c7a5
Upgrade videojs to 7.15.4 that ads is using. (#130)
## Issue
93 videojs double bundle
2021-10-26 17:48:22 -04:00
Thomas Zarebczan
0febd32c71
Revert "player background color (#86)" (#132)
This reverts commit e14ec9b83e.
2021-10-26 14:47:02 -04:00
infinite-persistence
a90c516c71
Reduce impact of scanning blocklists (#121)
## Issue
- Each tile was checking against 4 blocklists (blacklisted, filtered, muted, commentron) on every render. Loading the front-page with Cheese alone caused 1400 calls.
- This is also part of the reason why pressing Back into the tile list takes forever.

## Fix
Since we still need to perform the checks at the app side for now, tried to memoize the operation through a selector.
2021-10-25 10:56:31 -04:00
infinite-persistence
dad7264636
Handle re-reselect warning on null/undefined key
Should be a harmless warning, but cleaning up nonetheless.
2021-10-25 13:26:10 +08:00
infinite-persistence
27f346d8f1
Don't memoize selectors without transformation
It was not meant to be used for these cases -- wasting resources creating and going through the cache for each simple direct access.
2021-10-24 13:05:06 +08:00
infinite-persistence
e2176d0566
Don't connect to the Redux store when not needed.
The subscription still costs something per update cycle even when the parameters are null or empty objects.
2021-10-24 13:04:01 +08:00
GG2015
17121b2066
Wallet swap disabled (#107)
* Disabled wallet swap tab.

* Cleaned up UI since Swap is disabled.
2021-10-22 10:48:34 -04:00
infinite-persistence
1b43c54725
Defer blocklists slightly to not block me
Now, with the exception of connecting to lbry.com after re-opening the browser (i.e. establishing first connection), refreshing odysee.com is almost instantaneous.
2021-10-22 17:31:39 +08:00
infinite-persistence
398388de10
Track duration of startup events
Tracking only `user/me` for now.
2021-10-22 16:02:21 +08:00
infinite-persistence
b8c763f749
ClaimList: fix render due to un-memo'd callback. 2021-10-22 12:20:29 +08:00
infinite-persistence
b4f62e78de
Additional GA events via redux/lbryio hook (#110) 2021-10-22 11:07:48 +08:00
infinite-persistence
8c4224f1ce
createAnalyticsMiddleware: Handle 'BATCH_ACTIONS' 2021-10-22 10:56:44 +08:00
infinite-persistence
b7685a151d
Additional GA events via redux/lbryio hook
## Issue
85 Add additional GA events

## Approach
Instead of placing analytic calls all over the GUI code (no separation of concerns), try to do it through a redux middleware instead.

## Changes
- Updated GA event and parameter naming after understanding how reporting works.
- Removed unused analytics.
2021-10-22 10:56:43 +08:00
GG2015
e14ec9b83e
player background color (#86)
Changes player background color

Co-authored-by: Thomas Zarebczan <thomas.zarebczan@gmail.com>
2021-10-21 16:43:08 -04:00
Thomas Zarebczan
23525b0baa
FAQ stuff (#109) 2021-10-21 16:21:51 -04:00
Dan Peterson
d62f63aff8
delete duplicate flow type files (#105)
* delete duplicate flow type files

* merge types from deleted files

* revert dispatch to type any. (linting issues)
2021-10-20 13:33:31 -05:00
jessopb
dcd00c2308
Fix top search for channels (#104) 2021-10-20 12:55:21 -04:00
mayeaux
c782f73f30
switch macro (#102)
* switch macro

* allow skip and other options
2021-10-20 11:14:33 -04:00
infinite-persistence
6ff9a51058
Upgrade codemirror + module sharing
## Issue
Our `<CodeViewer>` and `react-simplemde-editor` uses `codemirror`, and they were each bundling a different version.

## Change
Re-generate yarn.lock for `codemirror`. Since we are upgrading anyway, upgraded to the latest and greatest.

## Test
- [x] Markdown editor -- looks ok. It inherited several fixes for code-blocks.
- [x] Code viewer -- looks ok.
2021-10-20 15:03:11 +08:00
infinite-persistence
9041e5e38d
Incremental selector memoization fixes (#92) 2021-10-20 12:24:07 +08:00
infinite-persistence
ce1621f7ed
Use selectClaimForUri in livestreams
Only picking components that are involved in a livestream for now. Ideally, all usages of `makeSelectClaimForUri` should be replaced -- will do it incrementally.
2021-10-20 11:29:18 +08:00
infinite-persistence
da63991972
Comment-selectors: fix memoization 2021-10-20 11:29:18 +08:00
infinite-persistence
b6ad4ae974
Comment-store: Don't memoize selectors without transformation 2021-10-20 11:29:17 +08:00
infinite-persistence
5d8fc40051
Cache restoreScrollPos to avoid render
`CommentCreate` was getting marked for every comment that comes in because the parent was marked.
2021-10-20 11:29:17 +08:00
infinite-persistence
4b0318cd38
Optimize tags and followedTags
followedTags:
- Moved the filtering to the reducer side, so that we don't do it every time. We can't rely on `createSelector` because the store will be invalidated on each `USER_STATE_POPULATE`, unfortunately.

tags:
- Memoize via re-reselect for the "ForUri" selector.
2021-10-20 11:29:16 +08:00
infinite-persistence
0c2c21b67e
re-reselect proof of concept + fix Date selector as first example
## Issue
`makeSelectDataForUri` always returns a new reference, so `ClaimPreview` was constantly being rendered. It's pretty expensive since `ClaimPreview`'s rendering checks against a huge blocklist, which is another issue on it's own.

## Changes
- This commit tests the usage of `re-reselect` as the solution to the multi-instance memoization problem (https://github.com/toomuchdesign/re-reselect/blob/master/examples/1-join-selectors.md)
2021-10-20 11:29:15 +08:00
infinite-persistence
9bbd72d179
Fix reaction-selector reference invalidation
## Issue
When comments are refreshed, each `Comment` gets rendered 4-5 times due to reference invalidation for `othersReacts` (the data didn't actually change).

## Change
For selectors without transformation, there is no need to memoize using `createSelector` -- just access it directly. Also, don't do things like `return a[id] || {}` in a reducer, because the reference to the empty object will be different on each call.

Always return directly from the state so that the same reference is returned.

This simple change avoided the wasted resources needed for `createSelector`, and reduced to render to just 2 (initial render, and when reactions are fetched).
2021-10-19 21:15:26 +08:00
infinite-persistence
249b73f8c6
Skip muted list update if no change
## Issue
Components render unnecessarily due to reference invalidation from `selectMutedChannels` selector.

## Notes
`selectMutedChannels` run and return a new reference each time the app gains focus. `createSelector` will not help in this case, because we are indeed invalidating the data in the store in `USER_STATE_POPULATE`.

## Changes
- Don't update the state if the array is identical in content.
- Fixed `selectMutedChannels` to return the reference from the store, so `createSelector` is not needed.
    - Also, the filtering is not needed because we've already done it in the reducer.

## Comments
I've done some profiling on large blocklists. The time needed for the array comparison is still an order magnitude lower than the time needed to render all the Components that got incorrectly marked by this.

The ideal solution is for the sync code to return a hash or timestamp of the array, so that we can compare that instead of the array.
2021-10-19 21:15:26 +08:00
infinite-persistence
aabfc41ce9
Remove unused props and selector calls. 2021-10-19 21:15:25 +08:00
infinite-persistence
5bcf89394e
Port redux/inc consolidation (#81) 2021-10-19 20:53:24 +08:00
infinite-persistence
35072c0400
Remove unused actions and test function.
The past-tense version of the PUBLISH_* action is no longer used.
2021-10-19 20:43:11 +08:00
infinite-persistence
296febcffa
Lint '/extras/*' + fixes
- Add `/extras` to the precommit hooks (lint, prettier).
- Remove `preinstall` since these modules don't exist anymore.

- Fix missing brace if one single-line if-statement.
2021-10-19 20:40:08 +08:00
infinite-persistence
cfdfdce2fe
Hush repetitive debug errors + remove from i18n 2021-10-19 20:40:07 +08:00
infinite-persistence
2a7f89d6b5
Post-merge updates and fixes
- Put back SETTINGS.LANGUAGE.
- Update import for `doResolveUris`.
2021-10-19 20:40:07 +08:00
Merge
30023422b8
Desktop cherry-pick: "7240 Integrate lbry redux and lbryinc" 2021-10-19 20:40:07 +08:00
infinite-persistence
702297e722
Spew 'analyze' results to 'web/dist' so that it doesn't appear in git. 2021-10-18 22:26:52 +08:00
infinite-persistence
07102c4988
Update 'yarn analyze' to do Web instead of Desktop
Since it might not be obvious to the user that we need a production build, added `yarn compile` to the step directly.
2021-10-18 22:00:44 +08:00
infinite-persistence
3b442531ef
Remove matomo + restore GA (#63) 2021-10-18 08:25:30 +08:00
infinite-persistence
f6e60abbf5
Convert to GA4 format
- 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.
2021-10-17 20:45:40 +08:00
infinite-persistence
dab1ca1cb7
Remove references to Desktop and lbry.tv 2021-10-17 20:45:39 +08:00
infinite-persistence
bba3a17977
Remove matomo + restore GA
Reverted/restored stuff from the following repo, with minimal modifications (trying to keep the diffs clean for future reference):
- lbry-desktop@5008972
- lbry-desktop@7fe88d8
2021-10-17 20:45:39 +08:00
GG2015
4a22814c75
Adds sub count to search and other areas. (#10)
Add follower counts to search
2021-10-16 14:12:09 -04:00
infinite-persistence
91be939c19
Fix linked-comment scrolling (again)
## Issue
Now that we batch-resolve the comment authors before displaying the comments, the linked-comment scrolling logic didn't work well with nested replies.

## Change
Previously, I didn't want to put the logic at the lowest level (`Comment`) because it was hard for the child to know whether to scroll or not. For example, we don't want to scroll when user changes the comment filters or presses the Refresh Comments button.

Relented and moved the logic to `Comment`, and pass a flag via `window` (I know this is frowned upon by some) to indicate whether a scrolling is needed.

This is probably more efficient overall as we don't need to scan the DOM, and with minimal delay as we scroll immediately after the linked-comment is mounted.

## Known issues
In markdown posts with lots of images, a layout shift due to delayed inline-image fetching can cause the scrolling to be inaccurate. This should be fixed by reserving space for markdown post images.
2021-10-16 13:40:33 +08:00
infinite-persistence
0b0f2848da
i18n - refix total comments
Meant to re-use strings, but I forgot to change the variable name.
2021-10-16 11:20:34 +08:00
Thomas Zarebczan
055d437865
fix total comments 2021-10-15 13:08:31 -04:00
infinite-persistence
d1493d5fb3
i18n 2021-10-15 14:23:40 +08:00
Thomas Zarebczan
b86a56f75b
Update README.md 2021-10-14 13:21:49 -04:00
infinite-persistence
8498554f23
Improve aesthetics for deleted channel names.
## Issue
- Comments: no spacing between the strings.
- "Unused" is not intuitive.

## Changes
- Use "[Removed]" instead.
- Localization.
2021-10-14 22:29:50 +08:00
infinite-persistence
2505d67a7d
[Comments] Batch fixes (#65) 2021-10-14 21:16:33 +08:00
saltrafael
03ea298236
Fix expanding comments and scroll pagination 2021-10-14 21:05:01 +08:00
saltrafael
a3302b1be8
Fix expansion broken with layout change 2021-10-14 21:05:00 +08:00
saltrafael
58db9576b9
Fix infinite resolve 2021-10-14 21:04:59 +08:00
saltrafael
a9b9c3ccf0
Revert "Revert "[Comments] Batch resolve" (#61)"
This reverts commit 0e96f8d468.
2021-10-14 21:04:58 +08:00
infinite-persistence
ea516f88dc Fix 'setting.Get' runaway calls
## Issue
60 setting.Get calls spiked since October

It was called 24 times per livestream page load.

## Notes
The effect was intended to be a one-time effect, but the dependency was changed in 2f4dedfb
2021-10-14 20:26:11 +08:00
mayeaux
5f55a3f128
use insecure mode (#74) 2021-10-14 11:55:46 +03:00
saltrafael
53063931ab
Fix markdown preview word break (#70) 2021-10-13 16:31:12 -04:00
mayeaux
6727e2766b
fix channel value (#67) 2021-10-13 19:07:57 +03:00
mayeaux
c10fc675db
fix channel value (#66) 2021-10-13 19:00:32 +03:00
mayeaux
fa889112c5
Ads setup (#62)
* re enable preload ads

* switch macro to aniview

* point towards test server

* improving documentation

* bugfix and turn skip back on

* only run twenty percent of the time for unauthed users

* allow for embeds

* enable show internal feature

* working prototype

* seems to work well

* bugfix

* review old aniview setup

* change to production channelid

* final touchups
2021-10-13 11:04:03 -04:00
infinite-persistence
0e96f8d468
Revert "[Comments] Batch resolve" (#61)
This reverts commit caadd889ce, reversing
changes made to 8b2c7a2b21.

## Issue
- Infinite `resolve` loop when deleted channel is present in the comments.
- Since it was only displayed comments with resolved channels, it masked away those comments. While that may or may not be regarded as a defect, I think we should do it at Commentron instead of at the app if we want to filter deleted channels. I vote to show comments from deleted channels, since it might have good conversation thread.
2021-10-13 08:59:32 -04:00
infinite-persistence
d5ad63c6e9
Comments: handle 'disable-support' tag (#59) 2021-10-13 15:24:55 +08:00
Bradley Ray
cd8f90c82d
added semicolon to import statement 2021-10-13 15:16:20 +08:00
Bradley Ray
24eb2ef8ec
change to import instead of redefining const 2021-10-13 15:16:19 +08:00
Bradley Ray
37ddc395ea
fixed disable-support for comments 2021-10-13 15:16:18 +08:00
Thomas Zarebczan
02a8099514
Take 99 2021-10-12 22:30:05 -04:00
Thomas Zarebczan
9dbee19961
Add test embed domain to rule out cards 2021-10-12 20:55:33 -04:00
Thomas Zarebczan
b49fed4cf5
fix config for thumbs
whoops

Fix encoded URLs
2021-10-12 20:31:10 -04:00
Thomas Zarebczan
2b5d32c313
Use cards.odysee.com (#56) 2021-10-12 19:16:39 -04:00
saltrafael
7c518aa712
[Comment/Livestream] Markdown and style fixes (#55)
* Fix CSS for live chat embeds

* Fix Markdown Lists in Comments

* Disable copy link menu option on livestream comments

* Fix nested indents in Live Chat

* Fix mentions and timestamps not parsed in bullet lists

* Highlight livestream comment and menu button on hover

* Fix mention parsing
2021-10-12 17:06:20 -04:00
infinite-persistence
6f3c43c95f
Fix recsys submission when user is null (#54)
## 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).
2021-10-12 12:10:35 -04:00
infinite-persistence
a168dbcc01
Fix livestream player height cut-off (#53) 2021-10-12 01:27:16 -04:00
Anthony
3087f7c367
list 100 transactions for fiat received and outgoing instead of 25 2021-10-11 12:57:59 -04:00
Thomas Zarebczan
3f969ae20d
Merge pull request #48 from OdyseeTeam/ip/rescys
Handle recsys crash `new|me` fails
2021-10-11 12:57:20 -04:00
infinite-persistence
19797c747e
Handle recsys crash new|me fails
## Issue
Potentially closes 44 "tor browser crash related to recsys?"
2021-10-11 15:34:01 +08:00
infinite-persistence
caadd889ce
[Comments] Batch resolve 2021-10-11 09:46:29 +08:00
1174 changed files with 73023 additions and 29675 deletions

View file

@ -2,117 +2,120 @@
# Copy this file to .env to make modifications # Copy this file to .env to make modifications
# Base config # --- Minimum Version (Format: YYYYMMDDNNN) ---
# Bump this when we want to nudge the user to refresh.
MINIMUM_VERSION=20220708001
# This is 'false' in the production instances:
IGNORE_MINIMUM_VERSION=true
# --- Base config ---
WEBPACK_WEB_PORT=9090 WEBPACK_WEB_PORT=9090
WEBPACK_ELECTRON_PORT=9091 WEBPACK_ELECTRON_PORT=9091
WEB_SERVER_PORT=1337 WEB_SERVER_PORT=1337
## APIS # -- APIs ---
LBRY_WEB_API=https://api.na-backend.odysee.com LBRY_WEB_API=https://api.na-backend.odysee.com
LBRY_WEB_STREAMING_API=https://cdn.lbryplayer.xyz LBRY_WEB_PUBLISH_API=https://publish.na-backend.odysee.com/v1
LBRY_WEB_PUBLISH_API_V2=https://publish.na-backend.odysee.com/api/v2/publish/
LBRY_WEB_BUFFER_API=https://collector-service.api.lbry.tv/api/v1/events/video LBRY_WEB_BUFFER_API=https://collector-service.api.lbry.tv/api/v1/events/video
COMMENT_SERVER_API=https://comments.odysee.com/api/v2 LBRY_API_URL=https://api.odysee.com
COMMENT_SERVER_NAME=Odysee COMMENT_SERVER_API=https://comments.odysee.tv/api/v2
SEARCH_SERVER_API=https://lighthouse.odysee.com/search SEARCH_SERVER_API_ALT=https://recsys.odysee.tv/search
SOCKETY_SERVER_API=wss://sockety.odysee.com/ws SEARCH_SERVER_API=https://lighthouse.odysee.tv/search
THUMBNAIL_CDN_URL=https://thumbnails.odysee.com/optimize/ SOCKETY_SERVER_API=wss://sockety.odysee.tv/ws
RECSYS_ENDPOINT=https://recsys.odysee.tv/v1/lvv
RECSYS_FYP_ENDPOINT=https://recsys.odysee.tv/v1/u
# -Disable boost due to instability:
# IMAGE_PROXY_URL=https://boost.vanwanet.com/index.php
THUMBNAIL_CDN_URL=https://thumbnails.odycdn.com/optimize/
THUMBNAIL_CARDS_CDN_URL=https://thumbnails.odycdn.com/card/s:1280:720/quality:85/plain/
LOCALE_API=https://api.odysee.com/legal/requirements
THUMBNAIL_HEIGHT=220 THUMBNAIL_HEIGHT=220
THUMBNAIL_HEIGHT_POSTER=720
THUMBNAIL_WIDTH=390 THUMBNAIL_WIDTH=390
THUMBNAIL_WIDTH_POSTER=1280
THUMBNAIL_QUALITY=85 THUMBNAIL_QUALITY=85
THUMBNAIL_CDN_SIZE_LIMIT_BYTES=5242880
PLAYER_SERVER=https://player.odycdn.com
WELCOME_VERSION=1.0 WELCOME_VERSION=1.0
# STRIPE # --- Stripe ---
# STRIPE_PUBLIC_KEY='pk_test_NoL1JWL7i1ipfhVId5KfDZgo' # STRIPE_PUBLIC_KEY='pk_test_NoL1JWL7i1ipfhVId5KfDZgo'
# Analytics # --- OG ---
MATOMO_URL=https://analytics.lbry.com/ OG_TITLE_SUFFIX=| odysee.com
MATOMO_ID=4 OG_HOMEPAGE_TITLE=Odysee
OG_IMAGE_URL=https://thumbnails.odycdn.com/optimize/s:1200:630/quality:85/plain/https://spee.ch/odysee-og:e.png
SITE_CANONICAL_URL=odysee.com
# OG # --- UI ---
OG_TITLE_SUFFIX=| lbry.tv DOMAIN=odysee.com
OG_HOMEPAGE_TITLE=lbry.tv URL=https://odysee.com
OG_IMAGE_URL= SITE_TITLE=Odysee
SITE_CANONICAL_URL=https://lbry.tv SITE_NAME=Odysee
SITE_DESCRIPTION=Explore a whole universe of videos on Odysee from regular people just like you!
SITE_HELP_EMAIL=help@odysee.com
LOGO_TITLE=odysee
TWITTER_ACCOUNT=OdyseeTeam
LOADING_BAR_COLOR=#e50054
# UI
## Custom Site info
DOMAIN=lbry.tv
URL=https://lbry.tv
SITE_TITLE=lbry.tv
SITE_NAME=lbry.tv
SITE_DESCRIPTION=Meet LBRY, an open, free, and community-controlled content wonderland.
SITE_HELP_EMAIL=help@lbry.com
LOGO_TITLE=lbry.tv
## Social media
TWITTER_ACCOUNT=LBRYcom
BRANDED_SITE=odysee BRANDED_SITE=odysee
SIMPLE_SITE=false
ENABLE_WILD_WEST=true
CUSTOM_HOMEPAGE=false
SHOW_ADS=true
ENABLE_MATURE=false
ENABLE_UI_NOTIFICATIONS=true
#SHOW_TAGS_INTRO=false
USE_LOCAL_HOMEPAGE_DATA=true
## IMAGE ASSETS AUTO_FOLLOW_CHANNELS=lbry://@lbry#3fda836a92faaceedfe398225fb9b2ee2ed1f01a
YRBL_HAPPY_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a
YRBL_SAD_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
#LOGIN_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/login/b671946e911c66c5fa7233afb35de2badd9eceb8/0e1d81
#LOGO=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
#LOGO_TEXT_LIGHT=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
#LOGO_TEXT_DARK=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
#AVATAR_DEFAULT=
#MISSING_THUMB_DEFAULT=
#FAVICON=
# LOCALE # --- Image Assets ---
YRBL_HAPPY_IMG_URL=https://thumbnails.odycdn.com/optimize/s:300:300/quality:85/plain/https://spee.ch/spaceman-happy:a.png
YRBL_SAD_IMG_URL=https://thumbnails.odycdn.com/optimize/s:300:300/quality:85/plain/https://spee.ch/spaceman-sad:d.png
LOGIN_IMG_URL=https://thumbnails.odycdn.com/optimize/s:400:507/quality:85/plain/https://player.odycdn.com/speech/odysee-sign-up:d.png
LOGO=https://thumbnails.odycdn.com/optimize/s:100:100/quality:85/plain/https://spee.ch/odysee-logo-png:3.png
LOGO_WHITE_TEXT=https://thumbnails.odycdn.com/optimize/s:1000:300/quality:85/plain/https://spee.ch/odysee-white-png:f.png
LOGO_DARK_TEXT=https://thumbnails.odycdn.com/optimize/s:1000:300/quality:85/plain/https://spee.ch/odysee-png:2.png
AVATAR_DEFAULT=https://thumbnails.odycdn.com/optimize/s:160:160/quality:85/plain/https://spee.ch/spaceman-png:2.png
MISSING_THUMB_DEFAULT=https://thumbnails.odycdn.com/optimize/s:390:220/quality:85/plain/https://spee.ch/missing-thumb-png
FAVICON=https://odysee.com/public/favicon-spaceman.png
# --- Locale ---
DEFAULT_LANGUAGE=en DEFAULT_LANGUAGE=en
## CUSTOM SETTINGS # --- Custom Settings ---
# Additional settings for below are found in ui/constants/settings and are for # Additional settings for below are found in ui/constants/settings and are for
# preventing user settings from applying to custom sites without overwriting them. # preventing user settings from applying to custom sites without overwriting them.
# UNSYNCED_SETTINGS='theme dark_mode_times automatic_dark_mode_enabled' # UNSYNCED_SETTINGS='theme dark_mode_times automatic_dark_mode_enabled'
## LINKED CONTENT WHITELIST # --- Linked Content Whitelist ---
KNOWN_APP_DOMAINS=lbry.tv,lbry.lat,odysee.com KNOWN_APP_DOMAINS=open.lbry.com,lbry.tv,lbry.lat,odysee.com
## CUSTOM CONTENT # --- Features & Limits ---
# If the following is true, copy custom/homepage.example.js to custom/homepage.js and modify CHANNEL_CREATION_LIMIT=5
CUSTOM_HOMEPAGE=false
# Add channels to auto-follow on first run
AUTO_FOLLOW_CHANNELS=lbry://@lbry#3fda836a92faaceedfe398225fb9b2ee2ed1f01a
## FEATURES AND LIMITS
SIMPLE_SITE=false
#BRANDED_SITE
ENABLE_COMMENT_REACTIONS=true
ENABLE_FILE_REACTIONS=false
ENABLE_CREATOR_REACTIONS=false
ENABLE_NO_SOURCE_CLAIMS=false
ENABLE_PREROLL_ADS=false
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS=4 CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS=4
CHANNEL_STAKED_LEVEL_LIVESTREAM=5 ENABLE_COMMENT_REACTIONS=true
ENABLE_CREATOR_REACTIONS=true
ENABLE_FILE_REACTIONS=true
ENABLE_NO_SOURCE_CLAIMS=true
ENABLE_PREROLL_ADS=true
LIGHTHOUSE_DEFAULT_TYPES=audio,video
WEB_PUBLISH_SIZE_LIMIT_GB=4 WEB_PUBLISH_SIZE_LIMIT_GB=4
LOADING_BAR_COLOR=#2bbb90
LIGHTHOUSE_DEFAULT_TYPES=audio,video,text,image,application
SHOW_ADS=true
## SIMPLE_SITE REPLACEMENTS
ENABLE_MATURE=true
ENABLE_UI_NOTIFICATIONS=false
#ENABLE_LINK_TO_APP=true
#FORCE_ANALYTICS=true
#ENABLE_ADVANCED_FILTER=true
#ENABLE_PAID_CONTENT=true #ENABLE_PAID_CONTENT=true
#USE_FOOTER=true
#USE_DISCOVER_WHITELIST=false
#ENABLE_WILD_WEST=false
#FULL_SIDE_LINKS=true
#SHOW_TAGS_INTRO=false
# SEARCH TYPES # --- Firebase ---
#VIDEO_ENABLED=true FIREBASE_API_KEY=AIzaSyAgc-4QORyglpYZ3qH9E5pDauEDOJXgM3A
#AUDIO_ENABLED=true FIREBASE_AUTH_DOMAIN=lbry-mobile.firebaseapp.com
#POSTS_ENABLED=true FIREBASE_PROJECT_ID=lbry-mobile
#IMAGES_ENABLED=true FIREBASE_STORAGE_BUCKET=lbry-mobile.appspot.com
#FILES_ENABLED=true FIREBASE_MESSAGING_SENDER_ID=638894153788
#MODELS_ENABLED=true FIREBASE_APP_ID=1:638894153788:web:35b295b15297201bd2e339
FIREBASE_MEASUREMENT_ID=G-2MPJGFEEXC
FIREBASE_VAPID_KEY=BFayEBpwMTU9GQQpXgitIJkfx-SD8-ltrFb3wLTZWgA27MfBhG4948pe0eERl432NzPrMKsbkXnA7ap_vLPgLYk
BRANDED_SITE=odysee # --- Development ---
REPORT_NEW_STRINGS=false

View file

@ -2,3 +2,6 @@ node_modules/*
./node_modules/** ./node_modules/**
**/node_modules/** **/node_modules/**
web/dist/** web/dist/**
**/plugins/inline-attachment/**
ui/component/viewers/videoViewer/internal/plugins/canAutoplay.js

View file

@ -2,6 +2,9 @@
"parser": "babel-eslint", "parser": "babel-eslint",
"extends": ["standard", "standard-jsx", "plugin:react/recommended", "plugin:flowtype/recommended"], "extends": ["standard", "standard-jsx", "plugin:react/recommended", "plugin:flowtype/recommended"],
"plugins": ["flowtype", "import", "react-hooks"], "plugins": ["flowtype", "import", "react-hooks"],
"parserOptions": {
"ecmaVersion": 2020
},
"env": { "env": {
"browser": true, "browser": true,
"node": true "node": true
@ -22,7 +25,13 @@
"rules": { "rules": {
"brace-style": 0, "brace-style": 0,
"camelcase": 0, "camelcase": 0,
"comma-dangle": ["error", "always-multiline"], "comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "always-multiline",
"exports": "always-multiline",
"functions": "never"
}],
"handle-callback-err": 0, "handle-callback-err": 0,
"indent": 0, "indent": 0,
"jsx-quotes": ["error", "prefer-double"], "jsx-quotes": ["error", "prefer-double"],

View file

@ -2,25 +2,22 @@
.*\.typeface\.json .*\.typeface\.json
.*/node_modules/findup/.* .*/node_modules/findup/.*
.*/node_modules/react-plastic/.* .*/node_modules/react-plastic/.*
.*/node_modules/raf-schd/.*
.*/node_modules/react-beautiful-dnd/.*
.*/node_modules/@emotion/.*
[include] [include]
[libs] [libs]
./flow-typed
node_modules/lbry-redux/flow-typed/
node_modules/lbryinc/flow-typed/
[untyped]
.*/node_modules/lbry-redux
.*/node_modules/lbryinc
[lints] [lints]
[options] [options]
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue suppress_comment=\\(.\\|\n\\)*\\$FlowIssue
suppress_comment=\\(.\\|\n\\)*\\$FlowIgnore
module.name_mapper='^constants\(.*\)$' -> '<PROJECT_ROOT>/ui/constants\1' module.name_mapper='^constants\(.*\)$' -> '<PROJECT_ROOT>/ui/constants\1'
module.name_mapper='^contexts\(.*\)$' -> '<PROJECT_ROOT>/ui/contexts\1'
module.name_mapper='^util\(.*\)$' -> '<PROJECT_ROOT>/ui/util\1' module.name_mapper='^util\(.*\)$' -> '<PROJECT_ROOT>/ui/util\1'
module.name_mapper='^redux\(.*\)$' -> '<PROJECT_ROOT>/ui/redux\1' module.name_mapper='^redux\(.*\)$' -> '<PROJECT_ROOT>/ui/redux\1'
module.name_mapper='^types\(.*\)$' -> '<PROJECT_ROOT>/ui/types\1' module.name_mapper='^types\(.*\)$' -> '<PROJECT_ROOT>/ui/types\1'
@ -31,17 +28,20 @@ module.name_mapper='^modal\(.*\)$' -> '<PROJECT_ROOT>/ui/modal\1'
module.name_mapper='^app\(.*\)$' -> '<PROJECT_ROOT>/ui/app\1' module.name_mapper='^app\(.*\)$' -> '<PROJECT_ROOT>/ui/app\1'
module.name_mapper='^native\(.*\)$' -> '<PROJECT_ROOT>/ui/native\1' module.name_mapper='^native\(.*\)$' -> '<PROJECT_ROOT>/ui/native\1'
module.name_mapper='^analytics\(.*\)$' -> '<PROJECT_ROOT>/ui/analytics\1' module.name_mapper='^analytics\(.*\)$' -> '<PROJECT_ROOT>/ui/analytics\1'
module.name_mapper='^recsys\(.*\)$' -> '<PROJECT_ROOT>/ui/recsys\1' module.name_mapper='^recsys\(.*\)$' -> '<PROJECT_ROOT>/extras/recsys\1'
module.name_mapper='^rewards\(.*\)$' -> '<PROJECT_ROOT>/ui/rewards\1' module.name_mapper='^rewards\(.*\)$' -> '<PROJECT_ROOT>/ui/rewards\1'
module.name_mapper='^i18n\(.*\)$' -> '<PROJECT_ROOT>/ui/i18n\1' module.name_mapper='^i18n\(.*\)$' -> '<PROJECT_ROOT>/ui/i18n\1'
module.name_mapper='^effects\(.*\)$' -> '<PROJECT_ROOT>/ui/effects\1' module.name_mapper='^effects\(.*\)$' -> '<PROJECT_ROOT>/ui/effects\1'
module.name_mapper='^comments\(.*\)$' -> '<PROJECT_ROOT>/ui/comments\1' module.name_mapper='^comments\(.*\)$' -> '<PROJECT_ROOT>/ui/comments\1'
module.name_mapper='^locale\(.*\)$' -> '<PROJECT_ROOT>/ui/locale\1'
module.name_mapper='^config\(.*\)$' -> '<PROJECT_ROOT>/config\1' module.name_mapper='^config\(.*\)$' -> '<PROJECT_ROOT>/config\1'
module.name_mapper='^web\/component\(.*\)$' -> '<PROJECT_ROOT>/web/component\1' module.name_mapper='^web\/component\(.*\)$' -> '<PROJECT_ROOT>/web/component\1'
module.name_mapper='^web\/effects\(.*\)$' -> '<PROJECT_ROOT>/web/effects\1' module.name_mapper='^web\/effects\(.*\)$' -> '<PROJECT_ROOT>/web/effects\1'
module.name_mapper='^web\/page\(.*\)$' -> '<PROJECT_ROOT>/web/page\1' module.name_mapper='^web\/page\(.*\)$' -> '<PROJECT_ROOT>/web/page\1'
module.name_mapper='^homepage\(.*\)$' -> '<PROJECT_ROOT>/ui/util/homepage\1' module.name_mapper='^homepage\(.*\)$' -> '<PROJECT_ROOT>/ui/util/homepage\1'
module.name_mapper='^scss\/component\(.*\)$' -> '<PROJECT_ROOT>/ui/scss/component/\1' module.name_mapper='^scss\/component\(.*\)$' -> '<PROJECT_ROOT>/ui/scss/component/\1'
module.name_mapper='^\$web\(.*\)$' -> '<PROJECT_ROOT>/web\1'
module.name_mapper='^\$ui\(.*\)$' -> '<PROJECT_ROOT>/ui\1'
esproposal.optional_chaining=enable esproposal.optional_chaining=enable

View file

@ -4,7 +4,6 @@ about: "Something isn't working \U0001F915"
title: '' title: ''
labels: 'type: bug' labels: 'type: bug'
assignees: '' assignees: ''
--- ---
<!-- <!--
@ -16,7 +15,7 @@ Before reporting any issues, please make sure that you're using the latest versi
- App releases: https://github.com/lbryio/lbry-desktop/releases - App releases: https://github.com/lbryio/lbry-desktop/releases
- Standalone daemon: https://github.com/lbryio/lbry/releases - Standalone daemon: https://github.com/lbryio/lbry/releases
We are also available on live chat at https://chat.lbry.com We are also available on live chat at https://chat.odysee.com
--> -->
**Bug** **Bug**
@ -24,6 +23,7 @@ A clear and concise description of what the bug is.
**To Reproduce** **To Reproduce**
Steps to reproduce the behavior: Steps to reproduce the behavior:
1. Go to '...' 1. Go to '...'
2. Click on '....' 2. Click on '....'
3. Scroll down to '....' 3. Scroll down to '....'
@ -49,6 +49,5 @@ If applicable, add screenshots to help explain your problem.
- LBRY Installation ID: - LBRY Installation ID:
- Operating system: - Operating system:
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

View file

@ -1,22 +1,22 @@
--- ---
name: "❤Say thank you" name: "❤Say thank you"
about: If you enjoy using the LBRY app, let us know! about: If you enjoy using Odysee's website, let us know!
title: LBRY rocks! title: Odysee rocks!
labels: '' labels: ''
assignees: '' assignees: ''
--- ---
If you are using the LBRY app - please let us know. We'd love to hear from you! If you are using the Odysee's website - please let us know. We'd love to hear from you!
If you would like to help Nock - any of the following is greatly appreciated. If you would like to help Nock - any of the following is greatly appreciated.
- Give the repository a star ⭐️ - Give the repository a star ⭐️
- Help out with issues - Help out with issues
- Blog about LBRY - Blog about Odysee
- Make tutorials - Make tutorials
- Give talks - Give talks
- Convince other people to use LBRY - Convince other people to use Odysee
- Anything your heart desires - Anything your heart desires
Thank you! 💐 Thank you! 💐

View file

@ -34,7 +34,6 @@ What kind of change does this PR introduce?
Please check all that apply to this PR using "x": Please check all that apply to this PR using "x":
- [ ] I have checked that this PR is not a duplicate of an existing PR (open, closed or merged) - [ ] I have checked that this PR is not a duplicate of an existing PR (open, closed or merged)
- [ ] I added a line describing my change to CHANGELOG.md
- [ ] I have checked that this PR does not introduce a breaking change - [ ] I have checked that this PR does not introduce a breaking change
- [ ] This PR introduces breaking changes and I have provided a detailed explanation below - [ ] This PR introduces breaking changes and I have provided a detailed explanation below

View file

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: Borales/actions-yarn@v2.3.0 - uses: Borales/actions-yarn@v3.0.0
- run: yarn lint - run: yarn lint
build: build:
@ -41,8 +41,6 @@ jobs:
yarn compile:web yarn compile:web
env: env:
# UI # UI
MATOMO_URL: https://analytics.lbry.com/
MATOMO_ID: 4
WELCOME_VERSION: 1.0 WELCOME_VERSION: 1.0
DOMAIN: odysee.com DOMAIN: odysee.com
URL: https://odysee.com URL: https://odysee.com
@ -50,8 +48,8 @@ jobs:
SITE_TITLE: Odysee SITE_TITLE: Odysee
SITE_NAME: Odysee SITE_NAME: Odysee
SHOW_ADS: false SHOW_ADS: false
YRBL_HAPPY_IMG_URL: https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a YRBL_HAPPY_IMG_URL: https://player.odycdn.com/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a
YRBL_SAD_IMG_URL: https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd YRBL_SAD_IMG_URL: https://player.odycdn.com/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
ENABLE_COMMENT_REACTIONS: true ENABLE_COMMENT_REACTIONS: true
ENABLE_NO_SOURCE_CLAIMS: true ENABLE_NO_SOURCE_CLAIMS: true
DEFAULT_LANGUAGE: en DEFAULT_LANGUAGE: en

2
.gitignore vendored
View file

@ -12,6 +12,7 @@ yarn-error.log
package-lock.json package-lock.json
.transifexrc .transifexrc
.idea/ .idea/
.vscode/
/build/daemon* /build/daemon*
/lbrytv/dist/ /lbrytv/dist/
/lbrytv/node_modules /lbrytv/node_modules
@ -36,3 +37,4 @@ package-lock.json
.env.ody .env.ody
.env.desktop .env.desktop
.env.lbrytv .env.lbrytv
analyzeResults*.html

View file

@ -1,8 +1,10 @@
{ {
"linters": { "linters": {
"ui/**/*.{js,jsx,scss,json}": ["prettier --write", "git add"], "ui/**/*.{js,jsx,scss,json}": ["prettier --write", "git add"],
"extras/**/*.{js,jsx,scss,json}": ["prettier --write", "git add"],
"web/**/*.{js,jsx,scss,json}": ["prettier --write", "git add"], "web/**/*.{js,jsx,scss,json}": ["prettier --write", "git add"],
"ui/**/*.{js,jsx}": ["eslint", "flow focus-check --color always", "git add"], "ui/**/*.{js,jsx}": ["eslint", "flow focus-check --color always", "git add"],
"extras/**/*.{js,jsx}": ["eslint", "flow focus-check --color always", "git add"],
"web/**/*.{js,jsx}": ["eslint", "git add"] "web/**/*.{js,jsx}": ["eslint", "git add"]
}, },
"ignore": ["node_modules", "web/dist/**/*", "dist/**/*", "package-lock.json"] "ignore": ["node_modules", "web/dist/**/*", "dist/**/*", "package-lock.json"]

3
.prettierignore Normal file
View file

@ -0,0 +1,3 @@
**/plugins/inline-attachment/**
**/plugins/videojs-http-streaming--override/playlist-selectors.js
**/ui/constants/errors.js

View file

@ -1,4 +1,4 @@
[defaults] [defaults]
url = https://sentry.lbry.tech/ url = https://sentry.odysee.tv/
org = lbry org = odysee
project = lbry-desktop-web project = odysee-web

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
# Contribute to LBRY # Contribute to Odysee
**First:** if you're unsure or afraid of anything, just ask or submit the issue or pull request anyways. You won't be yelled at for giving your best effort. The worst that can happen is that you'll be politely asked to change something. We appreciate any sort of contributions, and don't want a wall of rules to get in the way of that. **First:** if you're unsure or afraid of anything, just ask or submit the issue or pull request anyways. You won't be yelled at for giving your best effort. The worst that can happen is that you'll be politely asked to change something. We appreciate any sort of contributions, and don't want a wall of rules to get in the way of that.
@ -6,55 +6,52 @@ However, for those individuals who want a bit more guidance on the best way to c
## TL;DR? ## TL;DR?
- [Here](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee) - [Here](https://github.com/OdyseeTeam/odysee-frontend/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee)
is a list of help wanted issues. is a list of help wanted issues.
- Comment on an issue to let us know if you are going to work on it, don't take an issue that someone reserved less than 3 days ago. - Comment on an issue to let us know if you are going to work on it, don't take an issue that someone reserved less than 3 days ago.
- Submit a pull request and get paid in LBC. - Submit a pull request and get paid in Credits.
- Don't hesitate to contact us with any questions or comments. - Don't hesitate to contact us with any questions or comments.
## Contents ## Contents
- [Choose an Issue](#choose-an-issue) - [Choose an Issue](#choose-an-issue)
- [Code Overview](#code-overview) - [Code Overview](#code-overview)
- [Libraries](#libraries)
- [Flow](#flow) - [Flow](#flow)
- [Lint](#lint) - [Lint](#lint)
- [Code Formatting](#code-formatting) - [Code Formatting](#code-formatting)
- [Debug](#debug) - [Debug](#debug)
- [Submit a Pull Request](#submit-a-pull-request) - [Submit a Pull Request](#submit-a-pull-request)
- [Tom's "Voice of the User" Wishlist](#toms-voice-of-the-user-wishlist)
- [Get in Touch](#get-in-touch) - [Get in Touch](#get-in-touch)
- [More Information](#more-information)
## Choose an Issue ## Choose an Issue
LBRY is an open source project and therefore is developed out in the open for everyone to see. What Odysee is an open source project and therefore is developed out in the open for everyone to see. What
you see here are the latest source code changes and issues. you see here are the latest source code changes and issues.
Since LBRY is based on a decentralized community, we believe that the app will be stronger if it Since Odysee is based on a decentralized community, we believe that the app will be stronger if it
receives contributions from individuals outside the core team -- such as yourself! receives contributions from individuals outside the core team -- such as yourself!
To make contributing as easy and rewarding as possible, we have instituted the following system: To make contributing as easy and rewarding as possible, we have instituted the following system:
- Anyone can view all issues in the system by clicking on the - Anyone can view all issues in the system by clicking on the
[Issues](https://github.com/lbryio/lbry-desktop/issues) button at the top of the page. Feel free to [Issues](https://github.com/OdyseeTeam/odysee-frontend/issues) button at the top of the page. Feel free to
add an issue if you think we have missed something (and you might earn some LBC in the process add an issue if you think we have missed something (and you might earn some Credits in the process
because we do tip people for reporting bugs). because we do tip people for reporting bugs).
- Once on the [Issues](https://github.com/lbryio/lbry-desktop/issues) page, a potential contributor can - Once on the [Issues](https://github.com/OdyseeTeam/odysee-frontend/issues) page, a potential contributor can
filter issues by the filter issues by the
[Help Wanted](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee) [Help Wanted (in progress)](https://github.com/OdyseeTeam/odysee-frontend/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee)
label to see a curated list of suggested issues with which community members can help. label to see a curated list of suggested issues with which community members can help.
- Every - Every
[Help Wanted](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee) [Help Wanted](https://github.com/OdyseeTeam/odysee-frontend/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee)
issue is ranked on a scale from zero to four. issue is ranked on a scale from zero to four (in progress)
| Level | Description | | Level (in progress) | Description |
| ---------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| [**level 0**](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+0%22+no%3Aassignee) | Typos and text edits -- a tech-savvy non-programmer can fix these. | | [**level 0**](https://github.com/OdyseeTeam/odysee-frontend/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+0%22+no%3Aassignee) | Typos and text edits -- a tech-savvy non-programmer can fix these. |
| [**level 1**](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+1%22+no%3Aassignee) | Programming issues that require little knowledge of how the LBRY app works. | | [**level 1**](https://github.com/OdyseeTeam/odysee-frontend/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+1%22+no%3Aassignee) | Programming issues that require little knowledge of how the Odysee app works. |
| [**level 2**](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+2%22+no%3Aassignee) | Issues of average difficulty that require the developer to dig into how the app works a little bit. | | [**level 2**](https://github.com/OdyseeTeam/odysee-frontend/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+2%22+no%3Aassignee) | Issues of average difficulty that require the developer to dig into how the app works a little bit. |
| [**level 3**](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+3%22+no%3Aassignee) | Issues that are likely too tricky to be level 2 or require more thinking outside of the box. | | [**level 3**](https://github.com/OdyseeTeam/odysee-frontend/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+3%22+no%3Aassignee) | Issues that are likely too tricky to be level 2 or require more thinking outside of the box. |
| [**level 4**](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+4%22+no%3Aassignee) | Big features or really hard issues. | | [**level 4**](https://github.com/OdyseeTeam/odysee-frontend/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+4%22+no%3Aassignee) | Big features or really hard issues. |
The process of ranking issues is highly subjective. The purpose of sorting issues like this is to The process of ranking issues is highly subjective. The purpose of sorting issues like this is to
give contributors a general idea about the type of issues they are looking at. For instance, it could very well be give contributors a general idea about the type of issues they are looking at. For instance, it could very well be
@ -62,24 +59,19 @@ the case that a level 1 issue is more difficult than a level 2 issue. This syste
to help you find relevant issues, not to prevent you from working on issues that you otherwise to help you find relevant issues, not to prevent you from working on issues that you otherwise
would. If these rankings don't work for you, feel free to ignore them. would. If these rankings don't work for you, feel free to ignore them.
Although all contributions should have good UX, the [UX label, when applied in conjunction with Help Wanted](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3Aux+no%3Aassignee), indicates that the contributor ought to implement the feature in a creative way that specifically focuses on providing a good user experience. These issues often have no set instruction for how the experience should be and leave it to the contributor to figure out. This may be challenging for people who do not like UX, but also more fun and rewarding for those who do. Although all contributions should have good UX, the [UX label, when applied in conjunction with Help Wanted](https://github.com/OdyseeTeam/odysee-frontend/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3Aux+no%3Aassignee), indicates that the contributor ought to implement the feature in a creative way that specifically focuses on providing a good user experience. These issues often have no set instruction for how the experience should be and leave it to the contributor to figure out. This may be challenging for people who do not like UX, but also more fun and rewarding for those who do.
## Code Overview ## Code Overview
The entry point for this application is [`electron/index.js`](https://github.com/lbryio/lbry-desktop/blob/master/electron/index.js). This application is primarily written in JavaScript, utilizing [React](https://reactjs.org) and [Redux](https://redux.js.org) for UI and
This application is primarily written in JavaScript and is built on [Electron](https://electronjs.org)
while utilizing [React](https://reactjs.org) and [Redux](https://redux.js.org) for UI and
application state. application state.
The project comes with diverse tools for simplifying the development process and for providing The project comes with diverse tools for simplifying the development process and for providing
better code quality. It's recommended to make use of them thoroughly during ongoing development. We follow the well-known [Airbnb JavaScript Style Guide](https://airbnb.io/javascript/) for defining better code quality. It's recommended to make use of them thoroughly during ongoing development.
We follow the well-known [Airbnb JavaScript Style Guide](https://airbnb.io/javascript/) for defining
our styling rules and code best practices. our styling rules and code best practices.
### Libraries
This project uses [lbry-redux](https://github.com/lbryio/lbry-redux) and [lbryionc](https://github.com/lbryio/lbryinc) to share Redux and LBRY API specific code with other LBRY apps. Over time, more Redux code that is suitable to be shared will be moved into lbry-redux. If modifying Redux code, you may be asked to make some of your changes in lbry-redux rather than lbry-desktop. The steps to work with lbry-redux locally can be found [here](https://github.com/lbryio/lbry-redux#local-development).
### Flow ### Flow
[Flow](https://flow.org/) is a static type checker for JavaScript. Flow checks your code for [Flow](https://flow.org/) is a static type checker for JavaScript. Flow checks your code for
@ -140,7 +132,6 @@ There are a few tools integrated to the project that will ease the process of de
- [Chrome DevTools](https://developer.chrome.com/devtools) - [Chrome DevTools](https://developer.chrome.com/devtools)
- Also available for the main process as a [remote target](chrome://inspect/#devices). - Also available for the main process as a [remote target](chrome://inspect/#devices).
- [Electron Devtron](https://electronjs.org/devtron)
- [React DevTools](https://github.com/facebook/react-devtools) - [React DevTools](https://github.com/facebook/react-devtools)
- [Redux DevTools](https://github.com/gaearon/redux-devtools) - [Redux DevTools](https://github.com/gaearon/redux-devtools)
@ -149,19 +140,17 @@ There are a few tools integrated to the project that will ease the process of de
- After deciding what to work on, a potential contributor can - After deciding what to work on, a potential contributor can
[fork](https://help.github.com/articles/fork-a-repo/) this repository, make his or her changes, [fork](https://help.github.com/articles/fork-a-repo/) this repository, make his or her changes,
and submit a and submit a
[pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/). A [pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
contributor wanting to reserve an issue in advance can leave a comment saying that he or she is - A contributor wanting to reserve an issue in advance can leave a comment saying that he or she is
working on it. Contributors should respect other people's efforts to complete issues in a timely working on it. Contributors should respect other people's efforts to complete issues in a timely
manner and, therefore, not begin working on anything reserved (or updated) within the last 3 days. manner and, therefore, not begin working on anything reserved (or updated) within the last 3 days.
If someone has been officially assigned an issue via GitHub's assignment system, it is also not If someone has been officially assigned an issue via GitHub's assignment system, it is also not
available. Contributors are encouraged to ask if they have any questions about issue availability. available. Contributors are encouraged to ask if they have any questions about issue availability.
- The [changelog](https://github.com/lbryio/lbry-desktop/blob/master/CHANGELOG.md) should be updated to - Once the pull request is visible in the Odysee repo, a Odysee team member will review it and make sure
include a reference to the fix/change/addition. See previous entries for format.
- Once the pull request is visible in the LBRY repo, a LBRY team member will review it and make sure
it is up to our standards. At this point, the contributor may have to change his or her code based it is up to our standards. At this point, the contributor may have to change his or her code based
on our suggestions and comments. on our suggestions and comments.
- Then, upon a satisfactory review of the code, we will merge it and send the contributor a tip (in - Then, upon a satisfactory review of the code, we will merge it and send the contributor a tip (in
LBC) for the contribution. Credits or Cash) for the contribution.
We are dedicated to being fair and friendly in this process. In **general**, level 4 issues will be We are dedicated to being fair and friendly in this process. In **general**, level 4 issues will be
paid more than level 3 issues which will be paid more than level 2, and so on. However, this is not paid more than level 3 issues which will be paid more than level 2, and so on. However, this is not
@ -173,29 +162,20 @@ Also, we are here to enable you. We want you to succeed, so do not hesitate to a
need some information or assistance in completing an issue, please let us know! That is what we are need some information or assistance in completing an issue, please let us know! That is what we are
here for-- pushing development forward. here for-- pushing development forward.
Lastly, don't feel limited by this list. Should LBRY have built-in Tor support? Add it! It's not in Lastly, don't feel limited by this list. Should Odysee have built-in Tor support? Add it! It's not in
the issue tracker, but maybe it's a good idea. Do you think the search layout is unintuitive? Change the issue tracker, but maybe it's a good idea. Do you think the search layout is unintuitive? Change
it! We welcome all feedback and suggestions. That said, it may be the case that we do not wish to it! We welcome all feedback and suggestions. That said, it may be the case that we do not wish to
incorporate your change if you don't check with us first (also, please check with us especially if incorporate your change if you don't check with us first (also, please check with us especially if
you are planning on adding Tor support :P). If you want to add a feature that is not listed in the you are planning on adding Tor support :P). If you want to add a feature that is not listed in the
issue tracker, go ahead and [create an issue](https://github.com/lbryio/lbry-desktop/issues/new), and issue tracker, go ahead and [create an issue](https://github.com/OdyseeTeam/odysee-frontend/issues/new), and
say in the description that you would like to try to implement it yourself. This way we can tell you say in the description that you would like to try to implement it yourself. This way we can tell you
in advance if we will accept your changes and we can point you in the right direction. in advance if we will accept your changes and we can point you in the right direction.
# Tom's "Voice of the User" Wishlist
[Anything marked with **both** "Help Wanted" and "Tom's 'Voice of the User' Wishlist"](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22Tom%27s+%5C%22Voice+of+the+User%5C%22+Wishlist%22+label%3A%22help+wanted%22+no%3Aassignee)
will earn you an extra 50 LBC on top of what we would otherwise tip you.
# Get in Touch # Get in Touch
| Name | Role | Discord | Email | | Name | Role | Discord | Email |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------- | | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------- |
| [Tom](https://github.com/tzarebczan) | Community manager. He knows more than anyone about the app and all of its flaws. Reach out to him with any questions about how the app works, if a bug has been reported, or if a feature should be requested. | jiggytom | tom@lbry.com | | [Tom](https://github.com/tzarebczan) | Community manager. He knows more than anyone about the app and all of its flaws. Reach out to him with any questions about how the app works, if a bug has been reported, or if a feature should be requested. | jiggytom | tom@Odysee.com |
| [Sean](https://github.com/seanyesmunt) | The primary engineer working on the app. Feel free to ask any questions about the code. | sean | sean@lbry.com | | [Anthony](https://github.com/mayeaux) | The primary engineer working on the app. Feel free to ask any questions about the code. | Anthony | anthony.mayfield@odysee.com |
Join our Discord [here](https://chat.lbry.com/). Join our Discord [here](https://chat.odysee.com/).
# More Information
More information about contributing to LBRY [here](https://lbry.tech/contribute).

142
README.md
View file

@ -1,130 +1,61 @@
# Odysee Frontend - Odysee.com # Odysee Frontend - Odysee.com
This repo contains the UI and front end code that powers Odysee.com. This repo contains the UI and front end code that powers Odysee.com.
<a href="https://github.com/lbryio/lbry-desktop/blob/master/LICENSE" title="MIT licensed"> <a href="https://github.com/OdyseeTeam/odysee-frontend/blob/master/LICENSE" title="MIT licensed">
<img alt="npm" src="https://img.shields.io/dub/l/vibe-d.svg?style=flat"> <img alt="npm" src="https://img.shields.io/dub/l/vibe-d.svg?style=flat">
</a> </a>
<a href="https://GitHub.com/lbryio/lbry-desktop/releases/" title="GitHub release"> <a href="https://chat.odysee.com">
<img src="https://img.shields.io/github/release/lbryio/lbry-desktop.svg"/> <img src="https://img.shields.io/discord/362322208485277697.svg?logo=discord" alt="chat on Discord">
</a> </a>
<a href="https://travis-ci.org/lbryio/lbry-desktop">
<img src="https://travis-ci.org/lbryio/lbry-desktop.svg?branch=master" alt="Build Status" />
</a>
<a href="https://chat.lbry.com">
<img alt="GitHub contributors" src="https://img.shields.io/discord/362322208485277697.svg?logo=discord" alt="chat on Discord">
</a>
<h2>
<a href="https://forthebadge.com" title="forthebadge">
<img alt="forthebadge" src="https://forthebadge.com/images/badges/60-percent-of-the-time-works-every-time.svg">
</a>
<a href="https://forthebadge.com" title="forthebadge">
<img alt="forthebadge" src="https://forthebadge.com/images/badges/approved-by-veridian-dynamics.svg">
</a>
</h2>
## Table of Contents ## Table of Contents
1. [Install](#install) 1. [Usage](#usage)
2. [Usage](#usage) 2. [Running from Source](#running-from-source)
3. [Running from Source](#running-from-source) 3. [Contributing](#contributing)
4. [Contributing](#contributing) 4. [License](#license)
5. [License](#license) 5. [Security](#security)
6. [Security](#security) 6. [Contact](#contact)
7. [Contact](#contact)
## Install
[![Windows](https://img.shields.io/badge/Windows-Install-blue)](https://lbry.com/get/lbry.exe)
[![Linux](https://img.shields.io/badge/Linux-Install-blue)](https://lbry.com/get/lbry.deb)
[![MacOS](https://img.shields.io/badge/MacOS-Install-blue)](https://lbry.com/get/lbry.dmg)
We provide installers for Windows, macOS (v10.12.4, Sierra, or greater), and Debian-based Linux. See community maintained builds section for alternative Linux installations.
| | Windows | macOS | Linux |
| --------------------- | --------------------------------------------- | --------------------------------------------- | --------------------------------------------- |
| Latest Stable Release | [Download](https://lbry.com/get/lbry.exe) | [Download](https://lbry.com/get/lbry.dmg) | [Download](https://lbry.com/get/lbry.deb) |
| Latest Pre-release | [Download](https://lbry.com/get/lbry.pre.exe) | [Download](https://lbry.com/get/lbry.pre.dmg) | [Download](https://lbry.com/get/lbry.pre.deb) |
Our [releases page](https://github.com/lbryio/lbry-desktop/releases) also contains the latest
release, pre-releases, and past builds.
_Note: If the deb fails to install using the Ubuntu Software Center, install manually via `sudo dpkg -i <path to deb>`. You'll need to run `sudo apt-get install -f` if this is the first time installing it to install dependencies_
To install from source or make changes to the application, continue to the next section below.
**Community maintained** builds for Arch Linux and Flatpak are available, see below. These installs will need to be updated manually as the in-app update process only supports Debian installs at this time.
_Note: If coming from a deb install, the directory structure is different and you'll need to [migrate data](https://lbry.com/faq/backup-data)._
| | Flatpak | Arch | Nixpkgs | ARM/ARM64 |
| -------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------- |
| Latest Release | [FlatHub Page](https://flathub.org/apps/details/io.lbry.lbry-app) | [AUR Package](https://aur.archlinux.org/packages/lbry-app-bin/) | [Nixpkgs](https://search.nixos.org/packages?channel=unstable&show=lbry&query=lbry) | [Build Guide](https://lbry.tv/@LBRYarm:5) |
| Maintainers | [@kcSeb](https://keybase.io/kcseb) | [@kcSeb](https://keybase.io/kcseb) | [@Enderger](https://github.com/enderger) | [@Madiator2011](https://github.com/kodxana) |
## Usage ## Usage
Double click the installed application to interact with the LBRY network. Go to the website to interact on this frontend.
## Running from Source ## Running from Source
You can run the web version (lbry.tv), the electron app, or both at the same time.
#### Prerequisites #### Prerequisites
- [Git](https://git-scm.com/downloads) - [Git](https://git-scm.com/downloads)
- [Node.js](https://nodejs.org/en/download/) (v14 required) - [Node.js](https://nodejs.org/en/download/) (v14 required)
- [Yarn](https://yarnpkg.com/en/docs/install) - [Yarn](https://yarnpkg.com/en/docs/install)
1. Clone (or [fork](https://help.github.com/articles/fork-a-repo/)) this repository: `git clone https://github.com/lbryio/lbry-desktop` 1. Clone (or [fork](https://help.github.com/articles/fork-a-repo/)) this repository: `git clone https://github.com/OdyseeTeam/odysee-frontend`
2. Change directory into the cloned repository: `cd lbry-desktop` 2. Change directory into the cloned repository: `cd odysee-frontend`
3. Install the dependencies: `yarn` 3. Install the dependencies: `yarn`
#### Run the electron app
`yarn dev`
- If you want to build and launch the production app you can run `yarn build`. This will give you an executable inside the `/dist` folder. We use [electron-builder](https://github.com/electron-userland/electron-builder) to create distributable packages.
#### Run the web app for development #### Run the web app for development
`yarn dev:web` `yarn dev:web`
- This uses webpack-dev-server and includes hot-reloading. If you want to debug the [web server we use in production](https://github.com/lbryio/lbry-desktop/blob/master/web/index.js) you can run `yarn dev:web-server`. This starts a server at `localhost:1337` and does not include hot reloading. - This uses `webpack-dev-server` and includes hot-reloading. If you want to debug the [web server we use in production](https://github.com/OdyseeTeam/odysee-frontend/blob/master/web/index.js) you can run `yarn dev:web-server`. This starts a server at `localhost:1337` and does not include hot reloading.
#### Customize the web app #### Customize the web app
- In root directory, duplicate the .env.default file and rename it to .env then copy the code below and paste it anywhere in the .env file. - In root directory, duplicate the `.env.default` file as `.env` and make customizations there.
```
``` cp .env.defaults .env
cp .env.defaults .env nano .env
nano .env ```
``` - To specify your own OG-IMAGE:
- Either place a png named `v2-og.png` in the `/custom` folder or specify the `OG_IMAGE_URL` in .env file.
- To specify your own OG-IMAGE - To specify your own channels to be followed on first run:
You can either place a png named v2-og.png in the /custom folder or specify the OG_IMAGE_URL in .env - `AUTO_FOLLOW_URLS=lbry://@chan#123...a lbry://@chan2#456...a`
- To customize the homepage content:
- To specify your own channels to be followed on first run 1. Add `CUSTOM_HOMEPAGE=true` to the .env file.
`AUTO_FOLLOW_URLS=lbry://@chan#123...a lbry://@chan2#456...a` 2. Copy `/custom/homepage.example.js` to `/custom/homepage.js` and make desired changes to `homepage.js`.
- Finally, run `NODE_ENV=production yarn compile:web` to rebuild.
- If you want to customize the homepage content - _Note: You do not need to edit the `.env` file in the `/web` folder - that is copied during compilation._
1. add `CUSTOM_HOMEPAGE=true` to the '.env' file
2. copy `/custom/homepage.example.js` to `/custom/homepage.js` and make desired changes to `homepage.js`
- If you want up to two custom sidebar links
```
PINNED_URI_1=@someurl#2/someclaim#4
PINNED_LABEL_1=Linktext
PINNED_URI_2=$/discover?t=tag&[queryparams]
PINNED_LABEL_2=OtherLinkText
```
- Finally `NODE_ENV=production yarn compile:web` to rebuild
_Note: You don't need to edit the .env file in the /web folder - that is copied during compile._
#### Deploy the web app (_experimental_) #### Deploy the web app (_experimental_)
@ -136,17 +67,6 @@ PINNED_LABEL_2=OtherLinkText
6. Run `NODE_ENV=production yarn compile:web` to build 6. Run `NODE_ENV=production yarn compile:web` to build
7. Set up pm2 to start ./web/index.js 7. Set up pm2 to start ./web/index.js
#### Run both at the same time
Run the two commands above in separate terminal windows
```
yarn dev
// in another terminal window
yarn dev:web
```
#### Resetting your Packages #### Resetting your Packages
If the app isn't building, or `yarn xxx` commands aren't working you may need to just reset your `node_modules`. To do so you can run: `rm -r node_modules && yarn` or `del /s /q node_modules && yarn` on Windows. If the app isn't building, or `yarn xxx` commands aren't working you may need to just reset your `node_modules`. To do so you can run: `rm -r node_modules && yarn` or `del /s /q node_modules && yarn` on Windows.
@ -155,9 +75,9 @@ If you _really_ think something might have gone wrong, you can force your repo t
## Contributing ## Contributing
We :heart: contributions from everyone and contributions to this project are encouraged, and compensated. We welcome [bug reports](https://github.com/lbryio/lbry-desktop/issues/), [bug fixes](https://github.com/lbryio/lbry-desktop/pulls) and feedback is always appreciated. For more details, see [CONTRIBUTING.md](CONTRIBUTING.md). We :heart: contributions from everyone and contributions to this project are encouraged, and compensated. We welcome [bug reports](https://github.com/OdyseeTeam/odysee-frontend/issues/), [bug fixes](https://github.com/OdyseeTeam/odysee-frontend/pulls) and feedback is always appreciated. For more details, see [CONTRIBUTING.md](CONTRIBUTING.md).
## [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/lbryio/lbry-desktop/issues) [![GitHub contributors](https://img.shields.io/github/contributors/lbryio/lbry-desktop.svg)](https://GitHub.com/lbryio/lbry-desktop/graphs/contributors/) ## [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/OdyseeTeam/odysee-frontend/issues) [![GitHub contributors](https://img.shields.io/github/contributors/lbryio/lbry-desktop.svg)](https://GitHub.com/OdyseeTeam/odysee-frontend/graphs/contributors/)
## License ## License
@ -165,6 +85,4 @@ This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
## Security ## Security
We take security seriously. Please contact security@odysee.com regarding any security issues. Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it. Previous versions up to v0.50.2 were signed by [Sean Yesmunt](https://keybase.io/seanyesmunt/key.asc). For security issues, please reach out to security@odysee.com
New Releases are signed by [Jessop Breth](https://keybase.io/jessopb/key.asc).

View file

@ -3,28 +3,37 @@
require('dotenv-defaults').config({ silent: false }); require('dotenv-defaults').config({ silent: false });
const config = { const config = {
MATOMO_URL: process.env.MATOMO_URL, MINIMUM_VERSION: process.env.MINIMUM_VERSION,
MATOMO_ID: process.env.MATOMO_ID, IGNORE_MINIMUM_VERSION: process.env.IGNORE_MINIMUM_VERSION,
WEBPACK_WEB_PORT: process.env.WEBPACK_WEB_PORT, WEBPACK_WEB_PORT: process.env.WEBPACK_WEB_PORT,
WEBPACK_ELECTRON_PORT: process.env.WEBPACK_ELECTRON_PORT, WEBPACK_ELECTRON_PORT: process.env.WEBPACK_ELECTRON_PORT,
WEB_SERVER_PORT: process.env.WEB_SERVER_PORT, WEB_SERVER_PORT: process.env.WEB_SERVER_PORT,
LBRY_WEB_API: process.env.LBRY_WEB_API, //api.na-backend.odysee.com', LBRY_WEB_API: process.env.LBRY_WEB_API, // api.na-backend.odysee.com',
LBRY_WEB_PUBLISH_API: process.env.LBRY_WEB_PUBLISH_API, LBRY_WEB_PUBLISH_API: process.env.LBRY_WEB_PUBLISH_API,
LBRY_API_URL: process.env.LBRY_API_URL, //api.lbry.com', LBRY_WEB_PUBLISH_API_V2: process.env.LBRY_WEB_PUBLISH_API_V2,
LBRY_WEB_STREAMING_API: process.env.LBRY_WEB_STREAMING_API, //cdn.lbryplayer.xyz', LBRY_API_URL: process.env.LBRY_API_URL, // api.odysee.com',
LBRY_WEB_BUFFER_API: process.env.LBRY_WEB_BUFFER_API, LBRY_WEB_BUFFER_API: process.env.LBRY_WEB_BUFFER_API,
SEARCH_SERVER_API: process.env.SEARCH_SERVER_API, SEARCH_SERVER_API: process.env.SEARCH_SERVER_API,
SEARCH_SERVER_API_ALT: process.env.SEARCH_SERVER_API_ALT,
COMMENT_SERVER_API: process.env.COMMENT_SERVER_API, COMMENT_SERVER_API: process.env.COMMENT_SERVER_API,
COMMENT_SERVER_NAME: process.env.COMMENT_SERVER_NAME,
SOCKETY_SERVER_API: process.env.SOCKETY_SERVER_API, SOCKETY_SERVER_API: process.env.SOCKETY_SERVER_API,
LOCALE_API: process.env.LOCALE_API,
WELCOME_VERSION: process.env.WELCOME_VERSION, WELCOME_VERSION: process.env.WELCOME_VERSION,
DOMAIN: process.env.DOMAIN, DOMAIN: process.env.DOMAIN,
SHARE_DOMAIN_URL: process.env.SHARE_DOMAIN_URL, SHARE_DOMAIN_URL: process.env.SHARE_DOMAIN_URL,
URL: process.env.URL, URL: process.env.URL,
RECSYS_ENDPOINT: process.env.RECSYS_ENDPOINT,
RECSYS_FYP_ENDPOINT: process.env.RECSYS_FYP_ENDPOINT,
IMAGE_PROXY_URL: process.env.IMAGE_PROXY_URL,
THUMBNAIL_CDN_URL: process.env.THUMBNAIL_CDN_URL, THUMBNAIL_CDN_URL: process.env.THUMBNAIL_CDN_URL,
THUMBNAIL_CARDS_CDN_URL: process.env.THUMBNAIL_CARDS_CDN_URL,
THUMBNAIL_HEIGHT: process.env.THUMBNAIL_HEIGHT, THUMBNAIL_HEIGHT: process.env.THUMBNAIL_HEIGHT,
THUMBNAIL_HEIGHT_POSTER: process.env.THUMBNAIL_HEIGHT_POSTER,
THUMBNAIL_WIDTH: process.env.THUMBNAIL_WIDTH, THUMBNAIL_WIDTH: process.env.THUMBNAIL_WIDTH,
THUMBNAIL_WIDTH_POSTER: process.env.THUMBNAIL_WIDTH_POSTER,
THUMBNAIL_QUALITY: process.env.THUMBNAIL_QUALITY, THUMBNAIL_QUALITY: process.env.THUMBNAIL_QUALITY,
THUMBNAIL_CDN_SIZE_LIMIT_BYTES: process.env.THUMBNAIL_CDN_SIZE_LIMIT_BYTES,
PLAYER_SERVER: process.env.PLAYER_SERVER,
SITE_TITLE: process.env.SITE_TITLE, SITE_TITLE: process.env.SITE_TITLE,
SITE_NAME: process.env.SITE_NAME, SITE_NAME: process.env.SITE_NAME,
SITE_DESCRIPTION: process.env.SITE_DESCRIPTION, SITE_DESCRIPTION: process.env.SITE_DESCRIPTION,
@ -33,10 +42,9 @@ const config = {
TWITTER_ACCOUNT: process.env.TWITTER_ACCOUNT, TWITTER_ACCOUNT: process.env.TWITTER_ACCOUNT,
// LOGO // LOGO
LOGO_TITLE: process.env.LOGO_TITLE, LOGO_TITLE: process.env.LOGO_TITLE,
FAVICON: process.env.FAVICON,
LOGO: process.env.LOGO, LOGO: process.env.LOGO,
LOGO_TEXT_LIGHT: process.env.LOGO_TEXT_LIGHT, LOGO_WHITE_TEXT: process.env.LOGO_WHITE_TEXT,
LOGO_TEXT_DARK: process.env.LOGO_TEXT_DARK, LOGO_DARK_TEXT: process.env.LOGO_DARK_TEXT,
AVATAR_DEFAULT: process.env.AVATAR_DEFAULT, AVATAR_DEFAULT: process.env.AVATAR_DEFAULT,
MISSING_THUMB_DEFAULT: process.env.MISSING_THUMB_DEFAULT, MISSING_THUMB_DEFAULT: process.env.MISSING_THUMB_DEFAULT,
// OG // OG
@ -59,15 +67,11 @@ const config = {
ENABLE_NO_SOURCE_CLAIMS: process.env.ENABLE_NO_SOURCE_CLAIMS === 'true', ENABLE_NO_SOURCE_CLAIMS: process.env.ENABLE_NO_SOURCE_CLAIMS === 'true',
ENABLE_PREROLL_ADS: process.env.ENABLE_PREROLL_ADS === 'true', ENABLE_PREROLL_ADS: process.env.ENABLE_PREROLL_ADS === 'true',
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS: process.env.CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS, CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS: process.env.CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS,
CHANNEL_STAKED_LEVEL_LIVESTREAM: process.env.CHANNEL_STAKED_LEVEL_LIVESTREAM, CHANNEL_CREATION_LIMIT: process.env.CHANNEL_CREATION_LIMIT,
WEB_PUBLISH_SIZE_LIMIT_GB: process.env.WEB_PUBLISH_SIZE_LIMIT_GB, WEB_PUBLISH_SIZE_LIMIT_GB: process.env.WEB_PUBLISH_SIZE_LIMIT_GB,
LOADING_BAR_COLOR: process.env.LOADING_BAR_COLOR, LOADING_BAR_COLOR: process.env.LOADING_BAR_COLOR,
SIMPLE_SITE: process.env.SIMPLE_SITE === 'true', SIMPLE_SITE: process.env.SIMPLE_SITE === 'true',
SHOW_ADS: process.env.SHOW_ADS === 'true', SHOW_ADS: process.env.SHOW_ADS === 'true',
PINNED_URI_1: process.env.PINNED_URI_1,
PINNED_LABEL_1: process.env.PINNED_LABEL_1,
PINNED_URI_2: process.env.PINNED_URI_2,
PINNED_LABEL_2: process.env.PINNED_LABEL_2,
KNOWN_APP_DOMAINS: process.env.KNOWN_APP_DOMAINS ? process.env.KNOWN_APP_DOMAINS.split(',') : [], KNOWN_APP_DOMAINS: process.env.KNOWN_APP_DOMAINS ? process.env.KNOWN_APP_DOMAINS.split(',') : [],
STRIPE_PUBLIC_KEY: process.env.STRIPE_PUBLIC_KEY, STRIPE_PUBLIC_KEY: process.env.STRIPE_PUBLIC_KEY,
ENABLE_UI_NOTIFICATIONS: process.env.ENABLE_UI_NOTIFICATIONS === 'true', ENABLE_UI_NOTIFICATIONS: process.env.ENABLE_UI_NOTIFICATIONS === 'true',
@ -76,9 +80,30 @@ const config = {
SHOW_TAGS_INTRO: process.env.SHOW_TAGS_INTRO === 'true', SHOW_TAGS_INTRO: process.env.SHOW_TAGS_INTRO === 'true',
LIGHTHOUSE_DEFAULT_TYPES: process.env.LIGHTHOUSE_DEFAULT_TYPES, LIGHTHOUSE_DEFAULT_TYPES: process.env.LIGHTHOUSE_DEFAULT_TYPES,
BRANDED_SITE: process.env.BRANDED_SITE, BRANDED_SITE: process.env.BRANDED_SITE,
// FIREBASE SDK
FIREBASE_API_KEY: process.env.FIREBASE_API_KEY,
FIREBASE_AUTH_DOMAIN: process.env.FIREBASE_AUTH_DOMAIN,
FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID,
FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET,
FIREBASE_MESSAGING_SENDER_ID: process.env.FIREBASE_MESSAGING_SENDER_ID,
FIREBASE_APP_ID: process.env.FIREBASE_APP_ID,
FIREBASE_MEASUREMENT_ID: process.env.FIREBASE_MEASUREMENT_ID,
FIREBASE_VAPID_KEY: process.env.FIREBASE_VAPID_KEY,
AD_KEYWORD_BLOCKLIST: process.env.AD_KEYWORD_BLOCKLIST,
AD_KEYWORD_BLOCKLIST_CHECK_DESCRIPTION: process.env.AD_KEYWORD_BLOCKLIST_CHECK_DESCRIPTION,
// FROM COMMAND LINE
COMMIT_ID: process.env.COMMIT_ID,
NODE_ENV: process.env.NODE_ENV,
}; };
config.SDK_API_PATH = `${config.LBRY_WEB_API}/api/v1`;
config.PROXY_URL = `${config.SDK_API_PATH}/proxy`;
config.URL_DEV = `http://localhost:${config.WEBPACK_WEB_PORT}`; config.URL_DEV = `http://localhost:${config.WEBPACK_WEB_PORT}`;
config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`; config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`;
config.FAVICON = `/public/favicon-spaceman.png`;
module.exports = config; module.exports = config;

View file

@ -1,7 +1,7 @@
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import { spawn, execSync } from 'child_process'; import { spawn, execSync } from 'child_process';
import { Lbry } from 'lbry-redux'; import Lbry from 'lbry';
export default class Daemon { export default class Daemon {
static lbrynetPath = static lbrynetPath =

View file

@ -6,7 +6,7 @@ import SemVer from 'semver';
import https from 'https'; import https from 'https';
import { app, dialog, ipcMain, session, shell } from 'electron'; import { app, dialog, ipcMain, session, shell } from 'electron';
import { autoUpdater } from 'electron-updater'; import { autoUpdater } from 'electron-updater';
import { Lbry } from 'lbry-redux'; import Lbry from 'lbry';
import LbryFirstInstance from './LbryFirstInstance'; import LbryFirstInstance from './LbryFirstInstance';
import Daemon from './Daemon'; import Daemon from './Daemon';
import isDev from 'electron-is-dev'; import isDev from 'electron-is-dev';

View file

@ -1,5 +1,4 @@
import { app, Menu, shell } from 'electron'; import { app, Menu, shell } from 'electron';
import { ZOOM } from 'util/zoomWindow';
export default () => { export default () => {
const template = [ const template = [
@ -23,38 +22,6 @@ export default () => {
label: 'View', label: 'View',
submenu: [ submenu: [
{ role: 'reload' }, { role: 'reload' },
{
label: 'Zoom',
submenu: [
{
label: 'Zoom In',
accelerator: 'CmdOrCtrl+=',
click: (menuItem, browserWindow) => {
if (browserWindow) {
browserWindow.webContents.send('zoom-window', ZOOM.INCREMENT);
}
},
},
{
label: 'Zoom Out',
accelerator: 'CmdOrCtrl+-',
click: (menuItem, browserWindow) => {
if (browserWindow) {
browserWindow.webContents.send('zoom-window', ZOOM.DECREMENT);
}
},
},
{
label: 'Reset Zoom',
accelerator: 'CmdOrCtrl+0',
click: (menuItem, browserWindow) => {
if (browserWindow) {
browserWindow.webContents.send('zoom-window', ZOOM.RESET);
}
},
},
],
},
{ {
label: 'Developer', label: 'Developer',
submenu: [{ role: 'forcereload' }, { role: 'toggledevtools' }], submenu: [{ role: 'forcereload' }, { role: 'toggledevtools' }],

View file

@ -8,7 +8,7 @@ if (typeof global.fetch === 'object') {
global.fetch = global.fetch.default; global.fetch = global.fetch.default;
} }
const { Lbry } = require('lbry-redux'); const Lbry = require('lbry');
delete global.window; delete global.window;

View file

@ -0,0 +1,184 @@
// @flow
/*
LBRY FIRST does not work due to api changes
*/
import 'proxy-polyfill';
const CHECK_LBRYFIRST_STARTED_TRY_NUMBER = 200;
//
// Basic LBRYFIRST connection config
// Offers a proxy to call LBRYFIRST methods
//
const LbryFirst: LbryFirstTypes = {
isConnected: false,
connectPromise: null,
lbryFirstConnectionString: 'http://localhost:1337/rpc',
apiRequestHeaders: { 'Content-Type': 'application/json' },
// Allow overriding lbryFirst connection string (e.g. to `/api/proxy` for lbryweb)
setLbryFirstConnectionString: (value: string) => {
LbryFirst.lbryFirstConnectionString = value;
},
setApiHeader: (key: string, value: string) => {
LbryFirst.apiRequestHeaders = Object.assign(LbryFirst.apiRequestHeaders, { [key]: value });
},
unsetApiHeader: key => {
Object.keys(LbryFirst.apiRequestHeaders).includes(key) &&
delete LbryFirst.apiRequestHeaders['key'];
},
// Allow overriding Lbry methods
overrides: {},
setOverride: (methodName, newMethod) => {
LbryFirst.overrides[methodName] = newMethod;
},
getApiRequestHeaders: () => LbryFirst.apiRequestHeaders,
// LbryFirst Methods
status: (params = {}) => lbryFirstCallWithResult('status', params),
stop: () => lbryFirstCallWithResult('stop', {}),
version: () => lbryFirstCallWithResult('version', {}),
// Upload to youtube
upload: (params: { title: string, description: string, file_path: ?string } = {}) => {
// Only upload when originally publishing for now
if (!params.file_path) {
return Promise.resolve();
}
const uploadParams: {
Title: string,
Description: string,
FilePath: string,
Category: string,
Keywords: string,
} = {
Title: params.title,
Description: params.description,
FilePath: params.file_path,
Category: '',
Keywords: '',
};
return lbryFirstCallWithResult('youtube.Upload', uploadParams);
},
hasYTAuth: (token: string) => {
const hasYTAuthParams = {};
hasYTAuthParams.AuthToken = token;
return lbryFirstCallWithResult('youtube.HasAuth', hasYTAuthParams);
},
ytSignup: () => {
const emptyParams = {};
return lbryFirstCallWithResult('youtube.Signup', emptyParams);
},
remove: () => {
const emptyParams = {};
return lbryFirstCallWithResult('youtube.Remove', emptyParams);
},
// Connect to lbry-first
connect: () => {
if (LbryFirst.connectPromise === null) {
LbryFirst.connectPromise = new Promise((resolve, reject) => {
let tryNum = 0;
// Check every half second to see if the lbryFirst is accepting connections
function checkLbryFirstStarted() {
tryNum += 1;
LbryFirst.status()
.then(resolve)
.catch(() => {
if (tryNum <= CHECK_LBRYFIRST_STARTED_TRY_NUMBER) {
setTimeout(checkLbryFirstStarted, tryNum < 50 ? 400 : 1000);
} else {
reject(new Error('Unable to connect to LBRY'));
}
});
}
checkLbryFirstStarted();
});
}
// Flow thinks this could be empty, but it will always return a promise
// $FlowFixMe
return LbryFirst.connectPromise;
},
};
function checkAndParse(response) {
if (response.status >= 200 && response.status < 300) {
return response.json();
}
return response.json().then(json => {
let error;
if (json.error) {
const errorMessage = typeof json.error === 'object' ? json.error.message : json.error;
error = new Error(errorMessage);
} else {
error = new Error('Protocol error with unknown response signature');
}
return Promise.reject(error);
});
}
export function apiCall(method: string, params: ?{}, resolve: Function, reject: Function) {
const counter = new Date().getTime();
const paramsArray = [params];
const options = {
method: 'POST',
headers: LbryFirst.apiRequestHeaders,
body: JSON.stringify({
jsonrpc: '2.0',
method,
params: paramsArray,
id: counter,
}),
};
return fetch(LbryFirst.lbryFirstConnectionString, options)
.then(checkAndParse)
.then(response => {
const error = response.error || (response.result && response.result.error);
if (error) {
return reject(error);
}
return resolve(response.result);
})
.catch(reject);
}
function lbryFirstCallWithResult(name: string, params: ?{} = {}) {
return new Promise((resolve, reject) => {
apiCall(
name,
params,
result => {
resolve(result);
},
reject
);
});
}
// This is only for a fallback
// If there is a LbryFirst method that is being called by an app, it should be added to /flow-typed/LbryFirst.js
const lbryFirstProxy = new Proxy(LbryFirst, {
get(target: LbryFirstTypes, name: string) {
if (name in target) {
return target[name];
}
return (params = {}) =>
new Promise((resolve, reject) => {
apiCall(name, params, resolve, reject);
});
},
});
export default lbryFirstProxy;

View file

@ -0,0 +1,89 @@
// Claims
export const FETCH_FEATURED_CONTENT_STARTED = 'FETCH_FEATURED_CONTENT_STARTED';
export const FETCH_FEATURED_CONTENT_COMPLETED = 'FETCH_FEATURED_CONTENT_COMPLETED';
export const FETCH_TRENDING_CONTENT_STARTED = 'FETCH_TRENDING_CONTENT_STARTED';
export const FETCH_TRENDING_CONTENT_COMPLETED = 'FETCH_TRENDING_CONTENT_COMPLETED';
export const RESOLVE_URIS_STARTED = 'RESOLVE_URIS_STARTED';
export const RESOLVE_URIS_COMPLETED = 'RESOLVE_URIS_COMPLETED';
export const FETCH_CHANNEL_CLAIMS_STARTED = 'FETCH_CHANNEL_CLAIMS_STARTED';
export const FETCH_CHANNEL_CLAIMS_COMPLETED = 'FETCH_CHANNEL_CLAIMS_COMPLETED';
export const FETCH_CHANNEL_CLAIM_COUNT_STARTED = 'FETCH_CHANNEL_CLAIM_COUNT_STARTED';
export const FETCH_CHANNEL_CLAIM_COUNT_COMPLETED = 'FETCH_CHANNEL_CLAIM_COUNT_COMPLETED';
export const FETCH_CLAIM_LIST_MINE_STARTED = 'FETCH_CLAIM_LIST_MINE_STARTED';
export const FETCH_CLAIM_LIST_MINE_COMPLETED = 'FETCH_CLAIM_LIST_MINE_COMPLETED';
export const ABANDON_CLAIM_STARTED = 'ABANDON_CLAIM_STARTED';
export const ABANDON_CLAIM_SUCCEEDED = 'ABANDON_CLAIM_SUCCEEDED';
export const FETCH_CHANNEL_LIST_STARTED = 'FETCH_CHANNEL_LIST_STARTED';
export const FETCH_CHANNEL_LIST_COMPLETED = 'FETCH_CHANNEL_LIST_COMPLETED';
export const CREATE_CHANNEL_STARTED = 'CREATE_CHANNEL_STARTED';
export const CREATE_CHANNEL_COMPLETED = 'CREATE_CHANNEL_COMPLETED';
export const SET_PLAYING_URI = 'SET_PLAYING_URI';
export const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION';
export const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED';
export const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI';
export const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL';
// Subscriptions
export const CHANNEL_SUBSCRIBE = 'CHANNEL_SUBSCRIBE';
export const CHANNEL_UNSUBSCRIBE = 'CHANNEL_UNSUBSCRIBE';
export const CHANNEL_SUBSCRIPTION_ENABLE_NOTIFICATIONS = 'CHANNEL_SUBSCRIPTION_ENABLE_NOTIFICATIONS';
export const CHANNEL_SUBSCRIPTION_DISABLE_NOTIFICATIONS = 'CHANNEL_SUBSCRIPTION_DISABLE_NOTIFICATIONS';
export const HAS_FETCHED_SUBSCRIPTIONS = 'HAS_FETCHED_SUBSCRIPTIONS';
export const SET_SUBSCRIPTION_LATEST = 'SET_SUBSCRIPTION_LATEST';
export const UPDATE_SUBSCRIPTION_UNREADS = 'UPDATE_SUBSCRIPTION_UNREADS';
export const REMOVE_SUBSCRIPTION_UNREADS = 'REMOVE_SUBSCRIPTION_UNREADS';
export const CHECK_SUBSCRIPTION_STARTED = 'CHECK_SUBSCRIPTION_STARTED';
export const CHECK_SUBSCRIPTION_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
export const CHECK_SUBSCRIPTIONS_SUBSCRIBE = 'CHECK_SUBSCRIPTIONS_SUBSCRIBE';
export const FETCH_SUBSCRIPTIONS_START = 'FETCH_SUBSCRIPTIONS_START';
export const FETCH_SUBSCRIPTIONS_FAIL = 'FETCH_SUBSCRIPTIONS_FAIL';
export const FETCH_SUBSCRIPTIONS_SUCCESS = 'FETCH_SUBSCRIPTIONS_SUCCESS';
export const SET_VIEW_MODE = 'SET_VIEW_MODE';
export const GET_SUGGESTED_SUBSCRIPTIONS_START = 'GET_SUGGESTED_SUBSCRIPTIONS_START';
export const GET_SUGGESTED_SUBSCRIPTIONS_SUCCESS = 'GET_SUGGESTED_SUBSCRIPTIONS_SUCCESS';
export const GET_SUGGESTED_SUBSCRIPTIONS_FAIL = 'GET_SUGGESTED_SUBSCRIPTIONS_FAIL';
export const SUBSCRIPTION_FIRST_RUN_COMPLETED = 'SUBSCRIPTION_FIRST_RUN_COMPLETED';
export const VIEW_SUGGESTED_SUBSCRIPTIONS = 'VIEW_SUGGESTED_SUBSCRIPTIONS';
// Blacklist
export const FETCH_BLACK_LISTED_CONTENT_STARTED = 'FETCH_BLACK_LISTED_CONTENT_STARTED';
export const FETCH_BLACK_LISTED_CONTENT_COMPLETED = 'FETCH_BLACK_LISTED_CONTENT_COMPLETED';
export const FETCH_BLACK_LISTED_CONTENT_FAILED = 'FETCH_BLACK_LISTED_CONTENT_FAILED';
export const BLACK_LISTED_CONTENT_SUBSCRIBE = 'BLACK_LISTED_CONTENT_SUBSCRIBE';
// Filtered list
export const FETCH_FILTERED_CONTENT_STARTED = 'FETCH_FILTERED_CONTENT_STARTED';
export const FETCH_FILTERED_CONTENT_COMPLETED = 'FETCH_FILTERED_CONTENT_COMPLETED';
export const FETCH_FILTERED_CONTENT_FAILED = 'FETCH_FILTERED_CONTENT_FAILED';
export const FILTERED_CONTENT_SUBSCRIBE = 'FILTERED_CONTENT_SUBSCRIBE';
// Cost Info
export const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED';
export const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED';
// Stats
export const FETCH_VIEW_COUNT_STARTED = 'FETCH_VIEW_COUNT_STARTED';
export const FETCH_VIEW_COUNT_FAILED = 'FETCH_VIEW_COUNT_FAILED';
export const FETCH_VIEW_COUNT_COMPLETED = 'FETCH_VIEW_COUNT_COMPLETED';
export const FETCH_SUB_COUNT_STARTED = 'FETCH_SUB_COUNT_STARTED';
export const FETCH_SUB_COUNT_FAILED = 'FETCH_SUB_COUNT_FAILED';
export const FETCH_SUB_COUNT_COMPLETED = 'FETCH_SUB_COUNT_COMPLETED';
// Cross-device Sync
export const GET_SYNC_STARTED = 'GET_SYNC_STARTED';
export const GET_SYNC_COMPLETED = 'GET_SYNC_COMPLETED';
export const GET_SYNC_FAILED = 'GET_SYNC_FAILED';
export const SET_SYNC_STARTED = 'SET_SYNC_STARTED';
export const SET_SYNC_FAILED = 'SET_SYNC_FAILED';
export const SET_SYNC_COMPLETED = 'SET_SYNC_COMPLETED';
export const SET_DEFAULT_ACCOUNT = 'SET_DEFAULT_ACCOUNT';
export const SYNC_APPLY_STARTED = 'SYNC_APPLY_STARTED';
export const SYNC_APPLY_COMPLETED = 'SYNC_APPLY_COMPLETED';
export const SYNC_APPLY_FAILED = 'SYNC_APPLY_FAILED';
export const SYNC_APPLY_BAD_PASSWORD = 'SYNC_APPLY_BAD_PASSWORD';
export const SYNC_RESET = 'SYNC_RESET';
// User
export const GENERATE_AUTH_TOKEN_FAILURE = 'GENERATE_AUTH_TOKEN_FAILURE';
export const GENERATE_AUTH_TOKEN_STARTED = 'GENERATE_AUTH_TOKEN_STARTED';
export const GENERATE_AUTH_TOKEN_SUCCESS = 'GENERATE_AUTH_TOKEN_SUCCESS';

View file

@ -0,0 +1,5 @@
export const MINIMUM_PUBLISH_BID = 0.00000001;
export const CHANNEL_ANONYMOUS = 'anonymous';
export const CHANNEL_NEW = 'new';
export const PAGE_SIZE = 20;

View file

@ -0,0 +1,4 @@
export const ALREADY_CLAIMED =
'once the invite reward has been claimed the referrer cannot be changed';
export const REFERRER_NOT_FOUND =
'A lbry.tv account could not be found for the referrer you provided.';

View file

@ -0,0 +1,11 @@
export const YOUTUBE_SYNC_NOT_TRANSFERRED = 'not_transferred';
export const YOUTUBE_SYNC_PENDING = 'pending';
export const YOUTUBE_SYNC_PENDING_EMAIL = 'pendingemail';
export const YOUTUBE_SYNC_PENDING_TRANSFER = 'pending_transfer';
export const YOUTUBE_SYNC_COMPLETED_TRANSFER = 'completed_transfer';
export const YOUTUBE_SYNC_QUEUED = 'queued';
export const YOUTUBE_SYNC_SYNCING = 'syncing';
export const YOUTUBE_SYNC_SYNCED = 'synced';
export const YOUTUBE_SYNC_FAILED = 'failed';
export const YOUTUBE_SYNC_PENDINGUPGRADE = 'pendingupgrade';
export const YOUTUBE_SYNC_ABANDONDED = 'abandoned';

70
extras/lbryinc/index.js Normal file
View file

@ -0,0 +1,70 @@
import * as LBRYINC_ACTIONS from 'constants/action_types';
import * as YOUTUBE_STATUSES from 'constants/youtube';
import * as ERRORS from 'constants/errors';
import Lbryio from './lbryio';
export { Lbryio };
// constants
export { LBRYINC_ACTIONS, YOUTUBE_STATUSES, ERRORS };
// utils
export { doTransifexUpload } from 'util/transifex-upload';
// actions
export { doGenerateAuthToken } from './redux/actions/auth';
export { doFetchCostInfoForUri } from './redux/actions/cost_info';
export { doBlackListedOutpointsSubscribe } from './redux/actions/blacklist';
export { doFilteredOutpointsSubscribe } from './redux/actions/filtered';
// export { doFetchFeaturedUris, doFetchTrendingUris } from './redux/actions/homepage';
export { doFetchViewCount, doFetchSubCount } from './redux/actions/stats';
export {
doCheckSync,
doGetSync,
doSetSync,
doSetDefaultAccount,
doSyncApply,
doResetSync,
doSyncEncryptAndDecrypt,
} from 'redux/actions/sync';
// reducers
export { authReducer } from './redux/reducers/auth';
export { costInfoReducer } from './redux/reducers/cost_info';
export { blacklistReducer } from './redux/reducers/blacklist';
export { filteredReducer } from './redux/reducers/filtered';
// export { homepageReducer } from './redux/reducers/homepage';
export { statsReducer } from './redux/reducers/stats';
export { syncReducer } from './redux/reducers/sync';
// selectors
export { selectAuthToken, selectIsAuthenticating } from './redux/selectors/auth';
export {
selectFetchingCostInfoForUri,
selectCostInfoForUri,
selectAllCostInfoByUri,
selectFetchingCostInfo,
} from './redux/selectors/cost_info';
export { selectBlackListedOutpoints, selectBlacklistedOutpointMap } from './redux/selectors/blacklist';
export { selectFilteredOutpoints, selectFilteredOutpointMap } from './redux/selectors/filtered';
// export {
// selectFeaturedUris,
// selectFetchingFeaturedUris,
// selectTrendingUris,
// selectFetchingTrendingUris,
// } from './redux/selectors/homepage';
export { selectViewCount, selectViewCountForUri, selectSubCountForUri } from './redux/selectors/stats';
export { selectBanStateForUri } from './redux/selectors/ban';
export {
selectHasSyncedWallet,
selectSyncData,
selectSyncHash,
selectSetSyncErrorMessage,
selectGetSyncErrorMessage,
selectGetSyncIsPending,
selectSetSyncIsPending,
selectSyncApplyIsPending,
selectHashChanged,
selectSyncApplyErrorMessage,
selectSyncApplyPasswordError,
} from './redux/selectors/sync';

259
extras/lbryinc/lbryio.js Normal file
View file

@ -0,0 +1,259 @@
import * as ACTIONS from 'constants/action_types';
import Lbry from 'lbry';
import querystring from 'querystring';
import analytics from 'analytics';
const Lbryio = {
enabled: true,
authenticationPromise: null,
exchangePromise: null,
exchangeLastFetched: null,
CONNECTION_STRING: 'https://api.lbry.com/',
};
const EXCHANGE_RATE_TIMEOUT = 20 * 60 * 1000;
const INTERNAL_APIS_DOWN = 'internal_apis_down';
// We can't use env's because they aren't passed into node_modules
Lbryio.setLocalApi = (endpoint) => {
Lbryio.CONNECTION_STRING = endpoint.replace(/\/*$/, '/'); // exactly one slash at the end;
};
Lbryio.call = (resource, action, params = {}, method = 'get') => {
if (!Lbryio.enabled) {
return Promise.reject(new Error(__('LBRY internal API is disabled')));
}
if (!(method === 'get' || method === 'post')) {
return Promise.reject(new Error(__('Invalid method')));
}
function checkAndParse(response) {
if (response.status >= 200 && response.status < 300) {
return response.json();
}
if (response.status === 500) {
return Promise.reject(INTERNAL_APIS_DOWN);
}
if (response) {
return response.json().then((json) => {
let error;
if (json.error) {
error = new Error(json.error);
} else {
error = new Error('Unknown API error signature');
}
error.response = response; // This is primarily a hack used in actions/user.js
return Promise.reject(error);
});
}
}
function makeRequest(url, options) {
return fetch(url, options).then(checkAndParse);
}
return Lbryio.getAuthToken().then((token) => {
const fullParams = { auth_token: token, ...params };
Object.keys(fullParams).forEach((key) => {
const value = fullParams[key];
if (typeof value === 'object') {
fullParams[key] = JSON.stringify(value);
}
});
const qs = querystring.stringify(fullParams);
let url = `${Lbryio.CONNECTION_STRING}${resource}/${action}?${qs}`;
let options = {
method: 'GET',
};
if (method === 'post') {
options = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: qs,
};
url = `${Lbryio.CONNECTION_STRING}${resource}/${action}`;
}
return makeRequest(url, options).then((response) => {
sendCallAnalytics(resource, action, params);
return response.data;
});
});
};
Lbryio.authToken = null;
Lbryio.getAuthToken = () =>
new Promise((resolve) => {
if (Lbryio.authToken) {
resolve(Lbryio.authToken);
} else if (Lbryio.overrides.getAuthToken) {
Lbryio.overrides.getAuthToken().then((token) => {
resolve(token);
});
} else if (typeof window !== 'undefined') {
const { store } = window;
if (store) {
const state = store.getState();
const token = state.auth ? state.auth.authToken : null;
Lbryio.authToken = token;
resolve(token);
}
resolve(null);
} else {
resolve(null);
}
});
Lbryio.getCurrentUser = () => Lbryio.call('user', 'me');
Lbryio.authenticate = (domain, language) => {
if (!Lbryio.enabled) {
const params = {
id: 1,
primary_email: 'disabled@lbry.io',
has_verified_email: true,
is_identity_verified: true,
is_reward_approved: false,
language: language || 'en',
};
return new Promise((resolve) => {
resolve(params);
});
}
if (Lbryio.authenticationPromise === null) {
Lbryio.authenticationPromise = new Promise((resolve, reject) => {
Lbryio.getAuthToken()
.then((token) => {
if (!token || token.length > 60) {
return false;
}
// check that token works
return Lbryio.getCurrentUser()
.then((user) => user)
.catch((error) => {
if (error === INTERNAL_APIS_DOWN) {
throw new Error('Internal APIS down');
}
return false;
});
})
.then((user) => {
if (user) {
return user;
}
return Lbry.status()
.then(
(status) =>
new Promise((res, rej) => {
const appId =
domain && domain !== 'lbry.tv'
? (domain.replace(/[.]/gi, '') + status.installation_id).slice(0, 66)
: status.installation_id;
Lbryio.call(
'user',
'new',
{
auth_token: '',
language: language || 'en',
app_id: appId,
},
'post'
)
.then((response) => {
if (!response.auth_token) {
throw new Error('auth_token was not set in the response');
}
const { store } = window;
if (Lbryio.overrides.setAuthToken) {
Lbryio.overrides.setAuthToken(response.auth_token);
}
if (store) {
store.dispatch({
type: ACTIONS.GENERATE_AUTH_TOKEN_SUCCESS,
data: { authToken: response.auth_token },
});
}
Lbryio.authToken = response.auth_token;
return res(response);
})
.catch((error) => rej(error));
})
)
.then((newUser) => {
if (!newUser) {
return Lbryio.getCurrentUser();
}
return newUser;
});
})
.then(resolve, reject);
});
}
return Lbryio.authenticationPromise;
};
Lbryio.getStripeToken = () =>
Lbryio.CONNECTION_STRING.startsWith('http://localhost:')
? 'pk_test_NoL1JWL7i1ipfhVId5KfDZgo'
: 'pk_live_e8M4dRNnCCbmpZzduEUZBgJO';
Lbryio.getExchangeRates = () => {
if (!Lbryio.exchangeLastFetched || Date.now() - Lbryio.exchangeLastFetched > EXCHANGE_RATE_TIMEOUT) {
Lbryio.exchangePromise = new Promise((resolve, reject) => {
Lbryio.call('lbc', 'exchange_rate', {}, 'get', true)
.then(({ lbc_usd: LBC_USD, lbc_btc: LBC_BTC, btc_usd: BTC_USD }) => {
const rates = { LBC_USD, LBC_BTC, BTC_USD };
resolve(rates);
})
.catch(reject);
});
Lbryio.exchangeLastFetched = Date.now();
}
return Lbryio.exchangePromise;
};
// Allow overriding lbryio methods
// The desktop app will need to use it for getAuthToken because we use electron's ipcRenderer
Lbryio.overrides = {};
Lbryio.setOverride = (methodName, newMethod) => {
Lbryio.overrides[methodName] = newMethod;
};
function sendCallAnalytics(resource, action, params) {
switch (resource) {
case 'customer':
if (action === 'tip') {
analytics.reportEvent('spend_virtual_currency', {
// https://developers.google.com/analytics/devguides/collection/ga4/reference/events#spend_virtual_currency
value: params.amount,
virtual_currency_name: params.currency.toLowerCase(),
item_name: 'tip',
});
}
break;
default:
// Do nothing
break;
}
}
export default Lbryio;

View file

@ -0,0 +1,38 @@
import * as ACTIONS from 'constants/action_types';
import { Lbryio } from 'lbryinc';
export function doGenerateAuthToken(installationId) {
return dispatch => {
dispatch({
type: ACTIONS.GENERATE_AUTH_TOKEN_STARTED,
});
Lbryio.call(
'user',
'new',
{
auth_token: '',
language: 'en',
app_id: installationId,
},
'post'
)
.then(response => {
if (!response.auth_token) {
dispatch({
type: ACTIONS.GENERATE_AUTH_TOKEN_FAILURE,
});
} else {
dispatch({
type: ACTIONS.GENERATE_AUTH_TOKEN_SUCCESS,
data: { authToken: response.auth_token },
});
}
})
.catch(() => {
dispatch({
type: ACTIONS.GENERATE_AUTH_TOKEN_FAILURE,
});
});
};
}

View file

@ -0,0 +1,52 @@
import { Lbryio } from 'lbryinc';
import * as ACTIONS from 'constants/action_types';
const CHECK_BLACK_LISTED_CONTENT_INTERVAL = 60 * 60 * 1000;
export function doFetchBlackListedOutpoints() {
return dispatch => {
dispatch({
type: ACTIONS.FETCH_BLACK_LISTED_CONTENT_STARTED,
});
const success = ({ outpoints }) => {
const splitOutpoints = [];
if (outpoints) {
outpoints.forEach((outpoint, index) => {
const [txid, nout] = outpoint.split(':');
splitOutpoints[index] = { txid, nout: Number.parseInt(nout, 10) };
});
}
dispatch({
type: ACTIONS.FETCH_BLACK_LISTED_CONTENT_COMPLETED,
data: {
outpoints: splitOutpoints,
success: true,
},
});
};
const failure = ({ message: error }) => {
dispatch({
type: ACTIONS.FETCH_BLACK_LISTED_CONTENT_FAILED,
data: {
error,
success: false,
},
});
};
Lbryio.call('file', 'list_blocked', {
auth_token: '',
}).then(success, failure);
};
}
export function doBlackListedOutpointsSubscribe() {
return dispatch => {
dispatch(doFetchBlackListedOutpoints());
setInterval(() => dispatch(doFetchBlackListedOutpoints()), CHECK_BLACK_LISTED_CONTENT_INTERVAL);
};
}

View file

@ -0,0 +1,37 @@
// @flow
import * as ACTIONS from 'constants/action_types';
import { Lbryio } from 'lbryinc';
import { selectClaimForUri } from 'redux/selectors/claims';
// eslint-disable-next-line import/prefer-default-export
export function doFetchCostInfoForUri(uri: string) {
return async (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const claim = selectClaimForUri(state, uri);
if (!claim) return;
const fee = claim.value ? claim.value.fee : undefined;
let costInfo;
if (fee === undefined) {
costInfo = { cost: 0, includesData: true };
} else if (fee.currency === 'LBC') {
costInfo = { cost: fee.amount, includesData: true };
} else {
await Lbryio.getExchangeRates().then(({ LBC_USD }) => {
costInfo = { cost: fee.amount / LBC_USD, includesData: true };
});
}
dispatch({
type: ACTIONS.FETCH_COST_INFO_COMPLETED,
data: {
uri,
costInfo,
},
});
return costInfo;
};
}

View file

@ -0,0 +1,47 @@
import { Lbryio } from 'lbryinc';
import * as ACTIONS from 'constants/action_types';
const CHECK_FILTERED_CONTENT_INTERVAL = 60 * 60 * 1000;
export function doFetchFilteredOutpoints() {
return dispatch => {
dispatch({
type: ACTIONS.FETCH_FILTERED_CONTENT_STARTED,
});
const success = ({ outpoints }) => {
let formattedOutpoints = [];
if (outpoints) {
formattedOutpoints = outpoints.map(outpoint => {
const [txid, nout] = outpoint.split(':');
return { txid, nout: Number.parseInt(nout, 10) };
});
}
dispatch({
type: ACTIONS.FETCH_FILTERED_CONTENT_COMPLETED,
data: {
outpoints: formattedOutpoints,
},
});
};
const failure = ({ error }) => {
dispatch({
type: ACTIONS.FETCH_FILTERED_CONTENT_FAILED,
data: {
error,
},
});
};
Lbryio.call('file', 'list_filtered', { auth_token: '' }).then(success, failure);
};
}
export function doFilteredOutpointsSubscribe() {
return dispatch => {
dispatch(doFetchFilteredOutpoints());
setInterval(() => dispatch(doFetchFilteredOutpoints()), CHECK_FILTERED_CONTENT_INTERVAL);
};
}

View file

@ -0,0 +1,79 @@
import { Lbryio } from 'lbryinc';
import { batchActions } from 'util/batch-actions';
import { doResolveUris } from 'util/lbryURI';
import * as ACTIONS from 'constants/action_types';
export function doFetchFeaturedUris(offloadResolve = false) {
return dispatch => {
dispatch({
type: ACTIONS.FETCH_FEATURED_CONTENT_STARTED,
});
const success = ({ Uris }) => {
let urisToResolve = [];
Object.keys(Uris).forEach(category => {
urisToResolve = [...urisToResolve, ...Uris[category]];
});
const actions = [
{
type: ACTIONS.FETCH_FEATURED_CONTENT_COMPLETED,
data: {
uris: Uris,
success: true,
},
},
];
if (urisToResolve.length && !offloadResolve) {
actions.push(doResolveUris(urisToResolve));
}
dispatch(batchActions(...actions));
};
const failure = () => {
dispatch({
type: ACTIONS.FETCH_FEATURED_CONTENT_COMPLETED,
data: {
uris: {},
},
});
};
Lbryio.call('file', 'list_homepage').then(success, failure);
};
}
export function doFetchTrendingUris() {
return dispatch => {
dispatch({
type: ACTIONS.FETCH_TRENDING_CONTENT_STARTED,
});
const success = data => {
const urisToResolve = data.map(uri => uri.url);
const actions = [
doResolveUris(urisToResolve),
{
type: ACTIONS.FETCH_TRENDING_CONTENT_COMPLETED,
data: {
uris: data,
success: true,
},
},
];
dispatch(batchActions(...actions));
};
const failure = () => {
dispatch({
type: ACTIONS.FETCH_TRENDING_CONTENT_COMPLETED,
data: {
uris: [],
},
});
};
Lbryio.call('file', 'list_trending').then(success, failure);
};
}

View file

@ -0,0 +1,68 @@
// @flow
import { Lbryio } from 'lbryinc';
import * as ACTIONS from 'constants/action_types';
const FETCH_SUB_COUNT_MIN_INTERVAL_MS = 5 * 60 * 1000;
const FETCH_SUB_COUNT_IDLE_FIRE_MS = 100;
export const doFetchViewCount = (claimIdCsv: string) => (dispatch: Dispatch) => {
dispatch({ type: ACTIONS.FETCH_VIEW_COUNT_STARTED });
return Lbryio.call('file', 'view_count', { claim_id: claimIdCsv })
.then((result: Array<number>) => {
const viewCounts = result;
dispatch({ type: ACTIONS.FETCH_VIEW_COUNT_COMPLETED, data: { claimIdCsv, viewCounts } });
})
.catch((error) => {
dispatch({ type: ACTIONS.FETCH_VIEW_COUNT_FAILED, data: error });
});
};
const executeFetchSubCount = (claimIdCsv: string) => (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const subCountLastFetchedById = state.stats.subCountLastFetchedById;
const now = Date.now();
const claimIds = claimIdCsv.split(',').filter((id) => {
const prev = subCountLastFetchedById[id];
return !prev || now - prev > FETCH_SUB_COUNT_MIN_INTERVAL_MS;
});
if (claimIds.length === 0) {
return;
}
dispatch({ type: ACTIONS.FETCH_SUB_COUNT_STARTED });
return Lbryio.call('subscription', 'sub_count', { claim_id: claimIds.join(',') })
.then((result: Array<number>) => {
const subCounts = result;
dispatch({
type: ACTIONS.FETCH_SUB_COUNT_COMPLETED,
data: { claimIds, subCounts, fetchDate: now },
});
})
.catch((error) => {
dispatch({ type: ACTIONS.FETCH_SUB_COUNT_FAILED, data: error });
});
};
let fetchSubCountTimer;
let fetchSubCountQueue = '';
export const doFetchSubCount = (claimIdCsv: string) => (dispatch: Dispatch) => {
if (fetchSubCountTimer) {
clearTimeout(fetchSubCountTimer);
}
if (fetchSubCountQueue && !fetchSubCountQueue.endsWith(',')) {
fetchSubCountQueue += ',';
}
fetchSubCountQueue += claimIdCsv;
fetchSubCountTimer = setTimeout(() => {
dispatch(executeFetchSubCount(fetchSubCountQueue));
fetchSubCountQueue = '';
}, FETCH_SUB_COUNT_IDLE_FIRE_MS);
};

View file

@ -0,0 +1,289 @@
import * as ACTIONS from 'constants/action_types';
import { Lbryio } from 'lbryinc';
import Lbry from 'lbry';
import { doWalletEncrypt, doWalletDecrypt } from 'redux/actions/wallet';
const NO_WALLET_ERROR = 'no wallet found for this user';
export function doSetDefaultAccount(success, failure) {
return dispatch => {
dispatch({
type: ACTIONS.SET_DEFAULT_ACCOUNT,
});
Lbry.account_list()
.then(accountList => {
const { lbc_mainnet: accounts } = accountList;
let defaultId;
for (let i = 0; i < accounts.length; ++i) {
if (accounts[i].satoshis > 0) {
defaultId = accounts[i].id;
break;
}
}
// In a case where there's no balance on either account
// assume the second (which is created after sync) as default
if (!defaultId && accounts.length > 1) {
defaultId = accounts[1].id;
}
// Set the default account
if (defaultId) {
Lbry.account_set({ account_id: defaultId, default: true })
.then(() => {
if (success) {
success();
}
})
.catch(err => {
if (failure) {
failure(err);
}
});
} else if (failure) {
// no default account to set
failure('Could not set a default account'); // fail
}
})
.catch(err => {
if (failure) {
failure(err);
}
});
};
}
export function doSetSync(oldHash, newHash, data) {
return dispatch => {
dispatch({
type: ACTIONS.SET_SYNC_STARTED,
});
return Lbryio.call('sync', 'set', { old_hash: oldHash, new_hash: newHash, data }, 'post')
.then(response => {
if (!response.hash) {
throw Error('No hash returned for sync/set.');
}
return dispatch({
type: ACTIONS.SET_SYNC_COMPLETED,
data: { syncHash: response.hash },
});
})
.catch(error => {
dispatch({
type: ACTIONS.SET_SYNC_FAILED,
data: { error },
});
});
};
}
export function doGetSync(passedPassword, callback) {
const password = passedPassword === null || passedPassword === undefined ? '' : passedPassword;
function handleCallback(error, hasNewData) {
if (callback) {
if (typeof callback !== 'function') {
throw new Error('Second argument passed to "doGetSync" must be a function');
}
callback(error, hasNewData);
}
}
return dispatch => {
dispatch({
type: ACTIONS.GET_SYNC_STARTED,
});
const data = {};
Lbry.wallet_status()
.then(status => {
if (status.is_locked) {
return Lbry.wallet_unlock({ password });
}
// Wallet is already unlocked
return true;
})
.then(isUnlocked => {
if (isUnlocked) {
return Lbry.sync_hash();
}
data.unlockFailed = true;
throw new Error();
})
.then(hash => Lbryio.call('sync', 'get', { hash }, 'post'))
.then(response => {
const syncHash = response.hash;
data.syncHash = syncHash;
data.syncData = response.data;
data.changed = response.changed;
data.hasSyncedWallet = true;
if (response.changed) {
return Lbry.sync_apply({ password, data: response.data, blocking: true });
}
})
.then(response => {
if (!response) {
dispatch({ type: ACTIONS.GET_SYNC_COMPLETED, data });
handleCallback(null, data.changed);
return;
}
const { hash: walletHash, data: walletData } = response;
if (walletHash !== data.syncHash) {
// different local hash, need to synchronise
dispatch(doSetSync(data.syncHash, walletHash, walletData));
}
dispatch({ type: ACTIONS.GET_SYNC_COMPLETED, data });
handleCallback(null, data.changed);
})
.catch(syncAttemptError => {
if (data.unlockFailed) {
dispatch({ type: ACTIONS.GET_SYNC_FAILED, data: { error: syncAttemptError } });
if (password !== '') {
dispatch({ type: ACTIONS.SYNC_APPLY_BAD_PASSWORD });
}
handleCallback(syncAttemptError);
} else if (data.hasSyncedWallet) {
const error =
(syncAttemptError && syncAttemptError.message) || 'Error getting synced wallet';
dispatch({
type: ACTIONS.GET_SYNC_FAILED,
data: {
error,
},
});
// Temp solution until we have a bad password error code
// Don't fail on blank passwords so we don't show a "password error" message
// before users have ever entered a password
if (password !== '') {
dispatch({ type: ACTIONS.SYNC_APPLY_BAD_PASSWORD });
}
handleCallback(error);
} else {
// user doesn't have a synced wallet
dispatch({
type: ACTIONS.GET_SYNC_COMPLETED,
data: { hasSyncedWallet: false, syncHash: null },
});
// call sync_apply to get data to sync
// first time sync. use any string for old hash
if (syncAttemptError.message === NO_WALLET_ERROR) {
Lbry.sync_apply({ password })
.then(({ hash: walletHash, data: syncApplyData }) => {
dispatch(doSetSync('', walletHash, syncApplyData, password));
handleCallback();
})
.catch(syncApplyError => {
handleCallback(syncApplyError);
});
}
}
});
};
}
export function doSyncApply(syncHash, syncData, password) {
return dispatch => {
dispatch({
type: ACTIONS.SYNC_APPLY_STARTED,
});
Lbry.sync_apply({ password, data: syncData })
.then(({ hash: walletHash, data: walletData }) => {
dispatch({
type: ACTIONS.SYNC_APPLY_COMPLETED,
});
if (walletHash !== syncHash) {
// different local hash, need to synchronise
dispatch(doSetSync(syncHash, walletHash, walletData));
}
})
.catch(() => {
dispatch({
type: ACTIONS.SYNC_APPLY_FAILED,
data: {
error:
'Invalid password specified. Please enter the password for your previously synchronised wallet.',
},
});
});
};
}
export function doCheckSync() {
return dispatch => {
dispatch({
type: ACTIONS.GET_SYNC_STARTED,
});
Lbry.sync_hash().then(hash => {
Lbryio.call('sync', 'get', { hash }, 'post')
.then(response => {
const data = {
hasSyncedWallet: true,
syncHash: response.hash,
syncData: response.data,
hashChanged: response.changed,
};
dispatch({ type: ACTIONS.GET_SYNC_COMPLETED, data });
})
.catch(() => {
// user doesn't have a synced wallet
dispatch({
type: ACTIONS.GET_SYNC_COMPLETED,
data: { hasSyncedWallet: false, syncHash: null },
});
});
});
};
}
export function doResetSync() {
return dispatch =>
new Promise(resolve => {
dispatch({ type: ACTIONS.SYNC_RESET });
resolve();
});
}
export function doSyncEncryptAndDecrypt(oldPassword, newPassword, encrypt) {
return dispatch => {
const data = {};
return Lbry.sync_hash()
.then(hash => Lbryio.call('sync', 'get', { hash }, 'post'))
.then(syncGetResponse => {
data.oldHash = syncGetResponse.hash;
return Lbry.sync_apply({ password: oldPassword, data: syncGetResponse.data });
})
.then(() => {
if (encrypt) {
dispatch(doWalletEncrypt(newPassword));
} else {
dispatch(doWalletDecrypt());
}
})
.then(() => Lbry.sync_apply({ password: newPassword }))
.then(syncApplyResponse => {
if (syncApplyResponse.hash !== data.oldHash) {
return dispatch(doSetSync(data.oldHash, syncApplyResponse.hash, syncApplyResponse.data));
}
})
.catch(console.error);
};
}

View file

@ -0,0 +1,29 @@
import * as ACTIONS from 'constants/action_types';
const reducers = {};
const defaultState = {
authenticating: false,
};
reducers[ACTIONS.GENERATE_AUTH_TOKEN_FAILURE] = state =>
Object.assign({}, state, {
authToken: null,
authenticating: false,
});
reducers[ACTIONS.GENERATE_AUTH_TOKEN_STARTED] = state =>
Object.assign({}, state, {
authenticating: true,
});
reducers[ACTIONS.GENERATE_AUTH_TOKEN_SUCCESS] = (state, action) =>
Object.assign({}, state, {
authToken: action.data.authToken,
authenticating: false,
});
export function authReducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) return handler(state, action);
return state;
}

View file

@ -0,0 +1,37 @@
import * as ACTIONS from 'constants/action_types';
import { handleActions } from 'util/redux-utils';
const defaultState = {
fetchingBlackListedOutpoints: false,
fetchingBlackListedOutpointsSucceed: undefined,
blackListedOutpoints: undefined,
};
export const blacklistReducer = handleActions(
{
[ACTIONS.FETCH_BLACK_LISTED_CONTENT_STARTED]: state => ({
...state,
fetchingBlackListedOutpoints: true,
}),
[ACTIONS.FETCH_BLACK_LISTED_CONTENT_COMPLETED]: (state, action) => {
const { outpoints, success } = action.data;
return {
...state,
fetchingBlackListedOutpoints: false,
fetchingBlackListedOutpointsSucceed: success,
blackListedOutpoints: outpoints,
};
},
[ACTIONS.FETCH_BLACK_LISTED_CONTENT_FAILED]: (state, action) => {
const { error, success } = action.data;
return {
...state,
fetchingBlackListedOutpoints: false,
fetchingBlackListedOutpointsSucceed: success,
fetchingBlackListedOutpointsError: error,
};
},
},
defaultState
);

View file

@ -0,0 +1,38 @@
import { handleActions } from 'util/redux-utils';
import * as ACTIONS from 'constants/action_types';
const defaultState = {
fetching: {},
byUri: {},
};
export const costInfoReducer = handleActions(
{
[ACTIONS.FETCH_COST_INFO_STARTED]: (state, action) => {
const { uri } = action.data;
const newFetching = Object.assign({}, state.fetching);
newFetching[uri] = true;
return {
...state,
fetching: newFetching,
};
},
[ACTIONS.FETCH_COST_INFO_COMPLETED]: (state, action) => {
const { uri, costInfo } = action.data;
const newByUri = Object.assign({}, state.byUri);
const newFetching = Object.assign({}, state.fetching);
newByUri[uri] = costInfo;
delete newFetching[uri];
return {
...state,
byUri: newByUri,
fetching: newFetching,
};
},
},
defaultState
);

View file

@ -0,0 +1,34 @@
import * as ACTIONS from 'constants/action_types';
import { handleActions } from 'util/redux-utils';
const defaultState = {
loading: false,
filteredOutpoints: undefined,
};
export const filteredReducer = handleActions(
{
[ACTIONS.FETCH_FILTERED_CONTENT_STARTED]: state => ({
...state,
loading: true,
}),
[ACTIONS.FETCH_FILTERED_CONTENT_COMPLETED]: (state, action) => {
const { outpoints } = action.data;
return {
...state,
loading: false,
filteredOutpoints: outpoints,
};
},
[ACTIONS.FETCH_FILTERED_CONTENT_FAILED]: (state, action) => {
const { error } = action.data;
return {
...state,
loading: false,
fetchingFilteredOutpointsError: error,
};
},
},
defaultState
);

View file

@ -0,0 +1,48 @@
import { handleActions } from 'util/redux-utils';
import * as ACTIONS from 'constants/action_types';
const defaultState = {
fetchingFeaturedContent: false,
fetchingFeaturedContentFailed: false,
featuredUris: undefined,
fetchingTrendingContent: false,
fetchingTrendingContentFailed: false,
trendingUris: undefined,
};
export const homepageReducer = handleActions(
{
[ACTIONS.FETCH_FEATURED_CONTENT_STARTED]: state => ({
...state,
fetchingFeaturedContent: true,
}),
[ACTIONS.FETCH_FEATURED_CONTENT_COMPLETED]: (state, action) => {
const { uris, success } = action.data;
return {
...state,
fetchingFeaturedContent: false,
fetchingFeaturedContentFailed: !success,
featuredUris: uris,
};
},
[ACTIONS.FETCH_TRENDING_CONTENT_STARTED]: state => ({
...state,
fetchingTrendingContent: true,
}),
[ACTIONS.FETCH_TRENDING_CONTENT_COMPLETED]: (state, action) => {
const { uris, success } = action.data;
return {
...state,
fetchingTrendingContent: false,
fetchingTrendingContentFailed: !success,
trendingUris: uris,
};
},
},
defaultState
);

View file

@ -0,0 +1,80 @@
import { handleActions } from 'util/redux-utils';
import * as ACTIONS from 'constants/action_types';
const defaultState = {
fetchingViewCount: false,
viewCountError: undefined,
viewCountById: {},
fetchingSubCount: false,
subCountError: undefined,
subCountById: {},
subCountLastFetchedById: {},
};
export const statsReducer = handleActions(
{
[ACTIONS.FETCH_VIEW_COUNT_STARTED]: (state) => ({ ...state, fetchingViewCount: true }),
[ACTIONS.FETCH_VIEW_COUNT_FAILED]: (state, action) => ({
...state,
viewCountError: action.data,
}),
[ACTIONS.FETCH_VIEW_COUNT_COMPLETED]: (state, action) => {
const { claimIdCsv, viewCounts } = action.data;
const viewCountById = Object.assign({}, state.viewCountById);
const claimIds = claimIdCsv.split(',');
if (claimIds.length === viewCounts.length) {
claimIds.forEach((claimId, index) => {
viewCountById[claimId] = viewCounts[index];
});
}
return {
...state,
fetchingViewCount: false,
viewCountById,
};
},
[ACTIONS.FETCH_SUB_COUNT_STARTED]: (state) => ({ ...state, fetchingSubCount: true }),
[ACTIONS.FETCH_SUB_COUNT_FAILED]: (state, action) => ({
...state,
subCountError: action.data,
}),
[ACTIONS.FETCH_SUB_COUNT_COMPLETED]: (state, action) => {
const { claimIds, subCounts, fetchDate } = action.data;
const subCountById = Object.assign({}, state.subCountById);
const subCountLastFetchedById = Object.assign({}, state.subCountLastFetchedById);
let dataChanged = false;
if (claimIds.length === subCounts.length) {
claimIds.forEach((claimId, index) => {
if (subCountById[claimId] !== subCounts[index]) {
subCountById[claimId] = subCounts[index];
dataChanged = true;
}
subCountLastFetchedById[claimId] = fetchDate;
});
}
const newState = {
...state,
fetchingSubCount: false,
subCountLastFetchedById,
};
if (dataChanged) {
newState.subCountById = subCountById;
}
return newState;
},
},
defaultState
);

View file

@ -0,0 +1,89 @@
import * as ACTIONS from 'constants/action_types';
const reducers = {};
const defaultState = {
hasSyncedWallet: false,
syncHash: null,
syncData: null,
setSyncErrorMessage: null,
getSyncErrorMessage: null,
syncApplyErrorMessage: '',
syncApplyIsPending: false,
syncApplyPasswordError: false,
getSyncIsPending: false,
setSyncIsPending: false,
hashChanged: false,
};
reducers[ACTIONS.GET_SYNC_STARTED] = state =>
Object.assign({}, state, {
getSyncIsPending: true,
getSyncErrorMessage: null,
});
reducers[ACTIONS.GET_SYNC_COMPLETED] = (state, action) =>
Object.assign({}, state, {
syncHash: action.data.syncHash,
syncData: action.data.syncData,
hasSyncedWallet: action.data.hasSyncedWallet,
getSyncIsPending: false,
hashChanged: action.data.hashChanged,
});
reducers[ACTIONS.GET_SYNC_FAILED] = (state, action) =>
Object.assign({}, state, {
getSyncIsPending: false,
getSyncErrorMessage: action.data.error,
});
reducers[ACTIONS.SET_SYNC_STARTED] = state =>
Object.assign({}, state, {
setSyncIsPending: true,
setSyncErrorMessage: null,
});
reducers[ACTIONS.SET_SYNC_FAILED] = (state, action) =>
Object.assign({}, state, {
setSyncIsPending: false,
setSyncErrorMessage: action.data.error,
});
reducers[ACTIONS.SET_SYNC_COMPLETED] = (state, action) =>
Object.assign({}, state, {
setSyncIsPending: false,
setSyncErrorMessage: null,
hasSyncedWallet: true, // sync was successful, so the user has a synced wallet at this point
syncHash: action.data.syncHash,
});
reducers[ACTIONS.SYNC_APPLY_STARTED] = state =>
Object.assign({}, state, {
syncApplyPasswordError: false,
syncApplyIsPending: true,
syncApplyErrorMessage: '',
});
reducers[ACTIONS.SYNC_APPLY_COMPLETED] = state =>
Object.assign({}, state, {
syncApplyIsPending: false,
syncApplyErrorMessage: '',
});
reducers[ACTIONS.SYNC_APPLY_FAILED] = (state, action) =>
Object.assign({}, state, {
syncApplyIsPending: false,
syncApplyErrorMessage: action.data.error,
});
reducers[ACTIONS.SYNC_APPLY_BAD_PASSWORD] = state =>
Object.assign({}, state, {
syncApplyPasswordError: true,
});
reducers[ACTIONS.SYNC_RESET] = () => defaultState;
export function syncReducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) return handler(state, action);
return state;
}

View file

@ -0,0 +1,4 @@
const selectState = (state) => state.auth || {};
export const selectAuthToken = (state) => selectState(state).authToken;
export const selectIsAuthenticating = (state) => selectState(state).authenticating;

View file

@ -0,0 +1,68 @@
// @flow
// TODO: This should be in 'redux/selectors/claim.js'. Temporarily putting it
// here to get past importing issues with 'lbryinc', which the real fix might
// involve moving it from 'extras' to 'ui' (big change).
import { createCachedSelector } from 're-reselect';
import { selectClaimForUri } from 'redux/selectors/claims';
import { selectMutedChannels } from 'redux/selectors/blocked';
import { selectModerationBlockList } from 'redux/selectors/comments';
import { selectBlacklistedOutpointMap, selectFilteredOutpointMap } from 'lbryinc';
import { getChannelFromClaim } from 'util/claim';
import { isURIEqual } from 'util/lbryURI';
export const selectBanStateForUri = createCachedSelector(
selectClaimForUri,
selectBlacklistedOutpointMap,
selectFilteredOutpointMap,
selectMutedChannels,
selectModerationBlockList,
(claim, blackListedOutpointMap, filteredOutpointMap, mutedChannelUris, personalBlocklist) => {
const banState = {};
if (!claim) {
return banState;
}
const channelClaim = getChannelFromClaim(claim);
// This will be replaced once blocking is done at the wallet server level.
if (blackListedOutpointMap) {
if (
(channelClaim && blackListedOutpointMap[`${channelClaim.txid}:${channelClaim.nout}`]) ||
blackListedOutpointMap[`${claim.txid}:${claim.nout}`]
) {
banState['blacklisted'] = true;
}
}
// We're checking to see if the stream outpoint or signing channel outpoint
// is in the filter list.
if (filteredOutpointMap) {
if (
(channelClaim && filteredOutpointMap[`${channelClaim.txid}:${channelClaim.nout}`]) ||
filteredOutpointMap[`${claim.txid}:${claim.nout}`]
) {
banState['filtered'] = true;
}
}
// block stream claims
// block channel claims if we can't control for them in claim search
if (mutedChannelUris.length && channelClaim) {
if (mutedChannelUris.some((blockedUri) => isURIEqual(blockedUri, channelClaim.permanent_url))) {
banState['muted'] = true;
}
}
// Commentron blocklist
if (personalBlocklist.length && channelClaim) {
if (personalBlocklist.some((blockedUri) => isURIEqual(blockedUri, channelClaim.permanent_url))) {
banState['blocked'] = true;
}
}
return banState;
}
)((state, uri) => String(uri));

View file

@ -0,0 +1,15 @@
import { createSelector } from 'reselect';
export const selectState = (state) => state.blacklist || {};
export const selectBlackListedOutpoints = (state) => selectState(state).blackListedOutpoints;
export const selectBlacklistedOutpointMap = createSelector(selectBlackListedOutpoints, (outpoints) =>
outpoints
? outpoints.reduce((acc, val) => {
const outpoint = `${val.txid}:${val.nout}`;
acc[outpoint] = 1;
return acc;
}, {})
: {}
);

View file

@ -0,0 +1,16 @@
// @flow
type State = { costInfo: any };
export const selectState = (state: State) => state.costInfo || {};
export const selectAllCostInfoByUri = (state: State) => selectState(state).byUri;
export const selectFetchingCostInfo = (state: State) => selectState(state).fetching;
export const selectCostInfoForUri = (state: State, uri: string) => {
const costInfos = selectAllCostInfoByUri(state);
return costInfos && costInfos[uri];
};
export const selectFetchingCostInfoForUri = (state: State, uri: string) => {
const fetchingByUri = selectFetchingCostInfo(state);
return fetchingByUri && fetchingByUri[uri];
};

View file

@ -0,0 +1,15 @@
import { createSelector } from 'reselect';
export const selectState = (state) => state.filtered || {};
export const selectFilteredOutpoints = (state) => selectState(state).filteredOutpoints;
export const selectFilteredOutpointMap = createSelector(selectFilteredOutpoints, (outpoints) =>
outpoints
? outpoints.reduce((acc, val) => {
const outpoint = `${val.txid}:${val.nout}`;
acc[outpoint] = 1;
return acc;
}, {})
: {}
);

View file

@ -0,0 +1,6 @@
const selectState = (state) => state.homepage || {};
export const selectFeaturedUris = (state) => selectState(state).featuredUris;
export const selectFetchingFeaturedUris = (state) => selectState(state).fetchingFeaturedContent;
export const selectTrendingUris = (state) => selectState(state).trendingUris;
export const selectFetchingTrendingUris = (state) => selectState(state).fetchingTrendingContent;

View file

@ -0,0 +1,20 @@
// @flow
import { selectClaimIdForUri } from 'redux/selectors/claims';
type State = { claims: any, stats: any, user: UserState };
const selectState = (state: State) => state.stats || {};
export const selectViewCount = (state: State) => selectState(state).viewCountById;
export const selectSubCount = (state: State) => selectState(state).subCountById;
export const selectViewCountForUri = (state: State, uri: string) => {
const claimId = selectClaimIdForUri(state, uri);
const viewCountById = selectViewCount(state);
return claimId ? viewCountById[claimId] || 0 : 0;
};
export const selectSubCountForUri = (state: State, uri: string) => {
const claimId = selectClaimIdForUri(state, uri);
const subCountById = selectSubCount(state);
return claimId ? subCountById[claimId] || 0 : 0;
};

View file

@ -0,0 +1,13 @@
const selectState = (state) => state.sync || {};
export const selectHasSyncedWallet = (state) => selectState(state).hasSyncedWallet;
export const selectSyncHash = (state) => selectState(state).syncHash;
export const selectSyncData = (state) => selectState(state).syncData;
export const selectSetSyncErrorMessage = (state) => selectState(state).setSyncErrorMessage;
export const selectGetSyncErrorMessage = (state) => selectState(state).getSyncErrorMessage;
export const selectGetSyncIsPending = (state) => selectState(state).getSyncIsPending;
export const selectSetSyncIsPending = (state) => selectState(state).setSyncIsPending;
export const selectHashChanged = (state) => selectState(state).hashChanged;
export const selectSyncApplyIsPending = (state) => selectState(state).syncApplyIsPending;
export const selectSyncApplyErrorMessage = (state) => selectState(state).syncApplyErrorMessage;
export const selectSyncApplyPasswordError = (state) => selectState(state).syncApplyPasswordError;

View file

@ -0,0 +1,17 @@
// util for creating reducers
// based off of redux-actions
// https://redux-actions.js.org/docs/api/handleAction.html#handleactions
// eslint-disable-next-line import/prefer-default-export
export const handleActions = (actionMap, defaultState) => (state = defaultState, action) => {
const handler = actionMap[action.type];
if (handler) {
const newState = handler(state, action);
return Object.assign({}, state, newState);
}
// just return the original state if no handler
// returning a copy here breaks redux-persist
return state;
};

View file

@ -0,0 +1,10 @@
export function swapKeyAndValue(dict) {
const ret = {};
// eslint-disable-next-line no-restricted-syntax
for (const key in dict) {
if (dict.hasOwnProperty(key)) {
ret[dict[key]] = key;
}
}
return ret;
}

View file

@ -0,0 +1,78 @@
const apiBaseUrl = 'https://www.transifex.com/api/2/project';
const resource = 'app-strings';
export function doTransifexUpload(contents, project, token, success, fail) {
const url = `${apiBaseUrl}/${project}/resources/`;
const updateUrl = `${apiBaseUrl}/${project}/resource/${resource}/content/`;
const headers = {
Authorization: `Basic ${Buffer.from(`api:${token}`).toString('base64')}`,
'Content-Type': 'application/json',
};
const req = {
accept_translations: true,
i18n_type: 'KEYVALUEJSON',
name: resource,
slug: resource,
content: contents,
};
function handleResponse(text) {
let json;
try {
// transifex api returns Python dicts for some reason.
// Any way to get the api to return valid JSON?
json = JSON.parse(text);
} catch (e) {
// ignore
}
if (success) {
success(json || text);
}
}
function handleError(err) {
if (fail) {
fail(err.message ? err.message : 'Could not upload strings resource to Transifex');
}
}
// check if the resource exists
fetch(updateUrl, { headers })
.then(response => response.json())
.then(() => {
// perform an update
fetch(updateUrl, {
method: 'PUT',
headers,
body: JSON.stringify({ content: contents }),
})
.then(response => {
if (response.status !== 200 && response.status !== 201) {
throw new Error('failed to update transifex');
}
return response.text();
})
.then(handleResponse)
.catch(handleError);
})
.catch(() => {
// resource doesn't exist, create a fresh resource
fetch(url, {
method: 'POST',
headers,
body: JSON.stringify(req),
})
.then(response => {
if (response.status !== 200 && response.status !== 201) {
throw new Error('failed to upload to transifex');
}
return response.text();
})
.then(handleResponse)
.catch(handleError);
});
}

3
extras/recsys/index.js Normal file
View file

@ -0,0 +1,3 @@
import Recsys from './recsys';
export default Recsys;

331
extras/recsys/recsys.js Normal file
View file

@ -0,0 +1,331 @@
// @flow
import { RECSYS_ENDPOINT } from 'config';
import { selectUser } from 'redux/selectors/user';
import { selectRecommendedMetaForClaimId } from 'redux/selectors/search';
import { parseURI } from 'util/lbryURI';
import { getAuthToken } from 'util/saved-passwords';
import * as ACTIONS from 'constants/action_types';
import * as SETTINGS from 'constants/settings';
import { X_LBRY_AUTH_TOKEN } from 'constants/token';
import { makeSelectClaimForUri } from 'redux/selectors/claims';
import { selectPlayingUri, selectPrimaryUri } from 'redux/selectors/content';
import { selectClientSetting, selectDaemonSettings } from 'redux/selectors/settings';
import { selectIsSubscribedForClaimId } from 'redux/selectors/subscriptions';
// $FlowFixMe: cannot resolve..
import { history } from 'ui/store';
const recsysEndpoint = RECSYS_ENDPOINT;
const DEFAULT_RECSYS_ID = 'lighthouse-v0';
const getClaimIdsFromUris = (uris) => {
return uris
? uris.map((uri) => {
try {
const { claimId } = parseURI(uri);
return claimId;
} catch (e) {
return [];
}
})
: [];
};
const recsys: Recsys = {
entries: {},
debug: false,
/**
* Provides for creating, updating, and sending Clickstream data object Entries.
* Entries are Created either when recommendedContent loads, or when recommendedContent is clicked.
* If recommended content is clicked, An Entry with parentUuid is created.
* On page load, find an empty entry with your claimId, or create a new entry and record to it.
*/
/**
* Saves existing entries to persistence storage (in this case, Redux).
*/
saveEntries: function () {
if (window && window.store) {
window.store.dispatch({
type: ACTIONS.SET_RECSYS_ENTRIES,
data: recsys.entries,
});
}
},
/**
* Called when RecommendedContent was clicked.
* Adds index of clicked recommendation to parent entry
* Adds new Entry with parentUuid for destination page
* @param parentClaimId: string,
* @param newClaimId: string,
*/
onClickedRecommended: function (parentClaimId, newClaimId) {
const parentEntry = recsys.entries[parentClaimId] ? recsys.entries[parentClaimId] : null;
const parentUuid = parentEntry ? parentEntry['uuid'] : '';
const parentRecommendedClaims = parentEntry ? parentEntry['recClaimIds'] : [];
const parentClickedIndexes = parentEntry ? parentEntry['recClickedVideoIdx'] : [];
const indexClicked = parentRecommendedClaims.indexOf(newClaimId);
if (parentUuid) {
recsys.createRecsysEntry(newClaimId, parentUuid);
}
parentClickedIndexes.push(indexClicked);
// recsys.log('onClickedRecommended', { parentClaimId, newClaimId });
recsys.log('onClickedRecommended', newClaimId);
},
/**
* Page was loaded. Get or Create entry and populate it with default data,
* plus recommended content, recsysId, etc.
* Called from recommendedContent component
*
* @param claimId The ID of the content the recommendations are for.
* @param uris The recommended uris for `claimId`.
* @param uuid Specific uuid to use (e.g. for FYP); uses the recommendation's
* uuid otherwise.
*/
onRecsLoaded: function (claimId, uris, uuid = '') {
if (window && window.store) {
const state = window.store.getState();
const recommendedMeta = selectRecommendedMetaForClaimId(state, claimId);
if (!recsys.entries[claimId]) {
recsys.createRecsysEntry(claimId, null, uuid || recommendedMeta.uuid);
} else if (!recsys.entries[claimId].uuid) {
// Stubs might not have the uuid ready at the time. Refill now.
recsys.entries[claimId].uuid = uuid || recommendedMeta.uuid;
}
const claimIds = getClaimIdsFromUris(uris);
recsys.entries[claimId]['recsysId'] = recommendedMeta.poweredBy || DEFAULT_RECSYS_ID;
recsys.entries[claimId]['pageLoadedAt'] = Date.now();
// It is possible that `claimIds` include `null | undefined` entries
// instead of all being strings. I don't know if we should filter it,
// or change the `recClaimIds` definition. Leaving as is for now since
// any changes could affect existing recsys data set.
// -----------
// $FlowFixMe:
recsys.entries[claimId]['recClaimIds'] = claimIds;
}
recsys.log('onRecsLoaded', claimId);
},
/**
* Creates an Entry with optional parentUuid
* @param: claimId: string
* @param: parentUuid: string (optional)
* @param uuid Specific uuid to use (e.g. for FYP); uses the recommendation's
* uuid otherwise.
*/
createRecsysEntry: function (claimId, parentUuid, uuid = '') {
if (window && window.store && claimId) {
const state = window.store.getState();
const recommendedMeta = selectRecommendedMetaForClaimId(state, claimId);
const user = selectUser(state);
const userId = user ? user.id : null;
// Make a stub entry that will be filled out on page load
// $FlowIgnore: not everything is defined since this is a stub
recsys.entries[claimId] = {
uuid: uuid || recommendedMeta.uuid,
claimId: claimId,
recClickedVideoIdx: [],
pageLoadedAt: Date.now(),
events: [],
incognito: !(user && user.has_verified_email),
isFollowing: selectIsSubscribedForClaimId(state, claimId),
};
if (parentUuid) {
// $FlowFixMe: 'uid' should be a number, not null.
recsys.entries[claimId].uid = userId || null;
recsys.entries[claimId].parentUuid = parentUuid;
} else {
// $FlowFixMe: 'uid' should be a number, not null.
recsys.entries[claimId].uid = userId;
// $FlowFixMe: 'recsysId' should be a number, not null.
recsys.entries[claimId].recsysId = null;
recsys.entries[claimId].recClaimIds = [];
}
recsys.saveEntries();
}
recsys.log('createRecsysEntry', claimId);
},
updateRecsysEntry: function (claimId, key, value) {
const entry = recsys.entries[claimId];
if (entry) {
entry[key] = value;
}
},
/**
* Send event for claimId
* @param claimId
* @param isTentative Visibility change rather than tab closed.
*/
sendRecsysEntry: function (claimId, isTentative) {
const shareTelemetry =
IS_WEB || (window && window.store && selectDaemonSettings(window.store.getState()).share_usage_data);
if (recsys.entries[claimId] && shareTelemetry) {
// Exclude `events` in the submission https://github.com/OdyseeTeam/odysee-frontend/issues/1317
const { events, ...entryData } = recsys.entries[claimId];
const data = JSON.stringify(entryData);
return fetch(recsysEndpoint, {
method: 'POST',
headers: {
[X_LBRY_AUTH_TOKEN]: getAuthToken(),
'Content-Type': 'application/json',
},
body: data,
})
.then(() => {
if (!isTentative) {
delete recsys.entries[claimId];
recsys.saveEntries();
}
})
.catch((err) => {
console.log('RECSYS: failed to send entry', err);
});
}
recsys.log('sendRecsysEntry', claimId);
},
sendEntries: function (entries, isResumedSend) {
if (entries) {
if (Object.keys(recsys.entries).length !== 0) {
// Typically called on startup only.
console.warn('RECSYS: sendEntries() called on non-empty state. Data will be overwritten.');
}
recsys.entries = entries;
}
Object.keys(recsys.entries).forEach((claimId) => {
recsys.entries[claimId].isResumedSend = isResumedSend;
recsys.sendRecsysEntry(claimId, false); // Send and delete.
});
},
/**
* A player event fired. Get the Entry for the claimId, and add the events
* @param claimId
* @param event
*/
onRecsysPlayerEvent: function (claimId, event, isEmbedded) {
const state = window.store.getState();
const autoPlayNext = state && selectClientSetting(state, SETTINGS.AUTOPLAY_NEXT);
// Check if played through (4 = onEnded) and handle multiple events at end
if (recsys.entries[claimId] && !recsys.entries[claimId]['autoplay'] === true) {
if (autoPlayNext && event.event === 4) {
recsys.entries[claimId]['autoplay'] = true;
} else {
recsys.entries[claimId]['autoplay'] = false;
}
}
if (!recsys.entries[claimId]) {
recsys.createRecsysEntry(claimId);
// do something to show it's floating or autoplay
}
if (isEmbedded) {
recsys.entries[claimId]['isEmbed'] = true;
}
recsys.entries[claimId].events.push(event);
recsys.log('onRecsysPlayerEvent', claimId);
},
log: function (callName, claimId) {
if (recsys.debug) {
console.log(`Call: ***${callName}***, ClaimId: ${claimId}, Recsys Entries`, Object.assign({}, recsys.entries));
}
},
/**
* Player closed. Check to see if primaryUri = playingUri
* if so, send the Entry.
*/
onPlayerDispose: function (claimId, isEmbedded, totalPlayingTime) {
if (window && window.store) {
const state = window.store.getState();
const playingUri = selectPlayingUri(state);
const primaryUri = selectPrimaryUri(state);
const onFilePage = playingUri === primaryUri;
if (!onFilePage || isEmbedded) {
if (isEmbedded) {
recsys.entries[claimId]['isEmbed'] = true;
}
recsys.entries[claimId]['totalPlayTime'] = totalPlayingTime;
recsys.sendRecsysEntry(claimId);
}
}
recsys.log('PlayerDispose', claimId);
},
// /**
// * File page unmount or change event
// * Check to see if playingUri, floatingEnabled, primaryUri === playingUri
// * If not, send the Entry.
// * If floating enabled, leaving file page will pop out player, leading to
// * more events until player is disposed. Don't send unless floatingPlayer playingUri
// */
// onLeaveFilePage: function (primaryUri) {
// if (window && window.store) {
// const state = window.store.getState();
// const claim = makeSelectClaimForUri(primaryUri)(state);
// const claimId = claim ? claim.claim_id : null;
// const playingUri = selectPlayingUri(state);
// const actualPlayingUri = playingUri && playingUri.uri;
// // const primaryUri = selectPrimaryUri(state);
// const floatingPlayer = makeSelectClientSetting(SETTINGS.FLOATING_PLAYER)(state);
// // When leaving page, if floating player is enabled, play will continue.
// if (claimId) {
// recsys.entries[claimId]['pageExitedAt'] = Date.now();
// }
// const shouldSend =
// (claimId && floatingPlayer && actualPlayingUri && actualPlayingUri !== primaryUri) || !floatingPlayer || !actualPlayingUri;
// if (shouldSend) {
// recsys.sendRecsysEntry(claimId);
// }
// recsys.log('LeaveFile', claimId);
// }
// },
/**
* Navigate event
* Send all claimIds that aren't currently playing.
*/
onNavigate: function () {
if (window && window.store) {
const state = window.store.getState();
const playingUri = selectPlayingUri(state);
const actualPlayingUri = playingUri && playingUri.uri;
const claim = makeSelectClaimForUri(actualPlayingUri || '')(state);
const playingClaimId = claim ? claim.claim_id : null;
// const primaryUri = selectPrimaryUri(state);
const floatingPlayer = selectClientSetting(state, SETTINGS.FLOATING_PLAYER);
// When leaving page, if floating player is enabled, play will continue.
Object.keys(recsys.entries).forEach((claimId) => {
const shouldSkip = recsys.entries[claimId].parentUuid && !recsys.entries[claimId].recClaimIds;
if (!shouldSkip && ((claimId !== playingClaimId && floatingPlayer) || !floatingPlayer)) {
recsys.entries[claimId]['pageExitedAt'] = Date.now();
recsys.saveEntries();
// recsys.sendRecsysEntry(claimId); breaks pop out = off, not helping with browser close.
}
recsys.log('OnNavigate', claimId);
});
}
},
};
history.listen(() => {
recsys.onNavigate();
});
export default recsys;

38
flow-typed/Blocklist.js vendored Normal file
View file

@ -0,0 +1,38 @@
declare type BlocklistState = {
blockedChannels: Array<string>,
geoBlockedList: ?GBL,
};
declare type BlocklistAction = {
type: string,
data: {
uri: string,
},
};
// ****************************************************************************
// Geo-blocked list (GBL)
// ****************************************************************************
declare type GeoChannelId = string;
declare type GeoRestriction = {
id: string,
trigger?: string,
reason?: string,
message?: string,
};
declare type GeoConfig = {
countries?: Array<GeoRestriction>,
continents?: Array<GeoRestriction>,
specials?: Array<GeoRestriction>,
};
declare type GBL = {
livestreams?: { [GeoChannelId]: GeoConfig },
videos?: { [GeoChannelId]: GeoConfig }
};
// ****************************************************************************
// ****************************************************************************

216
flow-typed/Claim.js vendored Normal file
View file

@ -0,0 +1,216 @@
// @flow
declare type Claim = StreamClaim | ChannelClaim | CollectionClaim;
declare type ChannelClaim = GenericClaim & {
value: ChannelMetadata,
};
declare type CollectionClaim = GenericClaim & {
value: CollectionMetadata,
};
declare type StreamClaim = GenericClaim & {
value: StreamMetadata,
};
declare type GenericClaim = {
address: string, // address associated with tx
amount: string, // bid amount at time of tx
canonical_url: string, // URL with short id, includes channel with short id
claim_id: string, // unique claim identifier
claim_sequence: number, // not being used currently
claim_op: 'create' | 'update',
confirmations: number,
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
timestamp?: number, // date of last transaction
height: number, // block height the tx was confirmed
is_channel_signature_valid?: boolean,
is_my_output: boolean,
name: string,
normalized_name: string, // `name` normalized via unicode NFD spec,
nout: number, // index number for an output of a tx
permanent_url: string, // name + claim_id
short_url: string, // permanent_url with short id, no channel
txid: string, // unique tx id
type: 'claim' | 'update' | 'support',
value_type: 'stream' | 'channel' | 'collection',
signing_channel?: ChannelClaim,
reposted_claim?: GenericClaim,
repost_channel_url?: string,
repost_url?: string,
repost_bid_amount?: string,
purchase_receipt?: PurchaseReceipt,
meta: {
activation_height: number,
claims_in_channel?: number,
creation_height: number,
creation_timestamp: number,
effective_amount: string,
expiration_height: number,
is_controlling: boolean,
support_amount: string,
reposted: number,
trending_global: number,
trending_group: number,
trending_local: number,
trending_mixed: number,
},
};
declare type ClaimId = string;
declare type GenericMetadata = {
title?: string,
description?: string,
thumbnail?: {
url?: string,
},
languages?: Array<string>,
tags?: Array<string>,
locations?: Array<Location>,
};
declare type ChannelMetadata = GenericMetadata & {
public_key: string,
public_key_id: string,
cover_url?: string,
email?: string,
website_url?: string,
featured?: Array<string>,
};
declare type CollectionMetadata = GenericMetadata & {
claims: Array<string>,
}
declare type StreamMetadata = GenericMetadata & {
license?: string, // License "title" ex: Creative Commons, Custom copyright
license_url?: string, // Link to full license
release_time?: number, // linux timestamp
author?: string,
source: {
sd_hash: string,
media_type?: string,
hash?: string,
name?: string, // file name
size?: number, // size of file in bytes
},
// Only exists if a stream has a fee
fee?: Fee,
stream_type: 'video' | 'audio' | 'image' | 'software',
// Below correspond to `stream_type`
video?: {
duration: number,
height: number,
width: number,
},
audio?: {
duration: number,
},
image?: {
height: number,
width: number,
},
software?: {
os: string,
},
};
declare type Location = {
latitude?: number,
longitude?: number,
country?: string,
state?: string,
city?: string,
code?: string,
};
declare type Fee = {
amount: string,
currency: string,
address: string,
};
declare type PurchaseReceipt = {
address: string,
amount: string,
claim_id: string,
confirmations: number,
height: number,
nout: number,
timestamp: number,
txid: string,
type: 'purchase',
};
declare type ClaimActionResolveInfo = {
[string]: {
stream: ?StreamClaim,
channel: ?ChannelClaim,
claimsInChannel: ?number,
collection: ?CollectionClaim,
},
}
declare type ChannelUpdateParams = {
claim_id: string,
bid?: string,
title?: string,
cover_url?: string,
thumbnail_url?: string,
description?: string,
website_url?: string,
email?: string,
tags?: Array<string>,
replace?: boolean,
languages?: Array<string>,
locations?: Array<string>,
blocking?: boolean,
}
declare type ChannelPublishParams = {
name: string,
bid: string,
blocking?: true,
title?: string,
cover_url?: string,
thumbnail_url?: string,
description?: string,
website_url?: string,
email?: string,
tags?: Array<string>,
languages?: Array<string>,
}
declare type CollectionUpdateParams = {
claim_id: string,
claim_ids?: Array<string>,
bid?: string,
title?: string,
cover_url?: string,
thumbnail_url?: string,
description?: string,
website_url?: string,
email?: string,
tags?: Array<string>,
replace?: boolean,
languages?: Array<string>,
locations?: Array<string>,
blocking?: boolean,
}
declare type CollectionPublishParams = {
name: string,
bid: string,
claim_ids: Array<string>,
blocking?: true,
title?: string,
thumbnail_url?: string,
description?: string,
tags?: Array<string>,
languages?: Array<string>,
}

29
flow-typed/CoinSwap.js vendored Normal file
View file

@ -0,0 +1,29 @@
declare type CoinSwapInfo = {
chargeCode: string,
coins: Array<string>,
sendAddresses: { [string]: string},
sendAmounts: { [string]: any },
lbcAmount: number,
status?: {
status: string,
receiptCurrency: string,
receiptTxid: string,
lbcTxid: string,
},
}
declare type CoinSwapState = {
coinSwaps: Array<CoinSwapInfo>,
};
declare type CoinSwapAddAction = {
type: string,
data: CoinSwapInfo,
};
declare type CoinSwapRemoveAction = {
type: string,
data: {
chargeCode: string,
},
};

63
flow-typed/Collections.js vendored Normal file
View file

@ -0,0 +1,63 @@
declare type Collection = {
id: string,
items: Array<?string>,
name: string,
description?: string,
thumbnail?: {
url?: string,
},
type: string,
createdAt?: ?number,
updatedAt: number,
totalItems?: number,
itemCount?: number,
editsCleared?: boolean,
sourceId?: string, // if copied, claimId of original collection
};
declare type CollectionState = {
unpublished: CollectionGroup,
resolved: CollectionGroup,
pending: CollectionGroup,
edited: CollectionGroup,
builtin: CollectionGroup,
saved: Array<string>,
isResolvingCollectionById: { [string]: boolean },
error?: string | null,
queue: Collection,
};
declare type CollectionGroup = {
[string]: Collection,
};
declare type CollectionList = Array<Collection>;
declare type CollectionCreateParams = {
name: string,
description?: string,
thumbnail?: {
url?: string,
},
items: ?Array<string>,
type: string,
sourceId?: string, // if copied, claimId of original collection
};
declare type CollectionEditParams = {
uris?: Array<string>,
remove?: boolean,
replace?: boolean,
order?: { from: number, to: number },
type?: string,
name?: string,
description?: string,
thumbnail?: {
url?: string,
},
};
declare type CollectionFetchParams = {
collectionId: string,
pageSize?: number,
};

106
flow-typed/Comment.js vendored
View file

@ -18,6 +18,17 @@ declare type Comment = {
is_creator: boolean, is_creator: boolean,
is_global_mod: boolean, is_global_mod: boolean,
is_fiat?: boolean, is_fiat?: boolean,
removed?: boolean,
};
declare type CommentSubmitParams = {
comment: string,
claim_id: string,
parent_id?: string,
txid?: ?string,
payment_intent_id?: ?string,
environment?: ?string,
sticker: boolean,
}; };
declare type PerChannelSettings = { declare type PerChannelSettings = {
@ -26,11 +37,12 @@ declare type PerChannelSettings = {
min_tip_amount_comment?: number, min_tip_amount_comment?: number,
min_tip_amount_super_chat?: number, min_tip_amount_super_chat?: number,
slow_mode_min_gap?: number, slow_mode_min_gap?: number,
time_since_first_comment?: number,
}; };
// todo: relate individual comments to their commentId // todo: relate individual comments to their commentId
declare type CommentsState = { declare type CommentsState = {
commentsByUri: { [string]: string }, commentsByUri: { [string]: string }, // URI -> claimId (TODO: remove)
superChatsByUri: { [string]: { totalAmount: number, comments: Array<Comment> } }, superChatsByUri: { [string]: { totalAmount: number, comments: Array<Comment> } },
byId: { [string]: Array<string> }, // ClaimID -> list of fetched comment IDs. byId: { [string]: Array<string> }, // ClaimID -> list of fetched comment IDs.
totalCommentsById: {}, // ClaimId -> ultimate total (including replies) in commentron. totalCommentsById: {}, // ClaimId -> ultimate total (including replies) in commentron.
@ -39,12 +51,13 @@ declare type CommentsState = {
topLevelCommentsById: { [string]: Array<string> }, // ClaimID -> list of fetched top level comments. topLevelCommentsById: { [string]: Array<string> }, // ClaimID -> list of fetched top level comments.
topLevelTotalPagesById: { [string]: number }, // ClaimID -> total number of top-level pages in commentron. Based on COMMENT_PAGE_SIZE_TOP_LEVEL. topLevelTotalPagesById: { [string]: number }, // ClaimID -> total number of top-level pages in commentron. Based on COMMENT_PAGE_SIZE_TOP_LEVEL.
topLevelTotalCommentsById: { [string]: number }, // ClaimID -> total top level comments in commentron. topLevelTotalCommentsById: { [string]: number }, // ClaimID -> total top level comments in commentron.
commentById: { [string]: Comment }, commentById: { [string]: Comment }, // commentId -> Comment
linkedCommentAncestors: { [string]: Array<string> }, // {"linkedCommentId": ["parentId", "grandParentId", ...]} fetchedCommentAncestors: { [string]: Array<string> }, // {"fetchedCommentId": ["parentId", "grandParentId", ...]}
pinnedCommentsById: {}, // ClaimId -> array of pinned comment IDs pinnedCommentsById: {}, // ClaimId -> array of pinned comment IDs
isLoading: boolean, isLoading: boolean,
isLoadingById: boolean, isLoadingById: boolean,
isLoadingByParentId: { [string]: boolean }, isLoadingByParentId: { [string]: boolean },
isCommenting: boolean,
myComments: ?Set<string>, myComments: ?Set<string>,
isFetchingReacts: boolean, isFetchingReacts: boolean,
myReactsByCommentId: ?{ [string]: Array<string> }, // {"CommentId:MyChannelId": ["like", "dislike", ...]} myReactsByCommentId: ?{ [string]: Array<string> }, // {"CommentId:MyChannelId": ["like", "dislike", ...]}
@ -53,21 +66,42 @@ declare type CommentsState = {
moderationBlockList: ?Array<string>, // @KP rename to "personalBlockList"? moderationBlockList: ?Array<string>, // @KP rename to "personalBlockList"?
adminBlockList: ?Array<string>, adminBlockList: ?Array<string>,
moderatorBlockList: ?Array<string>, moderatorBlockList: ?Array<string>,
moderatorBlockListDelegatorsMap: {[string]: Array<string>}, // {"blockedUri": ["delegatorUri1", ""delegatorUri2", ...]} moderatorBlockListDelegatorsMap: { [string]: Array<string> }, // {"blockedUri": ["delegatorUri1", ""delegatorUri2", ...]}
fetchingModerationBlockList: boolean, fetchingModerationBlockList: boolean,
moderationDelegatesById: { [string]: Array<{ channelId: string, channelName: string }> }, moderationDelegatesById: { [string]: Array<{ channelId: string, channelName: string }> },
fetchingModerationDelegates: boolean, fetchingModerationDelegates: boolean,
moderationDelegatorsById: { [string]: { global: boolean, delegators: { name: string, claimId: string } }}, moderationDelegatorsById: { [string]: { global: boolean, delegators: { name: string, claimId: string } } },
fetchingModerationDelegators: boolean, fetchingModerationDelegators: boolean,
blockingByUri: {}, blockingByUri: {},
unBlockingByUri: {}, unBlockingByUri: {},
personalTimeoutMap: { [uri: string]: { blockedAt: string, bannedFor: number, banRemaining: number } }, personalTimeoutMap: { [uri: string]: { blockedAt: string, bannedFor: number, banRemaining: number } },
adminTimeoutMap: { [uri: string]: { blockedAt: string, bannedFor: number, banRemaining: number } }, adminTimeoutMap: { [uri: string]: { blockedAt: string, bannedFor: number, banRemaining: number } },
moderatorTimeoutMap: { [uri: string]: { blockedAt: string, bannedFor: number, banRemaining: number } }, moderatorTimeoutMap: { [uri: string]: { blockedAt: string, bannedFor: number, banRemaining: number } },
togglingForDelegatorMap: {[string]: Array<string>}, // {"blockedUri": ["delegatorUri1", ""delegatorUri2", ...]} togglingForDelegatorMap: { [string]: Array<string> }, // {"blockedUri": ["delegatorUri1", ""delegatorUri2", ...]}
settingsByChannelId: { [string]: PerChannelSettings }, // ChannelID -> settings settingsByChannelId: { [string]: PerChannelSettings }, // ChannelID -> settings
fetchingSettings: boolean, fetchingSettings: boolean,
fetchingBlockedWords: boolean, fetchingBlockedWords: boolean,
myCommentedChannelIdsById: { [string]: Array<string> }, // [content-claim-id] -> array of own channels IDs that have commented before.
};
// Authorization parameters for calls requiring user authentication
declare type Authorization = {
channel_name: string,
channel_id: string,
signature: string,
signing_ts: string,
};
// ModAuthorization parameters for calls requiring creator/moderator authentication
declare type ModAuthorization = {
// Publisher, Moderator or Commentron Admin
mod_channel_id: string,
mod_channel_name: string,
// Creator that Moderator is delegated from. Used for delegated moderation
creator_channel_id: string,
creator_channel_name: string,
signature: string,
signing_ts: string,
}; };
declare type CommentReactParams = { declare type CommentReactParams = {
@ -91,7 +125,7 @@ declare type ReactionReactParams = {
}; };
declare type ReactionReactResponse = { declare type ReactionReactResponse = {
Reactions: { [string]: { [string]: number} }, Reactions: { [string]: { [string]: number } },
}; };
declare type ReactionListParams = { declare type ReactionListParams = {
@ -115,10 +149,10 @@ declare type CommentListParams = {
channel_name?: string, // signing channel name of claim (enables 'commentsEnabled' check) channel_name?: string, // signing channel name of claim (enables 'commentsEnabled' check)
channel_id?: string, // signing channel claim id of claim (enables 'commentsEnabled' check) channel_id?: string, // signing channel claim id of claim (enables 'commentsEnabled' check)
author_claim_id?: string, // filters comments to just this author author_claim_id?: string, // filters comments to just this author
parent_id?: string, // filters comments to those under this thread parent_id?: ?string, // filters comments to those under this thread
top_level?: boolean, // filters to only top level comments top_level?: boolean, // filters to only top level comments
hidden?: boolean, // if true, will show hidden comments as well hidden?: boolean, // if true, will show hidden comments as well
sort_by?: number, // @see: ui/constants/comments.js::SORT_BY sort_by?: ?number, // @see: ui/constants/comments.js::SORT_BY
}; };
declare type CommentListResponse = { declare type CommentListResponse = {
@ -134,13 +168,13 @@ declare type CommentListResponse = {
declare type CommentByIdParams = { declare type CommentByIdParams = {
comment_id: string, comment_id: string,
with_ancestors: boolean, with_ancestors: boolean,
} };
declare type CommentByIdResponse = { declare type CommentByIdResponse = {
item: Comment, item: Comment,
items: Comment, items: Comment,
ancestors: Array<Comment>, ancestors: Array<Comment>,
} };
declare type CommentPinParams = { declare type CommentPinParams = {
comment_id: string, comment_id: string,
@ -149,27 +183,34 @@ declare type CommentPinParams = {
remove?: boolean, remove?: boolean,
signature: string, signature: string,
signing_ts: string, signing_ts: string,
} };
declare type CommentPinResponse = { declare type CommentPinResponse = {
items: Comment, // "items" is an inherited typo to match SDK. Will be "item" in a new version. items: Comment, // "items" is an inherited typo to match SDK. Will be "item" in a new version.
} };
declare type CommentEditParams = { declare type CommentEditParams = {
comment: string, comment: string,
comment_id: string, comment_id: string,
signature: string, signature: string,
signing_ts: string, signing_ts: string,
} };
declare type CommentEditResponse = Comment declare type CommentEditResponse = Comment;
declare type CommentAbandonParams = { declare type CommentAbandonParams = {
comment_id: string, comment_id: string,
creator_channel_id?: string, creator_channel_id?: string,
creator_channel_name?: string, creator_channel_name?: string,
channel_id?: string, signature?: string,
hexdata?: string, signing_ts?: string,
mod_channel_id?: string,
mod_channel_name?: string,
};
declare type MentionedChannel = {
channel_name: string,
channel_id: string,
}; };
declare type CommentCreateParams = { declare type CommentCreateParams = {
@ -177,8 +218,9 @@ declare type CommentCreateParams = {
claim_id: string, claim_id: string,
parent_id?: string, parent_id?: string,
signature: string, signature: string,
signing_ts: number, signing_ts: string,
support_tx_id?: string, support_tx_id?: string,
mentioned_channels?: Array<MentionedChannel>,
}; };
declare type SuperListParams = {}; declare type SuperListParams = {};
@ -203,9 +245,11 @@ declare type ModerationBlockParams = {
// Creator that Moderator is delegated from. Used for delegated moderation // Creator that Moderator is delegated from. Used for delegated moderation
creator_channel_id?: string, creator_channel_id?: string,
creator_channel_name?: string, creator_channel_name?: string,
// ID of comment to remove as part of this block
offending_comment_id?: string,
// Blocks identity from comment universally, requires Admin rights on commentron instance // Blocks identity from comment universally, requires Admin rights on commentron instance
block_all?: boolean, block_all?: boolean,
time_out?: number, time_out?: ?number,
// If true will delete all comments of the offender, requires Admin rights on commentron for universal delete // If true will delete all comments of the offender, requires Admin rights on commentron for universal delete
delete_all?: boolean, delete_all?: boolean,
// The usual signature stuff // The usual signature stuff
@ -231,36 +275,23 @@ declare type BlockedListArgs = {
signing_ts: string, signing_ts: string,
}; };
declare type ModerationAddDelegateParams = { declare type ModerationAddDelegateParams = Authorization & {
mod_channel_id: string, mod_channel_id: string,
mod_channel_name: string, mod_channel_name: string,
creator_channel_id: string,
creator_channel_name: string,
signature: string,
signing_ts: string,
}; };
declare type ModerationRemoveDelegateParams = { declare type ModerationRemoveDelegateParams = Authorization & {
mod_channel_id: string, mod_channel_id: string,
mod_channel_name: string, mod_channel_name: string,
creator_channel_id: string,
creator_channel_name: string,
signature: string,
signing_ts: string,
}; };
declare type ModerationListDelegatesParams = { declare type ModerationListDelegatesParams = Authorization;
creator_channel_id: string,
creator_channel_name: string,
signature: string,
signing_ts: string,
};
declare type ModerationAmIParams = { declare type ModerationAmIParams = {
channel_name: string, channel_name: string,
channel_id: string, channel_id: string,
signature: string, signature: string,
signing_ts: string signing_ts: string,
}; };
declare type SettingsParams = { declare type SettingsParams = {
@ -289,7 +320,8 @@ declare type UpdateSettingsParams = {
min_tip_amount_comment?: number, min_tip_amount_comment?: number,
min_tip_amount_super_chat?: number, min_tip_amount_super_chat?: number,
slow_mode_min_gap?: number, slow_mode_min_gap?: number,
} time_since_first_comment?: number,
};
declare type BlockWordParams = { declare type BlockWordParams = {
channel_name: string, channel_name: string,

370
flow-typed/Lbry.js vendored Normal file
View file

@ -0,0 +1,370 @@
// @flow
declare type StatusResponse = {
blob_manager: {
finished_blobs: number,
},
blockchain_headers: {
download_progress: number,
downloading_headers: boolean,
},
dht: {
node_id: string,
peers_in_routing_table: number,
},
hash_announcer: {
announce_queue_size: number,
},
installation_id: string,
is_running: boolean,
skipped_components: Array<string>,
startup_status: {
blob_manager: boolean,
blockchain_headers: boolean,
database: boolean,
dht: boolean,
exchange_rate_manager: boolean,
hash_announcer: boolean,
peer_protocol_server: boolean,
stream_manager: boolean,
upnp: boolean,
wallet: boolean,
},
stream_manager: {
managed_files: number,
},
upnp: {
aioupnp_version: string,
dht_redirect_set: boolean,
external_ip: string,
gateway: string,
peer_redirect_set: boolean,
redirects: {},
},
wallet: ?{
connected: string,
best_blockhash: string,
blocks: number,
blocks_behind: number,
is_encrypted: boolean,
is_locked: boolean,
headers_synchronization_progress: number,
available_servers: number,
},
};
declare type VersionResponse = {
build: string,
lbrynet_version: string,
os_release: string,
os_system: string,
platform: string,
processor: string,
python_version: string,
};
declare type BalanceResponse = {
available: string,
reserved: string,
reserved_subtotals: ?{
claims: string,
supports: string,
tips: string,
},
total: string,
};
declare type ResolveResponse = {
// Keys are the url(s) passed to resolve
[string]: { error?: {}, stream?: StreamClaim, channel?: ChannelClaim, collection?: CollectionClaim, claimsInChannel?: number },
};
declare type GetResponse = FileListItem & { error?: string };
declare type GenericTxResponse = {
height: number,
hex: string,
inputs: Array<{}>,
outputs: Array<{}>,
total_fee: string,
total_input: string,
total_output: string,
txid: string,
};
declare type PublishResponse = GenericTxResponse & {
// Only first value in outputs is a claim
// That's the only value we care about
outputs: Array<Claim>,
};
declare type ClaimSearchResponse = {
items: Array<Claim>,
page: number,
page_size: number,
total_items?: number,
total_pages?: number,
};
declare type ClaimListResponse = {
items: Array<ChannelClaim | Claim>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type ChannelCreateResponse = GenericTxResponse & {
outputs: Array<ChannelClaim>,
};
declare type ChannelUpdateResponse = GenericTxResponse & {
outputs: Array<ChannelClaim>,
};
declare type CommentCreateResponse = Comment;
declare type CommentUpdateResponse = Comment;
declare type MyReactions = {
// Keys are the commentId
[string]: Array<string>,
};
declare type OthersReactions = {
// Keys are the commentId
[string]: {
// Keys are the reaction_type, e.g. 'like'
[string]: number,
},
};
declare type CommentReactListResponse = {
my_reactions: Array<MyReactions>,
others_reactions: Array<OthersReactions>,
};
declare type CommentHideResponse = {
// keyed by the CommentIds entered
[string]: { hidden: boolean },
};
declare type CommentPinResponse = {
// keyed by the CommentIds entered
items: Comment,
};
declare type CommentAbandonResponse = {
// keyed by the CommentId given
abandoned: boolean,
claim_id: string,
};
declare type ChannelListResponse = {
items: Array<ChannelClaim>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type ChannelSignResponse = {
signature: string,
signing_ts: string,
};
declare type CollectionCreateResponse = {
outputs: Array<Claim>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
}
declare type CollectionListResponse = {
items: Array<Claim>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type CollectionResolveResponse = {
items: Array<Claim>,
total_items: number,
};
declare type CollectionResolveOptions = {
claim_id: string,
};
declare type CollectionListOptions = {
page: number,
page_size: number,
resolve?: boolean,
};
declare type FileListResponse = {
items: Array<FileListItem>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type TxListResponse = {
items: Array<Transaction>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type SupportListResponse = {
items: Array<Support>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type BlobListResponse = { items: Array<string> };
declare type WalletListResponse = Array<{
id: string,
name: string,
}>;
declare type WalletStatusResponse = {
is_encrypted: boolean,
is_locked: boolean,
is_syncing: boolean,
};
declare type SyncApplyResponse = {
hash: string,
data: string,
};
declare type SupportAbandonResponse = GenericTxResponse;
declare type StreamListResponse = {
items: Array<StreamClaim>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type StreamRepostOptions = {
name: string,
bid: string,
claim_id: string,
channel_id?: string,
};
declare type StreamRepostResponse = GenericTxResponse;
declare type PurchaseListResponse = {
items: Array<PurchaseReceipt & { claim: StreamClaim }>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type PurchaseListOptions = {
page: number,
page_size: number,
resolve: boolean,
claim_id?: string,
channel_id?: string,
};
//
// Types used in the generic Lbry object that is exported
//
declare type LbryTypes = {
isConnected: boolean,
connectPromise: any, // null |
connect: () => any, // void | Promise<any> ?
daemonConnectionString: string,
alternateConnectionString: string,
methodsUsingAlternateConnectionString: Array<string>,
apiRequestHeaders: { [key: string]: string },
setDaemonConnectionString: string => void,
setApiHeader: (string, string) => void,
unsetApiHeader: string => void,
overrides: { [string]: ?Function },
setOverride: (string, Function) => void,
// getMediaType: (?string, ?string) => string,
// Lbry Methods
stop: () => Promise<string>,
status: () => Promise<StatusResponse>,
version: () => Promise<VersionResponse>,
resolve: (params: {}) => Promise<ResolveResponse>,
get: (params: {}) => Promise<GetResponse>,
publish: (params: {}) => Promise<PublishResponse>,
claim_search: (params: {}) => Promise<ClaimSearchResponse>,
claim_list: (params: {}) => Promise<ClaimListResponse>,
channel_create: (params: {}) => Promise<ChannelCreateResponse>,
channel_update: (params: {}) => Promise<ChannelUpdateResponse>,
channel_import: (params: {}) => Promise<string>,
channel_list: (params: {}) => Promise<ChannelListResponse>,
channel_sign: (params: {}) => Promise<ChannelSignResponse>,
stream_abandon: (params: {}) => Promise<GenericTxResponse>,
stream_list: (params: {}) => Promise<StreamListResponse>,
channel_abandon: (params: {}) => Promise<GenericTxResponse>,
support_create: (params: {}) => Promise<GenericTxResponse>,
support_list: (params: {}) => Promise<SupportListResponse>,
support_abandon: (params: {}) => Promise<SupportAbandonResponse>,
stream_repost: (params: StreamRepostOptions) => Promise<StreamRepostResponse>,
purchase_list: (params: PurchaseListOptions) => Promise<PurchaseListResponse>,
collection_resolve: (params: CollectionResolveOptions) => Promise<CollectionResolveResponse>,
collection_list: (params: CollectionListOptions) => Promise<CollectionListResponse>,
collection_create: (params: {}) => Promise<CollectionCreateResponse>,
collection_update: (params: {}) => Promise<CollectionCreateResponse>,
// File fetching and manipulation
file_list: (params: {}) => Promise<FileListResponse>,
file_delete: (params: {}) => Promise<boolean>,
blob_delete: (params: {}) => Promise<string>,
blob_list: (params: {}) => Promise<BlobListResponse>,
file_set_status: (params: {}) => Promise<any>,
file_reflect: (params: {}) => Promise<any>,
// Preferences
preference_get: (params?: {}) => Promise<any>,
preference_set: (params: {}) => Promise<any>,
// Commenting
comment_update: (params: {}) => Promise<CommentUpdateResponse>,
comment_hide: (params: {}) => Promise<CommentHideResponse>,
comment_abandon: (params: {}) => Promise<CommentAbandonResponse>,
comment_list: (params: {}) => Promise<any>,
comment_create: (params: {}) => Promise<any>,
// Wallet utilities
wallet_balance: (params: {}) => Promise<BalanceResponse>,
wallet_decrypt: (prams: {}) => Promise<boolean>,
wallet_encrypt: (params: {}) => Promise<boolean>,
wallet_unlock: (params: {}) => Promise<boolean>,
wallet_list: (params: {}) => Promise<WalletListResponse>,
wallet_send: (params: {}) => Promise<GenericTxResponse>,
wallet_status: (params?: {}) => Promise<WalletStatusResponse>,
address_is_mine: (params: {}) => Promise<boolean>,
address_unused: (params: {}) => Promise<string>, // New address
address_list: (params: {}) => Promise<string>,
transaction_list: (params: {}) => Promise<TxListResponse>,
txo_list: (params: {}) => Promise<any>,
account_set: (params: {}) => Promise<any>,
account_list: (params?: {}) => Promise<any>,
// Sync
sync_hash: (params?: {}) => Promise<string>,
sync_apply: (params: {}) => Promise<SyncApplyResponse>,
// syncGet
// The app shouldn't need to do this
utxo_release: () => Promise<any>,
};

99
flow-typed/LbryFirst.js vendored Normal file
View file

@ -0,0 +1,99 @@
// @flow
declare type LbryFirstStatusResponse = {
Version: string,
Message: string,
Running: boolean,
Commit: string,
};
declare type LbryFirstVersionResponse = {
build: string,
lbrynet_version: string,
os_release: string,
os_system: string,
platform: string,
processor: string,
python_version: string,
};
/* SAMPLE UPLOAD RESPONSE (FULL)
"Video": {
"etag": "\"Dn5xIderbhAnUk5TAW0qkFFir0M/xlGLrlTox7VFTRcR8F77RbKtaU4\"",
"id": "8InjtdvVmwE",
"kind": "youtube#video",
"snippet": {
"categoryId": "22",
"channelId": "UCXiVsGTU88fJjheB2rqF0rA",
"channelTitle": "Mark Beamer",
"liveBroadcastContent": "none",
"localized": {
"title": "my title"
},
"publishedAt": "2020-05-05T04:17:53.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i9.ytimg.com/vi/8InjtdvVmwE/default.jpg?sqp=CMTQw_UF&rs=AOn4CLB6dlhZMSMrazDlWRsitPgCsn8fVw",
"width": 120
},
"high": {
"height": 360,
"url": "https://i9.ytimg.com/vi/8InjtdvVmwE/hqdefault.jpg?sqp=CMTQw_UF&rs=AOn4CLB-Je_7l6qvASRAR_bSGWZHaXaJWQ",
"width": 480
},
"medium": {
"height": 180,
"url": "https://i9.ytimg.com/vi/8InjtdvVmwE/mqdefault.jpg?sqp=CMTQw_UF&rs=AOn4CLCvSnDLqVznRNMKuvJ_0misY_chPQ",
"width": 320
}
},
"title": "my title"
},
"status": {
"embeddable": true,
"license": "youtube",
"privacyStatus": "private",
"publicStatsViewable": true,
"uploadStatus": "uploaded"
}
}
*/
declare type UploadResponse = {
Video: {
id: string,
snippet: {
channelId: string,
},
status: {
uploadStatus: string,
},
},
};
declare type HasYTAuthResponse = {
HashAuth: boolean,
};
declare type YTSignupResponse = {};
//
// Types used in the generic LbryFirst object that is exported
//
declare type LbryFirstTypes = {
isConnected: boolean,
connectPromise: ?Promise<any>,
connect: () => void,
lbryFirstConnectionString: string,
apiRequestHeaders: { [key: string]: string },
setApiHeader: (string, string) => void,
unsetApiHeader: string => void,
overrides: { [string]: ?Function },
setOverride: (string, Function) => void,
// LbryFirst Methods
stop: () => Promise<string>,
status: () => Promise<StatusResponse>,
version: () => Promise<VersionResponse>,
upload: any => Promise<?UploadResponse>,
hasYTAuth: string => Promise<HasYTAuthResponse>,
ytSignup: () => Promise<YTSignupResponse>,
};

5
flow-typed/Reflector.js vendored Normal file
View file

@ -0,0 +1,5 @@
declare type ReflectingUpdate = {
fileListItem: FileListItem,
progress: number | boolean,
stalled: boolean,
};

21
flow-typed/Tags.js vendored Normal file
View file

@ -0,0 +1,21 @@
declare type TagState = {
followedTags: FollowedTags,
knownTags: KnownTags,
};
declare type Tag = {
name: string,
};
declare type KnownTags = {
[string]: Tag,
};
declare type FollowedTags = Array<string>;
declare type TagAction = {
type: string,
data: {
name: string,
},
};

28
flow-typed/Transaction.js vendored Normal file
View file

@ -0,0 +1,28 @@
// @flow
declare type Transaction = {
amount: number,
claim_id: string,
claim_name: string,
fee: number,
nout: number,
txid: string,
type: string,
date: Date,
};
declare type Support = {
address: string,
amount: string,
claim_id: string,
confirmations: number,
height: string,
is_change: string,
is_mine: string,
name: string,
normalized_name: string,
nout: string,
permanent_url: string,
timestamp: number,
txid: string,
type: string,
};

27
flow-typed/Txo.js vendored Normal file
View file

@ -0,0 +1,27 @@
declare type Txo = {
amount: number,
claim_id: string,
normalized_name: string,
nout: number,
txid: string,
type: string,
value_type: string,
timestamp: number,
is_my_output: boolean,
is_my_input: boolean,
is_spent: boolean,
signing_channel?: {
channel_id: string,
},
};
declare type TxoListParams = {
page: number,
page_size: number,
type: string,
is_my_input?: boolean,
is_my_output?: boolean,
is_not_my_input?: boolean,
is_not_my_output?: boolean,
is_spent?: boolean,
};

34
flow-typed/content.js vendored
View file

@ -1,9 +1,37 @@
// @flow // @flow
declare type PlayingUri = { declare type ContentState = {
primaryUri: ?string,
playingUri: {
uri?: string,
collection: PlayingCollection,
},
positions: { [string]: { [string]: number } }, // claimId: { outpoint: position }
history: Array<WatchHistory>,
recommendationId: { [string]: string }, // claimId: recommendationId
recommendationParentId: { [string]: string }, // claimId: referrerId
recommendationUrls: { [string]: Array<string> }, // claimId: [lbryUrls...]
recommendationClicks: { [string]: Array<number> }, // "claimId": [clicked indices...]
lastViewedAnnouncement: ?string, // undefined = not seen in wallet.
recsysEntries: { [ClaimId]: RecsysEntry }, // Persistent shadow copy. The main one resides in RecSys.
};
declare type WatchHistory = {
uri: string, uri: string,
primaryUri: string, lastViewed: number,
pathname: string, };
declare type PlayingUri = {
uri?: ?string,
primaryUri?: string,
pathname?: string,
commentId?: string, commentId?: string,
collection: PlayingCollection,
source?: string, source?: string,
}; };
declare type PlayingCollection = {
collectionId?: ?string,
loop?: ?boolean,
shuffle?: ?{ newUrls: Array<string> },
};

5
flow-typed/gui.js vendored Normal file
View file

@ -0,0 +1,5 @@
declare type ListInjectedItem = {
node: Node | (index: number, lastVisibleIndex: ?number, pageSize: ?number) => Node,
index?: number,
};

View file

@ -8,20 +8,26 @@ declare type HomepageObject = {
declare type HomepageData = { declare type HomepageData = {
[string]: HomepageObject, [string]: HomepageObject,
default: any => any, default: (any) => any,
}; };
declare type RowDataItem = { declare type RowDataItem = {
id: string,
title: any, title: any,
link?: string, link?: string,
help?: any, help?: any,
icon?: string, icon?: string,
extra?: any, extra?: any,
pinnedUrls?: Array<string>, pinnedUrls?: Array<string>,
pinnedClaimIds?: Array<string>, // takes precedence over pinnedUrls
hideByDefault?: boolean,
options?: { options?: {
channelIds?: Array<string>, channelIds?: Array<string>,
excludedChannelIds?: Array<string>,
limitClaimsPerChannel?: number, limitClaimsPerChannel?: number,
pageSize?: number, pageSize?: number,
releaseTime?: string,
searchLanguages?: Array<string>,
}, },
route?: string, route?: string,
hideForUnauth?: boolean, hideForUnauth?: boolean,

2
flow-typed/i18n.js vendored Normal file
View file

@ -0,0 +1,2 @@
// @flow
declare function __(a: string, b?: {}): string;

23
flow-typed/lbryURI.js vendored Normal file
View file

@ -0,0 +1,23 @@
// @flow
declare type LbryUrlObj = {
// Path and channel will always exist when calling parseURI
// But they may not exist when code calls buildURI
isChannel?: boolean,
path?: string,
streamName?: string,
streamClaimId?: string,
channelName?: string,
channelClaimId?: string,
primaryClaimSequence?: number,
secondaryClaimSequence?: number,
primaryBidPosition?: number,
secondaryBidPosition?: number,
startTime?: number,
queryString?: string,
pathHash?: string,
// Below are considered deprecated and should not be used due to unreliableness with claim.canonical_url
claimName?: string,
claimId?: string,
contentName?: string,
};

View file

@ -18,24 +18,27 @@ declare type LivestreamReplayItem = {
uploadedAt: string, // Date? uploadedAt: string, // Date?
}, },
id: string, id: string,
} };
declare type LivestreamReplayData = Array<LivestreamReplayItem>; declare type LivestreamReplayData = Array<LivestreamReplayItem>;
declare type LivestreamState = { declare type LivestreamState = {
fetchingById: {}, fetchingById: {},
viewersById: {}, viewersById: {},
fetchingActiveLivestreams: boolean, fetchingActiveLivestreams: boolean | string,
activeLivestreams: ?LivestreamInfo, activeLivestreams: ?LivestreamInfo,
activeLivestreamsLastFetchedDate: number, activeLivestreamsLastFetchedDate: number,
activeLivestreamsLastFetchedOptions: {}, activeLivestreamsLastFetchedOptions: {},
} activeLivestreamsLastFetchedFailCount: number,
activeLivestreamInitialized: boolean,
socketConnectionById: { [id: string]: { connected: ?boolean, sub_category: ?string } },
};
declare type LivestreamInfo = { declare type LivestreamInfo = {
[/* creatorId */ string]: { [/* creatorId */ string]: {
live: boolean, live: boolean,
viewCount: number, viewCount: number,
creatorId: string, creatorId: string,
latestClaimId: string, claimId: string,
latestClaimUri: string, claimUri: string,
} },
} };

View file

@ -1,4 +1,103 @@
// @flow // @flow
import * as ACTIONS from 'constants/action_types';
/*
Toasts:
- First-in, first-out queue
- Simple messages that are shown in response to user interactions
- Never saved
- If they are the result of errors, use the isError flag when creating
- For errors that should interrupt user behavior, use Error
*/
declare type ToastParams = {
message: string,
subMessage?: string,
// title?: string,
linkText?: string,
linkTarget?: string,
isError?: boolean,
duration?: 'default' | 'long',
actionText?: string,
action?: () => void,
secondaryActionText?: string,
secondaryAction?: () => void,
};
declare type Toast = {
id: string,
params: ToastParams,
};
declare type DoToast = {
type: ACTIONS.CREATE_TOAST,
data: Toast,
};
/*
Notifications:
- List of notifications based on user interactions/app notifications
- Always saved, but can be manually deleted
- Can happen in the background, or because of user interaction (ex: publish confirmed)
*/
declare type Notification = {
id: string, // Unique id
dateCreated: number,
isRead: boolean, // Used to display "new" notifications that a user hasn't seen yet
source?: string, // The type/area an notification is from. Used for sorting (ex: publishes, transactions)
// We may want to use priority/isDismissed in the future to specify how urgent a notification is
// and if the user should see it immediately
// isDissmied: boolean,
// priority?: number
};
declare type DoNotification = {
type: ACTIONS.CREATE_NOTIFICATION,
data: Notification,
};
declare type DoEditNotification = {
type: ACTIONS.EDIT_NOTIFICATION,
data: {
notification: Notification,
},
};
declare type DoDeleteNotification = {
type: ACTIONS.DELETE_NOTIFICATION,
data: {
id: string, // The id to delete
},
};
/*
Errors:
- First-in, first-out queue
- Errors that should interupt user behavior
- For errors that can be shown without interrupting a user, use Toast with the isError flag
*/
declare type ErrorNotification = {
title: string,
text: string,
};
declare type DoError = {
type: ACTIONS.CREATE_ERROR,
data: ErrorNotification,
};
declare type DoDismissError = {
type: ACTIONS.DISMISS_ERROR,
};
/*
NotificationState
*/
declare type NotificationState = {
notifications: Array<Notification>,
errors: Array<ErrorNotification>,
toasts: Array<Toast>,
};
declare type WebNotification = { declare type WebNotification = {
active_at: string, active_at: string,
created_at: string, created_at: string,
@ -22,11 +121,14 @@ declare type WebNotification = {
}, },
dynamic: { dynamic: {
comment_author: string, comment_author: string,
comment_author_thumbnail?: string,
reply_author: string, reply_author: string,
hash: string, hash: string,
claim_title: string, claim_title: string,
claim_thumbnail?: string,
comment?: string, comment?: string,
channel_url: string, channel_url: string,
channel_thumbnail?: string,
}, },
email: {}, email: {},
}, },

30
flow-typed/publish.js vendored
View file

@ -14,6 +14,9 @@ declare type UpdatePublishFormData = {
thumbnailError?: boolean, thumbnailError?: boolean,
description?: string, description?: string,
language?: string, language?: string,
releaseTime?: number,
releaseTimeEdited?: number,
releaseTimeError?: string,
channel?: string, channel?: string,
channelId?: string, channelId?: string,
name?: string, name?: string,
@ -25,7 +28,7 @@ declare type UpdatePublishFormData = {
licenseType?: string, licenseType?: string,
uri?: string, uri?: string,
nsfw: boolean, nsfw: boolean,
isMarkdownPost: boolean, isMarkdownPost?: boolean,
}; };
declare type PublishParams = { declare type PublishParams = {
@ -52,3 +55,28 @@ declare type PublishParams = {
nsfw: boolean, nsfw: boolean,
tags: Array<Tag>, tags: Array<Tag>,
}; };
declare type TusUploader = any;
declare type FileUploadSdkParams = {
file_path: string | File,
claim_id: ?string,
name: ?string,
preview?: boolean,
remote_url?: string,
thumbnail_url?: string,
title?: string,
// Temporary values; remove when passing to SDK
guid: string,
uploadUrl?: string,
};
declare type FileUploadItem = {
params: FileUploadSdkParams,
file: File,
fileFingerprint: string,
progress: string,
status?: string,
uploader?: TusUploader | XMLHttpRequest,
resumable: boolean,
};

49
flow-typed/recsys.js vendored Normal file
View file

@ -0,0 +1,49 @@
declare type Recsys = {
entries: { [ClaimId]: RecsysEntry },
debug: boolean,
saveEntries: () => void,
onClickedRecommended: (parentClaimId: ClaimId, newClaimId: ClaimId) => void,
onRecsLoaded: (claimId: ClaimId, uris: Array<string>, uuid: string) => void,
createRecsysEntry: (claimId: ClaimId, parentUuid?: ?string, uuid?: string) => void,
updateRecsysEntry: (claimId: ClaimId, key: string, value: string) => void,
sendRecsysEntry: (claimId: ClaimId, isTentative?: boolean) => ?Promise<?Response>,
sendEntries: (entries: ?{ [ClaimId]: RecsysEntry }, isResumedSend: boolean) => void,
onRecsysPlayerEvent: (claimId: ClaimId, event: RecsysPlaybackEvent, isEmbedded: boolean) => void,
log: (callName: string, claimId: ClaimId) => void,
onPlayerDispose: (claimId: ClaimId, isEmbedded: boolean, totalPlayingTime: number) => void,
onNavigate: () => void,
};
declare type RecsysEntry = {
uuid: string,
parentUuid?: string,
claimId: string,
uid?: number,
deviceId?: number,
pageLoadedAt: number, // UNIX timestamp (in UTC)
pageExitedAt: number, // UNIX timestamp (in UTC)
events: Array<RecsysPlaybackEvent>,
recsysId: string, // Recommender that produced recs
recClaimIds: Array<string>, // Recommendations
recClickedVideoIdx: Array<number>, // Video clicked index
isEmbed: boolean,
remoteIp: any, // [bytes] Caller IP address
tentative: boolean, // Visibility change rather than tab close
autoplay: boolean, // Was the last human action before this?
commentPulls: number, // How many comment pull calls did the user request?
recorded_at: number,
user_agent: string,
accept_lang: string,
tokenVerified: boolean,
totalPlayTime: number,
finalPlayPosition: number,
incognito: number, // User not logged in.
isResumedSend: boolean, // Data sent after browser is re-opened.
};
declare type RecsysPlaybackEvent = {
event: number, // 0 = start, 1 = stop, 2 = scrub, 3 = speed, 4 = end_of_play
offset: number, // Where playback was at time of event
arg: number,
};

3
flow-typed/redux.js vendored
View file

@ -1,3 +1,6 @@
// @flow // @flow
/* eslint-disable no-use-before-define */
declare type GetState = () => any;
declare type Dispatch = any; declare type Dispatch = any;
/* eslint-enable */

21
flow-typed/search.js vendored
View file

@ -15,7 +15,7 @@ declare type SearchOptions = {
MEDIA_IMAGE: string, MEDIA_IMAGE: string,
MEDIA_APPLICATION: string, MEDIA_APPLICATION: string,
SORT: string, SORT: string,
SORT_ACCENDING: string, SORT_ASCENDING: string,
SORT_DESCENDING: string, SORT_DESCENDING: string,
EXACT: string, EXACT: string,
TIME_FILTER: string, TIME_FILTER: string,
@ -28,9 +28,18 @@ declare type SearchOptions = {
declare type SearchState = { declare type SearchState = {
options: SearchOptions, options: SearchOptions,
resultsByQuery: {}, resultsByQuery: { [string]: { uris: Array<string>, recsys: string, uuid: string } },
results: Array<string>,
hasReachedMaxResultsLength: {}, hasReachedMaxResultsLength: {},
searching: boolean, searching: boolean,
mentionQuery: string,
personalRecommendations: { gid: string, uris: Array<string>, fetched: boolean },
};
declare type SearchResults = {
body: Array<{ name: string, claimId: string}>,
poweredBy: string,
uuid: string,
}; };
declare type SearchSuccess = { declare type SearchSuccess = {
@ -40,7 +49,8 @@ declare type SearchSuccess = {
from: number, from: number,
size: number, size: number,
uris: Array<string>, uris: Array<string>,
recsys: string, poweredBy: string,
uuid: string,
}, },
}; };
@ -48,3 +58,8 @@ declare type UpdateSearchOptions = {
type: ACTIONS.UPDATE_SEARCH_OPTIONS, type: ACTIONS.UPDATE_SEARCH_OPTIONS,
data: SearchOptions, data: SearchOptions,
}; };
declare type FypParam = {
gid: string,
uuid: string,
};

View file

@ -13,6 +13,7 @@ declare type Following = {
declare type SubscriptionState = { declare type SubscriptionState = {
subscriptions: Array<Subscription>, subscriptions: Array<Subscription>,
lastActiveSubscriptions: ?Array<Subscription>,
following: Array<Following>, following: Array<Following>,
loading: boolean, loading: boolean,
firstRunCompleted: boolean, firstRunCompleted: boolean,

17
flow-typed/sync.js vendored Normal file
View file

@ -0,0 +1,17 @@
declare type SyncState = {
hasSyncedWallet: boolean,
syncHash: ?string,
syncData: ?string,
setSyncErrorMessage: ?string,
getSyncErrorMessage: ?string,
syncApplyErrorMessage: string,
syncApplyIsPending: boolean,
syncApplyPasswordError: boolean,
getSyncIsPending: boolean,
setSyncIsPending: boolean,
prefsReady: boolean,
syncLocked: boolean,
sharedStateSyncId: number,
hashChanged: boolean,
fatalError: boolean,
};

42
flow-typed/user.js vendored
View file

@ -32,4 +32,46 @@ declare type User = {
odysee_live_enabled: boolean, odysee_live_enabled: boolean,
odysee_live_disabled: boolean, odysee_live_disabled: boolean,
global_mod: boolean, global_mod: boolean,
publish_id: ?number,
is_odysee_user: boolean,
location: ?string,
};
declare type UserState ={
authenticationIsPending: boolean,
userIsPending: boolean,
emailNewIsPending: boolean,
emailNewErrorMessage: string,
emailToVerify: string,
emailAlreadyExists: boolean,
emailDoesNotExist: boolean,
resendingVerificationEmail: boolean,
passwordResetPending: boolean,
passwordResetSuccess: boolean,
passwordResetError: ?string,
passwordSetPending: boolean,
passwordSetSuccess: boolean,
passwordSetError: ?string,
inviteNewErrorMessage: string,
inviteNewIsPending: boolean,
inviteStatusIsPending: boolean,
invitesRemaining: ?number,
invitees: ?Array<string>,
referralLink: ?string,
referralCode: ?string,
user: ?User,
youtubeChannelImportPending: boolean,
youtubeChannelImportErrorMessage: string,
referrerSetIsPending: boolean,
referrerSetError: string,
odyseeMembershipName: ?string, // undefined: not fetched, '': no membership
odyseeMembershipsPerClaimIds: ?{ [string]: string },
locale: ?LocaleInfo,
};
declare type LocaleInfo = {
continent: string,
country: string,
gdpr_required: boolean,
is_eu_member: boolean,
}; };

View file

@ -1,26 +1,25 @@
{ {
"name": "lbry", "name": "odysee.com",
"version": "0.51.2", "version": "0.0.0",
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "description": "Explore a whole universe of videos on Odysee from regular people just like you!",
"keywords": [ "keywords": [
"lbry" "odysee"
], ],
"license": "MIT", "license": "MIT",
"homepage": "https://lbry.com/", "homepage": "https://odysee.com",
"bugs": { "bugs": {
"url": "https://github.com/lbryio/lbry-desktop/issues" "url": "https://github.com/OdyseeTeam/odysee-frontend/issues"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/lbryio/lbry-desktop" "url": "https://github.com/OdyseeTeam/odysee-frontend"
}, },
"author": { "author": {
"name": "LBRY Inc.", "name": "Odysee Inc.",
"email": "hello@lbry.com" "email": "hello@odysee.com"
}, },
"main": "./dist/electron/main.js", "main": "./dist/electron/main.js",
"scripts": { "scripts": {
"analyze": "source-map-explorer --only-mapped dist/electron/webpack/ui*.js --html dist/sourceMap.html",
"compile:electron": "node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js --config webpack.electron.config.js", "compile:electron": "node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js --config webpack.electron.config.js",
"compile:web": "yarn copyenv && cd web && node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js --config webpack.config.js", "compile:web": "yarn copyenv && cd web && node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js --config webpack.config.js",
"compile": "cross-env NODE_ENV=production yarn compile:electron && cross-env NODE_ENV=production yarn compile:web", "compile": "cross-env NODE_ENV=production yarn compile:electron && cross-env NODE_ENV=production yarn compile:web",
@ -38,18 +37,24 @@
"build:dir": "yarn build -- --dir -c.compression=store -c.mac.identity=null", "build:dir": "yarn build -- --dir -c.compression=store -c.mac.identity=null",
"crossenv": "./node_modules/cross-env/dist/bin/cross-env", "crossenv": "./node_modules/cross-env/dist/bin/cross-env",
"flow": "flow", "flow": "flow",
"lint": "eslint 'ui/**/*.{js,jsx}' && eslint 'web/**/*.{js,jsx}' && eslint 'electron/**/*.js' && flow", "lint": "eslint 'ui/**/*.{js,jsx}' && eslint 'extras/**/*.{js,jsx}' && eslint 'web/**/*.{js,jsx}' && eslint 'electron/**/*.js' && flow",
"lint-fix": "eslint --fix --quiet 'ui/**/*.{js,jsx}' && eslint --fix --quiet 'web/**/*.{js,jsx}' && eslint --fix --quiet 'electron/**/*.js'", "lint-fix": "eslint --fix --quiet 'ui/**/*.{js,jsx}' && eslint --fix --quiet 'extras/**/*.{js,jsx}' && eslint --fix --quiet 'web/**/*.{js,jsx}' && eslint --fix --quiet 'electron/**/*.js'",
"format": "prettier 'src/**/*.{js,jsx,scss,json}' --write", "format": "prettier 'src/**/*.{js,jsx,scss,json}' --write",
"flow-defs": "flow-typed install", "flow-defs": "flow-typed install",
"precommit": "lint-staged", "preinstall": "",
"preinstall": "yarn cache clean lbry-redux && yarn cache clean lbryinc",
"postinstall": "cd web && yarn && cd .. && if-env NODE_ENV=production && yarn postinstall:warning || if-env APP_ENV=web && echo 'Done installing deps' || yarn postinstall:electron", "postinstall": "cd web && yarn && cd .. && if-env NODE_ENV=production && yarn postinstall:warning || if-env APP_ENV=web && echo 'Done installing deps' || yarn postinstall:electron",
"postinstall:electron": "electron-builder install-app-deps && node ./build/downloadDaemon.js && node ./build/downloadLBRYFirst.js", "postinstall:electron": "electron-builder install-app-deps && node ./build/downloadDaemon.js && node ./build/downloadLBRYFirst.js",
"postinstall:warning": "echo '\n\nWARNING\n\nNot all node modules were installed because NODE_ENV is set to \"production\".\nThis should only be set after installing dependencies with \"yarn\". The app will not work.\n\n'" "postinstall:warning": "echo '\n\nWARNING\n\nNot all node modules were installed because NODE_ENV is set to \"production\".\nThis should only be set after installing dependencies with \"yarn\". The app will not work.\n\n'"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.6.0",
"@emotion/styled": "^11.6.0",
"@mui/material": "^5.6.2",
"@silvermine/videojs-airplay": "^1.1.0",
"@silvermine/videojs-chromecast": "^1.3.3",
"@ungap/from-entries": "^0.2.1",
"auto-launch": "^5.0.5", "auto-launch": "^5.0.5",
"core-js-pure": "^3.19.3",
"electron-dl": "^1.11.0", "electron-dl": "^1.11.0",
"electron-log": "^2.2.12", "electron-log": "^2.2.12",
"electron-notarize": "^1.0.0", "electron-notarize": "^1.0.0",
@ -59,16 +64,24 @@
"if-env": "^1.0.4", "if-env": "^1.0.4",
"match-sorter": "^6.3.0", "match-sorter": "^6.3.0",
"parse-duration": "^1.0.0", "parse-duration": "^1.0.0",
"react-datetime-picker": "^3.2.1", "player.js": "^0.1.0",
"proxy-polyfill": "0.1.6",
"re-reselect": "^4.0.0",
"react-beautiful-dnd": "^13.1.0",
"react-color": "^2.19.3",
"react-datetime-picker": "^3.4.3",
"react-plastic": "^1.1.1", "react-plastic": "^1.1.1",
"react-top-loading-bar": "^2.0.1", "react-top-loading-bar": "^2.0.1",
"remove-markdown": "^0.3.0", "remove-markdown": "^0.3.0",
"rss": "^1.2.2", "rss": "^1.2.2",
"source-map-explorer": "^2.5.2", "source-map-explorer": "^2.5.2",
"tempy": "^0.6.0", "tempy": "^0.6.0",
"tus-js-client": "^2.3.0",
"videojs-contrib-ads": "^6.9.0", "videojs-contrib-ads": "^6.9.0",
"videojs-ima": "^1.11.0", "videojs-ima": "^1.11.0",
"videojs-logo": "^2.1.4" "videojs-ima-player": "^0.5.6",
"videojs-logo": "^2.1.4",
"videojs-vtt-thumbnails": "https://github.com/OdyseeTeam/videojs-vtt-thumbnails"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.0.0", "@babel/core": "^7.0.0",
@ -84,13 +97,12 @@
"@babel/preset-flow": "^7.12.1", "@babel/preset-flow": "^7.12.1",
"@babel/preset-react": "^7.0.0", "@babel/preset-react": "^7.0.0",
"@babel/register": "^7.0.0", "@babel/register": "^7.0.0",
"@datapunt/matomo-tracker-js": "^0.1.4",
"@exponent/electron-cookies": "^2.0.0", "@exponent/electron-cookies": "^2.0.0",
"@hot-loader/react-dom": "^16.13", "@hot-loader/react-dom": "^16.13",
"@reach/auto-id": "^0.13.0", "@reach/auto-id": "^0.13.0",
"@reach/combobox": "^0.12.1", "@reach/combobox": "^0.12.1",
"@reach/menu-button": "0.7.4", "@reach/menu-button": "0.8.6",
"@reach/rect": "^0.13.0", "@reach/rect": "^0.16.0",
"@reach/tabs": "^0.1.5", "@reach/tabs": "^0.1.5",
"@reach/tooltip": "^0.12.1", "@reach/tooltip": "^0.12.1",
"@reach/utils": "^0.12.1", "@reach/utils": "^0.12.1",
@ -133,7 +145,7 @@
"electron-webpack": "^2.8.2", "electron-webpack": "^2.8.2",
"electron-window-state": "^4.1.1", "electron-window-state": "^4.1.1",
"emoji-dictionary": "^1.0.11", "emoji-dictionary": "^1.0.11",
"eslint": "^5.15.2", "eslint": "^7.5",
"eslint-config-prettier": "^2.9.0", "eslint-config-prettier": "^2.9.0",
"eslint-config-standard": "^12.0.0", "eslint-config-standard": "^12.0.0",
"eslint-config-standard-jsx": "^6.0.2", "eslint-config-standard-jsx": "^6.0.2",
@ -157,8 +169,6 @@
"imagesloaded": "^4.1.4", "imagesloaded": "^4.1.4",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git", "lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#0f930c4a7bfc7f164e6b3c6044050c1bc73f6ab8",
"lbryinc": "lbryio/lbryinc#0b4e41ef90d6347819dd3453f2f9398a5c1b4f36",
"lint-staged": "^7.0.2", "lint-staged": "^7.0.2",
"localforage": "^1.7.1", "localforage": "^1.7.1",
"lodash-es": "^4.17.14", "lodash-es": "^4.17.14",
@ -169,7 +179,7 @@
"node-libs-browser": "^2.1.0", "node-libs-browser": "^2.1.0",
"node-loader": "^0.6.0", "node-loader": "^0.6.0",
"node-wget": "^0.4.3", "node-wget": "^0.4.3",
"nodemon": "^1.19.1", "nodemon": "^2.0.15",
"postcss-import": "^12.0.1", "postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"postcss-rtl": "^1.7.3", "postcss-rtl": "^1.7.3",
@ -183,7 +193,7 @@
"react-awesome-lightbox": "^1.7.3", "react-awesome-lightbox": "^1.7.3",
"react-confetti": "^4.0.1", "react-confetti": "^4.0.1",
"react-dom": "^16.8.2", "react-dom": "^16.8.2",
"react-draggable": "^3.3.0", "react-draggable": "^4.4.4",
"react-google-recaptcha": "^2.0.1", "react-google-recaptcha": "^2.0.1",
"react-hot-loader": "^4.11.1", "react-hot-loader": "^4.11.1",
"react-modal": "^3.1.7", "react-modal": "^3.1.7",
@ -220,7 +230,7 @@
"unist-util-visit": "^2.0.3", "unist-util-visit": "^2.0.3",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"vast-client": "^3.1.1", "vast-client": "^3.1.1",
"video.js": "^7.13.3", "video.js": "^7.19.2",
"videojs-contrib-quality-levels": "^2.0.9", "videojs-contrib-quality-levels": "^2.0.9",
"videojs-event-tracking": "^1.0.1", "videojs-event-tracking": "^1.0.1",
"villain-react": "^1.0.9", "villain-react": "^1.0.9",
@ -241,6 +251,11 @@
"node": ">=7", "node": ">=7",
"yarn": "^1.3" "yarn": "^1.3"
}, },
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lbrySettings": { "lbrySettings": {
"lbrynetDaemonVersion": "0.99.0", "lbrynetDaemonVersion": "0.99.0",
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip", "lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip",

File diff suppressed because it is too large Load diff

71
static/img/cookie.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 30 KiB

View file

@ -1,10 +1,27 @@
<!DOCTYPE html> <!DOCTYPE html>
<html dir="ltr"> <html dir="ltr">
<head> <head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-BB8DNPB73F"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('consent', 'default', {
ad_storage: 'denied',
analytics_storage: 'denied',
});
gtag('js', new Date());
gtag('config', 'G-BB8DNPB73F');
</script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Expires" content="0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="preload" href="/public/font/v1/300.woff" as="font" type="font/woff" crossorigin /> <link rel="preload" href="/public/font/v1/300.woff" as="font" type="font/woff" crossorigin />
<link rel="preload" href="/public/font/v1/300i.woff" as="font" type="font/woff" crossorigin /> <link rel="preload" href="/public/font/v1/300i.woff" as="font" type="font/woff" crossorigin />
@ -13,7 +30,7 @@
<link rel="preload" href="/public/font/v1/700.woff" as="font" type="font/woff" crossorigin /> <link rel="preload" href="/public/font/v1/700.woff" as="font" type="font/woff" crossorigin />
<link rel="preload" href="/public/font/v1/700i.woff" as="font" type="font/woff" crossorigin /> <link rel="preload" href="/public/font/v1/700i.woff" as="font" type="font/woff" crossorigin />
<link rel="shortcut icon" href="/public/favicon-spaceman.png"> <link rel="shortcut icon" href="/public/favicon-spaceman.png" />
<style> <style>
@font-face { @font-face {

View file

@ -1,15 +1,38 @@
// @flow // @flow
import { Lbryio } from 'lbryinc'; import { Lbryio } from 'lbryinc';
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import MatomoTracker from '@datapunt/matomo-tracker-js'; import * as RENDER_MODES from 'constants/file_render_modes';
import { history } from './store'; import { SDK_API_PATH } from 'config';
import { SDK_API_PATH } from './index';
// @if TARGET='app' // --- GA ---
import Native from 'native'; // - Events: 500 max (cannot be deleted).
import ElectronCookies from '@exponent/electron-cookies'; // - Dimensions: 25 max (cannot be deleted, but can be "archived"). Usually
import { generateInitialUrl } from 'util/url'; // tied to an event parameter for reporting purposes.
// @endif //
import { MATOMO_ID, MATOMO_URL } from 'config'; // Given the limitations above, we need to plan ahead before adding new Events
// and Parameters.
//
// Events:
// - Find a Recommended Event that is closest to what you need.
// https://support.google.com/analytics/answer/9267735?hl=en
// - If doesn't exist, use a Custom Event.
//
// Parameters:
// - Custom parameters don't appear in automated reports until they are tied to
// a Dimension.
// - Add your entry to GA_DIMENSIONS below -- tt allows us to keep track so that
// we don't exceed the limit. Re-use existing parameters if possible.
// - Register the Dimension in GA Console to make it visible in reports.
export const GA_DIMENSIONS = {
TYPE: 'type',
ACTION: 'action',
VALUE: 'value',
START_TIME_MS: 'start_time_ms',
DURATION_MS: 'duration_ms',
END_TIME_MS: 'end_time_ms',
};
// import getConnectionSpeed from 'util/detect-user-bandwidth'; // import getConnectionSpeed from 'util/detect-user-bandwidth';
// let userDownloadBandwidthInBitsPerSecond; // let userDownloadBandwidthInBitsPerSecond;
@ -23,33 +46,22 @@ import { MATOMO_ID, MATOMO_URL } from 'config';
const isProduction = process.env.NODE_ENV === 'production'; const isProduction = process.env.NODE_ENV === 'production';
const devInternalApis = process.env.LBRY_API_URL && process.env.LBRY_API_URL.includes('dev'); const devInternalApis = process.env.LBRY_API_URL && process.env.LBRY_API_URL.includes('dev');
export const SHARE_INTERNAL = 'shareInternal';
const SHARE_THIRD_PARTY = 'shareThirdParty';
const WATCHMAN_BACKEND_ENDPOINT = 'https://watchman.na-backend.odysee.com/reports/playback'; const WATCHMAN_BACKEND_ENDPOINT = 'https://watchman.na-backend.odysee.com/reports/playback';
const SEND_DATA_TO_WATCHMAN_INTERVAL = 10; // in seconds const SEND_DATA_TO_WATCHMAN_INTERVAL = 10; // in seconds
// @if TARGET='app'
if (isProduction) {
ElectronCookies.enable({
origin: 'https://lbry.tv',
});
}
// @endif
type Analytics = { type Analytics = {
appStartTime: number,
eventStartTime: any,
error: (string) => Promise<any>, error: (string) => Promise<any>,
sentryError: ({} | string, {}) => Promise<any>, sentryError: ({} | string, {}) => Promise<any>,
pageView: (string, ?string) => void,
setUser: (Object) => void, setUser: (Object) => void,
toggleInternal: (boolean, ?boolean) => void, toggleInternal: (boolean, ?boolean) => void,
apiLogView: (string, string, string, ?number, ?() => void) => Promise<any>, apiLogView: (string, string, string, ?number, ?() => void) => Promise<any>,
apiLogPublish: (ChannelClaim | StreamClaim) => void, apiLogPublish: (ChannelClaim | StreamClaim) => void,
apiSyncTags: ({}) => void,
tagFollowEvent: (string, boolean, ?string) => void, tagFollowEvent: (string, boolean, ?string) => void,
playerLoadedEvent: (?boolean) => void, playerLoadedEvent: (string, ?boolean) => void,
playerStartedEvent: (?boolean) => void, playerVideoStartedEvent: (?boolean) => void,
videoStartEvent: (string, number, string, number, string, any, number) => void, videoStartEvent: (?string, number, string, ?number, string, any, ?number, boolean) => void,
videoIsPlaying: (boolean, any) => void, videoIsPlaying: (boolean, any) => void,
videoBufferEvent: ( videoBufferEvent: (
StreamClaim, StreamClaim,
@ -61,18 +73,20 @@ type Analytics = {
userId: string, userId: string,
playerPoweredBy: string, playerPoweredBy: string,
readyState: number, readyState: number,
isLivestream: boolean,
} }
) => Promise<any>, ) => Promise<any>,
adsFetchedEvent: () => void, adsFetchedEvent: () => void,
adsReceivedEvent: (any) => void,
adsErrorEvent: (any) => void,
emailProvidedEvent: () => void, emailProvidedEvent: () => void,
emailVerifiedEvent: () => void, emailVerifiedEvent: () => void,
rewardEligibleEvent: () => void, rewardEligibleEvent: () => void,
startupEvent: () => void, initAppStartTime: (startTime: number) => void,
startupEvent: (time: number) => void,
eventStarted: (name: string, time: number, id?: string) => void,
eventCompleted: (name: string, time: number, id?: string) => void,
purchaseEvent: (number) => void, purchaseEvent: (number) => void,
readyEvent: (number) => void,
openUrlEvent: (string) => void, openUrlEvent: (string) => void,
reportEvent: (string, any) => void,
}; };
type LogPublishParams = { type LogPublishParams = {
@ -84,10 +98,8 @@ type LogPublishParams = {
let internalAnalyticsEnabled: boolean = IS_WEB || false; let internalAnalyticsEnabled: boolean = IS_WEB || false;
// let thirdPartyAnalyticsEnabled: boolean = IS_WEB || false; // let thirdPartyAnalyticsEnabled: boolean = IS_WEB || false;
// @if TARGET='app'
if (window.localStorage.getItem(SHARE_INTERNAL) === 'true') internalAnalyticsEnabled = true; const isGaAllowed = internalAnalyticsEnabled && isProduction;
// if (window.localStorage.getItem(SHARE_THIRD_PARTY) === 'true') thirdPartyAnalyticsEnabled = true;
// @endif
/** /**
* Determine the mobile device type viewing the data * Determine the mobile device type viewing the data
@ -120,7 +132,7 @@ function getDeviceType() {
// variables initialized for watchman // variables initialized for watchman
let amountOfBufferEvents = 0; let amountOfBufferEvents = 0;
let amountOfBufferTimeInMS = 0; let amountOfBufferTimeInMS = 0;
let videoType, userId, claimUrl, playerPoweredBy, videoPlayer, bitrateAsBitsPerSecond; let videoType, userId, claimUrl, playerPoweredBy, videoPlayer, bitrateAsBitsPerSecond, isLivestream;
let lastSentTime; let lastSentTime;
// calculate data for backend, send them, and reset buffer data for next interval // calculate data for backend, send them, and reset buffer data for next interval
@ -137,20 +149,27 @@ async function sendAndResetWatchmanData() {
lastSentTime = new Date(); lastSentTime = new Date();
let protocol; let protocol;
if (videoType === 'application/x-mpegURL') { if (videoType === 'application/x-mpegURL' && !isLivestream) {
protocol = 'hls'; protocol = 'hls';
// get bandwidth if it exists from the texttrack (so it's accurate if user changes quality) // get bandwidth if it exists from the texttrack (so it's accurate if user changes quality)
// $FlowFixMe // $FlowFixMe
bitrateAsBitsPerSecond = videoPlayer.textTracks?.().tracks_[0]?.activeCues[0]?.value?.bandwidth; bitrateAsBitsPerSecond = videoPlayer.tech(true).vhs?.playlists?.media?.().attributes?.BANDWIDTH;
} else if (isLivestream) {
protocol = 'lvs';
// $FlowFixMe
bitrateAsBitsPerSecond = videoPlayer.tech(true).vhs?.playlists?.media?.().attributes?.BANDWIDTH;
} else { } else {
protocol = 'stb'; protocol = 'stb';
} }
// current position in video in MS // current position in video in MS
const positionInVideo = Math.round(videoPlayer.currentTime()) * 1000; const positionInVideo = isLivestream ? 0 : videoPlayer && Math.round(videoPlayer.currentTime()) * 1000;
// get the duration marking the time in the video for relative position calculation // get the duration marking the time in the video for relative position calculation
const totalDurationInSeconds = Math.round(videoPlayer.duration()); const totalDurationInSeconds = isLivestream ? 0 : videoPlayer && Math.round(videoPlayer.duration());
// temp: if buffering over the interval, the duration doesn't reset since we don't get an event
if (amountOfBufferTimeInMS > timeSinceLastIntervalSend) amountOfBufferTimeInMS = timeSinceLastIntervalSend;
// build object for watchman backend // build object for watchman backend
const objectToSend = { const objectToSend = {
@ -162,8 +181,8 @@ async function sendAndResetWatchmanData() {
protocol, protocol,
player: playerPoweredBy, player: playerPoweredBy,
user_id: userId.toString(), user_id: userId.toString(),
position: Math.round(positionInVideo), position: isLivestream ? 0 : Math.round(positionInVideo),
rel_position: Math.round((positionInVideo / (totalDurationInSeconds * 1000)) * 100), rel_position: isLivestream ? 0 : Math.round((positionInVideo / (totalDurationInSeconds * 1000)) * 100),
bitrate: bitrateAsBitsPerSecond, bitrate: bitrateAsBitsPerSecond,
bandwidth: undefined, bandwidth: undefined,
// ...(userDownloadBandwidthInBitsPerSecond && {bandwidth: userDownloadBandwidthInBitsPerSecond}), // add bandwidth if populated // ...(userDownloadBandwidthInBitsPerSecond && {bandwidth: userDownloadBandwidthInBitsPerSecond}), // add bandwidth if populated
@ -208,15 +227,14 @@ async function sendWatchmanData(body) {
}, },
body: JSON.stringify(body), body: JSON.stringify(body),
}); });
return response; return response;
} catch (err) { } catch (err) {}
console.log('ERROR FROM WATCHMAN BACKEND');
console.log(err);
}
} }
const analytics: Analytics = { const analytics: Analytics = {
appStartTime: 0,
eventStartTime: {},
// receive buffer events from tracking plugin and save buffer amounts and times for backend call // receive buffer events from tracking plugin and save buffer amounts and times for backend call
videoBufferEvent: async (claim, data) => { videoBufferEvent: async (claim, data) => {
amountOfBufferEvents = amountOfBufferEvents + 1; amountOfBufferEvents = amountOfBufferEvents + 1;
@ -255,18 +273,26 @@ const analytics: Analytics = {
startWatchmanIntervalIfNotRunning(); startWatchmanIntervalIfNotRunning();
} }
}, },
videoStartEvent: (claimId, duration, poweredBy, passedUserId, canonicalUrl, passedPlayer, videoBitrate) => { videoStartEvent: (
claimId,
timeToStartVideo,
poweredBy,
passedUserId,
canonicalUrl,
passedPlayer,
videoBitrate,
isLivestreamClaim
) => {
// populate values for watchman when video starts // populate values for watchman when video starts
userId = passedUserId; userId = passedUserId;
claimUrl = canonicalUrl; claimUrl = canonicalUrl;
playerPoweredBy = poweredBy; playerPoweredBy = poweredBy;
isLivestream = isLivestreamClaim;
videoType = passedPlayer.currentSource().type; videoType = passedPlayer.currentSource().type;
videoPlayer = passedPlayer; videoPlayer = passedPlayer;
bitrateAsBitsPerSecond = videoBitrate; bitrateAsBitsPerSecond = videoBitrate;
!isLivestreamClaim && sendPromMetric('time_to_start', timeToStartVideo, playerPoweredBy);
sendPromMetric('time_to_start', duration);
sendMatomoEvent('Media', 'TimeToStart', claimId, duration);
}, },
error: (message) => { error: (message) => {
return new Promise((resolve) => { return new Promise((resolve) => {
@ -292,45 +318,17 @@ const analytics: Analytics = {
} }
}); });
}, },
pageView: (path, search) => {
if (internalAnalyticsEnabled) {
const params: { href: string, customDimensions?: Array<{ id: number, value: ?string }> } = { href: `${path}` };
const dimensions = [];
const searchParams = search && new URLSearchParams(search);
if (searchParams && searchParams.get('src')) {
dimensions.push({ id: 1, value: searchParams.get('src') });
}
if (dimensions.length) {
params['customDimensions'] = dimensions;
}
MatomoInstance.trackPageView(params);
}
},
setUser: (userId) => { setUser: (userId) => {
if (internalAnalyticsEnabled && userId) { if (isGaAllowed && userId && window.gtag) {
window._paq.push(['setUserId', String(userId)]); window.gtag('set', { user_id: userId });
// @if TARGET='app'
Native.getAppVersionInfo().then(({ localVersion }) => {
sendMatomoEvent('Version', 'Desktop-Version', localVersion);
});
// @endif
} }
}, },
toggleInternal: (enabled: boolean): void => { toggleInternal: (enabled: boolean): void => {
// Always collect analytics on lbry.tv // Always collect analytics on Odysee for now.
// @if TARGET='app'
internalAnalyticsEnabled = enabled;
window.localStorage.setItem(SHARE_INTERNAL, enabled);
// @endif
}, },
toggleThirdParty: (enabled: boolean): void => { toggleThirdParty: (enabled: boolean): void => {
// Always collect analytics on lbry.tv // Always collect analytics on Odysee for now.
// @if TARGET='app'
// thirdPartyAnalyticsEnabled = enabled;
window.localStorage.setItem(SHARE_THIRD_PARTY, enabled);
// @endif
}, },
apiLogView: (uri, outpoint, claimId, timeToStart) => { apiLogView: (uri, outpoint, claimId, timeToStart) => {
@ -347,7 +345,6 @@ const analytics: Analytics = {
claim_id: claimId, claim_id: claimId,
}; };
// lbry.tv streams from AWS so we don't care about the time to start
if (timeToStart && !IS_WEB) { if (timeToStart && !IS_WEB) {
params.time_to_start = timeToStart; params.time_to_start = timeToStart;
} }
@ -380,104 +377,129 @@ const analytics: Analytics = {
Lbryio.call('event', 'publish', params); Lbryio.call('event', 'publish', params);
} }
}, },
apiSyncTags: (params) => {
if (internalAnalyticsEnabled && isProduction) {
Lbryio.call('content_tags', 'sync', params);
}
},
adsFetchedEvent: () => { adsFetchedEvent: () => {
sendMatomoEvent('Media', 'AdsFetched'); sendGaEvent('ad_fetched');
}, },
adsReceivedEvent: (response) => { playerLoadedEvent: (renderMode, embedded) => {
sendMatomoEvent('Media', 'AdsReceived', JSON.stringify(response)); const RENDER_MODE_TO_EVENT = (renderMode) => {
switch (renderMode) {
case RENDER_MODES.VIDEO:
return 'loaded_video';
case RENDER_MODES.AUDIO:
return 'loaded_audio';
case RENDER_MODES.MARKDOWN:
return 'loaded_markdown';
case RENDER_MODES.IMAGE:
return 'loaded_image';
case 'livestream':
return 'loaded_livestream';
default:
return 'loaded_misc';
}
};
sendGaEvent('player', {
[GA_DIMENSIONS.ACTION]: RENDER_MODE_TO_EVENT(renderMode),
[GA_DIMENSIONS.TYPE]: embedded ? 'embedded' : 'onsite',
});
}, },
adsErrorEvent: (response) => { playerVideoStartedEvent: (embedded) => {
sendMatomoEvent('Media', 'AdsError', JSON.stringify(response)); sendGaEvent('player', {
}, [GA_DIMENSIONS.ACTION]: 'started_video',
playerLoadedEvent: (embedded) => { [GA_DIMENSIONS.TYPE]: embedded ? 'embedded' : 'onsite',
sendMatomoEvent('Player', 'Loaded', embedded ? 'embedded' : 'onsite'); });
},
playerStartedEvent: (embedded) => {
sendMatomoEvent('Player', 'Started', embedded ? 'embedded' : 'onsite');
}, },
tagFollowEvent: (tag, following) => { tagFollowEvent: (tag, following) => {
sendMatomoEvent('Tag', following ? 'Tag-Follow' : 'Tag-Unfollow', tag); sendGaEvent('tags', {
}, [GA_DIMENSIONS.ACTION]: following ? 'follow' : 'unfollow',
channelBlockEvent: (uri, blocked, location) => { [GA_DIMENSIONS.VALUE]: tag,
sendMatomoEvent(blocked ? 'Channel-Hidden' : 'Channel-Unhidden', uri); });
}, },
emailProvidedEvent: () => { emailProvidedEvent: () => {
sendMatomoEvent('Engagement', 'Email-Provided'); sendGaEvent('engagement', {
[GA_DIMENSIONS.TYPE]: 'email_provided',
});
}, },
emailVerifiedEvent: () => { emailVerifiedEvent: () => {
sendMatomoEvent('Engagement', 'Email-Verified'); sendGaEvent('engagement', {
[GA_DIMENSIONS.TYPE]: 'email_verified',
});
}, },
rewardEligibleEvent: () => { rewardEligibleEvent: () => {
sendMatomoEvent('Engagement', 'Reward-Eligible'); sendGaEvent('engagement', {
[GA_DIMENSIONS.TYPE]: 'reward_eligible',
});
}, },
openUrlEvent: (url: string) => { openUrlEvent: (url: string) => {
sendMatomoEvent('Engagement', 'Open-Url', url); sendGaEvent('engagement', {
[GA_DIMENSIONS.TYPE]: 'open_url',
url,
});
}, },
trendingAlgorithmEvent: (trendingAlgorithm: string) => { trendingAlgorithmEvent: (trendingAlgorithm: string) => {
sendMatomoEvent('Engagement', 'Trending-Algorithm', trendingAlgorithm); sendGaEvent('engagement', {
[GA_DIMENSIONS.TYPE]: 'trending_algorithm',
trending_algorithm: trendingAlgorithm,
});
}, },
startupEvent: () => { initAppStartTime: (startTime: number) => {
sendMatomoEvent('Startup', 'Startup'); analytics.appStartTime = startTime;
}, },
readyEvent: (timeToReady: number) => { startupEvent: (time: number) => {
sendMatomoEvent('Startup', 'App-Ready', 'Time', timeToReady); if (analytics.appStartTime !== 0) {
sendGaEvent('diag_app_ready', {
[GA_DIMENSIONS.DURATION_MS]: time - analytics.appStartTime,
});
}
},
eventStarted: (name: string, time: number, id?: string) => {
const key = id || name;
analytics.eventStartTime[key] = time;
},
eventCompleted: (name: string, time: number, id?: string) => {
const key = id || name;
if (analytics.eventStartTime[key]) {
sendGaEvent(name, {
[GA_DIMENSIONS.START_TIME_MS]: analytics.eventStartTime[key] - analytics.appStartTime,
[GA_DIMENSIONS.DURATION_MS]: time - analytics.eventStartTime[key],
[GA_DIMENSIONS.END_TIME_MS]: time - analytics.appStartTime,
});
delete analytics.eventStartTime[key];
}
}, },
purchaseEvent: (purchaseInt: number) => { purchaseEvent: (purchaseInt: number) => {
sendMatomoEvent('Purchase', 'Purchase-Complete', 'someLabel', purchaseInt); sendGaEvent('purchase', {
// https://developers.google.com/analytics/devguides/collection/ga4/reference/events#purchase
[GA_DIMENSIONS.VALUE]: purchaseInt,
});
},
reportEvent: (event: string, params?: { [string]: string | number }) => {
sendGaEvent(event, params);
}, },
}; };
function sendMatomoEvent(category, action, name, value) { function sendGaEvent(event: string, params?: { [string]: string | number }) {
if (internalAnalyticsEnabled) { if (isGaAllowed && window.gtag) {
const event = { category, action, name, value }; window.gtag('event', event, params);
MatomoInstance.trackEvent(event);
} }
} }
function sendPromMetric(name: string, value?: number) { function sendPromMetric(name: string, value?: number, player: string) {
if (IS_WEB) { if (IS_WEB) {
let url = new URL(SDK_API_PATH + '/metric/ui'); let url = new URL(SDK_API_PATH + '/metric/ui');
const params = { name: name, value: value ? value.toString() : '' }; const params = { name: name, value: value ? value.toString() : '', player: player };
url.search = new URLSearchParams(params).toString(); url.search = new URLSearchParams(params).toString();
return fetch(url, { method: 'post' }); return fetch(url, { method: 'post' }).catch(function (error) {});
} }
} }
const MatomoInstance = new MatomoTracker({ // Activate
urlBase: MATOMO_URL, if (isGaAllowed && window.gtag) {
siteId: MATOMO_ID, // optional, default value: `1` window.gtag('consent', 'update', {
// heartBeat: { // optional, enabled by default ad_storage: 'granted',
// active: true, // optional, default value: true analytics_storage: 'granted',
// seconds: 10 // optional, default value: `15 });
// }, }
// linkTracking: false // optional, default value: true
});
// Manually call the first page view
// React Router doesn't include this on `history.listen`
// @if TARGET='web'
analytics.pageView(window.location.pathname + window.location.search, window.location.search);
// @endif
// @if TARGET='app'
analytics.pageView(
window.location.pathname.split('.html')[1] + window.location.search || generateInitialUrl(window.location.hash)
);
// @endif;
// Listen for url changes and report
// This will include search queries
history.listen((location) => {
const { pathname, search } = location;
const page = `${pathname}${search}`;
analytics.pageView(page, search);
});
export default analytics; export default analytics;

View file

@ -1,25 +1,17 @@
// @flow // @flow
import { COMMENT_SERVER_API } from 'config'; import { COMMENT_SERVER_API } from 'config';
// prettier-ignore
const Comments = { const Comments = {
url: COMMENT_SERVER_API, url: COMMENT_SERVER_API,
enabled: Boolean(COMMENT_SERVER_API), enabled: Boolean(COMMENT_SERVER_API),
isCustomServer: false,
setServerUrl: (customUrl: ?string) => {
Comments.url = customUrl === undefined ? COMMENT_SERVER_API : customUrl;
Comments.enabled = Boolean(Comments.url);
Comments.isCustomServer = Comments.url !== COMMENT_SERVER_API;
},
moderation_block: (params: ModerationBlockParams) => fetchCommentsApi('moderation.Block', params), moderation_block: (params: ModerationBlockParams) => fetchCommentsApi('moderation.Block', params),
moderation_unblock: (params: ModerationBlockParams) => fetchCommentsApi('moderation.UnBlock', params), moderation_unblock: (params: ModerationBlockParams) => fetchCommentsApi('moderation.UnBlock', params),
moderation_block_list: (params: BlockedListArgs) => fetchCommentsApi('moderation.BlockedList', params), moderation_block_list: (params: BlockedListArgs) => fetchCommentsApi('moderation.BlockedList', params),
moderation_add_delegate: (params: ModerationAddDelegateParams) => fetchCommentsApi('moderation.AddDelegate', params), moderation_add_delegate: (params: ModerationAddDelegateParams) => fetchCommentsApi('moderation.AddDelegate', params),
moderation_remove_delegate: (params: ModerationRemoveDelegateParams) => moderation_remove_delegate: (params: ModerationRemoveDelegateParams) => fetchCommentsApi('moderation.RemoveDelegate', params),
fetchCommentsApi('moderation.RemoveDelegate', params), moderation_list_delegates: (params: ModerationListDelegatesParams) => fetchCommentsApi('moderation.ListDelegates', params),
moderation_list_delegates: (params: ModerationListDelegatesParams) =>
fetchCommentsApi('moderation.ListDelegates', params),
moderation_am_i: (params: ModerationAmIParams) => fetchCommentsApi('moderation.AmI', params), moderation_am_i: (params: ModerationAmIParams) => fetchCommentsApi('moderation.AmI', params),
comment_list: (params: CommentListParams) => fetchCommentsApi('comment.List', params), comment_list: (params: CommentListParams) => fetchCommentsApi('comment.List', params),
comment_abandon: (params: CommentAbandonParams) => fetchCommentsApi('comment.Abandon', params), comment_abandon: (params: CommentAbandonParams) => fetchCommentsApi('comment.Abandon', params),
@ -39,9 +31,7 @@ const Comments = {
}; };
function fetchCommentsApi(method: string, params: {}) { function fetchCommentsApi(method: string, params: {}) {
if (!Comments.url) { if (!Comments.enabled) {
return Promise.reject(new Error('Commenting server is not set.'));
} else if (!Comments.enabled) {
return Promise.reject('Comments are not currently enabled.'); // eslint-disable-line return Promise.reject('Comments are not currently enabled.'); // eslint-disable-line
} }

View file

@ -1,8 +1,3 @@
import { connect } from 'react-redux';
import IframeReact from './view'; import IframeReact from './view';
const select = state => ({}); export default IframeReact;
const perform = () => ({});
export default connect(select, perform)(IframeReact);

View file

@ -1,6 +1,3 @@
import { connect } from 'react-redux';
import AbandonedChannelPreview from './view'; import AbandonedChannelPreview from './view';
const select = (state, props) => ({}); export default AbandonedChannelPreview;
export default connect(select)(AbandonedChannelPreview);

View file

@ -2,7 +2,7 @@
import React from 'react'; import React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import ChannelThumbnail from 'component/channelThumbnail'; import ChannelThumbnail from 'component/channelThumbnail';
import { parseURI } from 'lbry-redux'; import { parseURI } from 'util/lbryURI';
import ChannelBlockButton from 'component/channelBlockButton'; import ChannelBlockButton from 'component/channelBlockButton';
import ChannelMuteButton from 'component/channelMuteButton'; import ChannelMuteButton from 'component/channelMuteButton';
import SubscribeButton from 'component/subscribeButton'; import SubscribeButton from 'component/subscribeButton';

View file

@ -1,78 +1,65 @@
import { hot } from 'react-hot-loader/root'; import { hot } from 'react-hot-loader/root';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUploadCount } from 'lbryinc'; import {
import { selectGetSyncErrorMessage, selectSyncFatalError } from 'redux/selectors/sync'; selectGetSyncErrorMessage,
import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user'; selectPrefsReady,
import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user'; selectSyncFatalError,
selectSyncIsLocked,
} from 'redux/selectors/sync';
import { doUserSetReferrer } from 'redux/actions/user';
import { doSetLastViewedAnnouncement } from 'redux/actions/content';
import { selectUser, selectUserLocale, selectUserVerifiedEmail, selectHomepageFetched } from 'redux/selectors/user';
import { selectUnclaimedRewards } from 'redux/selectors/rewards'; import { selectUnclaimedRewards } from 'redux/selectors/rewards';
import { doFetchChannelListMine, doFetchCollectionListMine } from 'redux/actions/claims';
import { selectMyChannelClaimIds } from 'redux/selectors/claims';
import { import {
doFetchChannelListMine,
doFetchCollectionListMine,
SETTINGS,
selectMyChannelUrls,
doResolveUris,
} from 'lbry-redux';
import { selectSubscriptions } from 'redux/selectors/subscriptions';
import {
makeSelectClientSetting,
selectLanguage, selectLanguage,
selectLoadedLanguages, selectLoadedLanguages,
selectThemePath, selectThemePath,
selectDefaultChannelClaim,
} from 'redux/selectors/settings'; } from 'redux/selectors/settings';
import { import { selectModal, selectActiveChannelClaim, selectIsReloadRequired } from 'redux/selectors/app';
selectIsUpgradeAvailable, import { selectUploadCount } from 'redux/selectors/publish';
selectAutoUpdateDownloaded, import { doOpenAnnouncements, doSetLanguage, doSetDefaultChannel } from 'redux/actions/settings';
selectModal,
selectActiveChannelClaim,
} from 'redux/selectors/app';
import { doGetWalletSyncPreference, doSetLanguage } from 'redux/actions/settings';
import { doSyncLoop } from 'redux/actions/sync'; import { doSyncLoop } from 'redux/actions/sync';
import { import { doSignIn, doSetIncognito } from 'redux/actions/app';
doDownloadUpgradeRequested,
doSignIn,
doGetAndPopulatePreferences,
doSetActiveChannel,
doSetIncognito,
} from 'redux/actions/app';
import { doFetchModBlockedList, doFetchCommentModAmIList } from 'redux/actions/comments'; import { doFetchModBlockedList, doFetchCommentModAmIList } from 'redux/actions/comments';
import App from './view'; import App from './view';
const select = (state) => ({ const select = (state) => ({
user: selectUser(state), user: selectUser(state),
accessToken: selectAccessToken(state), locale: selectUserLocale(state),
theme: selectThemePath(state), theme: selectThemePath(state),
language: selectLanguage(state), language: selectLanguage(state),
syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state),
languages: selectLoadedLanguages(state), languages: selectLoadedLanguages(state),
autoUpdateDownloaded: selectAutoUpdateDownloaded(state), isReloadRequired: selectIsReloadRequired(state),
isUpgradeAvailable: selectIsUpgradeAvailable(state), prefsReady: selectPrefsReady(state),
syncError: selectGetSyncErrorMessage(state), syncError: selectGetSyncErrorMessage(state),
syncIsLocked: selectSyncIsLocked(state),
uploadCount: selectUploadCount(state), uploadCount: selectUploadCount(state),
rewards: selectUnclaimedRewards(state), rewards: selectUnclaimedRewards(state),
isAuthenticated: selectUserVerifiedEmail(state), isAuthenticated: selectUserVerifiedEmail(state),
currentModal: selectModal(state), currentModal: selectModal(state),
syncFatalError: selectSyncFatalError(state), syncFatalError: selectSyncFatalError(state),
activeChannelClaim: selectActiveChannelClaim(state), activeChannelClaim: selectActiveChannelClaim(state),
myChannelUrls: selectMyChannelUrls(state), myChannelClaimIds: selectMyChannelClaimIds(state),
subscriptions: selectSubscriptions(state), homepageFetched: selectHomepageFetched(state),
defaultChannelClaim: selectDefaultChannelClaim(state),
}); });
const perform = (dispatch) => ({ const perform = {
fetchAccessToken: () => dispatch(doFetchAccessToken()), fetchChannelListMine: doFetchChannelListMine,
fetchChannelListMine: () => dispatch(doFetchChannelListMine()), fetchCollectionListMine: doFetchCollectionListMine,
fetchCollectionListMine: () => dispatch(doFetchCollectionListMine()), setLanguage: doSetLanguage,
setLanguage: (language) => dispatch(doSetLanguage(language)), signIn: doSignIn,
signIn: () => dispatch(doSignIn()), syncLoop: doSyncLoop,
requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()), setReferrer: doUserSetReferrer,
updatePreferences: () => dispatch(doGetAndPopulatePreferences()), setIncognito: doSetIncognito,
getWalletSyncPref: () => dispatch(doGetWalletSyncPreference()), fetchModBlockedList: doFetchModBlockedList,
syncLoop: (noInterval) => dispatch(doSyncLoop(noInterval)), fetchModAmIList: doFetchCommentModAmIList,
setReferrer: (referrer, doClaim) => dispatch(doUserSetReferrer(referrer, doClaim)), doOpenAnnouncements,
setActiveChannelIfNotSet: () => dispatch(doSetActiveChannel()), doSetLastViewedAnnouncement,
setIncognito: () => dispatch(doSetIncognito()), doSetDefaultChannel,
fetchModBlockedList: () => dispatch(doFetchModBlockedList()), };
resolveUris: (uris) => dispatch(doResolveUris(uris)),
fetchModAmIList: () => dispatch(doFetchCommentModAmIList()),
});
export default hot(connect(select, perform)(App)); export default hot(connect(select, perform)(App));

View file

@ -1,27 +1,28 @@
// @flow // @flow
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
import React, { useEffect, useRef, useState, useLayoutEffect } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { lazyImport } from 'util/lazyImport'; import { lazyImport } from 'util/lazyImport';
import classnames from 'classnames'; import { tusUnlockAndNotify, tusHandleTabUpdates } from 'util/tus';
import analytics from 'analytics'; import analytics from 'analytics';
import { buildURI, parseURI } from 'lbry-redux'; import { setSearchUserId } from 'redux/actions/search';
import { SIMPLE_SITE } from 'config'; import { parseURI, buildURI } from 'util/lbryURI';
import { generateGoogleCacheUrl } from 'util/url';
import Router from 'component/router/index'; import Router from 'component/router/index';
import ModalRouter from 'modal/modalRouter';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import { openContextMenu } from 'util/context-menu';
import useKonamiListener from 'util/enhanced-layout'; import useKonamiListener from 'util/enhanced-layout';
import Yrbl from 'component/yrbl';
import FileRenderFloating from 'component/fileRenderFloating'; import FileRenderFloating from 'component/fileRenderFloating';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import usePrevious from 'effects/use-previous'; import usePrevious from 'effects/use-previous';
import Nag from 'component/common/nag';
import REWARDS from 'rewards'; import REWARDS from 'rewards';
import usePersistedState from 'effects/use-persisted-state'; import usePersistedState from 'effects/use-persisted-state';
import useConnectionStatus from 'effects/use-connection-status';
import Spinner from 'component/spinner'; import Spinner from 'component/spinner';
import LANGUAGES from 'constants/languages'; import LANGUAGES from 'constants/languages';
// @if TARGET='app' import AdsSticky from 'web/component/adsSticky';
import useZoom from 'effects/use-zoom'; import YoutubeWelcome from 'web/component/youtubeReferralWelcome';
import useHistoryNav from 'effects/use-history-nav';
// @endif
// @if TARGET='web'
import { import {
useDegradedPerformance, useDegradedPerformance,
STATUS_OK, STATUS_OK,
@ -29,203 +30,268 @@ import {
STATUS_FAILING, STATUS_FAILING,
STATUS_DOWN, STATUS_DOWN,
} from 'web/effects/use-degraded-performance'; } from 'web/effects/use-degraded-performance';
// @endif
import LANGUAGE_MIGRATIONS from 'constants/language-migrations'; import LANGUAGE_MIGRATIONS from 'constants/language-migrations';
import { useIsMobile } from 'effects/use-screensize';
import getLanguagesForCountry from 'constants/country_languages';
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
const FileDrop = lazyImport(() => import('component/fileDrop' /* webpackChunkName: "secondary" */)); const FileDrop = lazyImport(() => import('component/fileDrop' /* webpackChunkName: "fileDrop" */));
const ModalRouter = lazyImport(() => import('modal/modalRouter' /* webpackChunkName: "secondary" */)); const NagContinueFirstRun = lazyImport(() => import('component/nagContinueFirstRun' /* webpackChunkName: "nagCFR" */));
const Nag = lazyImport(() => import('component/common/nag' /* webpackChunkName: "secondary" */)); const NagLocaleSwitch = lazyImport(() => import('component/nagLocaleSwitch' /* webpackChunkName: "nagLocaleSwitch" */));
const NagContinueFirstRun = lazyImport(() =>
import('component/nagContinueFirstRun' /* webpackChunkName: "secondary" */)
);
const OpenInAppLink = lazyImport(() => import('web/component/openInAppLink' /* webpackChunkName: "secondary" */));
// @if TARGET='web'
const NagDataCollection = lazyImport(() =>
import('web/component/nag-data-collection' /* webpackChunkName: "secondary" */)
);
const NagDegradedPerformance = lazyImport(() => const NagDegradedPerformance = lazyImport(() =>
import('web/component/nag-degraded-performance' /* webpackChunkName: "secondary" */) import('web/component/nag-degraded-performance' /* webpackChunkName: "NagDegradedPerformance" */)
); );
const NagNoUser = lazyImport(() => import('web/component/nag-no-user' /* webpackChunkName: "nag-no-user" */)); const NagNoUser = lazyImport(() => import('web/component/nag-no-user' /* webpackChunkName: "nag-no-user" */));
const NagSunset = lazyImport(() => import('web/component/nag-sunset' /* webpackChunkName: "nag-no-user" */)); const NagSunset = lazyImport(() => import('web/component/nag-sunset' /* webpackChunkName: "nag-sunset" */));
const YoutubeWelcome = lazyImport(() =>
import('web/component/youtubeReferralWelcome' /* webpackChunkName: "secondary" */)
);
// @endif
const SyncFatalError = lazyImport(() => import('component/syncFatalError' /* webpackChunkName: "syncFatalError" */)); const SyncFatalError = lazyImport(() => import('component/syncFatalError' /* webpackChunkName: "syncFatalError" */));
const Yrbl = lazyImport(() => import('component/yrbl' /* webpackChunkName: "yrbl" */));
// **************************************************************************** // ****************************************************************************
export const MAIN_WRAPPER_CLASS = 'main-wrapper'; export const MAIN_WRAPPER_CLASS = 'main-wrapper';
export const IS_MAC = navigator.userAgent.indexOf('Mac OS X') !== -1; export const IS_MAC = navigator.userAgent.indexOf('Mac OS X') !== -1;
// button numbers pulled from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button // const imaLibraryPath = 'https://imasdk.googleapis.com/js/sdkloader/ima3.js';
const MOUSE_BACK_BTN = 3; const oneTrustScriptSrc = 'https://cdn.cookielaw.org/scripttemplates/otSDKStub.js';
const MOUSE_FORWARD_BTN = 4;
const LATEST_PATH = `/$/${PAGES.LATEST}/`;
const LIVE_PATH = `/$/${PAGES.LIVE_NOW}/`;
const EMBED_PATH = `/$/${PAGES.EMBED}/`;
type Props = { type Props = {
language: string, language: string,
languages: Array<string>, languages: Array<string>,
theme: string, theme: string,
user: ?{ id: string, has_verified_email: boolean, is_reward_approved: boolean }, user: ?{ id: string, has_verified_email: boolean, is_reward_approved: boolean },
location: { pathname: string, hash: string, search: string }, locale: ?LocaleInfo,
history: { location: { pathname: string, hash: string, search: string, hostname: string, reload: () => void },
goBack: () => void, history: { push: (string) => void, location: { pathname: string }, replace: (string) => void },
goForward: () => void,
index: number,
length: number,
push: (string) => void,
},
fetchAccessToken: () => void,
fetchChannelListMine: () => void, fetchChannelListMine: () => void,
fetchCollectionListMine: () => void, fetchCollectionListMine: () => void,
signIn: () => void, signIn: () => void,
requestDownloadUpgrade: () => void,
onSignedIn: () => void,
setLanguage: (string) => void, setLanguage: (string) => void,
isUpgradeAvailable: boolean, isReloadRequired: boolean,
autoUpdateDownloaded: boolean,
updatePreferences: () => Promise<any>,
getWalletSyncPref: () => Promise<any>,
uploadCount: number, uploadCount: number,
balance: ?number, balance: ?number,
syncIsLocked: boolean,
syncError: ?string, syncError: ?string,
syncEnabled: boolean, prefsReady: boolean,
rewards: Array<Reward>, rewards: Array<Reward>,
setReferrer: (string, boolean) => void, setReferrer: (string, boolean) => void,
isAuthenticated: boolean, isAuthenticated: boolean,
socketConnect: () => void,
syncLoop: (?boolean) => void, syncLoop: (?boolean) => void,
currentModal: any, currentModal: any,
syncFatalError: boolean, syncFatalError: boolean,
activeChannelClaim: ?ChannelClaim, activeChannelClaim: ?ChannelClaim,
myChannelUrls: ?Array<string>, myChannelClaimIds: ?Array<string>,
subscriptions: Array<Subscription>,
setActiveChannelIfNotSet: () => void,
setIncognito: (boolean) => void, setIncognito: (boolean) => void,
fetchModBlockedList: () => void, fetchModBlockedList: () => void,
resolveUris: (Array<string>) => void,
fetchModAmIList: () => void, fetchModAmIList: () => void,
homepageFetched: boolean,
defaultChannelClaim: ?any,
doOpenAnnouncements: () => void,
doSetLastViewedAnnouncement: (hash: string) => void,
doSetDefaultChannel: (claimId: string) => void,
}; };
function App(props: Props) { function App(props: Props) {
const { const {
theme, theme,
user, user,
fetchAccessToken, locale,
location,
fetchChannelListMine, fetchChannelListMine,
fetchCollectionListMine, fetchCollectionListMine,
signIn, signIn,
autoUpdateDownloaded, isReloadRequired,
isUpgradeAvailable,
requestDownloadUpgrade,
uploadCount, uploadCount,
history, history,
syncError, syncError,
syncIsLocked,
prefsReady,
language, language,
languages, languages,
setLanguage, setLanguage,
updatePreferences,
getWalletSyncPref,
rewards, rewards,
setReferrer, setReferrer,
isAuthenticated, isAuthenticated,
syncLoop, syncLoop,
currentModal, currentModal,
syncFatalError, syncFatalError,
myChannelUrls, myChannelClaimIds,
activeChannelClaim, activeChannelClaim,
setActiveChannelIfNotSet,
setIncognito, setIncognito,
fetchModBlockedList, fetchModBlockedList,
resolveUris,
subscriptions,
fetchModAmIList, fetchModAmIList,
homepageFetched,
defaultChannelClaim,
doOpenAnnouncements,
doSetLastViewedAnnouncement,
doSetDefaultChannel,
} = props; } = props;
const isMobile = useIsMobile();
const appRef = useRef(); const appRef = useRef();
const isEnhancedLayout = useKonamiListener(); const isEnhancedLayout = useKonamiListener();
const [hasSignedIn, setHasSignedIn] = useState(false); const [hasSignedIn, setHasSignedIn] = useState(false);
const [readyForSync, setReadyForSync] = useState(false);
const [readyForPrefs, setReadyForPrefs] = useState(false);
const hasVerifiedEmail = user && Boolean(user.has_verified_email); const hasVerifiedEmail = user && Boolean(user.has_verified_email);
const isRewardApproved = user && user.is_reward_approved; const isRewardApproved = user && user.is_reward_approved;
const previousHasVerifiedEmail = usePrevious(hasVerifiedEmail); const previousHasVerifiedEmail = usePrevious(hasVerifiedEmail);
const previousRewardApproved = usePrevious(isRewardApproved); const previousRewardApproved = usePrevious(isRewardApproved);
// @if TARGET='web'
const [showAnalyticsNag, setShowAnalyticsNag] = usePersistedState('analytics-nag', true); const [localeLangs, setLocaleLangs] = React.useState();
const [localeSwitchDismissed] = usePersistedState('locale-switch-dismissed', false);
const [lbryTvApiStatus, setLbryTvApiStatus] = useState(STATUS_OK); const [lbryTvApiStatus, setLbryTvApiStatus] = useState(STATUS_OK);
// @endif
const { pathname, hash, search } = props.location; const { pathname, hash, search, hostname } = location;
const [upgradeNagClosed, setUpgradeNagClosed] = useState(false); const [retryingSync, setRetryingSync] = useState(false);
const [resolvedSubscriptions, setResolvedSubscriptions] = useState(false); const [langRenderKey, setLangRenderKey] = useState(0);
const [sidebarOpen] = usePersistedState('sidebar', true);
const [seenSunsestMessage, setSeenSunsetMessage] = usePersistedState('lbrytv-sunset', false); const [seenSunsestMessage, setSeenSunsetMessage] = usePersistedState('lbrytv-sunset', false);
const showUpgradeButton =
(autoUpdateDownloaded || (process.platform === 'linux' && isUpgradeAvailable)) && !upgradeNagClosed;
// referral claiming // referral claiming
const referredRewardAvailable = rewards && rewards.some((reward) => reward.reward_type === REWARDS.TYPE_REFEREE); const referredRewardAvailable = rewards && rewards.some((reward) => reward.reward_type === REWARDS.TYPE_REFEREE);
const urlParams = new URLSearchParams(search); const urlParams = new URLSearchParams(search);
const rawReferrerParam = urlParams.get('r'); const rawReferrerParam = urlParams.get('r');
const fromLbrytvParam = urlParams.get('sunset'); const fromLbrytvParam = urlParams.get('sunset');
const sanitizedReferrerParam = rawReferrerParam && rawReferrerParam.replace(':', '#'); const sanitizedReferrerParam = rawReferrerParam && rawReferrerParam.replace(':', '#');
const shouldHideNag = pathname.startsWith(`/$/${PAGES.EMBED}`) || pathname.startsWith(`/$/${PAGES.AUTH_VERIFY}`); const embedPath = pathname.startsWith(EMBED_PATH);
const shouldHideNag = embedPath || pathname.startsWith(`/$/${PAGES.AUTH_VERIFY}`);
const userId = user && user.id; const userId = user && user.id;
const useCustomScrollbar = !IS_MAC; const hasMyChannels = myChannelClaimIds && myChannelClaimIds.length > 0;
const hasMyChannels = myChannelUrls && myChannelUrls.length > 0; const hasNoChannels = myChannelClaimIds && myChannelClaimIds.length === 0;
const hasNoChannels = myChannelUrls && myChannelUrls.length === 0;
const shouldMigrateLanguage = LANGUAGE_MIGRATIONS[language]; const shouldMigrateLanguage = LANGUAGE_MIGRATIONS[language];
const hasActiveChannelClaim = activeChannelClaim !== undefined; const renderFiledrop = !isMobile && isAuthenticated;
const isPersonalized = !IS_WEB || hasVerifiedEmail; const connectionStatus = useConnectionStatus();
const renderFiledrop = !IS_WEB || isAuthenticated;
const urlPath = pathname + hash;
const latestContentPath = urlPath.startsWith(LATEST_PATH);
const liveContentPath = urlPath.startsWith(LIVE_PATH);
const featureParam = urlParams.get('feature');
const embedLatestPath = embedPath && (featureParam === PAGES.LATEST || featureParam === PAGES.LIVE_NOW);
const isNewestPath = latestContentPath || liveContentPath || embedLatestPath;
let path;
if (isNewestPath) {
path = urlPath.replace(embedLatestPath ? EMBED_PATH : latestContentPath ? LATEST_PATH : LIVE_PATH, '');
} else {
// Remove the leading "/" added by the browser
path = urlPath.slice(1);
}
path = path.replace(/:/g, '#');
if (isNewestPath && !path.startsWith('@')) {
path = `@${path}`;
}
if (search && search.startsWith('?q=cache:')) {
generateGoogleCacheUrl(search, path);
}
let uri; let uri;
try { try {
const newpath = buildURI(parseURI(pathname.slice(1).replace(/:/g, '#'))); // here queryString and startTime are "removed" from the buildURI process
uri = newpath + hash; // to build only the uri itself
} catch (e) {} const { queryString, startTime, ...parsedUri } = parseURI(path);
uri = buildURI({ ...parsedUri });
} catch (e) {
const match = path.match(/[#/:]/);
// @if TARGET='web' if (!path.startsWith('$/') && match && match.index) {
function handleAnalyticsDismiss() { uri = `lbry://${path.slice(0, match.index)}`;
setShowAnalyticsNag(false); }
}
function getStatusNag() {
// Handle "offline" first. Everything else is meaningless if it's offline.
if (!connectionStatus.online) {
return <Nag type="helpful" message={__('You are offline. Check your internet connection.')} />;
}
// Only 1 nag is possible, so show the most important:
if (user === null) {
return <NagNoUser />;
}
if (lbryTvApiStatus === STATUS_DEGRADED || lbryTvApiStatus === STATUS_FAILING) {
if (!shouldHideNag) {
return <NagDegradedPerformance onClose={() => setLbryTvApiStatus(STATUS_OK)} />;
}
}
if (syncFatalError) {
if (!retryingSync) {
return (
<Nag
type="error"
message={__('Failed to synchronize settings. Wait a while before retrying.')}
actionText={__('Retry')}
onClick={() => {
syncLoop(true);
setRetryingSync(true);
setTimeout(() => setRetryingSync(false), 4000);
}}
/>
);
}
} else if (isReloadRequired) {
return (
<Nag
message={__('A new version of Odysee is available.')}
actionText={__('Refresh')}
onClick={() => window.location.reload()}
/>
);
}
if (localeLangs && !embedPath && !localeSwitchDismissed && homepageFetched) {
const noLanguageSet = language === 'en' && languages.length === 1;
return <NagLocaleSwitch localeLangs={localeLangs} noLanguageSet={noLanguageSet} onFrontPage={pathname === '/'} />;
}
} }
// @endif
useEffect(() => { useEffect(() => {
if (userId) { if (userId) {
analytics.setUser(userId); analytics.setUser(userId);
setSearchUserId(userId);
} }
}, [userId]); }, [userId]);
useEffect(() => { useEffect(() => {
if (!uploadCount) return; if (syncIsLocked) {
const handleBeforeUnload = (event) => { const handleBeforeUnload = (event) => {
event.preventDefault(); event.preventDefault();
event.returnValue = 'magic'; // without setting this to something it doesn't work event.returnValue = __('There are unsaved settings. Exit the Settings Page to finalize them.');
}; };
window.addEventListener('beforeunload', handleBeforeUnload); window.addEventListener('beforeunload', handleBeforeUnload);
return () => window.removeEventListener('beforeunload', handleBeforeUnload); return () => window.removeEventListener('beforeunload', handleBeforeUnload);
}
}, [syncIsLocked]);
useEffect(() => {
if (!uploadCount) return;
const handleUnload = (event) => tusUnlockAndNotify();
const handleBeforeUnload = (event) => {
event.preventDefault();
event.returnValue = __('There are pending uploads.'); // without setting this to something it doesn't work
};
window.addEventListener('unload', handleUnload);
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('unload', handleUnload);
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, [uploadCount]); }, [uploadCount]);
// allows user to navigate history using the forward and backward buttons on a mouse
useEffect(() => { useEffect(() => {
const handleForwardAndBackButtons = (e) => { if (!uploadCount) return;
switch (e.button) {
case MOUSE_BACK_BTN: const onStorageUpdate = (e) => tusHandleTabUpdates(e.key);
history.index > 0 && history.goBack(); window.addEventListener('storage', onStorageUpdate);
break;
case MOUSE_FORWARD_BTN: return () => window.removeEventListener('storage', onStorageUpdate);
history.index < history.length - 1 && history.goForward(); }, [uploadCount]);
break;
}
};
window.addEventListener('mouseup', handleForwardAndBackButtons);
return () => window.removeEventListener('mouseup', handleForwardAndBackButtons);
});
// allows user to pause miniplayer using the spacebar without the page scrolling down // allows user to pause miniplayer using the spacebar without the page scrolling down
useEffect(() => { useEffect(() => {
@ -238,16 +304,6 @@ function App(props: Props) {
return () => window.removeEventListener('keydown', handleKeyPress); return () => window.removeEventListener('keydown', handleKeyPress);
}, []); }, []);
// Enable ctrl +/- zooming on Desktop.
// @if TARGET='app'
useZoom();
// @endif
// Enable 'Alt + Left/Right' for history navigation on Desktop.
// @if TARGET='app'
useHistoryNav(history);
// @endif
useEffect(() => { useEffect(() => {
if (referredRewardAvailable && sanitizedReferrerParam && isRewardApproved) { if (referredRewardAvailable && sanitizedReferrerParam && isRewardApproved) {
setReferrer(sanitizedReferrerParam, true); setReferrer(sanitizedReferrerParam, true);
@ -263,13 +319,11 @@ function App(props: Props) {
ReactModal.setAppElement(wrapperElement); ReactModal.setAppElement(wrapperElement);
} }
fetchAccessToken();
// @if TARGET='app' // @if TARGET='app'
fetchChannelListMine(); // This is fetched after a user is signed in on web fetchChannelListMine(); // This is fetched after a user is signed in on web
fetchCollectionListMine(); fetchCollectionListMine();
// @endif // @endif
}, [appRef, fetchAccessToken, fetchChannelListMine, fetchCollectionListMine]); }, [appRef, fetchChannelListMine, fetchCollectionListMine]);
useEffect(() => { useEffect(() => {
// $FlowFixMe // $FlowFixMe
@ -277,9 +331,12 @@ function App(props: Props) {
}, [theme]); }, [theme]);
useEffect(() => { useEffect(() => {
if (hasMyChannels && !hasActiveChannelClaim) { // $FlowFixMe
setActiveChannelIfNotSet(); document.body.style.overflowY = currentModal ? 'hidden' : '';
} else if (hasNoChannels) { }, [currentModal]);
useEffect(() => {
if (hasNoChannels) {
setIncognito(true); setIncognito(true);
} }
@ -287,7 +344,14 @@ function App(props: Props) {
fetchModBlockedList(); fetchModBlockedList();
fetchModAmIList(); fetchModAmIList();
} }
}, [hasMyChannels, hasNoChannels, hasActiveChannelClaim, setActiveChannelIfNotSet, setIncognito]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [hasMyChannels, hasNoChannels, setIncognito]);
useEffect(() => {
if (hasMyChannels && activeChannelClaim && !defaultChannelClaim && prefsReady) {
doSetDefaultChannel(activeChannelClaim.claim_id);
}
}, [activeChannelClaim, defaultChannelClaim, doSetDefaultChannel, hasMyChannels, prefsReady]);
useEffect(() => { useEffect(() => {
// $FlowFixMe // $FlowFixMe
@ -325,12 +389,11 @@ function App(props: Props) {
} }
}, [previousRewardApproved, isRewardApproved]); }, [previousRewardApproved, isRewardApproved]);
// Load IMA3 SDK for aniview: DISABLED FOR NOW // Load IMA3 SDK for aniview
// @if TARGET='web'
// useEffect(() => { // useEffect(() => {
// if (ENABLE_PREROLL_ADS) { // if (!isAuthenticated && SHOW_ADS) {
// const script = document.createElement('script'); // const script = document.createElement('script');
// script.src = `https://imasdk.googleapis.com/js/sdkloader/ima3.js`; // script.src = imaLibraryPath;
// script.async = true; // script.async = true;
// // $FlowFixMe // // $FlowFixMe
// document.body.appendChild(script); // document.body.appendChild(script);
@ -339,47 +402,84 @@ function App(props: Props) {
// document.body.removeChild(script); // document.body.removeChild(script);
// }; // };
// } // }
// }); // }, []);
// @endif
// @if TARGET='app' // add OneTrust script
useEffect(() => { useEffect(() => {
if (updatePreferences && getWalletSyncPref && readyForPrefs) { // don't add script for embedded content
getWalletSyncPref() function inIframe() {
.then(() => updatePreferences()) try {
.then(() => { return window.self !== window.top;
setReadyForSync(true); } catch (e) {
}); return true;
} }
}, [updatePreferences, getWalletSyncPref, setReadyForSync, readyForPrefs, hasVerifiedEmail]); }
// @endif
if (inIframe() || !locale || !locale.gdpr_required) {
return;
}
// $FlowFixMe
const useProductionOneTrust = process.env.NODE_ENV === 'production' && hostname === 'odysee.com';
const script = document.createElement('script');
script.src = oneTrustScriptSrc;
script.setAttribute('charset', 'UTF-8');
if (useProductionOneTrust) {
script.setAttribute('data-domain-script', '8a792d84-50a5-4b69-b080-6954ad4d4606');
} else {
script.setAttribute('data-domain-script', '8a792d84-50a5-4b69-b080-6954ad4d4606-test');
}
const secondScript = document.createElement('script');
// OneTrust asks to add this
secondScript.innerHTML = 'function OptanonWrapper() { }';
// $FlowFixMe
document.head.appendChild(script);
// $FlowFixMe
document.head.appendChild(secondScript);
return () => {
try {
// $FlowFixMe
document.head.removeChild(script);
// $FlowFixMe
document.head.removeChild(secondScript);
} catch (err) {
// eslint-disable-next-line no-console
// console.log(err); <-- disabling this ... it's clogging up Sentry logs.
}
};
// (one time after locale is fetched)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [locale]);
useEffect(() => {
if (locale) {
const countryCode = locale.country;
const langs = getLanguagesForCountry(countryCode) || [];
const supportedLangs = langs.filter((lang) => lang !== 'en' && SUPPORTED_LANGUAGES[lang]);
if (supportedLangs.length > 0) {
setLocaleLangs(supportedLangs);
}
}
}, [locale]);
// ready for sync syncs, however after signin when hasVerifiedEmail, that syncs too. // ready for sync syncs, however after signin when hasVerifiedEmail, that syncs too.
useEffect(() => { useEffect(() => {
// signInSyncPref is cleared after sharedState loop. // signInSyncPref is cleared after sharedState loop.
const syncLoopWithoutInterval = () => syncLoop(true); const syncLoopWithoutInterval = () => syncLoop(true);
if (readyForSync && hasVerifiedEmail) { if (hasSignedIn && hasVerifiedEmail) {
// In case we are syncing. // In case we are syncing.
syncLoop(); syncLoop();
// @if TARGET='web'
window.addEventListener('focus', syncLoopWithoutInterval); window.addEventListener('focus', syncLoopWithoutInterval);
// @endif
} }
// @if TARGET='web'
return () => { return () => {
window.removeEventListener('focus', syncLoopWithoutInterval); window.removeEventListener('focus', syncLoopWithoutInterval);
}; };
// @endif }, [hasSignedIn, hasVerifiedEmail, syncLoop]);
}, [readyForSync, hasVerifiedEmail, syncLoop]);
// We know someone is logging in or not when we get their user object
// We'll use this to determine when it's time to pull preferences
// This will no longer work if desktop users no longer get a user object from lbryinc
useEffect(() => {
if (user) {
setReadyForPrefs(true);
}
}, [user, setReadyForPrefs]);
useEffect(() => { useEffect(() => {
if (syncError && isAuthenticated && !pathname.includes(PAGES.AUTH_WALLET_PASSWORD) && !currentModal) { if (syncError && isAuthenticated && !pathname.includes(PAGES.AUTH_WALLET_PASSWORD) && !currentModal) {
@ -388,30 +488,34 @@ function App(props: Props) {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [syncError, pathname, isAuthenticated]); }, [syncError, pathname, isAuthenticated]);
useEffect(() => {
if (prefsReady) {
doOpenAnnouncements();
}
}, [prefsReady]);
useEffect(() => {
window.clearLastViewedAnnouncement = () => {
console.log('Clearing history. Please wait ...');
doSetLastViewedAnnouncement('');
};
}, []);
// Keep this at the end to ensure initial setup effects are run first // Keep this at the end to ensure initial setup effects are run first
useEffect(() => { useEffect(() => {
if (!hasSignedIn && hasVerifiedEmail) { if (!hasSignedIn && hasVerifiedEmail) {
signIn(); signIn();
setHasSignedIn(true); setHasSignedIn(true);
if (IS_WEB) setReadyForSync(true);
} }
}, [hasVerifiedEmail, signIn, hasSignedIn]); }, [hasVerifiedEmail, signIn, hasSignedIn]);
// batch resolve subscriptions to be used by the sideNavigation component.
// add it here so that it only resolves the first time, despite route changes.
// useLayoutEffect because it has to be executed before the sideNavigation component requests them
useLayoutEffect(() => {
if (sidebarOpen && isPersonalized && subscriptions && !resolvedSubscriptions) {
setResolvedSubscriptions(true);
resolveUris(subscriptions.map((sub) => sub.uri));
}
}, [sidebarOpen, isPersonalized, resolvedSubscriptions, subscriptions, resolveUris, setResolvedSubscriptions]);
// @if TARGET='web'
useDegradedPerformance(setLbryTvApiStatus, user); useDegradedPerformance(setLbryTvApiStatus, user);
// @endif
// @if TARGET='web' useEffect(() => {
// When language is changed or translations are fetched, we render.
setLangRenderKey(Date.now());
}, [language, languages]);
// Require an internal-api user on lbry.tv // Require an internal-api user on lbry.tv
// This also prevents the site from loading in the un-authed state while we wait for internal-apis to return for the first time // This also prevents the site from loading in the un-authed state while we wait for internal-apis to return for the first time
// It's not needed on desktop since there is no un-authed state // It's not needed on desktop since there is no un-authed state
@ -422,76 +526,43 @@ function App(props: Props) {
</div> </div>
); );
} }
// @endif
if (syncFatalError) { if (connectionStatus.online && lbryTvApiStatus === STATUS_DOWN) {
// TODO: Rename `SyncFatalError` since it has nothing to do with syncing.
return ( return (
<React.Suspense fallback={null}> <React.Suspense fallback={null}>
<SyncFatalError <SyncFatalError lbryTvApiStatus={lbryTvApiStatus} />
// @if TARGET='web'
lbryTvApiStatus={lbryTvApiStatus}
// @endif
/>
</React.Suspense> </React.Suspense>
); );
} }
return ( return (
<div <div className={MAIN_WRAPPER_CLASS} ref={appRef} key={langRenderKey}>
className={classnames(MAIN_WRAPPER_CLASS, { {lbryTvApiStatus === STATUS_DOWN ? (
// @if TARGET='app'
[`${MAIN_WRAPPER_CLASS}--mac`]: IS_MAC,
// @endif
[`${MAIN_WRAPPER_CLASS}--scrollbar`]: useCustomScrollbar,
})}
ref={appRef}
onContextMenu={IS_WEB ? undefined : (e) => openContextMenu(e)}
>
{IS_WEB && lbryTvApiStatus === STATUS_DOWN ? (
<React.Suspense fallback={null}>
<Yrbl <Yrbl
className="main--empty" className="main--empty"
title={__('lbry.tv is currently down')} title={__('odysee.com is currently down')}
subtitle={__('My wheel broke, but the good news is that someone from LBRY is working on it.')} subtitle={__('My wheel broke, but the good news is that someone from LBRY is working on it.')}
/> />
</React.Suspense>
) : ( ) : (
<React.Fragment> <React.Fragment>
<Router /> <AdsSticky uri={uri} />
<React.Suspense fallback={null}> <Router uri={uri} embedLatestPath={embedLatestPath} />
<ModalRouter /> <ModalRouter />
{renderFiledrop && <FileDrop />}
</React.Suspense> <React.Suspense fallback={null}>{renderFiledrop && <FileDrop />}</React.Suspense>
<FileRenderFloating /> <FileRenderFloating />
<React.Suspense fallback={null}> <React.Suspense fallback={null}>
{isEnhancedLayout && <Yrbl className="yrbl--enhanced" />} {isEnhancedLayout && <Yrbl className="yrbl--enhanced" />}
{/* @if TARGET='app' */}
{showUpgradeButton && (
<Nag
message={__('An upgrade is available.')}
actionText={__('Install Now')}
onClick={requestDownloadUpgrade}
onClose={() => setUpgradeNagClosed(true)}
/>
)}
{/* @endif */}
{/* @if TARGET='web' */}
<YoutubeWelcome /> <YoutubeWelcome />
{!SIMPLE_SITE && !shouldHideNag && <OpenInAppLink uri={uri} />}
{!shouldHideNag && <NagContinueFirstRun />} {!shouldHideNag && <NagContinueFirstRun />}
{fromLbrytvParam && !seenSunsestMessage && !shouldHideNag && ( {fromLbrytvParam && !seenSunsestMessage && !shouldHideNag && (
<NagSunset email={hasVerifiedEmail} onClose={() => setSeenSunsetMessage(true)} /> <NagSunset email={hasVerifiedEmail} onClose={() => setSeenSunsetMessage(true)} />
)} )}
{(lbryTvApiStatus === STATUS_DEGRADED || lbryTvApiStatus === STATUS_FAILING) && !shouldHideNag && ( {getStatusNag()}
<NagDegradedPerformance onClose={() => setLbryTvApiStatus(STATUS_OK)} />
)}
{!SIMPLE_SITE && lbryTvApiStatus === STATUS_OK && showAnalyticsNag && !shouldHideNag && (
<NagDataCollection onClose={handleAnalyticsDismiss} />
)}
{user === null && <NagNoUser />}
{/* @endif */}
</React.Suspense> </React.Suspense>
</React.Fragment> </React.Fragment>
)} )}

View file

@ -1,8 +1,8 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectClaimForUri } from 'lbry-redux'; import { makeSelectClaimForUri, selectClaimIsNsfwForUri } from 'redux/selectors/claims';
import { withRouter } from 'react-router';
import AutoplayCountdown from './view'; import AutoplayCountdown from './view';
import { selectModal } from 'redux/selectors/app'; import { selectModal } from 'redux/selectors/app';
import { doOpenModal } from 'redux/actions/app';
/* /*
AutoplayCountdown does not fetch it's own next content to play, it relies on <RecommendedContent> being rendered. AutoplayCountdown does not fetch it's own next content to play, it relies on <RecommendedContent> being rendered.
@ -11,6 +11,11 @@ import { selectModal } from 'redux/selectors/app';
const select = (state, props) => ({ const select = (state, props) => ({
nextRecommendedClaim: makeSelectClaimForUri(props.nextRecommendedUri)(state), nextRecommendedClaim: makeSelectClaimForUri(props.nextRecommendedUri)(state),
modal: selectModal(state), modal: selectModal(state),
isMature: selectClaimIsNsfwForUri(state, props.uri),
}); });
export default withRouter(connect(select, null)(AutoplayCountdown)); const perform = {
doOpenModal,
};
export default connect(select, perform)(AutoplayCountdown);

View file

@ -6,33 +6,40 @@ import I18nMessage from 'component/i18nMessage';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import debounce from 'util/debounce'; import debounce from 'util/debounce';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import * as MODALS from 'constants/modal_types';
const DEBOUNCE_SCROLL_HANDLER_MS = 150; const DEBOUNCE_SCROLL_HANDLER_MS = 150;
const CLASSNAME_AUTOPLAY_COUNTDOWN = 'autoplay-countdown'; const CLASSNAME_AUTOPLAY_COUNTDOWN = 'autoplay-countdown';
type Props = { type Props = {
history: { push: (string) => void }, uri?: string,
nextRecommendedClaim: ?StreamClaim, nextRecommendedClaim: ?StreamClaim,
nextRecommendedUri: string, nextRecommendedUri: string,
modal: { id: string, modalProps: {} }, modal: { id: string, modalProps: {} },
skipPaid: boolean, skipPaid: boolean,
skipMature: boolean,
isMature: boolean,
doNavigate: () => void, doNavigate: () => void,
doReplay: () => void, doReplay: () => void,
doPrevious: () => void, doPrevious: () => void,
onCanceled: () => void, onCanceled: () => void,
doOpenModal: (id: string, props: {}) => void,
}; };
function AutoplayCountdown(props: Props) { function AutoplayCountdown(props: Props) {
const { const {
uri,
nextRecommendedUri, nextRecommendedUri,
nextRecommendedClaim, nextRecommendedClaim,
history: { push },
modal, modal,
skipPaid, skipPaid,
skipMature,
isMature,
doNavigate, doNavigate,
doReplay, doReplay,
doPrevious, doPrevious,
onCanceled, onCanceled,
doOpenModal,
} = props; } = props;
const nextTitle = nextRecommendedClaim && nextRecommendedClaim.value && nextRecommendedClaim.value.title; const nextTitle = nextRecommendedClaim && nextRecommendedClaim.value && nextRecommendedClaim.value.title;
@ -44,14 +51,25 @@ function AutoplayCountdown(props: Props) {
const [timerPaused, setTimerPaused] = React.useState(false); const [timerPaused, setTimerPaused] = React.useState(false);
const anyModalPresent = modal !== undefined && modal !== null; const anyModalPresent = modal !== undefined && modal !== null;
const isTimerPaused = timerPaused || anyModalPresent; const isTimerPaused = timerPaused || anyModalPresent;
const shouldSkipMature = skipMature && isMature;
const skipCurrentVideo = skipPaid || shouldSkipMature;
function isAnyInputFocused() {
const activeElement = document.activeElement;
const inputTypes = ['input', 'select', 'textarea'];
return activeElement && inputTypes.includes(activeElement.tagName.toLowerCase());
}
function shouldPauseAutoplay() { function shouldPauseAutoplay() {
// TODO: use ref instead querySelector
const elm = document.querySelector(`.${CLASSNAME_AUTOPLAY_COUNTDOWN}`); const elm = document.querySelector(`.${CLASSNAME_AUTOPLAY_COUNTDOWN}`);
return elm && elm.getBoundingClientRect().top < 0; return isAnyInputFocused() || (elm && elm.getBoundingClientRect().top < 0);
} }
function getMsgPlayingNext() { function getMsgPlayingNext() {
if (skipPaid) { if (shouldSkipMature) {
return __('Skipping mature content in %seconds_left% seconds...', { seconds_left: timer });
} else if (skipPaid) {
return __('Playing next free content in %seconds_left% seconds...', { seconds_left: timer }); return __('Playing next free content in %seconds_left% seconds...', { seconds_left: timer });
} else { } else {
return __('Playing in %seconds_left% seconds...', { seconds_left: timer }); return __('Playing in %seconds_left% seconds...', { seconds_left: timer });
@ -75,14 +93,14 @@ function AutoplayCountdown(props: Props) {
React.useEffect(() => { React.useEffect(() => {
let interval; let interval;
if (!timerCanceled && nextRecommendedUri) { if (!timerCanceled && nextRecommendedUri) {
if (isTimerPaused) { if (isTimerPaused || isAnyInputFocused()) {
clearInterval(interval); clearInterval(interval);
setTimer(countdownTime); setTimer(countdownTime);
} else { } else {
interval = setInterval(() => { interval = setInterval(() => {
const newTime = timer - 1; const newTime = timer - 1;
if (newTime === 0) { if (newTime === 0) {
if (skipPaid) setTimer(countdownTime); if (skipCurrentVideo) setTimer(countdownTime);
doNavigate(); doNavigate();
} else { } else {
setTimer(timer - 1); setTimer(timer - 1);
@ -93,7 +111,7 @@ function AutoplayCountdown(props: Props) {
return () => { return () => {
clearInterval(interval); clearInterval(interval);
}; };
}, [timer, doNavigate, push, timerCanceled, isTimerPaused, nextRecommendedUri, skipPaid]); }, [doNavigate, isTimerPaused, nextRecommendedUri, skipCurrentVideo, timer, timerCanceled]);
if (timerCanceled || !nextRecommendedUri) { if (timerCanceled || !nextRecommendedUri) {
return null; return null;
@ -131,7 +149,7 @@ function AutoplayCountdown(props: Props) {
/> />
</div> </div>
)} )}
{skipPaid && doPrevious && ( {skipCurrentVideo && doPrevious && (
<div> <div>
<Button <Button
label={__('Play Previous')} label={__('Play Previous')}
@ -143,12 +161,16 @@ function AutoplayCountdown(props: Props) {
)} )}
<div> <div>
<Button <Button
label={skipPaid ? __('Purchase?') : __('Replay?')} label={shouldSkipMature ? undefined : skipPaid ? __('Purchase?') : __('Replay?')}
button="link" button="link"
iconRight={skipPaid ? ICONS.WALLET : ICONS.REPLAY} icon={shouldSkipMature ? undefined : skipPaid ? ICONS.WALLET : ICONS.REPLAY}
onClick={() => { onClick={() => {
setTimerCanceled(true); setTimerCanceled(true);
if (skipPaid) {
doOpenModal(MODALS.AFFIRM_PURCHASE, { uri, cancelCb: () => setTimerCanceled(false) });
} else {
doReplay(); doReplay();
}
}} }}
/> />
</div> </div>

View file

@ -118,7 +118,7 @@ export default function BlockList(props: Props) {
return ( return (
<> <>
<div className="help--notice">{help}</div> <div className="help--notice">{help}</div>
<div className="section"> <div className="section" style={{ zIndex: '4' }}>
<SearchList <SearchList
list={localList} list={localList}
placeholder={__('e.g. odysee')} placeholder={__('e.g. odysee')}

View file

@ -2,11 +2,13 @@ import Button from './view';
import React, { forwardRef } from 'react'; import React, { forwardRef } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectHasChannels } from 'redux/selectors/claims';
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
pathname: state.router.location.pathname, pathname: state.router.location.pathname,
emailVerified: selectUserVerifiedEmail(state), emailVerified: selectUserVerifiedEmail(state),
user: selectUser(state), user: selectUser(state),
hasChannels: selectHasChannels(state),
}); });
const ConnectedButton = connect(mapStateToProps)(Button); const ConnectedButton = connect(mapStateToProps)(Button);

View file

@ -19,6 +19,7 @@ type Props = {
disabled: ?boolean, disabled: ?boolean,
children: ?Node, children: ?Node,
navigate: ?string, navigate: ?string,
navigateTarget?: string,
className: ?string, className: ?string,
description: ?string, description: ?string,
type: string, type: string,
@ -35,6 +36,8 @@ type Props = {
pathname: string, pathname: string,
emailVerified: boolean, emailVerified: boolean,
requiresAuth: ?boolean, requiresAuth: ?boolean,
requiresChannel: ?boolean,
hasChannels: boolean,
myref: any, myref: any,
dispatch: any, dispatch: any,
'aria-label'?: string, 'aria-label'?: string,
@ -59,6 +62,7 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
disabled, disabled,
children, children,
navigate, navigate,
navigateTarget,
className, className,
description, description,
button, button,
@ -67,6 +71,8 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
activeClass, activeClass,
emailVerified, emailVerified,
requiresAuth, requiresAuth,
requiresChannel,
hasChannels,
myref, myref,
dispatch, // <button> doesn't know what to do with dispatch dispatch, // <button> doesn't know what to do with dispatch
pathname, pathname,
@ -139,15 +145,25 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
)} )}
{children && children} {children && children}
{iconRight && <Icon icon={iconRight} iconColor={iconColor} size={size} />} {iconRight && <Icon icon={iconRight} iconColor={iconColor} size={iconSize || size} />}
</span> </span>
); );
// check if the link is for odysee.com
function isAnOdyseeLink(urlString) {
return (
urlString && (urlString.indexOf('https://odysee.com') !== -1 || urlString.indexOf('http://odysee.com') !== -1)
);
}
// if it's an internal link we won't open a new tab
const isAnInternalLink = (href || navigate) && (isAnOdyseeLink(href) || isAnOdyseeLink(navigate));
if (href || (navigate && navigate.startsWith('http'))) { if (href || (navigate && navigate.startsWith('http'))) {
// TODO: replace the below with an outbound link tracker for matomo // TODO: replace the below with an outbound link tracker for matomo
return ( return (
<a <a
target="_blank" target={navigateTarget || (isAnInternalLink ? '' : '_blank')}
rel="noopener noreferrer" rel="noopener noreferrer"
href={href || navigate} href={href || navigate}
className={combinedClassName} className={combinedClassName}
@ -183,8 +199,12 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
} }
} }
if (requiresAuth && !emailVerified) { if ((requiresAuth && !emailVerified) || (requiresChannel && !hasChannels)) {
let redirectUrl = `/$/${PAGES.AUTH}?redirect=${pathname}`; // requiresChannel can be used for both requiresAuth and requiresChannel,
// since if the button requiresChannel, it also implies it requiresAuth in order to proceed
// so using requiresChannel means: unauth users are sent to signup, auth users to create channel
const page = !emailVerified ? PAGES.AUTH : PAGES.CHANNEL_NEW;
let redirectUrl = `/$/${page}?redirect=${pathname}`;
if (authSrc) { if (authSrc) {
redirectUrl += `&src=${authSrc}`; redirectUrl += `&src=${authSrc}`;

View file

@ -0,0 +1,37 @@
import { connect } from 'react-redux';
import { doCollectionEdit } from 'redux/actions/collections';
import { selectCollectionForIdHasClaimUrl, selectUrlsForCollectionId } from 'redux/selectors/collections';
import { selectClaimForUri } from 'redux/selectors/claims';
import * as COLLECTIONS_CONSTS from 'constants/collections';
import ButtonAddToQueue from './view';
import { doToast } from 'redux/actions/notifications';
import { doUriInitiatePlay, doSetPlayingUri } from 'redux/actions/content';
import { selectPlayingUri } from 'redux/selectors/content';
const select = (state, props) => {
const { uri } = props;
const playingUri = selectPlayingUri(state);
const { collectionId } = playingUri.collection || {};
const { permanent_url: playingUrl } = selectClaimForUri(state, playingUri.uri) || {};
return {
playingUri,
playingUrl,
hasClaimInQueue: selectCollectionForIdHasClaimUrl(state, COLLECTIONS_CONSTS.QUEUE_ID, uri),
hasPlayingUriInQueue: Boolean(
playingUrl && selectCollectionForIdHasClaimUrl(state, COLLECTIONS_CONSTS.QUEUE_ID, playingUrl)
),
playingCollectionUrls:
collectionId && collectionId !== COLLECTIONS_CONSTS.QUEUE_ID && selectUrlsForCollectionId(state, collectionId),
};
};
const perform = {
doToast,
doCollectionEdit,
doUriInitiatePlay,
doSetPlayingUri,
};
export default connect(select, perform)(ButtonAddToQueue);

View file

@ -0,0 +1,97 @@
// @flow
import * as ICONS from 'constants/icons';
import React from 'react';
import Button from 'component/button';
import * as COLLECTIONS_CONSTS from 'constants/collections';
import { MenuItem } from '@reach/menu-button';
import Icon from 'component/common/icon';
type Props = {
uri: string,
focusable: boolean,
menuItem?: boolean,
// -- redux --
hasClaimInQueue: boolean,
hasPlayingUriInQueue: boolean,
playingUri: PlayingUri,
playingUrl: ?string,
playingCollectionUrls: ?Array<string>,
doToast: (props: { message: string }) => void,
doCollectionEdit: (id: string, any) => void,
doUriInitiatePlay: (playingOptions: PlayingUri, isPlayable?: boolean, isFloating?: boolean) => void,
doSetPlayingUri: (props: any) => void,
};
function ButtonAddToQueue(props: Props) {
const {
uri,
focusable = true,
menuItem,
hasClaimInQueue,
hasPlayingUriInQueue,
playingUri,
playingUrl,
playingCollectionUrls,
doToast,
doCollectionEdit,
doUriInitiatePlay,
doSetPlayingUri,
} = props;
function handleQueue(e) {
if (e) e.preventDefault();
doToast({ message: hasClaimInQueue ? __('Item removed from Queue') : __('Item added to Queue') });
const itemsToAdd = playingCollectionUrls || [playingUrl];
doCollectionEdit(COLLECTIONS_CONSTS.QUEUE_ID, {
uris: playingUrl && playingUrl !== uri && !hasPlayingUriInQueue ? [...itemsToAdd, uri] : [uri],
remove: hasClaimInQueue,
type: 'playlist',
});
if (!hasClaimInQueue) {
const paramsToAdd = {
collection: { collectionId: COLLECTIONS_CONSTS.QUEUE_ID },
source: COLLECTIONS_CONSTS.QUEUE_ID,
};
if (playingUrl) {
// adds the queue collection id to the playingUri data so it can be used and updated by other components
if (!hasPlayingUriInQueue) doSetPlayingUri({ ...playingUri, ...paramsToAdd });
} else {
// There is nothing playing and added a video to queue -> the first item will play on the floating player with the list open
doUriInitiatePlay({ uri, ...paramsToAdd }, true, true);
}
}
}
// label that is shown after hover
const label = !hasClaimInQueue ? __('Add to Queue') : __('In Queue');
if (menuItem) {
return (
<MenuItem className="comment__menu-option" onSelect={handleQueue}>
<div className="menu__link">
<Icon aria-hidden icon={hasClaimInQueue ? ICONS.PLAYLIST_FILLED : ICONS.PLAYLIST} />
{hasClaimInQueue ? __('In Queue') : __('Add to Queue')}
</div>
</MenuItem>
);
}
return (
<div className="claim-preview__hover-actions third-item">
<Button
title={__('Queue Mode')}
label={label}
className="button--file-action"
icon={hasClaimInQueue ? ICONS.PLAYLIST_FILLED : ICONS.PLAYLIST_ADD}
onClick={(e) => handleQueue(e)}
tabIndex={focusable ? 0 : -1}
/>
</div>
);
}
export default ButtonAddToQueue;

View file

@ -1,5 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectMetadataItemForUri, makeSelectClaimForUri } from 'lbry-redux'; import { makeSelectMetadataItemForUri, makeSelectClaimForUri } from 'redux/selectors/claims';
import { selectUser } from 'redux/selectors/user';
import ChannelAbout from './view'; import ChannelAbout from './view';
const select = (state, props) => ({ const select = (state, props) => ({
@ -8,6 +9,7 @@ const select = (state, props) => ({
website: makeSelectMetadataItemForUri(props.uri, 'website_url')(state), website: makeSelectMetadataItemForUri(props.uri, 'website_url')(state),
email: makeSelectMetadataItemForUri(props.uri, 'email')(state), email: makeSelectMetadataItemForUri(props.uri, 'email')(state),
languages: makeSelectMetadataItemForUri(props.uri, 'languages')(state), languages: makeSelectMetadataItemForUri(props.uri, 'languages')(state),
user: selectUser(state),
}); });
export default connect(select, null)(ChannelAbout); export default connect(select, null)(ChannelAbout);

View file

@ -17,6 +17,7 @@ type Props = {
email: ?string, email: ?string,
website: ?string, website: ?string,
languages: Array<string>, languages: Array<string>,
user: ?User,
}; };
const formatEmail = (email: string) => { const formatEmail = (email: string) => {
@ -29,8 +30,9 @@ const formatEmail = (email: string) => {
}; };
function ChannelAbout(props: Props) { function ChannelAbout(props: Props) {
const { claim, uri, description, email, website, languages } = props; const { claim, uri, description, email, website, languages, user } = props;
const claimId = claim && claim.claim_id; const claimId = claim && claim.claim_id;
const canView = user && user.global_mod;
return ( return (
<div className="card"> <div className="card">
@ -94,7 +96,7 @@ function ChannelAbout(props: Props) {
<div className="media__info-text media__info-text--constrained">{claim.claim_id}</div> <div className="media__info-text media__info-text--constrained">{claim.claim_id}</div>
</div> </div>
<label>{__('Staked LBRY Credits')}</label> <label>{__('Staked Credits')}</label>
<div className="media__info-text"> <div className="media__info-text">
<CreditAmount <CreditAmount
badge={false} badge={false}
@ -111,8 +113,7 @@ function ChannelAbout(props: Props) {
/> />
)} )}
</div> </div>
{canView && <YoutubeBadge channelClaimId={claimId} />}
<YoutubeBadge channelClaimId={claimId} />
</Fragment> </Fragment>
</section> </section>
</div> </div>

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectClaimIdForUri } from 'lbry-redux'; import { selectClaimIdForUri } from 'redux/selectors/claims';
import { import {
doCommentModUnBlock, doCommentModUnBlock,
doCommentModBlock, doCommentModBlock,
@ -43,7 +43,7 @@ const select = (state, props) => {
isBlocked, isBlocked,
isToggling, isToggling,
isBlockingOrUnBlocking: makeSelectUriIsBlockingOrUnBlocking(props.uri)(state), isBlockingOrUnBlocking: makeSelectUriIsBlockingOrUnBlocking(props.uri)(state),
creatorId: makeSelectClaimIdForUri(props.creatorUri)(state), creatorId: selectClaimIdForUri(state, props.creatorUri),
}; };
}; };

Some files were not shown because too many files have changed in this diff Show more